aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCory Barker <cobark@google.com>2022-06-30 19:56:47 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2022-06-30 19:56:47 +0000
commit3cdf346579adc9751acb7fb28bb0e1f56db98f91 (patch)
tree2db9ca57cd1f0315199ba9a28933f62c7f4ee0a9
parentd94a43ad0c3cc20b78a9d49798f9f90ccd5feb7d (diff)
parente3b7c39c0037458d68bf9f374bf3812fd6f7edf4 (diff)
downloadAFLplusplus-3cdf346579adc9751acb7fb28bb0e1f56db98f91.tar.gz
Merge remote-tracking branch upstream-stable am: 847ac56921 am: 1f1113e9e4 am: 6a557435e5 am: e3b7c39c00
Original change: https://android-review.googlesource.com/c/platform/external/AFLplusplus/+/2133182 Change-Id: Ibbfe3396138a41b3ddb9547ea0e098d7615bfe88 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--.clang-format148
-rwxr-xr-x.custom-format.py144
-rw-r--r--.dockerignore65
-rw-r--r--.github/FUNDING.yml13
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.md32
-rw-r--r--.github/ISSUE_TEMPLATE/feature_request.md20
-rw-r--r--.github/workflows/build_aflplusplus_docker.yaml30
-rw-r--r--.github/workflows/ci.yml53
-rw-r--r--.github/workflows/codeql-analysis.yml32
-rw-r--r--.github/workflows/rust_custom_mutator.yml30
-rw-r--r--.gitignore99
-rw-r--r--Android.bp418
-rw-r--r--CITATION.cff31
-rw-r--r--CONTRIBUTING.md59
l---------Changelog.md1
-rw-r--r--Dockerfile81
-rw-r--r--GNUmakefile741
-rw-r--r--GNUmakefile.gcc_plugin198
-rw-r--r--GNUmakefile.llvm529
-rw-r--r--LICENSE437
-rw-r--r--METADATA24
-rw-r--r--MODULE_LICENSE_APACHE20
-rw-r--r--Makefile42
-rw-r--r--OWNERS8
-rw-r--r--README.md255
-rw-r--r--TODO.md35
-rwxr-xr-xafl-cmin542
-rwxr-xr-xafl-cmin.bash493
-rwxr-xr-xafl-persistent-config133
-rwxr-xr-xafl-plot328
-rwxr-xr-xafl-system-config137
-rwxr-xr-xafl-whatsup307
-rwxr-xr-xafl-wine-trace80
l---------config.h1
-rw-r--r--dictionaries/README.md42
-rw-r--r--dictionaries/aff.dict73
-rw-r--r--dictionaries/ass.dict112
-rw-r--r--dictionaries/atom.dict33
-rw-r--r--dictionaries/av1_dc.dict5
-rw-r--r--dictionaries/bash.dict152
-rw-r--r--dictionaries/bdf.dict30
-rw-r--r--dictionaries/bmp.dict10
-rw-r--r--dictionaries/bz2.dict3
-rw-r--r--dictionaries/creole.dict14
-rw-r--r--dictionaries/css.dict354
-rw-r--r--dictionaries/csv.dict6
-rw-r--r--dictionaries/dds.dict35
-rw-r--r--dictionaries/djvu.dict34
-rw-r--r--dictionaries/docommand.dict688
-rw-r--r--dictionaries/exif.dict222
-rw-r--r--dictionaries/fbs.dict42
-rw-r--r--dictionaries/ftp.dict124
-rw-r--r--dictionaries/gif.dict18
-rw-r--r--dictionaries/graphviz.dict373
-rw-r--r--dictionaries/heif.dict76
-rw-r--r--dictionaries/hoextdown.dict49
-rw-r--r--dictionaries/html_tags.dict160
-rw-r--r--dictionaries/http.dict119
-rw-r--r--dictionaries/icc.dict591
-rw-r--r--dictionaries/iccprofile.dict25
-rw-r--r--dictionaries/icns.dict43
-rw-r--r--dictionaries/initfile.dict688
-rw-r--r--dictionaries/jbig2.dict98
-rw-r--r--dictionaries/jpeg.dict22
-rw-r--r--dictionaries/jpeg2000.dict22
-rw-r--r--dictionaries/js.dict107
-rw-r--r--dictionaries/json.dict61
-rw-r--r--dictionaries/jsonnet.dict60
-rw-r--r--dictionaries/markdown.dict28
-rw-r--r--dictionaries/math.dict20
-rw-r--r--dictionaries/mathml.dict279
-rw-r--r--dictionaries/mp4.dict82
-rw-r--r--dictionaries/mysqld.dict1
-rw-r--r--dictionaries/ogg.dict36
-rw-r--r--dictionaries/openexr.dict57
-rw-r--r--dictionaries/otf.dict963
-rw-r--r--dictionaries/pbm.dict29
-rw-r--r--dictionaries/pcap.dict10
-rw-r--r--dictionaries/pdf.dict1466
-rw-r--r--dictionaries/perl.dict16
-rw-r--r--dictionaries/png.dict38
-rw-r--r--dictionaries/proj4.dict249
-rw-r--r--dictionaries/protobuf.dict40
-rw-r--r--dictionaries/ps.dict433
-rw-r--r--dictionaries/psd.dict180
-rw-r--r--dictionaries/regexp.dict244
-rw-r--r--dictionaries/riff.dict17
-rw-r--r--dictionaries/rss.dict31
-rw-r--r--dictionaries/rst.dict21
-rw-r--r--dictionaries/rtf.dict408
-rw-r--r--dictionaries/sas.dict37
-rw-r--r--dictionaries/spss.dict46
-rw-r--r--dictionaries/sql.dict282
-rw-r--r--dictionaries/stata.dict22
-rw-r--r--dictionaries/svg.dict170
-rw-r--r--dictionaries/tex.dict122
-rw-r--r--dictionaries/theme-load-fuzz.dict9
-rw-r--r--dictionaries/tiff.dict51
-rw-r--r--dictionaries/tokener_parse_ex.dict18
-rw-r--r--dictionaries/toml.dict22
-rw-r--r--dictionaries/type42.dict25
-rw-r--r--dictionaries/url.dict62
-rw-r--r--dictionaries/utf8.dict73
-rw-r--r--dictionaries/vcf.dict119
-rw-r--r--dictionaries/vhd.dict10
-rw-r--r--dictionaries/vpx_dec.dict8
-rw-r--r--dictionaries/wav.dict25
-rw-r--r--dictionaries/webm.dict152
-rw-r--r--dictionaries/webp.dict20
-rw-r--r--dictionaries/wkt.dict35
-rw-r--r--dictionaries/x86.dict1885
-rw-r--r--dictionaries/xml.dict72
-rw-r--r--dictionaries/xml_UTF_16.dict103
-rw-r--r--dictionaries/xml_UTF_16BE.dict103
-rw-r--r--dictionaries/xml_UTF_16LE.dict103
-rw-r--r--dictionaries/xpath.dict66
-rw-r--r--dictionaries/xslt.dict118
-rw-r--r--dictionaries/yaml.dict79
-rw-r--r--dictionaries/yara.dict196
-rw-r--r--dictionaries/zip.dict3
-rw-r--r--docs/COPYING202
-rw-r--r--docs/Changelog.md3111
-rw-r--r--docs/FAQ.md257
-rw-r--r--docs/INSTALL.md182
-rw-r--r--docs/README.md65
-rw-r--r--docs/afl-fuzz_approach.md543
-rw-r--r--docs/best_practices.md192
-rw-r--r--docs/custom_mutators.md311
-rw-r--r--docs/env_variables.md812
-rw-r--r--docs/features.md118
-rw-r--r--docs/fuzzing_binary-only_targets.md310
-rw-r--r--docs/fuzzing_in_depth.md949
-rw-r--r--docs/ideas.md57
-rw-r--r--docs/important_changes.md60
-rw-r--r--docs/resources/0_fuzzing_process_overview.drawio.svg4
-rw-r--r--docs/resources/1_instrument_target.drawio.svg4
-rw-r--r--docs/resources/2_prepare_campaign.drawio.svg4
-rw-r--r--docs/resources/3_fuzz_target.drawio.svg4
-rw-r--r--docs/resources/4_manage_campaign.drawio.svg4
-rw-r--r--docs/resources/afl_gzip.pngbin0 -> 594870 bytes
-rw-r--r--docs/resources/grafana-afl++.json1816
-rw-r--r--docs/resources/screenshot.pngbin0 -> 144422 bytes
-rw-r--r--docs/resources/statsd-grafana.pngbin0 -> 163646 bytes
-rw-r--r--docs/rpc_statsd.md190
-rw-r--r--docs/third_party_tools.md59
-rw-r--r--docs/tutorials.md40
-rw-r--r--dynamic_list.txt56
-rw-r--r--include/afl-as.h775
-rw-r--r--include/afl-fuzz.h1269
-rw-r--r--include/afl-prealloc.h143
-rw-r--r--include/alloc-inl.h779
-rw-r--r--include/android-ashmem.h84
-rw-r--r--include/cmplog.h89
-rw-r--r--include/common.h136
-rw-r--r--include/config.h510
-rw-r--r--include/coverage-32.h112
-rw-r--r--include/coverage-64.h194
-rw-r--r--include/debug.h405
-rw-r--r--include/envs.h236
-rw-r--r--include/forkserver.h225
-rw-r--r--include/hash.h114
-rw-r--r--include/list.h183
-rw-r--r--include/sharedmem.h63
-rw-r--r--include/snapshot-inl.h115
-rw-r--r--include/types.h196
-rw-r--r--include/xxhash.h6269
-rw-r--r--instrumentation/Makefile2
-rw-r--r--instrumentation/README.cmplog.md44
-rw-r--r--instrumentation/README.gcc_plugin.md102
-rw-r--r--instrumentation/README.instrument_list.md131
-rw-r--r--instrumentation/README.laf-intel.md49
-rw-r--r--instrumentation/README.llvm.md278
-rw-r--r--instrumentation/README.lto.md364
-rw-r--r--instrumentation/README.persistent_mode.md198
-rw-r--r--instrumentation/SanitizerCoverageLTO.so.cc1791
-rw-r--r--instrumentation/SanitizerCoveragePCGUARD.so.cc1551
-rw-r--r--instrumentation/afl-compiler-rt.o.c2317
-rw-r--r--instrumentation/afl-llvm-common.cc600
-rw-r--r--instrumentation/afl-llvm-common.h60
-rw-r--r--instrumentation/afl-llvm-dict2file.so.cc746
-rw-r--r--instrumentation/afl-llvm-lto-instrumentlist.so.cc175
-rw-r--r--instrumentation/afl-llvm-pass.so.cc1105
-rw-r--r--instrumentation/afl-llvm-rt-lto.o.c27
-rw-r--r--instrumentation/cmplog-instructions-pass.cc713
-rw-r--r--instrumentation/cmplog-routines-pass.cc793
-rw-r--r--instrumentation/cmplog-switches-pass.cc478
-rw-r--r--instrumentation/compare-transform-pass.so.cc775
-rw-r--r--instrumentation/llvm-alternative-coverage.h21
-rw-r--r--instrumentation/split-compares-pass.so.cc1654
-rw-r--r--instrumentation/split-switches-pass.so.cc541
-rw-r--r--src/README.md29
-rw-r--r--src/afl-analyze.c1154
-rw-r--r--src/afl-as.c657
-rw-r--r--src/afl-cc.c2201
-rw-r--r--src/afl-common.c1246
-rw-r--r--src/afl-forkserver.c1691
-rw-r--r--src/afl-fuzz-bitmap.c824
-rw-r--r--src/afl-fuzz-cmplog.c87
-rw-r--r--src/afl-fuzz-extras.c828
-rw-r--r--src/afl-fuzz-init.c2960
-rw-r--r--src/afl-fuzz-mutators.c545
-rw-r--r--src/afl-fuzz-one.c5735
-rw-r--r--src/afl-fuzz-python.c894
-rw-r--r--src/afl-fuzz-queue.c1354
-rw-r--r--src/afl-fuzz-redqueen.c2936
-rw-r--r--src/afl-fuzz-run.c1022
-rw-r--r--src/afl-fuzz-state.c649
-rw-r--r--src/afl-fuzz-stats.c2249
-rw-r--r--src/afl-fuzz-statsd.c275
-rw-r--r--src/afl-fuzz.c2659
-rw-r--r--src/afl-gotcpu.c322
-rw-r--r--src/afl-ld-lto.c365
-rw-r--r--src/afl-performance.c110
-rw-r--r--src/afl-sharedmem.c367
-rw-r--r--src/afl-showmap.c1464
-rw-r--r--src/afl-tmin.c1354
-rw-r--r--test-instr.c71
-rwxr-xr-xtest/checkcommit.sh41
-rwxr-xr-xtest/test-all.sh25
-rwxr-xr-xtest/test-basic.sh262
-rw-r--r--test/test-cmplog.c43
-rw-r--r--test/test-compcov.c62
-rw-r--r--test/test-custom-mutator.c20
-rwxr-xr-xtest/test-custom-mutators.sh125
-rw-r--r--test/test-dlopen.c39
-rw-r--r--test/test-floatingpoint.c33
-rwxr-xr-xtest/test-fpExtra.sh39
-rw-r--r--test/test-fp_Infcases.c124
-rw-r--r--test/test-fp_NaNcases.c86
-rw-r--r--test/test-fp_cases.c213
-rw-r--r--test/test-fp_minusZerocases.c35
-rwxr-xr-xtest/test-frida-mode.sh111
-rwxr-xr-xtest/test-gcc-plugin.sh116
-rw-r--r--test/test-int_cases.c443
-rwxr-xr-xtest/test-libextensions.sh41
-rwxr-xr-xtest/test-llvm-lto.sh81
-rwxr-xr-xtest/test-llvm.sh299
-rw-r--r--test/test-multiple-mutators.c23
-rwxr-xr-xtest/test-performance.sh239
-rwxr-xr-xtest/test-post.sh14
-rwxr-xr-xtest/test-pre.sh143
-rwxr-xr-xtest/test-qemu-mode.sh214
-rw-r--r--test/test-uint_cases.c232
-rwxr-xr-xtest/test-unicorn-mode.sh112
-rwxr-xr-xtest/test-unittests.sh11
-rw-r--r--test/test-unsigaction.c31
-rw-r--r--test/unittests/unit_hash.c80
-rw-r--r--test/unittests/unit_list.c140
-rw-r--r--test/unittests/unit_maybe_alloc.c227
-rw-r--r--test/unittests/unit_preallocable.c122
-rw-r--r--test/unittests/unit_rand.c90
-rw-r--r--testcases/README.md17
-rw-r--r--testcases/archives/common/ar/small_archive.a8
-rw-r--r--testcases/archives/common/bzip2/small_archive.bz2bin0 -> 176 bytes
-rw-r--r--testcases/archives/common/cab/small_archive.cabbin0 -> 220 bytes
-rw-r--r--testcases/archives/common/compress/small_archive.Zbin0 -> 168 bytes
-rw-r--r--testcases/archives/common/cpio/small_archive.cpiobin0 -> 512 bytes
-rw-r--r--testcases/archives/common/gzip/small_archive.gzbin0 -> 159 bytes
-rw-r--r--testcases/archives/common/lzo/small_archive.lzobin0 -> 217 bytes
-rw-r--r--testcases/archives/common/rar/small_archive.rarbin0 -> 230 bytes
-rw-r--r--testcases/archives/common/tar/small_archive.tarbin0 -> 2048 bytes
-rw-r--r--testcases/archives/common/xz/small_archive.xzbin0 -> 228 bytes
-rw-r--r--testcases/archives/common/zip/small_archive.zipbin0 -> 289 bytes
-rw-r--r--testcases/archives/exotic/arj/small_archive.arjbin0 -> 269 bytes
-rw-r--r--testcases/archives/exotic/lha/small_archive.lhabin0 -> 182 bytes
-rw-r--r--testcases/archives/exotic/lrzip/small_archive.lrzbin0 -> 260 bytes
-rw-r--r--testcases/archives/exotic/lzip/small_archive.lzbin0 -> 195 bytes
-rw-r--r--testcases/archives/exotic/lzma/small_archive.lzmabin0 -> 182 bytes
-rw-r--r--testcases/archives/exotic/rzip/small_archive.rzbin0 -> 262 bytes
-rw-r--r--testcases/archives/exotic/zoo/small_archive.zoobin0 -> 336 bytes
-rw-r--r--testcases/images/bmp/not_kitty.bmpbin0 -> 630 bytes
-rw-r--r--testcases/images/gif/not_kitty.gifbin0 -> 198 bytes
-rw-r--r--testcases/images/ico/not_kitty.icobin0 -> 367 bytes
-rw-r--r--testcases/images/jp2/not_kitty.jp2bin0 -> 293 bytes
-rw-r--r--testcases/images/jpeg/not_kitty.jpgbin0 -> 413 bytes
-rw-r--r--testcases/images/jxr/not_kitty.jxrbin0 -> 498 bytes
-rw-r--r--testcases/images/png/not_kitty.pngbin0 -> 218 bytes
-rw-r--r--testcases/images/png/not_kitty_alpha.pngbin0 -> 376 bytes
-rw-r--r--testcases/images/png/not_kitty_gamma.pngbin0 -> 228 bytes
-rw-r--r--testcases/images/png/not_kitty_icc.pngbin0 -> 427 bytes
-rw-r--r--testcases/images/tiff/not_kitty.tiffbin0 -> 448 bytes
-rw-r--r--testcases/images/webp/not_kitty.webpbin0 -> 226 bytes
-rw-r--r--testcases/multimedia/h264/small_movie.mp4bin0 -> 1267 bytes
-rw-r--r--testcases/others/elf/small_exec.elfbin0 -> 324 bytes
-rw-r--r--testcases/others/js/small_script.js1
-rw-r--r--testcases/others/pcap/small_capture.pcapbin0 -> 114 bytes
-rw-r--r--testcases/others/pdf/small.pdf2
-rw-r--r--testcases/others/rtf/small_document.rtf1
-rw-r--r--testcases/others/sql/simple_queries.sql3
-rw-r--r--testcases/others/text/hello_world.txt1
-rw-r--r--testcases/others/xml/small_document.xml1
l---------types.h1
-rw-r--r--utils/README.md75
-rw-r--r--utils/afl_network_proxy/GNUmakefile50
-rw-r--r--utils/afl_network_proxy/Makefile2
-rw-r--r--utils/afl_network_proxy/README.md64
-rw-r--r--utils/afl_network_proxy/afl-network-client.c417
-rw-r--r--utils/afl_network_proxy/afl-network-server.c686
-rw-r--r--utils/afl_proxy/Makefile7
-rw-r--r--utils/afl_proxy/README.md9
-rw-r--r--utils/afl_proxy/afl-proxy.c251
-rw-r--r--utils/afl_untracer/Makefile16
-rw-r--r--utils/afl_untracer/README.md66
-rw-r--r--utils/afl_untracer/TODO2
-rw-r--r--utils/afl_untracer/afl-untracer.c781
-rw-r--r--utils/afl_untracer/ghidra_get_patchpoints.java84
-rw-r--r--utils/afl_untracer/ida_get_patchpoints.py63
-rw-r--r--utils/afl_untracer/libtestinstr.c35
-rw-r--r--utils/afl_untracer/patches.txt34
-rw-r--r--utils/aflpp_driver/GNUmakefile52
-rw-r--r--utils/aflpp_driver/Makefile2
-rw-r--r--utils/aflpp_driver/README.md43
-rw-r--r--utils/aflpp_driver/aflpp_driver.c374
-rw-r--r--utils/aflpp_driver/aflpp_driver_test.c24
-rw-r--r--utils/aflpp_driver/aflpp_qemu_driver.c42
-rw-r--r--utils/aflpp_driver/aflpp_qemu_driver_hook.c31
-rwxr-xr-xutils/analysis_scripts/queue2csv.sh122
-rw-r--r--utils/argv_fuzzing/Makefile58
-rw-r--r--utils/argv_fuzzing/README.md16
-rw-r--r--utils/argv_fuzzing/argv-fuzz-inl.h90
-rw-r--r--utils/argv_fuzzing/argvfuzz.c49
-rwxr-xr-xutils/asan_cgroups/limit_memory.sh157
-rw-r--r--utils/bash_shellshock/shellshock-fuzz.diff59
-rw-r--r--utils/canvas_harness/canvas_harness.html170
-rwxr-xr-xutils/clang_asm_normalize/as75
-rwxr-xr-xutils/crash_triage/triage_crashes.sh118
-rw-r--r--utils/defork/Makefile64
-rw-r--r--utils/defork/README.md11
-rw-r--r--utils/defork/defork.c51
-rw-r--r--utils/defork/forking_target.c49
-rwxr-xr-xutils/distributed_fuzzing/sync_script.sh97
-rw-r--r--utils/libdislocator/Makefile44
-rw-r--r--utils/libdislocator/README.md70
-rw-r--r--utils/libdislocator/libdislocator.so.c572
-rw-r--r--utils/libpng_no_checksum/libpng-nocrc.patch15
-rw-r--r--utils/libtokencap/Makefile94
-rw-r--r--utils/libtokencap/README.md69
-rw-r--r--utils/libtokencap/libtokencap.so.c798
-rw-r--r--utils/persistent_mode/Makefile10
-rw-r--r--utils/persistent_mode/persistent_demo.c118
-rw-r--r--utils/persistent_mode/persistent_demo_new.c123
-rw-r--r--utils/persistent_mode/test-instr.c75
-rw-r--r--utils/plot_ui/Makefile10
-rw-r--r--utils/plot_ui/README.md15
-rw-r--r--utils/plot_ui/afl-plot-ui.c173
-rwxr-xr-xutils/qbdi_mode/README.md206
-rw-r--r--utils/qbdi_mode/assets/screen1.pngbin0 -> 88333 bytes
-rwxr-xr-xutils/qbdi_mode/build.sh57
-rwxr-xr-xutils/qbdi_mode/demo-so.c41
-rwxr-xr-xutils/qbdi_mode/template.cpp251
-rw-r--r--utils/qemu_persistent_hook/Makefile6
-rw-r--r--utils/qemu_persistent_hook/README.md19
-rw-r--r--utils/qemu_persistent_hook/read_into_rdi.c34
-rw-r--r--utils/qemu_persistent_hook/test.c35
-rw-r--r--utils/socket_fuzzing/Makefile61
-rw-r--r--utils/socket_fuzzing/README.md11
-rw-r--r--utils/socket_fuzzing/socketfuzz.c110
357 files changed, 99895 insertions, 0 deletions
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 00000000..478c7a84
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,148 @@
+---
+Language: Cpp
+# BasedOnStyle: Google
+AccessModifierOffset: -1
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: true
+AlignEscapedNewlines: Left
+AlignOperands: true
+AlignTrailingComments: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: true
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: false
+AllowShortIfStatementsOnASingleLine: true
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: true
+AlwaysBreakTemplateDeclarations: Yes
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+ AfterClass: false
+ AfterControlStatement: false
+ AfterEnum: false
+ AfterFunction: false
+ AfterNamespace: false
+ AfterObjCDeclaration: false
+ AfterStruct: false
+ AfterUnion: false
+ AfterExternBlock: false
+ BeforeCatch: false
+ BeforeElse: false
+ IndentBraces: false
+ SplitEmptyFunction: true
+ SplitEmptyRecord: true
+ SplitEmptyNamespace: true
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Attach
+BreakBeforeInheritanceComma: false
+BreakInheritanceList: BeforeColon
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializersBeforeComma: false
+BreakConstructorInitializers: BeforeColon
+BreakAfterJavaFieldAnnotations: false
+BreakStringLiterals: true
+ColumnLimit: 80
+CommentPragmas: '^ IWYU pragma:'
+CompactNamespaces: false
+ConstructorInitializerAllOnOneLineOrOnePerLine: true
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DerivePointerAlignment: false
+DisableFormat: false
+ExperimentalAutoDetectBinPacking: false
+FixNamespaceComments: true
+ForEachMacros:
+ - foreach
+ - Q_FOREACH
+ - BOOST_FOREACH
+IncludeBlocks: Preserve
+IncludeCategories:
+ - Regex: '^<ext/.*\.h>'
+ Priority: 2
+ - Regex: '^<.*\.h>'
+ Priority: 1
+ - Regex: '^<.*'
+ Priority: 2
+ - Regex: '.*'
+ Priority: 3
+IncludeIsMainRegex: '([-_](test|unittest))?$'
+IndentCaseLabels: true
+IndentPPDirectives: BeforeHash
+IndentWidth: 2
+IndentWrappedFunctionNames: false
+JavaScriptQuotes: Leave
+JavaScriptWrapImports: true
+KeepEmptyLinesAtTheStartOfBlocks: false
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBinPackProtocolList: Never
+ObjCBlockIndentWidth: 2
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakAssignment: 2
+PenaltyBreakBeforeFirstCallParameter: 1
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyBreakTemplateDeclaration: 10
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 200
+PointerAlignment: Right
+RawStringFormats:
+ - Language: Cpp
+ Delimiters:
+ - cc
+ - CC
+ - cpp
+ - Cpp
+ - CPP
+ - 'c++'
+ - 'C++'
+ CanonicalDelimiter: ''
+ BasedOnStyle: google
+ - Language: TextProto
+ Delimiters:
+ - pb
+ - PB
+ - proto
+ - PROTO
+ EnclosingFunctions:
+ - EqualsProto
+ - EquivToProto
+ - PARSE_PARTIAL_TEXT_PROTO
+ - PARSE_TEST_PROTO
+ - PARSE_TEXT_PROTO
+ - ParseTextOrDie
+ - ParseTextProtoOrDie
+ CanonicalDelimiter: ''
+ BasedOnStyle: google
+ReflowComments: true
+SortIncludes: false
+SortUsingDeclarations: true
+SpaceAfterCStyleCast: false
+SpaceAfterTemplateKeyword: true
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeCpp11BracedList: false
+SpaceBeforeCtorInitializerColon: true
+SpaceBeforeInheritanceColon: true
+SpaceBeforeParens: ControlStatements
+SpaceBeforeRangeBasedForLoopColon: true
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 2
+SpacesInAngles: false
+SpacesInContainerLiterals: true
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard: Auto
+TabWidth: 8
+UseTab: Never
+...
+
diff --git a/.custom-format.py b/.custom-format.py
new file mode 100755
index 00000000..7ac63396
--- /dev/null
+++ b/.custom-format.py
@@ -0,0 +1,144 @@
+#!/usr/bin/env python3
+#
+# american fuzzy lop++ - custom code formatter
+# --------------------------------------------
+#
+# Written and maintaned by Andrea Fioraldi <andreafioraldi@gmail.com>
+#
+# Copyright 2015, 2016, 2017 Google Inc. All rights reserved.
+# Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+
+import subprocess
+import sys
+import os
+import re
+
+# string_re = re.compile('(\\"(\\\\.|[^"\\\\])*\\")') # future use
+
+with open(".clang-format") as f:
+ fmt = f.read()
+
+CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN")
+if CLANG_FORMAT_BIN is None:
+ o = 0
+ try:
+ p = subprocess.Popen(["clang-format-11", "--version"], stdout=subprocess.PIPE)
+ o, _ = p.communicate()
+ o = str(o, "utf-8")
+ o = re.sub(r".*ersion ", "", o)
+ # o = o[len("clang-format version "):].strip()
+ o = o[: o.find(".")]
+ o = int(o)
+ except:
+ print("clang-format-11 is needed. Aborted.")
+ exit(1)
+ # if o < 7:
+ # if subprocess.call(['which', 'clang-format-7'], stdout=subprocess.PIPE) == 0:
+ # CLANG_FORMAT_BIN = 'clang-format-7'
+ # elif subprocess.call(['which', 'clang-format-8'], stdout=subprocess.PIPE) == 0:
+ # CLANG_FORMAT_BIN = 'clang-format-8'
+ # elif subprocess.call(['which', 'clang-format-9'], stdout=subprocess.PIPE) == 0:
+ # CLANG_FORMAT_BIN = 'clang-format-9'
+ # elif subprocess.call(['which', 'clang-format-11'], stdout=subprocess.PIPE) == 0:
+ # CLANG_FORMAT_BIN = 'clang-format-11'
+ # else:
+ # print ("clang-format 7 or above is needed. Aborted.")
+ # exit(1)
+ else:
+ CLANG_FORMAT_BIN = "clang-format-11"
+
+COLUMN_LIMIT = 80
+for line in fmt.split("\n"):
+ line = line.split(":")
+ if line[0].strip() == "ColumnLimit":
+ COLUMN_LIMIT = int(line[1].strip())
+
+
+def custom_format(filename):
+ p = subprocess.Popen([CLANG_FORMAT_BIN, filename], stdout=subprocess.PIPE)
+ src, _ = p.communicate()
+ src = str(src, "utf-8")
+
+ in_define = False
+ last_line = None
+ out = ""
+
+ for line in src.split("\n"):
+ if line.lstrip().startswith("#"):
+ if line[line.find("#") + 1 :].lstrip().startswith("define"):
+ in_define = True
+
+ if (
+ "/*" in line
+ and not line.strip().startswith("/*")
+ and line.endswith("*/")
+ and len(line) < (COLUMN_LIMIT - 2)
+ ):
+ cmt_start = line.rfind("/*")
+ line = (
+ line[:cmt_start]
+ + " " * (COLUMN_LIMIT - 2 - len(line))
+ + line[cmt_start:]
+ )
+
+ define_padding = 0
+ if last_line is not None and in_define and last_line.endswith("\\"):
+ last_line = last_line[:-1]
+ define_padding = max(0, len(last_line[last_line.rfind("\n") + 1 :]))
+
+ if (
+ last_line is not None
+ and last_line.strip().endswith("{")
+ and line.strip() != ""
+ ):
+ line = (" " * define_padding + "\\" if in_define else "") + "\n" + line
+ elif (
+ last_line is not None
+ and last_line.strip().startswith("}")
+ and line.strip() != ""
+ ):
+ line = (" " * define_padding + "\\" if in_define else "") + "\n" + line
+ elif (
+ line.strip().startswith("}")
+ and last_line is not None
+ and last_line.strip() != ""
+ ):
+ line = (" " * define_padding + "\\" if in_define else "") + "\n" + line
+
+ if not line.endswith("\\"):
+ in_define = False
+
+ out += line + "\n"
+ last_line = line
+
+ return out
+
+
+args = sys.argv[1:]
+if len(args) == 0:
+ print("Usage: ./format.py [-i] <filename>")
+ print()
+ print(" The -i option, if specified, let the script to modify in-place")
+ print(" the source files. By default the results are written to stdout.")
+ print()
+ exit(1)
+
+in_place = False
+if args[0] == "-i":
+ in_place = True
+ args = args[1:]
+
+for filename in args:
+ code = custom_format(filename)
+ if in_place:
+ with open(filename, "w") as f:
+ f.write(code)
+ else:
+ print(code)
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 00000000..d05bf1c6
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,65 @@
+.test
+.test2
+.sync_tmp
+*.o
+*.so
+*.pyc
+*.dSYM
+as
+ld
+in
+out
+core*
+afl-analyze
+afl-as
+afl-clang
+afl-clang\+\+
+afl-clang-fast
+afl-clang-fast\+\+
+afl-clang-lto
+afl-clang-lto\+\+
+afl-fuzz
+afl-g\+\+
+afl-gcc
+afl-gcc-fast
+afl-g\+\+-fast
+afl-gotcpu
+afl-ld
+afl-ld-lto
+afl-qemu-trace
+afl-showmap
+afl-tmin
+afl-analyze.8
+afl-as.8
+afl-clang-fast\+\+.8
+afl-clang-fast.8
+afl-clang-lto.8
+afl-clang-lto\+\+.8
+afl-cmin.8
+afl-cmin.bash.8
+afl-fuzz.8
+afl-gcc.8
+afl-gcc-fast.8
+afl-g\+\+-fast.8
+afl-gotcpu.8
+afl-plot.8
+afl-showmap.8
+afl-system-config.8
+afl-tmin.8
+afl-whatsup.8
+qemu_mode/libcompcov/compcovtest
+qemu_mode/qemu-*
+unicorn_mode/samples/*/\.test-*
+unicorn_mode/samples/*/output
+unicorn_mode/unicornafl
+test/unittests/unit_maybe_alloc
+test/unittests/unit_preallocable
+test/unittests/unit_list
+test/unittests/unit_rand
+test/unittests/unit_hash
+examples/afl_network_proxy/afl-network-server
+examples/afl_network_proxy/afl-network-client
+examples/afl_frida/afl-frida
+examples/afl_frida/libtestinstr.so
+examples/afl_frida/frida-gum-example.c
+examples/afl_frida/frida-gum.h \ No newline at end of file
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 00000000..97e23585
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,13 @@
+# These are supported funding model platforms
+
+# Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
+github: AFLplusplus
+patreon: # Replace with a single Patreon username
+open_collective: AFLplusplusEU
+ko_fi: # Replace with a single Ko-fi username
+tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
+community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
+liberapay: # Replace with a single Liberapay username
+issuehunt: # Replace with a single IssueHunt username
+otechie: # Replace with a single Otechie username
+custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 00000000..0d80f4a3
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,32 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**IMPORTANT**
+1. You have verified that the issue to be present in the current `dev` branch.
+2. Please supply the command line options and relevant environment variables,
+ e.g., a copy-paste of the contents of `out/default/fuzzer_setup`.
+
+Thank you for making AFL++ better!
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+1. ...
+2. ...
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screen output/Screenshots**
+If applicable, add copy-paste of the screen output or screenshot that shows the issue. Please ensure the output is in **English** and not in Chinese, Russian, German, etc.
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 00000000..bbcbbe7d
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,20 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.github/workflows/build_aflplusplus_docker.yaml b/.github/workflows/build_aflplusplus_docker.yaml
new file mode 100644
index 00000000..fa96da8e
--- /dev/null
+++ b/.github/workflows/build_aflplusplus_docker.yaml
@@ -0,0 +1,30 @@
+name: Publish Docker Images
+
+on:
+ push:
+ branches: [ stable ]
+# paths:
+# - Dockerfile
+
+jobs:
+ push_to_registry:
+ name: Push Docker images to Dockerhub
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@master
+ - name: Set up QEMU
+ uses: docker/setup-qemu-action@v1
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v1
+ - name: Login to Dockerhub
+ uses: docker/login-action@v1
+ with:
+ username: ${{ secrets.DOCKER_USERNAME }}
+ password: ${{ secrets.DOCKER_TOKEN }}
+ - name: Publish aflpp to Registry
+ uses: docker/build-push-action@v2
+ with:
+ context: .
+ platforms: linux/amd64,linux/arm64
+ push: true
+ tags: aflplusplus/aflplusplus:latest
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 00000000..886148df
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,53 @@
+name: CI
+
+on:
+ push:
+ branches: [ stable, dev ]
+ pull_request:
+ branches: [ stable, dev ]
+
+jobs:
+ linux:
+ runs-on: '${{ matrix.os }}'
+ strategy:
+ matrix:
+ os: [ubuntu-20.04, ubuntu-18.04]
+ env:
+ AFL_SKIP_CPUFREQ: 1
+ AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: 1
+ steps:
+ - uses: actions/checkout@v2
+ - name: debug
+ run: apt-cache search plugin-dev | grep gcc-; echo; apt-cache search clang-format- | grep clang-format-
+ - name: update
+ run: sudo apt-get update && sudo apt-get upgrade -y
+ - name: install packages
+ run: sudo apt-get install -y -m -f --install-suggests build-essential git libtool libtool-bin automake bison libglib2.0-0 clang llvm-dev libc++-dev findutils libcmocka-dev python3-dev python3-setuptools ninja-build
+ - name: compiler installed
+ run: gcc -v; echo; clang -v
+ - name: install gcc plugin
+ run: sudo apt-get install -y -m -f --install-suggests $(readlink /usr/bin/gcc)-plugin-dev
+ - name: build afl++
+ run: make distrib ASAN_BUILD=1
+ - name: run tests
+ run: sudo -E ./afl-system-config; make tests
+ macos:
+ runs-on: macOS-latest
+ env:
+ AFL_MAP_SIZE: 65536
+ AFL_SKIP_CPUFREQ: 1
+ AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: 1
+ steps:
+ - uses: actions/checkout@v2
+ - name: install
+ run: brew install make gcc
+ - name: fix install
+ run: cd /usr/local/bin; ln -s gcc-11 gcc; ln -s g++-11 g++; which gcc; gcc -v
+ - name: build
+ run: export PATH=/usr/local/Cellar/llvm/*/":$PATH"; export CC=/usr/local/Cellar/llvm/*/bin/clang; export CXX="$CC"++; export LLVM_CONFIG=/usr/local/Cellar/llvm/*/bin/llvm-config; sudo -E ./afl-system-config; gmake ASAN_BUILD=1
+ - name: frida
+ run: export CC=/usr/local/Cellar/llvm/*/bin/clang; export CXX="$CC"++; cd frida_mode; gmake
+ - name: run tests
+ run: sudo -E ./afl-system-config; export CC=/usr/local/Cellar/llvm/*/bin/clang; export CXX="$CC"++; export PATH=/usr/local/Cellar/llvm/*/":/usr/local/bin:$PATH"; export LLVM_CONFIG=/usr/local/Cellar/llvm/*/bin/llvm-config; gmake tests
+ - name: force frida test for MacOS
+ run: export AFL_PATH=`pwd`; /usr/local/bin/gcc -o test-instr test-instr.c; mkdir in; echo > in/in; AFL_NO_UI=1 ./afl-fuzz -O -i in -o out -V 5 -- ./test-instr
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
new file mode 100644
index 00000000..eda8dfd0
--- /dev/null
+++ b/.github/workflows/codeql-analysis.yml
@@ -0,0 +1,32 @@
+name: "CodeQL"
+
+on:
+ push:
+ branches: [ stable, dev ]
+ pull_request:
+ branches: [ stable, dev ]
+
+jobs:
+ analyze:
+ name: Analyze
+ runs-on: ubuntu-latest
+
+ strategy:
+ fail-fast: false
+ matrix:
+ language: [ 'cpp' ]
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v1
+ with:
+ languages: ${{ matrix.language }}
+
+ - name: Autobuild
+ uses: github/codeql-action/autobuild@v1
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v1
diff --git a/.github/workflows/rust_custom_mutator.yml b/.github/workflows/rust_custom_mutator.yml
new file mode 100644
index 00000000..de2b184a
--- /dev/null
+++ b/.github/workflows/rust_custom_mutator.yml
@@ -0,0 +1,30 @@
+name: Rust Custom Mutators
+
+on:
+ push:
+ branches: [ stable, dev ]
+ pull_request:
+ branches: [ stable, dev ]
+
+jobs:
+ test:
+ name: Test Rust Custom Mutator Support
+ runs-on: '${{ matrix.os }}'
+ defaults:
+ run:
+ working-directory: custom_mutators/rust
+ strategy:
+ matrix:
+ os: [ubuntu-20.04]
+ steps:
+ - uses: actions/checkout@v2
+ - name: Install Rust Toolchain
+ uses: actions-rs/toolchain@v1
+ with:
+ toolchain: stable
+ - name: Check Code Compiles
+ run: cargo check
+ - name: Run General Tests
+ run: cargo test
+ - name: Run Tests for afl_internals feature flag
+ run: cd custom_mutator && cargo test --features=afl_internals \ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..22ee6bf1
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,99 @@
+.test
+.test2
+.sync_tmp
+.vscode
+*.o
+*.so
+*.swp
+*.pyc
+*.dSYM
+as
+a.out
+ld
+in
+out
+core*
+compile_commands.json
+afl-analyze
+afl-as
+afl-clang
+afl-clang++
+afl-clang-fast
+afl-clang-fast++
+afl-clang-lto
+afl-clang-lto++
+afl-fuzz
+afl-g++
+afl-gcc
+afl-gcc-fast
+afl-g++-fast
+afl-gotcpu
+afl-ld
+afl-ld-lto
+afl-cs-proxy
+afl-qemu-trace
+afl-showmap
+afl-tmin
+afl-analyze.8
+afl-as.8
+afl-clang-fast++.8
+afl-clang-fast.8
+afl-clang-lto.8
+afl-clang-lto++.8
+afl-cmin.8
+afl-cmin.bash.8
+afl-fuzz.8
+afl-c++.8
+afl-cc.8
+afl-gcc.8
+afl-g++.8
+afl-gcc-fast.8
+afl-g++-fast.8
+afl-gotcpu.8
+afl-plot.8
+afl-showmap.8
+afl-system-config.8
+afl-tmin.8
+afl-whatsup.8
+afl-persistent-config.8
+afl-c++
+afl-cc
+afl-lto
+afl-lto++
+afl-lto++.8
+afl-lto.8
+qemu_mode/libcompcov/compcovtest
+qemu_mode/qemu-*
+qemu_mode/qemuafl
+unicorn_mode/samples/*/\.test-*
+unicorn_mode/samples/*/output/
+test/unittests/unit_maybe_alloc
+test/unittests/unit_preallocable
+test/unittests/unit_list
+test/unittests/unit_rand
+test/unittests/unit_hash
+examples/afl_network_proxy/afl-network-server
+examples/afl_network_proxy/afl-network-client
+examples/afl_frida/afl-frida
+examples/afl_frida/libtestinstr.so
+examples/afl_frida/frida-gum-example.c
+examples/afl_frida/frida-gum.h
+examples/aflpp_driver/libAFLDriver.a
+examples/aflpp_driver/libAFLQemuDriver.a
+libAFLDriver.a
+libAFLQemuDriver.a
+test/.afl_performance
+gmon.out
+afl-frida-trace.so
+utils/afl_network_proxy/afl-network-client
+utils/afl_network_proxy/afl-network-server
+utils/plot_ui/afl-plot-ui
+*.o.tmp
+utils/afl_proxy/afl-proxy
+utils/optimin/build
+utils/optimin/optimin
+utils/persistent_mode/persistent_demo
+utils/persistent_mode/persistent_demo_new
+utils/persistent_mode/test-instr
+!coresight_mode
+!coresight_mode/coresight-trace
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 00000000..ac1d5cb6
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,418 @@
+//
+// NOTE: This file is outdated. None of the AFL++ team uses Android hence
+// we need users to keep this updated.
+// In the current state it will likely fail, please send fixes!
+// Also, this should build frida_mode.
+//
+
+
+cc_defaults {
+ name: "afl-defaults",
+
+ local_include_dirs: [
+ "include",
+ "instrumentation",
+ ],
+
+ cflags: [
+ "-flto=full",
+ "-funroll-loops",
+ "-Wno-pointer-sign",
+ "-Wno-pointer-arith",
+ "-Wno-sign-compare",
+ "-Wno-unused-parameter",
+ "-Wno-unused-function",
+ "-Wno-format",
+ "-Wno-user-defined-warnings",
+ "-DAFL_LLVM_USE_TRACE_PC=1",
+ "-DBIN_PATH=\"out/host/linux-x86/bin\"",
+ "-DDOC_PATH=\"out/host/linux-x86/shared/doc/afl\"",
+ "-D__USE_GNU",
+ "-DDEBUG_BUILD",
+ "-U_FORTIFY_SOURCE",
+ "-ggdb3",
+ "-g",
+ "-O0",
+ "-fno-omit-frame-pointer",
+ "-fPIC",
+ ],
+
+ target: {
+ android_arm64: {
+ cflags: [
+ "-D__ANDROID__",
+ ],
+ },
+ android_arm: {
+ cflags: [
+ "-D__ANDROID__",
+ ],
+ },
+ android_x86_64: {
+ cflags: [
+ "-D__ANDROID__",
+ ],
+ },
+ android_x86: {
+ cflags: [
+ "-D__ANDROID__",
+ ],
+ },
+ },
+}
+
+cc_binary {
+ name: "afl-fuzz",
+ sanitize: {
+ never: true,
+ },
+ host_supported: true,
+ compile_multilib: "64",
+
+ defaults: [
+ "afl-defaults",
+ ],
+
+ srcs: [
+ "src/afl-fuzz*.c",
+ "src/afl-common.c",
+ "src/afl-sharedmem.c",
+ "src/afl-forkserver.c",
+ "src/afl-performance.c",
+ ],
+}
+
+cc_binary {
+ name: "afl-showmap",
+ static_executable: true,
+ host_supported: true,
+
+ defaults: [
+ "afl-defaults",
+ ],
+
+ srcs: [
+ "src/afl-showmap.c",
+ "src/afl-common.c",
+ "src/afl-sharedmem.c",
+ "src/afl-forkserver.c",
+ "src/afl-performance.c",
+ ],
+}
+
+cc_binary {
+ name: "afl-tmin",
+ static_executable: true,
+ host_supported: true,
+
+ defaults: [
+ "afl-defaults",
+ ],
+
+ srcs: [
+ "src/afl-tmin.c",
+ "src/afl-common.c",
+ "src/afl-sharedmem.c",
+ "src/afl-forkserver.c",
+ "src/afl-performance.c",
+ ],
+}
+
+cc_binary {
+ name: "afl-analyze",
+ static_executable: true,
+ host_supported: true,
+
+ defaults: [
+ "afl-defaults",
+ ],
+
+ srcs: [
+ "src/afl-analyze.c",
+ "src/afl-common.c",
+ "src/afl-sharedmem.c",
+ "src/afl-performance.c",
+ ],
+}
+
+cc_binary {
+ name: "afl-gotcpu",
+ static_executable: true,
+ host_supported: true,
+
+ defaults: [
+ "afl-defaults",
+ ],
+
+ srcs: [
+ "src/afl-gotcpu.c",
+ "src/afl-common.c",
+ ],
+}
+
+cc_binary_host {
+ name: "afl-cc",
+ static_executable: true,
+
+ defaults: [
+ "afl-defaults",
+ ],
+
+ cflags: [
+ "-DAFL_PATH=\"out/host/linux-x86/lib64\"",
+ "-DAFL_CLANG_FLTO=\"-flto=full\"",
+ "-DUSE_BINDIR=1",
+ "-DLLVM_BINDIR=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin\"",
+ "-DLLVM_LIBDIR=\"prebuilts/clang/host/linux-x86/clang-r383902b/lib64\"",
+ "-DCLANGPP_BIN=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin/clang++\"",
+ "-DAFL_REAL_LD=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin/ld.lld\"",
+ "-DLLVM_LTO=1",
+ "-DLLVM_MAJOR=11",
+ "-DLLVM_MINOR=2",
+ ],
+
+ srcs: [
+ "src/afl-cc.c",
+ "src/afl-common.c",
+ ],
+
+ symlinks: [
+ "afl-clang-fast",
+ "afl-clang-fast++",
+ ],
+}
+
+cc_library_static {
+ name: "afl-compiler-rt",
+ compile_multilib: "64",
+ vendor_available: true,
+ host_supported: true,
+ recovery_available: true,
+ sdk_version: "9",
+
+ apex_available: [
+ "com.android.adbd",
+ "com.android.appsearch",
+ "com.android.art",
+ "com.android.bluetooth.updatable",
+ "com.android.cellbroadcast",
+ "com.android.conscrypt",
+ "com.android.extservices",
+ "com.android.cronet",
+ "com.android.neuralnetworks",
+ "com.android.media",
+ "com.android.media.swcodec",
+ "com.android.mediaprovider",
+ "com.android.permission",
+ "com.android.runtime",
+ "com.android.resolv",
+ "com.android.tethering",
+ "com.android.wifi",
+ "com.android.sdkext",
+ "com.android.os.statsd",
+ "//any",
+ ],
+
+ defaults: [
+ "afl-defaults",
+ ],
+
+ srcs: [
+ "instrumentation/afl-compiler-rt.o.c",
+ ],
+}
+
+cc_library_headers {
+ name: "libafl_headers",
+ vendor_available: true,
+ host_supported: true,
+
+ export_include_dirs: [
+ "include",
+ "instrumentation",
+ ],
+}
+
+/*
+cc_prebuilt_library_static {
+ name: "libfrida-gum",
+ compile_multilib: "64",
+ strip: {
+ none: true,
+ },
+
+ srcs: [
+ "utils/afl_frida/android/libfrida-gum.a",
+ ],
+
+ export_include_dirs: [
+ "utils/afl_frida/android",
+ ],
+}
+
+cc_library_shared {
+ name: "libtestinstr",
+
+ srcs: [
+ "utils/afl_frida/libtestinstr.c",
+ ],
+
+ cflags: [
+ "-O0",
+ "-fPIC",
+ ],
+}
+
+cc_binary {
+ name: "afl-frida",
+ compile_multilib: "64",
+
+ defaults: [
+ "afl-defaults",
+ ],
+
+ cflags: [
+ "-g",
+ "-O0",
+ "-Wno-format",
+ "-Wno-pointer-sign",
+ "-fpermissive",
+ "-fPIC",
+ ],
+
+ static_libs: [
+ "afl-compiler-rt",
+ "libfrida-gum",
+ ],
+
+ shared_libs: [
+ "libdl",
+ "liblog",
+ ],
+
+ srcs: [
+ "utils/afl_frida/afl-frida.c",
+ ],
+
+ local_include_dirs: [
+ "utils/afl_frida",
+ "utils/afl_frida/android",
+ ],
+}
+*/
+
+cc_binary {
+ name: "afl-fuzz-32",
+ sanitize: {
+ never: true,
+ },
+ host_supported: true,
+ compile_multilib: "32",
+
+ defaults: [
+ "afl-defaults",
+ ],
+
+ srcs: [
+ "src/afl-fuzz*.c",
+ "src/afl-common.c",
+ "src/afl-sharedmem.c",
+ "src/afl-forkserver.c",
+ "src/afl-performance.c",
+ ],
+}
+
+cc_binary_host {
+ name: "afl-cc-32",
+ compile_multilib: "32",
+ static_executable: true,
+
+ defaults: [
+ "afl-defaults",
+ ],
+
+ cflags: [
+ "-DAFL_PATH=\"out/host/linux-x86/lib64\"",
+ "-DAFL_CLANG_FLTO=\"-flto=full\"",
+ "-DUSE_BINDIR=1",
+ "-DLLVM_BINDIR=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin\"",
+ "-DLLVM_LIBDIR=\"prebuilts/clang/host/linux-x86/clang-r383902b/lib64\"",
+ "-DCLANGPP_BIN=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin/clang++\"",
+ "-DAFL_REAL_LD=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin/ld.lld\"",
+ "-DLLVM_LTO=1",
+ "-DLLVM_MAJOR=11",
+ "-DLLVM_MINOR=2",
+ ],
+
+ srcs: [
+ "src/afl-cc.c",
+ "src/afl-common.c",
+ ],
+
+ symlinks: [
+ "afl-clang-fast-32",
+ "afl-clang-fast++-32",
+ ],
+}
+
+cc_library_static {
+ name: "afl-compiler-rt-32",
+ compile_multilib: "32",
+ vendor_available: true,
+ host_supported: true,
+ recovery_available: true,
+ sdk_version: "9",
+
+ apex_available: [
+ "com.android.adbd",
+ "com.android.appsearch",
+ "com.android.art",
+ "com.android.bluetooth.updatable",
+ "com.android.cellbroadcast",
+ "com.android.conscrypt",
+ "com.android.extservices",
+ "com.android.cronet",
+ "com.android.neuralnetworks",
+ "com.android.media",
+ "com.android.media.swcodec",
+ "com.android.mediaprovider",
+ "com.android.permission",
+ "com.android.runtime",
+ "com.android.resolv",
+ "com.android.tethering",
+ "com.android.wifi",
+ "com.android.sdkext",
+ "com.android.os.statsd",
+ "//any",
+ ],
+
+ defaults: [
+ "afl-defaults",
+ ],
+
+ srcs: [
+ "instrumentation/afl-compiler-rt.o.c",
+ ],
+}
+
+/*
+cc_prebuilt_library_static {
+ name: "libfrida-gum-32",
+ compile_multilib: "32",
+ strip: {
+ none: true,
+ },
+
+ srcs: [
+ "utils/afl_frida/android/arm/libfrida-gum.a",
+ ],
+
+ export_include_dirs: [
+ "utils/afl_frida/android/arm",
+ ],
+}
+*/
+
+subdirs = [
+ "custom_mutators",
+]
diff --git a/CITATION.cff b/CITATION.cff
new file mode 100644
index 00000000..37a4a174
--- /dev/null
+++ b/CITATION.cff
@@ -0,0 +1,31 @@
+cff-version: 1.2.0
+message: "If you use this software, please cite it as below."
+authors:
+ - given-names: Marc
+ family-names: Heuse
+ email: mh@mh-sec.de
+ - given-names: Heiko
+ family-names: Eißfeldt
+ email: heiko.eissfeldt@hexco.de
+ - given-names: Andrea
+ family-names: Fioraldi
+ email: andreafioraldi@gmail.com
+ - given-names: Dominik
+ family-names: Maier
+ email: mail@dmnk.co
+title: "AFL++"
+version: 4.00c
+type: software
+date-released: 2022-01-26
+url: "https://github.com/AFLplusplus/AFLplusplus"
+keywords:
+ - fuzzing
+ - fuzzer
+ - fuzz-testing
+ - instrumentation
+ - afl-fuzz
+ - qemu
+ - llvm
+ - unicorn-emulator
+ - securiy
+license: AGPL-3.0-or-later
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 00000000..0042bf28
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,59 @@
+# Contributing to AFL++
+
+## How to submit a pull request
+
+All contributions (pull requests) must be made against our `dev` branch.
+
+Each modified source file, before merging, must be formatted.
+
+```
+make code-format
+```
+
+This should be fine if you modified one of the files already present in the
+project, or added a file in a directory we already format, otherwise run:
+
+```
+./.custom-format.py -i file-that-you-have-created.c
+```
+
+Regarding the coding style, please follow the AFL style. No camel case at all
+and use AFL's macros wherever possible (e.g., WARNF, FATAL, MAP_SIZE, ...).
+
+Remember that AFL++ has to build and run on many platforms, so generalize your
+Makefiles/GNUmakefile (or your patches to our pre-existing Makefiles) to be as
+generic as possible.
+
+## How to contribute to the docs
+
+We welcome contributions to our docs.
+
+Before creating a new file, please check if your content matches an existing
+file in one the following folders:
+
+* [docs/](docs/) (this is where you can find most of our docs content)
+* [frida_mode/](frida_mode/)
+* [instrumentation/](instrumentation/)
+* [qemu_mode/](qemu_mode/)
+* [unicorn_mode/](unicorn_mode/)
+
+When working on the docs, please keep the following guidelines in mind:
+
+* Edit or create Markdown files and use Markdown markup.
+ * Do: fuzzing_gui_program.md
+ * Don't: fuzzing_gui_program.txt
+* Use underscore in file names.
+ * Do: fuzzing_network_service.md
+ * Don't: fuzzing-network-service.md
+* Use a maximum of 80 characters per line to make reading in a console easier.
+* Make all pull requests against `dev`, see
+ [#how-to-submit-a-pull-request-to-afl](#how-to-submit-a-pull-request-to-afl).
+
+And finally, here are some best practices for writing docs content:
+
+* Use clear and simple language.
+* Structure your content with headings and paragraphs.
+* Use bulleted lists to present similar content in a way that makes it easy to
+ scan.
+* Use numbered lists for procedures or prioritizing.
+* Link to related content, for example, prerequisites or in-depth discussions. \ No newline at end of file
diff --git a/Changelog.md b/Changelog.md
new file mode 120000
index 00000000..c50d6ab3
--- /dev/null
+++ b/Changelog.md
@@ -0,0 +1 @@
+docs/Changelog.md \ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 00000000..bdfa1c56
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,81 @@
+#
+# This Dockerfile for AFLplusplus uses Ubuntu 22.04 jammy and
+# installs LLVM 14 for afl-clang-lto support :-)
+#
+
+FROM ubuntu:22.04 AS aflplusplus
+LABEL "maintainer"="afl++ team <afl@aflplus.plus>"
+LABEL "about"="AFLplusplus docker image"
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+env NO_ARCH_OPT 1
+
+RUN apt-get update && \
+ apt-get -y install --no-install-suggests --no-install-recommends \
+ automake \
+ cmake \
+ meson \
+ ninja-build \
+ bison flex \
+ build-essential \
+ git \
+ python3 python3-dev python3-setuptools python-is-python3 \
+ libtool libtool-bin \
+ libglib2.0-dev \
+ wget vim jupp nano bash-completion less \
+ apt-utils apt-transport-https ca-certificates gnupg dialog \
+ libpixman-1-dev \
+ gnuplot-nox \
+ && rm -rf /var/lib/apt/lists/*
+
+# TODO: reactivate in timely manner
+#RUN echo "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main" >> /etc/apt/sources.list && \
+# wget -qO - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
+
+RUN echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu jammy main" >> /etc/apt/sources.list && \
+ apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 1E9377A2BA9EF27F
+
+RUN apt-get update && apt-get full-upgrade -y && \
+ apt-get -y install --no-install-suggests --no-install-recommends \
+ gcc-12 g++-12 gcc-12-plugin-dev gdb lcov \
+ clang-14 clang-tools-14 libc++1-14 libc++-14-dev \
+ libc++abi1-14 libc++abi-14-dev libclang1-14 libclang-14-dev \
+ libclang-common-14-dev libclang-cpp14 libclang-cpp14-dev liblld-14 \
+ liblld-14-dev liblldb-14 liblldb-14-dev libllvm14 libomp-14-dev \
+ libomp5-14 lld-14 lldb-14 llvm-14 llvm-14-dev llvm-14-runtime llvm-14-tools
+
+# arm64 doesn't have gcc-multilib, and it's only used for -m32 support on x86
+ARG TARGETPLATFORM
+RUN [ "$TARGETPLATFORM" = "linux/amd64" ] && \
+ apt-get -y install --no-install-suggests --no-install-recommends \
+ gcc-10-multilib gcc-multilib || true
+
+RUN rm -rf /var/lib/apt/lists/*
+
+RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 0
+RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-12 0
+
+ENV LLVM_CONFIG=llvm-config-14
+ENV AFL_SKIP_CPUFREQ=1
+ENV AFL_TRY_AFFINITY=1
+ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1
+
+RUN git clone --depth=1 https://github.com/vanhauser-thc/afl-cov /afl-cov
+RUN cd /afl-cov && make install && cd ..
+
+COPY . /AFLplusplus
+WORKDIR /AFLplusplus
+
+RUN export CC=gcc-12 && export CXX=g++-12 && make clean && \
+ make distrib && make install && make clean
+
+RUN sh -c 'echo set encoding=utf-8 > /root/.vimrc'
+RUN echo '. /etc/bash_completion' >> ~/.bashrc
+RUN echo 'alias joe="joe --wordwrap --joe_state -nobackup"' >> ~/.bashrc
+RUN echo "export PS1='"'[afl++ \h] \w$(__git_ps1) \$ '"'" >> ~/.bashrc
+ENV IS_DOCKER="1"
+
+# Disabled as there are now better alternatives
+#COPY --from=aflplusplus/afl-dyninst /usr/local/lib/libdyninstAPI_RT.so /usr/local/lib/libdyninstAPI_RT.so
+#COPY --from=aflplusplus/afl-dyninst /afl-dyninst/libAflDyninst.so /usr/local/lib/libAflDyninst.so
diff --git a/GNUmakefile b/GNUmakefile
new file mode 100644
index 00000000..072bd09d
--- /dev/null
+++ b/GNUmakefile
@@ -0,0 +1,741 @@
+#
+# american fuzzy lop++ - makefile
+# -----------------------------
+#
+# Originally written by Michal Zalewski
+#
+# Copyright 2013, 2014, 2015, 2016, 2017 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+
+# For Heiko:
+#TEST_MMAP=1
+# the hash character is treated differently in different make versions
+# so use a variable for '#'
+HASH=\#
+
+PREFIX ?= /usr/local
+BIN_PATH = $(PREFIX)/bin
+HELPER_PATH = $(PREFIX)/lib/afl
+DOC_PATH = $(PREFIX)/share/doc/afl
+MISC_PATH = $(PREFIX)/share/afl
+MAN_PATH = $(PREFIX)/share/man/man8
+
+PROGNAME = afl
+VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
+
+# PROGS intentionally omit afl-as, which gets installed elsewhere.
+
+PROGS = afl-fuzz afl-showmap afl-tmin afl-gotcpu afl-analyze
+SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-whatsup afl-system-config afl-persistent-config afl-cc
+MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8) afl-as.8
+ASAN_OPTIONS=detect_leaks=0
+
+SYS = $(shell uname -s)
+ARCH = $(shell uname -m)
+
+$(info [*] Compiling afl++ for OS $(SYS) on ARCH $(ARCH))
+
+ifdef NO_SPLICING
+ override CFLAGS_OPT += -DNO_SPLICING
+endif
+
+ifdef ASAN_BUILD
+ $(info Compiling ASAN version of binaries)
+ override CFLAGS += $(ASAN_CFLAGS)
+ LDFLAGS += $(ASAN_LDFLAGS)
+endif
+ifdef UBSAN_BUILD
+ $(info Compiling UBSAN version of binaries)
+ override CFLAGS += -fsanitize=undefined -fno-omit-frame-pointer
+ override LDFLAGS += -fsanitize=undefined
+endif
+ifdef MSAN_BUILD
+ $(info Compiling MSAN version of binaries)
+ CC := clang
+ override CFLAGS += -fsanitize=memory -fno-omit-frame-pointer
+ override LDFLAGS += -fsanitize=memory
+endif
+
+ifeq "$(findstring android, $(shell $(CC) --version 2>/dev/null))" ""
+ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
+ CFLAGS_FLTO ?= -flto=full
+else
+ ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
+ CFLAGS_FLTO ?= -flto=thin
+ else
+ ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
+ CFLAGS_FLTO ?= -flto
+ endif
+ endif
+endif
+endif
+
+#ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -fno-move-loop-invariants -fdisable-tree-cunrolli -x c - -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
+# SPECIAL_PERFORMANCE += -fno-move-loop-invariants -fdisable-tree-cunrolli
+#endif
+
+#ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -march=native -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
+# ifndef SOURCE_DATE_EPOCH
+# HAVE_MARCHNATIVE = 1
+# CFLAGS_OPT += -march=native
+# endif
+#endif
+
+ifneq "$(SYS)" "Darwin"
+ #ifeq "$(HAVE_MARCHNATIVE)" "1"
+ # SPECIAL_PERFORMANCE += -march=native
+ #endif
+ # OS X does not like _FORTIFY_SOURCE=2
+ ifndef DEBUG
+ CFLAGS_OPT += -D_FORTIFY_SOURCE=2
+ endif
+else
+ # On some odd MacOS system configurations, the Xcode sdk path is not set correctly
+ SDK_LD = -L$(shell xcrun --show-sdk-path)/usr/lib
+ LDFLAGS += $(SDK_LD)
+endif
+
+ifeq "$(SYS)" "SunOS"
+ CFLAGS_OPT += -Wno-format-truncation
+ LDFLAGS = -lkstat -lrt
+endif
+
+ifdef STATIC
+ $(info Compiling static version of binaries, disabling python though)
+ # Disable python for static compilation to simplify things
+ PYTHON_OK = 0
+ PYFLAGS=
+ PYTHON_INCLUDE = /
+
+ CFLAGS_OPT += -static
+ LDFLAGS += -lm -lpthread -lz -lutil
+endif
+
+ifdef PROFILING
+ $(info Compiling with profiling information, for analysis: gprof ./afl-fuzz gmon.out > prof.txt)
+ override CFLAGS_OPT += -pg -DPROFILING=1
+ override LDFLAGS += -pg
+endif
+
+ifdef INTROSPECTION
+ $(info Compiling with introspection documentation)
+ override CFLAGS_OPT += -DINTROSPECTION=1
+endif
+
+ifneq "$(ARCH)" "x86_64"
+ ifneq "$(patsubst i%86,i386,$(ARCH))" "i386"
+ ifneq "$(ARCH)" "amd64"
+ ifneq "$(ARCH)" "i86pc"
+ AFL_NO_X86=1
+ endif
+ endif
+ endif
+endif
+
+ifdef DEBUG
+ $(info Compiling DEBUG version of binaries)
+ override CFLAGS += -ggdb3 -O0 -Wall -Wextra -Werror $(CFLAGS_OPT)
+else
+ CFLAGS ?= -O2 $(CFLAGS_OPT) # -funroll-loops is slower on modern compilers
+endif
+
+override CFLAGS += -g -Wno-pointer-sign -Wno-variadic-macros -Wall -Wextra -Wno-pointer-arith \
+ -fPIC -I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \
+ -DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\"
+# -fstack-protector
+
+ifeq "$(SYS)" "FreeBSD"
+ override CFLAGS += -I /usr/local/include/
+ override LDFLAGS += -L /usr/local/lib/
+endif
+
+ifeq "$(SYS)" "DragonFly"
+ override CFLAGS += -I /usr/local/include/
+ override LDFLAGS += -L /usr/local/lib/
+endif
+
+ifeq "$(SYS)" "OpenBSD"
+ override CFLAGS += -I /usr/local/include/ -mno-retpoline
+ override LDFLAGS += -Wl,-z,notext -L /usr/local/lib/
+endif
+
+ifeq "$(SYS)" "NetBSD"
+ override CFLAGS += -I /usr/pkg/include/
+ override LDFLAGS += -L /usr/pkg/lib/
+endif
+
+ifeq "$(SYS)" "Haiku"
+ SHMAT_OK=0
+ override CFLAGS += -DUSEMMAP=1 -Wno-error=format
+ override LDFLAGS += -Wno-deprecated-declarations -lgnu -lnetwork
+ #SPECIAL_PERFORMANCE += -DUSEMMAP=1
+endif
+
+AFL_FUZZ_FILES = $(wildcard src/afl-fuzz*.c)
+
+ifneq "$(shell command -v python3m 2>/dev/null)" ""
+ ifneq "$(shell command -v python3m-config 2>/dev/null)" ""
+ PYTHON_INCLUDE ?= $(shell python3m-config --includes)
+ PYTHON_VERSION ?= $(strip $(shell python3m --version 2>&1))
+ # Starting with python3.8, we need to pass the `embed` flag. Earlier versions didn't know this flag.
+ ifeq "$(shell python3m-config --embed --libs 2>/dev/null | grep -q lpython && echo 1 )" "1"
+ PYTHON_LIB ?= $(shell python3m-config --libs --embed --ldflags)
+ else
+ PYTHON_LIB ?= $(shell python3m-config --ldflags)
+ endif
+ endif
+endif
+
+ifeq "$(PYTHON_INCLUDE)" ""
+ ifneq "$(shell command -v python3 2>/dev/null)" ""
+ ifneq "$(shell command -v python3-config 2>/dev/null)" ""
+ PYTHON_INCLUDE ?= $(shell python3-config --includes)
+ PYTHON_VERSION ?= $(strip $(shell python3 --version 2>&1))
+ # Starting with python3.8, we need to pass the `embed` flag. Earier versions didn't know this flag.
+ ifeq "$(shell python3-config --embed --libs 2>/dev/null | grep -q lpython && echo 1 )" "1"
+ PYTHON_LIB ?= $(shell python3-config --libs --embed --ldflags)
+ else
+ PYTHON_LIB ?= $(shell python3-config --ldflags)
+ endif
+ endif
+ endif
+endif
+
+ifeq "$(PYTHON_INCLUDE)" ""
+ ifneq "$(shell command -v python 2>/dev/null)" ""
+ ifneq "$(shell command -v python-config 2>/dev/null)" ""
+ PYTHON_INCLUDE ?= $(shell python-config --includes)
+ PYTHON_LIB ?= $(shell python-config --ldflags)
+ PYTHON_VERSION ?= $(strip $(shell python --version 2>&1))
+ endif
+ endif
+endif
+
+# Old Ubuntu and others dont have python/python3-config so we hardcode 3.7
+ifeq "$(PYTHON_INCLUDE)" ""
+ ifneq "$(shell command -v python3.7 2>/dev/null)" ""
+ ifneq "$(shell command -v python3.7-config 2>/dev/null)" ""
+ PYTHON_INCLUDE ?= $(shell python3.7-config --includes)
+ PYTHON_LIB ?= $(shell python3.7-config --ldflags)
+ PYTHON_VERSION ?= $(strip $(shell python3.7 --version 2>&1))
+ endif
+ endif
+endif
+
+# Old Ubuntu and others dont have python/python2-config so we hardcode 2.7
+ifeq "$(PYTHON_INCLUDE)" ""
+ ifneq "$(shell command -v python2.7 2>/dev/null)" ""
+ ifneq "$(shell command -v python2.7-config 2>/dev/null)" ""
+ PYTHON_INCLUDE ?= $(shell python2.7-config --includes)
+ PYTHON_LIB ?= $(shell python2.7-config --ldflags)
+ PYTHON_VERSION ?= $(strip $(shell python2.7 --version 2>&1))
+ endif
+ endif
+endif
+
+ifdef SOURCE_DATE_EPOCH
+ BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u "+%Y-%m-%d")
+else
+ BUILD_DATE ?= $(shell date "+%Y-%m-%d")
+endif
+
+ifneq "$(filter Linux GNU%,$(SYS))" ""
+ override LDFLAGS += -ldl -lrt -lm
+endif
+
+ifneq "$(findstring FreeBSD, $(SYS))" ""
+ override CFLAGS += -pthread
+ override LDFLAGS += -lpthread
+endif
+
+ifneq "$(findstring NetBSD, $(SYS))" ""
+ override CFLAGS += -pthread
+ override LDFLAGS += -lpthread
+endif
+
+ifneq "$(findstring OpenBSD, $(SYS))" ""
+ override CFLAGS += -pthread
+ override LDFLAGS += -lpthread
+endif
+
+COMM_HDR = include/alloc-inl.h include/config.h include/debug.h include/types.h
+
+ifeq "$(shell echo '$(HASH)include <Python.h>@int main() {return 0; }' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test $(PYTHON_INCLUDE) $(LDFLAGS) $(PYTHON_LIB) 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
+ PYTHON_OK=1
+ PYFLAGS=-DUSE_PYTHON $(PYTHON_INCLUDE) $(LDFLAGS) $(PYTHON_LIB) -DPYTHON_VERSION="\"$(PYTHON_VERSION)\""
+else
+ PYTHON_OK=0
+ PYFLAGS=
+endif
+
+ifdef NO_PYTHON
+ PYTHON_OK=0
+ PYFLAGS=
+endif
+
+IN_REPO=0
+ifeq "$(shell command -v git >/dev/null && git status >/dev/null 2>&1 && echo 1 || echo 0)" "1"
+ IN_REPO=1
+endif
+ifeq "$(shell command -v svn >/dev/null && svn proplist . 2>/dev/null && echo 1 || echo 0)" "1"
+ IN_REPO=1
+endif
+
+ifeq "$(shell echo 'int main() { return 0;}' | $(CC) $(CFLAGS) -fsanitize=address -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
+ ASAN_CFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer -DASAN_BUILD
+ ASAN_LDFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer
+endif
+
+ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
+ SHMAT_OK=1
+else
+ SHMAT_OK=0
+ override CFLAGS+=-DUSEMMAP=1
+ LDFLAGS += -Wno-deprecated-declarations
+endif
+
+ifdef TEST_MMAP
+ SHMAT_OK=0
+ override CFLAGS += -DUSEMMAP=1
+ LDFLAGS += -Wno-deprecated-declarations
+endif
+
+.PHONY: all
+all: test_x86 test_shm test_python ready $(PROGS) afl-as llvm gcc_plugin test_build all_done
+ -$(MAKE) -C utils/aflpp_driver
+
+.PHONY: llvm
+llvm:
+ -$(MAKE) -j4 -f GNUmakefile.llvm
+ @test -e afl-cc || { echo "[-] Compiling afl-cc failed. You seem not to have a working compiler." ; exit 1; }
+
+.PHONY: gcc_plugin
+gcc_plugin:
+ifneq "$(SYS)" "Darwin"
+ -$(MAKE) -f GNUmakefile.gcc_plugin
+endif
+
+.PHONY: man
+man: $(MANPAGES)
+
+.PHONY: test
+test: tests
+
+.PHONY: tests
+tests: source-only
+ @cd test ; ./test-all.sh
+ @rm -f test/errors
+
+.PHONY: performance-tests
+performance-tests: performance-test
+.PHONY: test-performance
+test-performance: performance-test
+
+.PHONY: performance-test
+performance-test: source-only
+ @cd test ; ./test-performance.sh
+
+
+# hint: make targets are also listed in the top level README.md
+.PHONY: help
+help:
+ @echo "HELP --- the following make targets exist:"
+ @echo "=========================================="
+ @echo "all: the main afl++ binaries and llvm/gcc instrumentation"
+ @echo "binary-only: everything for binary-only fuzzing: frida_mode, nyx_mode, qemu_mode, frida_mode, unicorn_mode, coresight_mode, libdislocator, libtokencap"
+ @echo "source-only: everything for source code fuzzing: nyx_mode, libdislocator, libtokencap"
+ @echo "distrib: everything (for both binary-only and source code fuzzing)"
+ @echo "man: creates simple man pages from the help option of the programs"
+ @echo "install: installs everything you have compiled with the build option above"
+ @echo "clean: cleans everything compiled (not downloads when on a checkout)"
+ @echo "deepclean: cleans everything including downloads"
+ @echo "uninstall: uninstall afl++ from the system"
+ @echo "code-format: format the code, do this before you commit and send a PR please!"
+ @echo "tests: this runs the test framework. It is more catered for the developers, but if you run into problems this helps pinpointing the problem"
+ @echo "unit: perform unit tests (based on cmocka and GNU linker)"
+ @echo "document: creates afl-fuzz-document which will only do one run and save all manipulated inputs into out/queue/mutations"
+ @echo "help: shows these build options :-)"
+ @echo "=========================================="
+ @echo "Recommended: \"distrib\" or \"source-only\", then \"install\""
+ @echo
+ @echo Known build environment options:
+ @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 INTROSPECTION - compile afl-fuzz with mutation introspection
+ @echo NO_PYTHON - disable python support
+ @echo NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for normal fuzzing
+ @echo NO_NYX - disable building nyx mode dependencies
+ @echo AFL_NO_X86 - if compiling on non-intel/amd platforms
+ @echo "LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g. Debian)"
+ @echo "=========================================="
+ @echo e.g.: make ASAN_BUILD=1
+
+.PHONY: test_x86
+ifndef AFL_NO_X86
+test_x86:
+ @echo "[*] Checking for the default compiler cc..."
+ @type $(CC) >/dev/null || ( echo; echo "Oops, looks like there is no compiler '"$(CC)"' in your path."; echo; echo "Don't panic! You can restart with '"$(_)" CC=<yourCcompiler>'."; echo; exit 1 )
+ @echo "[*] Testing the PATH environment variable..."
+ @test "$${PATH}" != "$${PATH#.:}" && { echo "Please remove current directory '.' from PATH to avoid recursion of 'as', thanks!"; echo; exit 1; } || :
+ @echo "[*] Checking for the ability to compile x86 code..."
+ @echo 'int main() { __asm__("xorb %al, %al"); }' | $(CC) $(CFLAGS) $(LDFLAGS) -w -x c - -o .test1 || ( echo; echo "Oops, looks like your compiler can't generate x86 code."; echo; echo "Don't panic! You can use the LLVM or QEMU mode, but see docs/INSTALL first."; echo "(To ignore this error, set AFL_NO_X86=1 and try again.)"; echo; exit 1 )
+ @rm -f .test1
+else
+test_x86:
+ @echo "[!] Note: skipping x86 compilation checks (AFL_NO_X86 set)."
+endif
+
+.PHONY: test_shm
+ifeq "$(SHMAT_OK)" "1"
+test_shm:
+ @echo "[+] shmat seems to be working."
+ @rm -f .test2
+else
+test_shm:
+ @echo "[-] shmat seems not to be working, switching to mmap implementation"
+endif
+
+.PHONY: test_python
+ifeq "$(PYTHON_OK)" "1"
+test_python:
+ @rm -f .test 2> /dev/null
+ @echo "[+] $(PYTHON_VERSION) support seems to be working."
+else
+test_python:
+ @echo "[-] You seem to need to install the package python3-dev, python2-dev or python-dev (and perhaps python[23]-apt), but it is optional so we continue"
+endif
+
+.PHONY: ready
+ready:
+ @echo "[+] Everything seems to be working, ready to compile."
+
+afl-as: src/afl-as.c include/afl-as.h $(COMM_HDR) | test_x86
+ $(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS)
+ @ln -sf afl-as as
+
+src/afl-performance.o : $(COMM_HDR) src/afl-performance.c include/hash.h
+ $(CC) $(CFLAGS) $(CFLAGS_OPT) -Iinclude -c src/afl-performance.c -o src/afl-performance.o
+
+src/afl-common.o : $(COMM_HDR) src/afl-common.c include/common.h
+ $(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-common.c -o src/afl-common.o
+
+src/afl-forkserver.o : $(COMM_HDR) src/afl-forkserver.c include/forkserver.h
+ $(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-forkserver.c -o src/afl-forkserver.o
+
+src/afl-sharedmem.o : $(COMM_HDR) src/afl-sharedmem.c include/sharedmem.h
+ $(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-sharedmem.c -o src/afl-sharedmem.o
+
+afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o | test_x86
+ $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS) -lm
+
+afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86
+ $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS)
+
+afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86
+ $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS)
+
+afl-analyze: src/afl-analyze.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o src/afl-forkserver.o $(COMM_HDR) | test_x86
+ $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o src/afl-forkserver.o -o $@ $(LDFLAGS)
+
+afl-gotcpu: src/afl-gotcpu.c src/afl-common.o $(COMM_HDR) | test_x86
+ $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o -o $@ $(LDFLAGS)
+
+.PHONY: document
+document: afl-fuzz-document
+
+# document all mutations and only do one run (use with only one input file!)
+afl-fuzz-document: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-performance.o | test_x86
+ $(CC) -D_DEBUG=\"1\" -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.c src/afl-performance.o -o afl-fuzz-document $(PYFLAGS) $(LDFLAGS)
+
+test/unittests/unit_maybe_alloc.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_maybe_alloc.c $(AFL_FUZZ_FILES)
+ @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_maybe_alloc.c -o test/unittests/unit_maybe_alloc.o
+
+unit_maybe_alloc: test/unittests/unit_maybe_alloc.o
+ @$(CC) $(CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_maybe_alloc.o -o test/unittests/unit_maybe_alloc $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
+ ./test/unittests/unit_maybe_alloc
+
+test/unittests/unit_hash.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_hash.c $(AFL_FUZZ_FILES) src/afl-performance.o
+ @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_hash.c -o test/unittests/unit_hash.o
+
+unit_hash: test/unittests/unit_hash.o src/afl-performance.o
+ @$(CC) $(CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_hash $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
+ ./test/unittests/unit_hash
+
+test/unittests/unit_rand.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_rand.c $(AFL_FUZZ_FILES) src/afl-performance.o
+ @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_rand.c -o test/unittests/unit_rand.o
+
+unit_rand: test/unittests/unit_rand.o src/afl-common.o src/afl-performance.o
+ @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_rand $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
+ ./test/unittests/unit_rand
+
+test/unittests/unit_list.o : $(COMM_HDR) include/list.h test/unittests/unit_list.c $(AFL_FUZZ_FILES)
+ @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_list.c -o test/unittests/unit_list.o
+
+unit_list: test/unittests/unit_list.o
+ @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_list.o -o test/unittests/unit_list $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
+ ./test/unittests/unit_list
+
+test/unittests/unit_preallocable.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_preallocable.c $(AFL_FUZZ_FILES)
+ @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_preallocable.c -o test/unittests/unit_preallocable.o
+
+unit_preallocable: test/unittests/unit_preallocable.o
+ @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_preallocable.o -o test/unittests/unit_preallocable $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
+ ./test/unittests/unit_preallocable
+
+.PHONY: unit_clean
+unit_clean:
+ @rm -f ./test/unittests/unit_preallocable ./test/unittests/unit_list ./test/unittests/unit_maybe_alloc test/unittests/*.o
+
+.PHONY: unit
+ifneq "$(SYS)" "Darwin"
+unit: unit_maybe_alloc unit_preallocable unit_list unit_clean unit_rand unit_hash
+else
+unit:
+ @echo [-] unit tests are skipped on Darwin \(lacks GNU linker feature --wrap\)
+endif
+
+.PHONY: code-format
+code-format:
+ ./.custom-format.py -i src/*.c
+ ./.custom-format.py -i include/*.h
+ ./.custom-format.py -i instrumentation/*.h
+ ./.custom-format.py -i instrumentation/*.cc
+ ./.custom-format.py -i instrumentation/*.c
+ ./.custom-format.py -i *.h
+ ./.custom-format.py -i *.c
+ @#./.custom-format.py -i custom_mutators/*/*.c* # destroys libfuzzer :-(
+ @#./.custom-format.py -i custom_mutators/*/*.h # destroys honggfuzz :-(
+ ./.custom-format.py -i utils/*/*.c*
+ ./.custom-format.py -i utils/*/*.h
+ ./.custom-format.py -i test/*.c
+ ./.custom-format.py -i frida_mode/src/*.c
+ ./.custom-format.py -i frida_mode/include/*.h
+ -./.custom-format.py -i frida_mode/src/*/*.c
+ ./.custom-format.py -i qemu_mode/libcompcov/*.c
+ ./.custom-format.py -i qemu_mode/libcompcov/*.cc
+ ./.custom-format.py -i qemu_mode/libcompcov/*.h
+ ./.custom-format.py -i qemu_mode/libqasan/*.c
+ ./.custom-format.py -i qemu_mode/libqasan/*.h
+
+
+.PHONY: test_build
+ifndef AFL_NO_X86
+test_build: afl-cc afl-gcc afl-as afl-showmap
+ @echo "[*] Testing the CC wrapper afl-cc and its instrumentation output..."
+ @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN; ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-cc test-instr.c $(LDFLAGS) -o test-instr 2>&1 || (echo "Oops, afl-cc failed"; exit 1 )
+ ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
+ echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
+ @rm -f test-instr
+ @cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation of afl-cc does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi
+ @echo
+ @echo "[+] All right, the instrumentation of afl-cc seems to be working!"
+# @echo "[*] Testing the CC wrapper afl-gcc and its instrumentation output..."
+# @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN; AFL_CC=$(CC) ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-gcc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-gcc failed"; exit 1 )
+# ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
+# echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
+# @rm -f test-instr
+# @cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation of afl-gcc does not seem to be behaving correctly!"; \
+# gcc -v 2>&1 | grep -q -- --with-as= && ( echo; echo "Gcc is configured not to use an external assembler with the -B option." ) || \
+# ( echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue." ); echo; exit 0; fi
+# @echo
+# @echo "[+] All right, the instrumentation of afl-gcc seems to be working!"
+else
+test_build: afl-cc afl-as afl-showmap
+ @echo "[!] Note: skipping build tests (you may need to use LLVM or QEMU mode)."
+endif
+
+.PHONY: all_done
+all_done: test_build
+ @test -e afl-cc && echo "[+] Main compiler 'afl-cc' successfully built!" || { echo "[-] Main compiler 'afl-cc' failed to build, set up a working build environment first!" ; exit 1 ; }
+ @test -e cmplog-instructions-pass.so && echo "[+] LLVM mode for 'afl-cc' successfully built!" || echo "[-] LLVM mode for 'afl-cc' failed to build, likely you either don't have llvm installed, or you need to set LLVM_CONFIG, to point to e.g. llvm-config-11. See instrumentation/README.llvm.md how to do this. Highly recommended!"
+ @test -e SanitizerCoverageLTO.so && echo "[+] LLVM LTO mode for 'afl-cc' successfully built!" || echo "[-] LLVM LTO mode for 'afl-cc' failed to build, this would need LLVM 11+, see instrumentation/README.lto.md how to build it"
+ @test -e afl-gcc-pass.so && echo "[+] gcc_plugin for 'afl-cc' successfully built!" || echo "[-] gcc_plugin for 'afl-cc' failed to build, unless you really need it that is fine - or read instrumentation/README.gcc_plugin.md how to build it"
+ @echo "[+] All done! Be sure to review the README.md - it's pretty short and useful."
+ @if [ "$(SYS)" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD for fuzzing software not\nspecifically for MacOS.\n\n"; fi
+ @! tty <&1 >/dev/null || printf "\033[0;30mNOTE: If you can read this, your terminal probably uses white background.\nThis will make the UI hard to read. See docs/status_screen.md for advice.\033[0m\n" 2>/dev/null
+
+.NOTPARALLEL: clean all
+
+.PHONY: clean
+clean:
+ rm -rf $(PROGS) afl-fuzz-document afl-as as afl-g++ afl-clang afl-clang++ *.o src/*.o *~ a.out core core.[1-9][0-9]* *.stackdump .test .test1 .test2 test-instr .test-instr0 .test-instr1 afl-cs-proxy afl-qemu-trace afl-gcc-fast afl-g++-fast ld *.so *.8 test/unittests/*.o test/unittests/unit_maybe_alloc test/unittests/preallocable .afl-* afl-gcc afl-g++ afl-clang afl-clang++ test/unittests/unit_hash test/unittests/unit_rand *.dSYM lib*.a
+ -$(MAKE) -f GNUmakefile.llvm clean
+ -$(MAKE) -f GNUmakefile.gcc_plugin clean
+ -$(MAKE) -C utils/libdislocator clean
+ -$(MAKE) -C utils/libtokencap clean
+ $(MAKE) -C utils/aflpp_driver clean
+ -$(MAKE) -C utils/afl_network_proxy clean
+ -$(MAKE) -C utils/socket_fuzzing clean
+ -$(MAKE) -C utils/argv_fuzzing clean
+ -$(MAKE) -C utils/plot_ui clean
+ -$(MAKE) -C qemu_mode/unsigaction clean
+ -$(MAKE) -C qemu_mode/libcompcov clean
+ -$(MAKE) -C qemu_mode/libqasan clean
+ -$(MAKE) -C frida_mode clean
+ rm -rf nyx_mode/packer/linux_initramfs/init.cpio.gz nyx_mode/libnyx/libnyx/target/release/* nyx_mode/QEMU-Nyx/x86_64-softmmu/qemu-system-x86_64
+ifeq "$(IN_REPO)" "1"
+ -test -e coresight_mode/coresight-trace/Makefile && $(MAKE) -C coresight_mode/coresight-trace clean || true
+ -test -e qemu_mode/qemuafl/Makefile && $(MAKE) -C qemu_mode/qemuafl clean || true
+ -test -e unicorn_mode/unicornafl/Makefile && $(MAKE) -C unicorn_mode/unicornafl clean || true
+ -test -e nyx_mode/QEMU-Nyx/Makefile && $(MAKE) -C nyx_mode/QEMU-Nyx clean || true
+else
+ rm -rf coresight_mode/coresight_trace
+ rm -rf qemu_mode/qemuafl
+ rm -rf unicorn_mode/unicornafl
+endif
+
+.PHONY: deepclean
+deepclean: clean
+ rm -rf coresight_mode/coresight-trace
+ rm -rf unicorn_mode/unicornafl
+ rm -rf qemu_mode/qemuafl
+ rm -rf nyx_mode/libnyx nyx_mode/packer nyx_mode/QEMU-Nyx
+ifeq "$(IN_REPO)" "1"
+ git checkout coresight_mode/coresight-trace
+ git checkout unicorn_mode/unicornafl
+ git checkout qemu_mode/qemuafl
+ git checkout nyx_mode/libnyx
+ git checkout nyx_mode/packer
+ git checkout nyx_mode/QEMU-Nyx
+endif
+
+.PHONY: distrib
+distrib: all
+ -$(MAKE) -j4 -f GNUmakefile.llvm
+ifneq "$(SYS)" "Darwin"
+ -$(MAKE) -f GNUmakefile.gcc_plugin
+endif
+ -$(MAKE) -C utils/libdislocator
+ -$(MAKE) -C utils/libtokencap
+ -$(MAKE) -C utils/afl_network_proxy
+ -$(MAKE) -C utils/socket_fuzzing
+ -$(MAKE) -C utils/argv_fuzzing
+ # -$(MAKE) -C utils/plot_ui
+ -$(MAKE) -C frida_mode
+ifneq "$(SYS)" "Darwin"
+ifeq "$(ARCH)" "aarch64"
+ -$(MAKE) -C coresight_mode
+endif
+ifeq "$(SYS)" "Linux"
+ifndef NO_NYX
+ -cd nyx_mode && ./build_nyx_support.sh
+endif
+endif
+ -cd qemu_mode && sh ./build_qemu_support.sh
+ -cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
+endif
+
+.PHONY: binary-only
+binary-only: test_shm test_python ready $(PROGS)
+ -$(MAKE) -C utils/libdislocator
+ -$(MAKE) -C utils/libtokencap
+ -$(MAKE) -C utils/afl_network_proxy
+ -$(MAKE) -C utils/socket_fuzzing
+ -$(MAKE) -C utils/argv_fuzzing
+ # -$(MAKE) -C utils/plot_ui
+ -$(MAKE) -C frida_mode
+ifneq "$(SYS)" "Darwin"
+ifeq "$(ARCH)" "aarch64"
+ -$(MAKE) -C coresight_mode
+endif
+ifeq "$(SYS)" "Linux"
+ifndef NO_NYX
+ -cd nyx_mode && ./build_nyx_support.sh
+endif
+endif
+ -cd qemu_mode && sh ./build_qemu_support.sh
+ -cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
+endif
+
+.PHONY: source-only
+source-only: all
+ -$(MAKE) -j4 -f GNUmakefile.llvm
+ifneq "$(SYS)" "Darwin"
+ -$(MAKE) -f GNUmakefile.gcc_plugin
+endif
+ -$(MAKE) -C utils/libdislocator
+ -$(MAKE) -C utils/libtokencap
+ # -$(MAKE) -C utils/plot_ui
+ifeq "$(SYS)" "Linux"
+ifndef NO_NYX
+ -cd nyx_mode && ./build_nyx_support.sh
+endif
+endif
+
+%.8: %
+ @echo .TH $* 8 $(BUILD_DATE) "afl++" > $@
+ @echo .SH NAME >> $@
+ @echo .B $* >> $@
+ @echo >> $@
+ @echo .SH SYNOPSIS >> $@
+ @./$* -h 2>&1 | head -n 3 | tail -n 1 | sed 's/^\.\///' >> $@
+ @echo >> $@
+ @echo .SH OPTIONS >> $@
+ @echo .nf >> $@
+ @./$* -hh 2>&1 | tail -n +4 >> $@
+ @echo >> $@
+ @echo .SH AUTHOR >> $@
+ @echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <domenukk@gmail.com>" >> $@
+ @echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> $@
+ @echo >> $@
+ @echo .SH LICENSE >> $@
+ @echo Apache License Version 2.0, January 2004 >> $@
+
+.PHONY: install
+install: all $(MANPAGES)
+ @install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH)
+ @rm -f $${DESTDIR}$(BIN_PATH)/afl-plot.sh
+ @rm -f $${DESTDIR}$(BIN_PATH)/afl-as
+ @rm -f $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-32.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-64.o $${DESTDIR}$(HELPER_PATH)/afl-gcc-rt.o
+ install -m 755 $(PROGS) $(SH_PROGS) $${DESTDIR}$(BIN_PATH)
+ @if [ -f afl-qemu-trace ]; then install -m 755 afl-qemu-trace $${DESTDIR}$(BIN_PATH); fi
+ @if [ -f utils/plot_ui/afl-plot-ui ]; then install -m 755 utils/plot_ui/afl-plot-ui $${DESTDIR}$(BIN_PATH); fi
+ @if [ -f libdislocator.so ]; then set -e; install -m 755 libdislocator.so $${DESTDIR}$(HELPER_PATH); fi
+ @if [ -f libtokencap.so ]; then set -e; install -m 755 libtokencap.so $${DESTDIR}$(HELPER_PATH); fi
+ @if [ -f libcompcov.so ]; then set -e; install -m 755 libcompcov.so $${DESTDIR}$(HELPER_PATH); fi
+ @if [ -f libqasan.so ]; then set -e; install -m 755 libqasan.so $${DESTDIR}$(HELPER_PATH); fi
+ @if [ -f afl-fuzz-document ]; then set -e; install -m 755 afl-fuzz-document $${DESTDIR}$(BIN_PATH); fi
+ @if [ -f socketfuzz32.so -o -f socketfuzz64.so ]; then $(MAKE) -C utils/socket_fuzzing install; fi
+ @if [ -f argvfuzz32.so -o -f argvfuzz64.so ]; then $(MAKE) -C utils/argv_fuzzing install; fi
+ @if [ -f afl-frida-trace.so ]; then install -m 755 afl-frida-trace.so $${DESTDIR}$(HELPER_PATH); fi
+ @if [ -f libnyx.so ]; then install -m 755 libnyx.so $${DESTDIR}$(HELPER_PATH); fi
+ @if [ -f utils/afl_network_proxy/afl-network-server ]; then $(MAKE) -C utils/afl_network_proxy install; fi
+ @if [ -f utils/aflpp_driver/libAFLDriver.a ]; then set -e; install -m 644 utils/aflpp_driver/libAFLDriver.a $${DESTDIR}$(HELPER_PATH); fi
+ @if [ -f utils/aflpp_driver/libAFLQemuDriver.a ]; then set -e; install -m 644 utils/aflpp_driver/libAFLQemuDriver.a $${DESTDIR}$(HELPER_PATH); fi
+ -$(MAKE) -f GNUmakefile.llvm install
+ifneq "$(SYS)" "Darwin"
+ -$(MAKE) -f GNUmakefile.gcc_plugin install
+endif
+ ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-gcc
+ ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-g++
+ ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang
+ ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang++
+ @mkdir -m 0755 -p ${DESTDIR}$(MAN_PATH)
+ install -m0644 *.8 ${DESTDIR}$(MAN_PATH)
+ install -m 755 afl-as $${DESTDIR}$(HELPER_PATH)
+ ln -sf afl-as $${DESTDIR}$(HELPER_PATH)/as
+ install -m 644 docs/*.md $${DESTDIR}$(DOC_PATH)
+ cp -r testcases/ $${DESTDIR}$(MISC_PATH)
+ cp -r dictionaries/ $${DESTDIR}$(MISC_PATH)
+
+.PHONY: uninstall
+uninstall:
+ -cd $${DESTDIR}$(BIN_PATH) && rm -f $(PROGS) $(SH_PROGS) afl-cs-proxy afl-qemu-trace afl-plot-ui afl-fuzz-document afl-network-server afl-g* afl-plot.sh afl-as afl-ld-lto afl-c* afl-lto*
+ -cd $${DESTDIR}$(HELPER_PATH) && rm -f afl-g*.*o afl-llvm-*.*o afl-compiler-*.*o libdislocator.so libtokencap.so libcompcov.so libqasan.so afl-frida-trace.so libnyx.so socketfuzz*.so argvfuzz*.so libAFLDriver.a libAFLQemuDriver.a as afl-as SanitizerCoverage*.so compare-transform-pass.so cmplog-*-pass.so split-*-pass.so dynamic_list.txt
+ -rm -rf $${DESTDIR}$(MISC_PATH)/testcases $${DESTDIR}$(MISC_PATH)/dictionaries
+ -sh -c "ls docs/*.md | sed 's|^docs/|$${DESTDIR}$(DOC_PATH)/|' | xargs rm -f"
+ -cd $${DESTDIR}$(MAN_PATH) && rm -f $(MANPAGES)
+ -rmdir $${DESTDIR}$(BIN_PATH) 2>/dev/null
+ -rmdir $${DESTDIR}$(HELPER_PATH) 2>/dev/null
+ -rmdir $${DESTDIR}$(MISC_PATH) 2>/dev/null
+ -rmdir $${DESTDIR}$(DOC_PATH) 2>/dev/null
+ -rmdir $${DESTDIR}$(MAN_PATH) 2>/dev/null
diff --git a/GNUmakefile.gcc_plugin b/GNUmakefile.gcc_plugin
new file mode 100644
index 00000000..e21203ae
--- /dev/null
+++ b/GNUmakefile.gcc_plugin
@@ -0,0 +1,198 @@
+#
+# american fuzzy lop++ - GCC plugin instrumentation
+# -----------------------------------------------
+#
+# Written by Austin Seipp <aseipp@pobox.com> and
+# Laszlo Szekeres <lszekeres@google.com> and
+# Michal Zalewski and
+# Heiko Eißfeldt <heiko@hexco.de>
+#
+# GCC integration design is based on the LLVM design, which comes
+# from Laszlo Szekeres.
+#
+# Copyright 2015 Google Inc. All rights reserved.
+# Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+#TEST_MMAP=1
+PREFIX ?= /usr/local
+HELPER_PATH ?= $(PREFIX)/lib/afl
+BIN_PATH ?= $(PREFIX)/bin
+DOC_PATH ?= $(PREFIX)/share/doc/afl
+MAN_PATH ?= $(PREFIX)/share/man/man8
+
+VERSION = $(shell grep '^$(HASH)define VERSION ' ./config.h | cut -d '"' -f2)
+
+CFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=2
+CFLAGS_SAFE := -Wall -Iinclude -Wno-pointer-sign \
+ -DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
+ -DGCC_VERSION=\"$(GCCVER)\" -DGCC_BINDIR=\"$(GCCBINDIR)\" \
+ -Wno-unused-function
+override CFLAGS += $(CFLAGS_SAFE)
+
+CXXFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=2
+CXXEFLAGS := $(CXXFLAGS) -Wall -std=c++11
+
+CC ?= gcc
+CXX ?= g++
+
+SYS = $(shell uname -s)
+
+ifeq "clang" "$(CC)"
+ CC = gcc
+ CXX = g++
+endif
+
+ifeq "clang++" "$(CXX)"
+ CC = gcc
+ CXX = g++
+endif
+
+ifeq "$(findstring Foundation,$(shell $(CC) --version))" ""
+ CC = gcc
+ CXX = g++
+endif
+
+PLUGIN_BASE = "$(shell $(CC) -print-file-name=plugin)"
+PLUGIN_FLAGS = -fPIC -fno-rtti -I$(PLUGIN_BASE)/include -I$(PLUGIN_BASE)
+HASH=\#
+
+GCCVER = $(shell $(CC) --version 2>/dev/null | awk 'NR == 1 {print $$NF}')
+GCCBINDIR = $(shell dirname `command -v $(CC)` 2>/dev/null )
+
+ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
+ SHMAT_OK=1
+else
+ SHMAT_OK=0
+ override CFLAGS_SAFE += -DUSEMMAP=1
+endif
+
+ifeq "$(TEST_MMAP)" "1"
+ SHMAT_OK=0
+ override CFLAGS_SAFE += -DUSEMMAP=1
+endif
+
+ifneq "$(SYS)" "Haiku"
+ifneq "$(SYS)" "OpenBSD"
+ LDFLAGS += -lrt
+endif
+else
+ CFLAGS_SAFE += -DUSEMMAP=1
+endif
+
+ifeq "$(SYS)" "OpenBSD"
+ CC = egcc
+ CXX = eg++
+ PLUGIN_FLAGS += -I/usr/local/include
+endif
+
+ifeq "$(SYS)" "DragonFly"
+ PLUGIN_FLAGS += -I/usr/local/include
+endif
+
+ifeq "$(SYS)" "SunOS"
+ PLUGIN_FLAGS += -I/usr/include/gmp
+endif
+
+
+PROGS = ./afl-gcc-pass.so ./afl-compiler-rt.o ./afl-compiler-rt-32.o ./afl-compiler-rt-64.o
+
+.PHONY: all
+all: test_shm test_deps $(PROGS) test_build all_done
+
+.PHONY: test_shm
+ifeq "$(SHMAT_OK)" "1"
+test_shm:
+ @echo "[+] shmat seems to be working."
+ @rm -f .test2
+else
+test_shm:
+ @echo "[-] shmat seems not to be working, switching to mmap implementation"
+endif
+
+.PHONY: test_deps
+test_deps:
+ @echo "[*] Checking for working '$(CC)'..."
+ @command -v $(CC) >/dev/null 2>&1 || ( echo "[-] Oops, can't find '$(CC)'. Make sure that it's in your \$$PATH (or set \$$CC and \$$CXX)."; exit 1 )
+# @echo "[*] Checking for gcc for plugin support..."
+# @$(CC) -v 2>&1 | grep -q -- --enable-plugin || ( echo "[-] Oops, this gcc has not been configured with plugin support."; exit 1 )
+ @echo "[*] Checking for gcc plugin development header files..."
+ @test -d `$(CC) -print-file-name=plugin`/include || ( echo "[-] Oops, can't find gcc header files. Be sure to install 'gcc-X-plugin-dev'."; exit 1 )
+ @echo "[*] Checking for './afl-showmap'..."
+ @test -f ./afl-showmap || ( echo "[-] Oops, can't find './afl-showmap'. Be sure to compile AFL first."; exit 1 )
+ @echo "[+] All set and ready to build."
+
+afl-common.o: ./src/afl-common.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ $(LDFLAGS)
+
+./afl-compiler-rt.o: instrumentation/afl-compiler-rt.o.c
+ $(CC) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -fPIC -c $< -o $@
+
+./afl-compiler-rt-32.o: instrumentation/afl-compiler-rt.o.c
+ @printf "[*] Building 32-bit variant of the runtime (-m32)... "
+ @$(CC) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
+
+./afl-compiler-rt-64.o: instrumentation/afl-compiler-rt.o.c
+ @printf "[*] Building 64-bit variant of the runtime (-m64)... "
+ @$(CC) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
+
+./afl-gcc-pass.so: instrumentation/afl-gcc-pass.so.cc | test_deps
+ $(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@
+ ln -sf afl-cc afl-gcc-fast
+ ln -sf afl-cc afl-g++-fast
+ ln -sf afl-cc.8 afl-gcc-fast.8
+ ln -sf afl-cc.8 afl-g++-fast.8
+
+.PHONY: test_build
+test_build: $(PROGS)
+ @echo "[*] Testing the CC wrapper and instrumentation output..."
+ unset AFL_USE_ASAN AFL_USE_MSAN; ASAN_OPTIONS=detect_leaks=0 AFL_QUIET=1 AFL_INST_RATIO=100 AFL_PATH=. AFL_CC=$(CC) ./afl-gcc-fast $(CFLAGS) $(CPPFLAGS) ./test-instr.c -o test-instr $(LDFLAGS)
+ ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr </dev/null
+ echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
+ @rm -f test-instr
+ @cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi
+ @echo "[+] All right, the instrumentation seems to be working!"
+
+.PHONY: all_done
+all_done: test_build
+ @echo "[+] All done! You can now use './afl-gcc-fast' to compile programs."
+
+.NOTPARALLEL: clean
+
+%.8: %
+ @echo .TH $* 8 `date "+%Y-%m-%d"` "afl++" > ./$@
+ @echo .SH NAME >> ./$@
+ @echo .B $* >> ./$@
+ @echo >> ./$@
+ @echo .SH SYNOPSIS >> ./$@
+ @./$* -h 2>&1 | head -n 3 | tail -n 1 | sed 's/^\.\///' >> ./$@
+ @echo >> ./$@
+ @echo .SH OPTIONS >> ./$@
+ @echo .nf >> ./$@
+ @./$* -h 2>&1 | tail -n +4 >> ./$@
+ @echo >> ./$@
+ @echo .SH AUTHOR >> ./$@
+ @echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <domenukk@gmail.com>" >> ./$@
+ @echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> ./$@
+ @echo >> ./$@
+ @echo .SH LICENSE >> ./$@
+ @echo Apache License Version 2.0, January 2004 >> ./$@
+ ln -sf afl-cc.8 ./afl-g++-fast.8
+
+.PHONY: install
+install: all
+ ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-gcc-fast
+ ln -sf afl-c++ $${DESTDIR}$(BIN_PATH)/afl-g++-fast
+ ln -sf afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH)/afl-gcc-rt.o
+ install -m 755 ./afl-gcc-pass.so $${DESTDIR}$(HELPER_PATH)
+ install -m 644 -T instrumentation/README.gcc_plugin.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.md
+
+.PHONY: clean
+clean:
+ rm -f *.o *.so *~ a.out core core.[1-9][0-9]* test-instr .test-instr0 .test-instr1 .test2
+ rm -f $(PROGS) afl-common.o ./afl-g++-fast ./afl-g*-fast.8 instrumentation/*.o
diff --git a/GNUmakefile.llvm b/GNUmakefile.llvm
new file mode 100644
index 00000000..e775ca98
--- /dev/null
+++ b/GNUmakefile.llvm
@@ -0,0 +1,529 @@
+# american fuzzy lop++ - LLVM instrumentation
+# -----------------------------------------
+#
+# Written by Laszlo Szekeres <lszekeres@google.com> and
+# Michal Zalewski
+#
+# LLVM integration design comes from Laszlo Szekeres.
+#
+# Copyright 2015, 2016 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+
+# For Heiko:
+#TEST_MMAP=1
+HASH=\#
+
+PREFIX ?= /usr/local
+HELPER_PATH ?= $(PREFIX)/lib/afl
+BIN_PATH ?= $(PREFIX)/bin
+DOC_PATH ?= $(PREFIX)/share/doc/afl
+MISC_PATH ?= $(PREFIX)/share/afl
+MAN_PATH ?= $(PREFIX)/share/man/man8
+
+BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u "+%Y-%m-%d")
+
+VERSION = $(shell grep '^$(HASH)define VERSION ' ./config.h | cut -d '"' -f2)
+
+SYS = $(shell uname -s)
+
+ifeq "$(SYS)" "OpenBSD"
+ LLVM_CONFIG ?= $(BIN_PATH)/llvm-config
+ HAS_OPT = $(shell test -x $(BIN_PATH)/opt && echo 0 || echo 1)
+ ifeq "$(HAS_OPT)" "1"
+ $(warning llvm_mode needs a complete llvm installation (versions 6.0 up to 13) -> e.g. "pkg_add llvm-7.0.1p9")
+ endif
+else
+ LLVM_CONFIG ?= llvm-config
+endif
+
+LLVMVER = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/git//' | sed 's/svn//' )
+LLVM_MAJOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/\..*//' )
+LLVM_MINOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/.*\.//' | sed 's/git//' | sed 's/svn//' | sed 's/ .*//' )
+LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^[0-2]\.|^3.[0-7]\.' && echo 1 || echo 0 )
+LLVM_TOO_NEW = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[5-9]' && echo 1 || echo 0 )
+LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[0-9]' && echo 1 || echo 0 )
+LLVM_10_OK = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[1-9]|^10\.[1-9]|^10\.0.[1-9]' && echo 1 || echo 0 )
+LLVM_HAVE_LTO = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[1-9]' && echo 1 || echo 0 )
+LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null)
+LLVM_LIBDIR = $(shell $(LLVM_CONFIG) --libdir 2>/dev/null)
+LLVM_STDCXX = gnu++11
+LLVM_APPLE_XCODE = $(shell $(CC) -v 2>&1 | grep -q Apple && echo 1 || echo 0)
+LLVM_LTO = 0
+
+ifeq "$(LLVMVER)" ""
+ $(warning [!] llvm_mode needs llvm-config, which was not found. Set LLVM_CONFIG to its path and retry.)
+endif
+
+ifeq "$(LLVM_UNSUPPORTED)" "1"
+ $(error llvm_mode only supports llvm from version 3.8 onwards)
+endif
+
+ifeq "$(LLVM_TOO_NEW)" "1"
+ $(warning you are using an in-development llvm version - this might break llvm_mode!)
+endif
+
+LLVM_TOO_OLD=1
+
+ifeq "$(LLVM_MAJOR)" "9"
+ $(info [+] llvm_mode detected llvm 9, enabling neverZero implementation)
+ LLVM_TOO_OLD=0
+endif
+
+ifeq "$(LLVM_NEW_API)" "1"
+ $(info [+] llvm_mode detected llvm 10+, enabling neverZero implementation and c++14)
+ LLVM_STDCXX = c++14
+ LLVM_TOO_OLD=0
+endif
+
+ifeq "$(LLVM_TOO_OLD)" "1"
+ $(info [!] llvm_mode detected an old version of llvm, upgrade to at least 9 or preferable 11!)
+ $(shell sleep 1)
+endif
+
+ifeq "$(LLVM_MAJOR)" "15"
+ $(info [!] llvm_mode detected llvm 15, which is currently broken for LTO plugins.)
+ LLVM_LTO = 0
+ LLVM_HAVE_LTO = 0
+endif
+
+ifeq "$(LLVM_HAVE_LTO)" "1"
+ $(info [+] llvm_mode detected llvm 11+, enabling afl-lto LTO implementation)
+ LLVM_LTO = 1
+ #TEST_MMAP = 1
+endif
+
+ifeq "$(LLVM_LTO)" "0"
+ $(info [+] llvm_mode detected llvm < 11 or llvm 15, afl-lto LTO will not be build.)
+endif
+
+ifeq "$(LLVM_APPLE_XCODE)" "1"
+ $(warning llvm_mode will not compile with Xcode clang...)
+endif
+
+# We were using llvm-config --bindir to get the location of clang, but
+# this seems to be busted on some distros, so using the one in $PATH is
+# probably better.
+
+CC = $(LLVM_BINDIR)/clang
+CXX = $(LLVM_BINDIR)/clang++
+
+# llvm-config --bindir may not providing a valid path, so ...
+ifeq "$(shell test -e $(CC) || echo 1 )" "1"
+ # however we must ensure that this is not a "CC=gcc make"
+ ifeq "$(shell command -v $(CC) 2> /dev/null)" ""
+ # we do not have a valid CC variable so we try alternatives
+ ifeq "$(shell test -e '$(BIN_DIR)/clang' && echo 1)" "1"
+ # we found one in the local install directory, lets use these
+ CC = $(BIN_DIR)/clang
+ else
+ # hope for the best
+ $(warning we have trouble finding clang - llvm-config is not helping us)
+ CC = clang
+ endif
+ endif
+endif
+# llvm-config --bindir may not providing a valid path, so ...
+ifeq "$(shell test -e $(CXX) || echo 1 )" "1"
+ # however we must ensure that this is not a "CXX=g++ make"
+ ifeq "$(shell command -v $(CXX) 2> /dev/null)" ""
+ # we do not have a valid CXX variable so we try alternatives
+ ifeq "$(shell test -e '$(BIN_DIR)/clang++' && echo 1)" "1"
+ # we found one in the local install directory, lets use these
+ CXX = $(BIN_DIR)/clang++
+ else
+ # hope for the best
+ $(warning we have trouble finding clang++ - llvm-config is not helping us)
+ CXX = clang++
+ endif
+ endif
+endif
+
+# sanity check.
+# Are versions of clang --version and llvm-config --version equal?
+CLANGVER = $(shell $(CC) --version | sed -E -ne '/^.*version\ (1?[0-9]\.[0-9]\.[0-9]).*/s//\1/p')
+
+# I disable this because it does not make sense with what we did before (marc)
+# We did exactly set these 26 lines above with these values, and it would break
+# "CC=gcc make" etc. usages
+ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" ""
+ CC_SAVE := $(LLVM_BINDIR)/clang
+else
+ CC_SAVE := $(CC)
+endif
+ifeq "$(findstring clang, $(shell $(CXX) --version 2>/dev/null))" ""
+ CXX_SAVE := $(LLVM_BINDIR)/clang++
+else
+ CXX_SAVE := $(CXX)
+endif
+
+CLANG_BIN := $(CC_SAVE)
+CLANGPP_BIN := $(CXX_SAVE)
+
+ifeq "$(CC_SAVE)" "$(LLVM_BINDIR)/clang"
+ USE_BINDIR = 1
+else
+ ifeq "$(CXX_SAVE)" "$(LLVM_BINDIR)/clang++"
+ USE_BINDIR = 1
+ else
+ USE_BINDIR = 0
+ endif
+endif
+
+# On old platform we cannot compile with clang because std++ libraries are too
+# old. For these we need to use gcc/g++, so if we find REAL_CC and REAL_CXX
+# variable we override the compiler variables here
+ifneq "$(REAL_CC)" ""
+ CC = $(REAL_CC)
+endif
+ifneq "$(REAL_CXX)" ""
+ CXX = $(REAL_CXX)
+endif
+
+#
+# Now it can happen that CC points to clang - but there is no clang on the
+# system. Then we fall back to cc
+#
+ifeq "$(shell command -v $(CC) 2>/dev/null)" ""
+ CC = cc
+endif
+ifeq "$(shell command -v $(CXX) 2>/dev/null)" ""
+ CXX = c++
+endif
+
+
+# After we set CC/CXX we can start makefile magic tests
+
+#ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -march=native -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
+# CFLAGS_OPT = -march=native
+#endif
+
+ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
+ AFL_CLANG_FLTO ?= -flto=full
+else
+ ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
+ AFL_CLANG_FLTO ?= -flto=thin
+ else
+ ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
+ AFL_CLANG_FLTO ?= -flto
+ endif
+ endif
+endif
+
+ifeq "$(LLVM_LTO)" "1"
+ ifneq "$(AFL_CLANG_FLTO)" ""
+ ifeq "$(AFL_REAL_LD)" ""
+ ifneq "$(shell readlink $(LLVM_BINDIR)/ld.lld 2>&1)" ""
+ AFL_REAL_LD = $(LLVM_BINDIR)/ld.lld
+ else
+ $(warning ld.lld not found, cannot enable LTO mode)
+ LLVM_LTO = 0
+ endif
+ endif
+ else
+ $(warning clang option -flto is not working - maybe LLVMgold.so not found - cannot enable LTO mode)
+ LLVM_LTO = 0
+ endif
+endif
+
+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
+ $(warning -fuse-ld is not working, cannot enable LTO mode)
+ LLVM_LTO = 0
+ endif
+endif
+
+ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -fdebug-prefix-map=$(CURDIR)=llvm_mode -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
+ AFL_CLANG_DEBUG_PREFIX = -fdebug-prefix-map="$(CURDIR)=llvm_mode"
+else
+ AFL_CLANG_DEBUG_PREFIX =
+endif
+
+CFLAGS ?= -O3 -funroll-loops -fPIC -D_FORTIFY_SOURCE=2
+CFLAGS_SAFE := -Wall -g -Wno-cast-qual -Wno-variadic-macros -Wno-pointer-sign -I ./include/ -I ./instrumentation/ \
+ -DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
+ -DLLVM_BINDIR=\"$(LLVM_BINDIR)\" -DVERSION=\"$(VERSION)\" \
+ -DLLVM_LIBDIR=\"$(LLVM_LIBDIR)\" -DLLVM_VERSION=\"$(LLVMVER)\" \
+ -Wno-deprecated -DAFL_CLANG_FLTO=\"$(AFL_CLANG_FLTO)\" \
+ -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 \
+ $(AFL_CLANG_DEBUG_PREFIX)
+override CFLAGS += $(CFLAGS_SAFE)
+
+ifdef AFL_TRACE_PC
+ $(info Compile option AFL_TRACE_PC is deprecated, just set AFL_LLVM_INSTRUMENT=PCGUARD to activate when compiling targets )
+endif
+
+CXXFLAGS ?= -O3 -funroll-loops -fPIC -D_FORTIFY_SOURCE=2
+override CXXFLAGS += -Wall -g -I ./include/ \
+ -DVERSION=\"$(VERSION)\" -Wno-variadic-macros \
+ -DLLVM_MINOR=$(LLVM_MINOR) -DLLVM_MAJOR=$(LLVM_MAJOR)
+
+ifneq "$(shell $(LLVM_CONFIG) --includedir) 2> /dev/null" ""
+ CLANG_CFL = -I$(shell $(LLVM_CONFIG) --includedir)
+endif
+ifneq "$(LLVM_CONFIG)" ""
+ CLANG_CFL += -I$(shell dirname $(LLVM_CONFIG))/../include
+endif
+CLANG_CPPFL = `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fPIC $(CXXFLAGS) -Wno-deprecated-declarations
+CLANG_LFL = `$(LLVM_CONFIG) --ldflags` $(LDFLAGS)
+
+
+# User teor2345 reports that this is required to make things work on MacOS X.
+ifeq "$(SYS)" "Darwin"
+ CLANG_LFL += -Wl,-flat_namespace -Wl,-undefined,suppress
+ override LLVM_HAVE_LTO := 0
+ override LLVM_LTO := 0
+else
+ CLANG_CPPFL += -Wl,-znodelete
+endif
+
+ifeq "$(SYS)" "OpenBSD"
+ CLANG_LFL += `$(LLVM_CONFIG) --libdir`/libLLVM.so
+ CLANG_CPPFL += -mno-retpoline
+ CFLAGS += -mno-retpoline
+ # Needed for unwind symbols
+ LDFLAGS += -lc++abi -lpthread
+endif
+
+ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
+ SHMAT_OK=1
+else
+ SHMAT_OK=0
+ CFLAGS_SAFE += -DUSEMMAP=1
+ LDFLAGS += -Wno-deprecated-declarations
+endif
+
+ifeq "$(TEST_MMAP)" "1"
+ SHMAT_OK=0
+ CFLAGS_SAFE += -DUSEMMAP=1
+ LDFLAGS += -Wno-deprecated-declarations
+endif
+
+PROGS_ALWAYS = ./afl-cc ./afl-compiler-rt.o ./afl-compiler-rt-32.o ./afl-compiler-rt-64.o
+PROGS = $(PROGS_ALWAYS) ./afl-llvm-pass.so ./SanitizerCoveragePCGUARD.so ./split-compares-pass.so ./split-switches-pass.so ./cmplog-routines-pass.so ./cmplog-instructions-pass.so ./cmplog-switches-pass.so ./afl-llvm-dict2file.so ./compare-transform-pass.so ./afl-ld-lto ./afl-llvm-lto-instrumentlist.so ./SanitizerCoverageLTO.so
+
+# If prerequisites are not given, warn, do not build anything, and exit with code 0
+ifeq "$(LLVMVER)" ""
+ NO_BUILD = 1
+endif
+
+ifneq "$(LLVM_UNSUPPORTED)$(LLVM_APPLE_XCODE)" "00"
+ NO_BUILD = 1
+endif
+
+ifeq "$(NO_BUILD)" "1"
+ TARGETS = test_shm $(PROGS_ALWAYS) afl-cc.8
+else
+ TARGETS = test_shm test_deps $(PROGS) afl-cc.8 test_build all_done
+endif
+
+LLVM_MIN_4_0_1 = $(shell awk 'function tonum(ver, a) {split(ver,a,"."); return a[1]*1000000+a[2]*1000+a[3]} BEGIN { exit tonum(ARGV[1]) >= tonum(ARGV[2]) }' $(LLVMVER) 4.0.1; echo $$?)
+
+.PHONY: all
+all: $(TARGETS)
+
+.PHONY: test_shm
+ifeq "$(SHMAT_OK)" "1"
+test_shm:
+ @echo "[+] shmat seems to be working."
+ @rm -f .test2
+else
+test_shm:
+ @echo "[-] shmat seems not to be working, switching to mmap implementation"
+endif
+
+.PHONY: no_build
+no_build:
+ @printf "%b\\n" "\\033[0;31mPrerequisites are not met, skipping build llvm_mode\\033[0m"
+
+.PHONY: test_deps
+test_deps:
+ @echo "[*] Checking for working 'llvm-config'..."
+ ifneq "$(LLVM_APPLE_XCODE)" "1"
+ @type $(LLVM_CONFIG) >/dev/null 2>&1 || ( echo "[-] Oops, can't find 'llvm-config'. Install clang or set \$$LLVM_CONFIG or \$$PATH beforehand."; echo " (Sometimes, the binary will be named llvm-config-11 or something like that.)"; exit 1 )
+ endif
+ @echo "[*] Checking for working '$(CC)'..."
+ @type $(CC) >/dev/null 2>&1 || ( echo "[-] Oops, can't find '$(CC)'. Make sure that it's in your \$$PATH (or set \$$CC and \$$CXX)."; exit 1 )
+ @echo "[*] Checking for matching versions of '$(CC)' and '$(LLVM_CONFIG)'"
+ifneq "$(CLANGVER)" "$(LLVMVER)"
+ @echo "[!] WARNING: we have llvm-config version $(LLVMVER) and a clang version $(CLANGVER)"
+else
+ @echo "[*] We have llvm-config version $(LLVMVER) with a clang version $(CLANGVER), good."
+endif
+ @echo "[*] Checking for './afl-showmap'..."
+ @test -f ./afl-showmap || ( echo "[-] Oops, can't find './afl-showmap'. Be sure to compile AFL first."; exit 1 )
+ @echo "[+] All set and ready to build."
+
+instrumentation/afl-common.o: ./src/afl-common.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ $(LDFLAGS)
+
+./afl-cc: src/afl-cc.c instrumentation/afl-common.o
+ $(CC) $(CLANG_CFL) $(CFLAGS) $(CPPFLAGS) $< instrumentation/afl-common.o -o $@ -DLLVM_MINOR=$(LLVM_MINOR) -DLLVM_MAJOR=$(LLVM_MAJOR) $(LDFLAGS) -DCFLAGS_OPT=\"$(CFLAGS_OPT)\" -lm
+ @ln -sf afl-cc ./afl-c++
+ @ln -sf afl-cc ./afl-gcc
+ @ln -sf afl-cc ./afl-g++
+ @ln -sf afl-cc ./afl-clang
+ @ln -sf afl-cc ./afl-clang++
+ @ln -sf afl-cc ./afl-clang-fast
+ @ln -sf afl-cc ./afl-clang-fast++
+ifneq "$(AFL_CLANG_FLTO)" ""
+ifeq "$(LLVM_LTO)" "1"
+ @ln -sf afl-cc ./afl-clang-lto
+ @ln -sf afl-cc ./afl-clang-lto++
+ @ln -sf afl-cc ./afl-lto
+ @ln -sf afl-cc ./afl-lto++
+endif
+endif
+
+instrumentation/afl-llvm-common.o: instrumentation/afl-llvm-common.cc instrumentation/afl-llvm-common.h
+ $(CXX) $(CFLAGS) $(CPPFLAGS) `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fPIC -std=$(LLVM_STDCXX) -c $< -o $@
+
+./afl-llvm-pass.so: instrumentation/afl-llvm-pass.so.cc instrumentation/afl-llvm-common.o | test_deps
+ifeq "$(LLVM_MIN_4_0_1)" "0"
+ $(info [!] N-gram branch coverage instrumentation is not available for llvm version $(LLVMVER))
+endif
+ $(CXX) $(CLANG_CPPFL) -Wdeprecated -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
+
+./SanitizerCoveragePCGUARD.so: instrumentation/SanitizerCoveragePCGUARD.so.cc instrumentation/afl-llvm-common.o | test_deps
+ifeq "$(LLVM_10_OK)" "1"
+ -$(CXX) $(CLANG_CPPFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) -Wno-deprecated-copy-dtor -Wdeprecated instrumentation/afl-llvm-common.o
+endif
+
+./afl-llvm-lto-instrumentlist.so: instrumentation/afl-llvm-lto-instrumentlist.so.cc instrumentation/afl-llvm-common.o
+ifeq "$(LLVM_LTO)" "1"
+ $(CXX) $(CLANG_CPPFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
+endif
+
+./afl-ld-lto: src/afl-ld-lto.c
+ifeq "$(LLVM_LTO)" "1"
+ $(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@
+endif
+
+./SanitizerCoverageLTO.so: instrumentation/SanitizerCoverageLTO.so.cc instrumentation/afl-llvm-common.o
+ifeq "$(LLVM_LTO)" "1"
+ $(CXX) $(CLANG_CPPFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
+ $(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -fPIC -c instrumentation/afl-llvm-rt-lto.o.c -o ./afl-llvm-rt-lto.o
+ @$(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m64 -fPIC -c instrumentation/afl-llvm-rt-lto.o.c -o ./afl-llvm-rt-lto-64.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi
+ @$(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m32 -fPIC -c instrumentation/afl-llvm-rt-lto.o.c -o ./afl-llvm-rt-lto-32.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi
+endif
+
+# laf
+./split-switches-pass.so: instrumentation/split-switches-pass.so.cc instrumentation/afl-llvm-common.o | test_deps
+ $(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
+./compare-transform-pass.so: instrumentation/compare-transform-pass.so.cc instrumentation/afl-llvm-common.o | test_deps
+ $(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
+./split-compares-pass.so: instrumentation/split-compares-pass.so.cc instrumentation/afl-llvm-common.o | test_deps
+ $(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
+# /laf
+
+./cmplog-routines-pass.so: instrumentation/cmplog-routines-pass.cc instrumentation/afl-llvm-common.o | test_deps
+ $(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
+
+./cmplog-instructions-pass.so: instrumentation/cmplog-instructions-pass.cc instrumentation/afl-llvm-common.o | test_deps
+ $(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
+
+./cmplog-switches-pass.so: instrumentation/cmplog-switches-pass.cc instrumentation/afl-llvm-common.o | test_deps
+ $(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
+
+afl-llvm-dict2file.so: instrumentation/afl-llvm-dict2file.so.cc instrumentation/afl-llvm-common.o | test_deps
+ $(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
+
+.PHONY: document
+document:
+ $(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS_SAFE) $(CPPFLAGS) $(CLANG_CFL) -O3 -Wno-unused-result -fPIC -c instrumentation/afl-compiler-rt.o.c -o ./afl-compiler-rt.o
+ @$(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS_SAFE) $(CPPFLAGS) $(CLANG_CFL) -O3 -Wno-unused-result -m32 -fPIC -c instrumentation/afl-compiler-rt.o.c -o ./afl-compiler-rt-32.o 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
+ @$(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS_SAFE) $(CPPFLAGS) $(CLANG_CFL) -O3 -Wno-unused-result -m64 -fPIC -c instrumentation/afl-compiler-rt.o.c -o ./afl-compiler-rt-64.o 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
+
+./afl-compiler-rt.o: instrumentation/afl-compiler-rt.o.c
+ $(CC) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -fPIC -c $< -o $@
+
+./afl-compiler-rt-32.o: instrumentation/afl-compiler-rt.o.c
+ @printf "[*] Building 32-bit variant of the runtime (-m32)... "
+ @$(CC) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
+
+./afl-compiler-rt-64.o: instrumentation/afl-compiler-rt.o.c
+ @printf "[*] Building 64-bit variant of the runtime (-m64)... "
+ @$(CC) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
+
+.PHONY: test_build
+test_build: $(PROGS)
+ @echo "[*] Testing the CC wrapper and instrumentation output..."
+ unset AFL_USE_ASAN AFL_USE_MSAN AFL_INST_RATIO; ASAN_OPTIONS=detect_leaks=0 AFL_QUIET=1 AFL_PATH=. AFL_LLVM_LAF_ALL=1 ./afl-cc $(CFLAGS) $(CPPFLAGS) ./test-instr.c -o test-instr $(LDFLAGS)
+ ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
+ echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
+ @rm -f test-instr
+ @cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi
+ @echo "[+] All right, the instrumentation seems to be working!"
+
+.PHONY: all_done
+all_done: test_build
+ @echo "[+] All done! You can now use './afl-cc' to compile programs."
+
+.NOTPARALLEL: clean
+
+.PHONY: install
+install: all
+ @install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH)
+ @if [ -f ./afl-cc ]; then set -e; install -m 755 ./afl-cc $${DESTDIR}$(BIN_PATH); ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-c++; fi
+ @rm -f $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt*.o $${DESTDIR}$(HELPER_PATH)/afl-gcc-rt*.o
+ @if [ -f ./afl-compiler-rt.o ]; then set -e; install -m 755 ./afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH); fi
+ @if [ -f ./afl-lto ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-lto; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-lto++; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ./afl-llvm-rt-lto*.o ./afl-llvm-lto-instrumentlist.so $${DESTDIR}$(HELPER_PATH); fi
+ @if [ -f ./afl-ld-lto ]; then set -e; install -m 755 ./afl-ld-lto $${DESTDIR}$(BIN_PATH); fi
+ @if [ -f ./afl-compiler-rt-32.o ]; then set -e; install -m 755 ./afl-compiler-rt-32.o $${DESTDIR}$(HELPER_PATH); fi
+ @if [ -f ./afl-compiler-rt-64.o ]; then set -e; install -m 755 ./afl-compiler-rt-64.o $${DESTDIR}$(HELPER_PATH); fi
+ @if [ -f ./compare-transform-pass.so ]; then set -e; install -m 755 ./*.so $${DESTDIR}$(HELPER_PATH); fi
+ @if [ -f ./compare-transform-pass.so ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-fast ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang-fast++ ; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang++ ; fi
+ @if [ -f ./SanitizerCoverageLTO.so ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang-lto++ ; fi
+ set -e; install -m 644 ./dynamic_list.txt $${DESTDIR}$(HELPER_PATH)
+ install -m 644 instrumentation/README.*.md $${DESTDIR}$(DOC_PATH)/
+
+%.8: %
+ @echo .TH $* 8 $(BUILD_DATE) "afl++" > ./$@
+ @echo .SH NAME >> ./$@
+ @printf "%s" ".B $* \- " >> ./$@
+ @./$* -h 2>&1 | head -n 1 | sed -e "s/$$(printf '\e')[^m]*m//g" >> ./$@
+ @echo .B $* >> ./$@
+ @echo >> ./$@
+ @echo .SH SYNOPSIS >> ./$@
+ @./$* -h 2>&1 | head -n 3 | tail -n 1 | sed 's/^\.\///' >> ./$@
+ @echo >> ./$@
+ @echo .SH OPTIONS >> ./$@
+ @echo .nf >> ./$@
+ @./$* -h 2>&1 | tail -n +4 >> ./$@
+ @echo >> ./$@
+ @echo .SH AUTHOR >> ./$@
+ @echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <domenukk@gmail.com>" >> ./$@
+ @echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> ./$@
+ @echo >> ./$@
+ @echo .SH LICENSE >> ./$@
+ @echo Apache License Version 2.0, January 2004 >> ./$@
+ @ln -sf afl-cc.8 ./afl-c++.8
+ @ln -sf afl-cc.8 ./afl-clang-fast.8
+ @ln -sf afl-cc.8 ./afl-clang-fast++.8
+ifneq "$(AFL_CLANG_FLTO)" ""
+ifeq "$(LLVM_LTO)" "1"
+ @ln -sf afl-cc.8 ./afl-clang-lto.8
+ @ln -sf afl-cc.8 ./afl-clang-lto++.8
+ @ln -sf afl-cc.8 ./afl-lto.8
+ @ln -sf afl-cc.8 ./afl-lto++.8
+endif
+endif
+
+.PHONY: clean
+clean:
+ rm -f *.o *.so *~ a.out core core.[1-9][0-9]* .test2 test-instr .test-instr0 .test-instr1 *.dwo
+ rm -f $(PROGS) afl-common.o ./afl-c++ ./afl-lto ./afl-lto++ ./afl-clang-lto* ./afl-clang-fast* ./afl-clang*.8 ./ld ./afl-ld ./afl-compiler-rt*.o ./afl-llvm-rt*.o instrumentation/*.o
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 00000000..08e58dd2
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,437 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+--- LLVM Exceptions to the Apache 2.0 License ----
+
+As an exception, if, as a result of your compiling your source code, portions
+of this Software are embedded into an Object form of such source code, you
+may redistribute such embedded portions in such Object form without complying
+with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
+
+In addition, if you combine or link compiled forms of this Software with
+software that is licensed under the GPLv2 ("Combined Software") and if a
+court of competent jurisdiction determines that the patent provision (Section
+3), the indemnity provision (Section 9) or other Section of the License
+conflicts with the conditions of the GPLv2, you may retroactively and
+prospectively choose to deem waived or otherwise exclude such Section(s) of
+the License, but only in their entirety and only with respect to the Combined
+Software.
+
+
+
+
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/METADATA b/METADATA
new file mode 100644
index 00000000..06830cc4
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,24 @@
+
+name: "AFLplusplus"
+description:
+ "AFLplusplus (american fuzzy lop plus plus) is a fuzzer"
+
+third_party: {
+ type: PACKAGE,
+ url {
+ type: HOMEPAGE
+ value: "https://aflplus.plus"
+ }
+ url {
+ type: GIT
+ value: "https://github.com/AFLplusplus/AFLplusplus"
+ }
+license_type: NOTICE
+ version: "ba3c7bfe40f9b17a691958e3525828385127ad25"
+ last_upgrade_date {
+ year: 2022
+ month: 6
+ day: 6
+ }
+}
+
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/MODULE_LICENSE_APACHE2
diff --git a/Makefile b/Makefile
new file mode 100644
index 00000000..96f67991
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,42 @@
+all:
+ @echo trying to use GNU make...
+ @gmake all || echo please install GNUmake
+
+source-only:
+ @gmake source-only
+
+binary-only:
+ @gmake binary-only
+
+distrib:
+ @gmake distrib
+
+man:
+ @gmake man
+
+install:
+ @gmake install
+
+document:
+ @gmake document
+
+deepclean:
+ @gmake deepclean
+
+code-format:
+ @gmake code-format
+
+help:
+ @gmake help
+
+tests:
+ @gmake tests
+
+unit:
+ @gmake unit
+
+unit_clean:
+ @gmake unit_clean
+
+clean:
+ @gmake clean
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 00000000..fc888c99
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,8 @@
+cobark@google.com
+hamzeh@google.com
+jonbottarini@google.com
+artemiev@google.com
+davfu@google.com
+kalder@google.com
+mhahmad@google.com
+
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..a29ce792
--- /dev/null
+++ b/README.md
@@ -0,0 +1,255 @@
+# American Fuzzy Lop plus plus (AFL++)
+
+<img align="right" src="https://raw.githubusercontent.com/AFLplusplus/Website/master/static/aflpp_bg.svg" alt="AFL++ logo" width="250" heigh="250">
+
+Release version: [4.00c](https://github.com/AFLplusplus/AFLplusplus/releases)
+
+GitHub version: 4.01a
+
+Repository:
+[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
+
+AFL++ is maintained by:
+
+* Marc "van Hauser" Heuse <mh@mh-sec.de>
+* Heiko "hexcoder-" Eißfeldt <heiko.eissfeldt@hexco.de>
+* Andrea Fioraldi <andreafioraldi@gmail.com>
+* Dominik Maier <mail@dmnk.co>
+* Documentation: Jana Aydinbas <jana.aydinbas@gmail.com>
+
+Originally developed by Michał "lcamtuf" Zalewski.
+
+AFL++ is a superior fork to Google's AFL - more speed, more and better
+mutations, more and better instrumentation, custom module support, etc.
+
+You are free to copy, modify, and distribute AFL++ with attribution under the
+terms of the Apache-2.0 License. See the [LICENSE](LICENSE) for details.
+
+## Getting started
+
+Here is some information to get you started:
+
+* For an overview of the AFL++ documentation and a very helpful graphical guide,
+ please visit [docs/README.md](docs/README.md).
+* To get you started with tutorials, go to
+ [docs/tutorials.md](docs/tutorials.md).
+* For releases, see the
+ [Releases tab](https://github.com/AFLplusplus/AFLplusplus/releases) and
+ [branches](#branches). The best branches to use are, however, `stable` or
+ `dev` - depending on your risk appetite. Also take a look at the list of
+ [important changes in AFL++](docs/important_changes.md) and the list of
+ [features](docs/features.md).
+* If you want to use AFL++ for your academic work, check the
+ [papers page](https://aflplus.plus/papers/) on the website.
+* To cite our work, look at the [Cite](#cite) section.
+* For comparisons, use the fuzzbench `aflplusplus` setup, or use
+ `afl-clang-fast` with `AFL_LLVM_CMPLOG=1`. You can find the `aflplusplus`
+ default configuration on Google's
+ [fuzzbench](https://github.com/google/fuzzbench/tree/master/fuzzers/aflplusplus).
+
+## Building and installing AFL++
+
+To have AFL++ easily available with everything compiled, pull the image directly
+from the Docker Hub (available for x86_64 and arm64):
+
+```shell
+docker pull aflplusplus/aflplusplus
+docker run -ti -v /location/of/your/target:/src aflplusplus/aflplusplus
+```
+
+This image is automatically generated when a push to the stable repo happens
+(see [branches](#branches)). If you use the command above, you will find your
+target source code in `/src` in the container.
+
+To build AFL++ yourself - *which we recommend* - continue at
+[docs/INSTALL.md](docs/INSTALL.md).
+
+## Quick start: Fuzzing with AFL++
+
+*NOTE: Before you start, please read about the
+[common sense risks of fuzzing](docs/fuzzing_in_depth.md#0-common-sense-risks).*
+
+This is a quick start for fuzzing targets with the source code available. To
+read about the process in detail, see
+[docs/fuzzing_in_depth.md](docs/fuzzing_in_depth.md).
+
+To learn about fuzzing other targets, see:
+* Binary-only targets:
+ [docs/fuzzing_binary-only_targets.md](docs/fuzzing_binary-only_targets.md)
+* Network services:
+ [docs/best_practices.md#fuzzing-a-network-service](docs/best_practices.md#fuzzing-a-network-service)
+* GUI programs:
+ [docs/best_practices.md#fuzzing-a-gui-program](docs/best_practices.md#fuzzing-a-gui-program)
+
+Step-by-step quick start:
+
+1. Compile the program or library to be fuzzed using `afl-cc`. A common way to
+ do this would be:
+
+ ```
+ CC=/path/to/afl-cc CXX=/path/to/afl-c++ ./configure --disable-shared
+ make clean all
+ ```
+
+2. Get a small but valid input file that makes sense to the program. When
+ fuzzing verbose syntax (SQL, HTTP, etc.), create a dictionary as described in
+ [dictionaries/README.md](dictionaries/README.md), too.
+
+3. If the program reads from stdin, run `afl-fuzz` like so:
+
+ ```
+ ./afl-fuzz -i seeds_dir -o output_dir -- \
+ /path/to/tested/program [...program's cmdline...]
+ ```
+
+ To add a dictionary, add `-x /path/to/dictionary.txt` to afl-fuzz.
+
+ If the program takes input from a file, you can put `@@` in the program's
+ command line; AFL++ will put an auto-generated file name in there for you.
+
+4. Investigate anything shown in red in the fuzzer UI by promptly consulting
+ [docs/afl-fuzz_approach.md#understanding-the-status-screen](docs/afl-fuzz_approach.md#understanding-the-status-screen).
+
+5. You will find found crashes and hangs in the subdirectories `crashes/` and
+ `hangs/` in the `-o output_dir` directory. You can replay the crashes by
+ feeding them to the target, e.g. if your target is using stdin:
+
+ ```
+ cat output_dir/crashes/id:000000,* | /path/to/tested/program [...program's cmdline...]
+ ```
+
+ You can generate cores or use gdb directly to follow up the crashes.
+
+6. We cannot stress this enough - if you want to fuzz effectively, read the
+ [docs/fuzzing_in_depth.md](docs/fuzzing_in_depth.md) document!
+
+## Contact
+
+Questions? Concerns? Bug reports?
+
+* The contributors can be reached via (e.g., by creating an issue):
+ [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus).
+* Take a look at our [FAQ](docs/FAQ.md). If you find an interesting or important
+ question missing, submit it via
+ [https://github.com/AFLplusplus/AFLplusplus/discussions](https://github.com/AFLplusplus/AFLplusplus/discussions).
+* Best: join the [Awesome Fuzzing](https://discord.gg/gCraWct) Discord server.
+* There is a (not really used) mailing list for the AFL/AFL++ project
+ ([browse archive](https://groups.google.com/group/afl-users)). To compare
+ notes with other users or to get notified about major new features, send an
+ email to <afl-users+subscribe@googlegroups.com>, but note that this is not
+ managed by us.
+
+## Branches
+
+The following branches exist:
+
+* [release](https://github.com/AFLplusplus/AFLplusplus/tree/release): the latest
+ release
+* [stable/trunk](https://github.com/AFLplusplus/AFLplusplus/): stable state of
+ AFL++ - it is synced from dev from time to time when we are satisfied with its
+ stability
+* [dev](https://github.com/AFLplusplus/AFLplusplus/tree/dev): development state
+ of AFL++ - bleeding edge and you might catch a checkout which does not compile
+ or has a bug. **We only accept PRs (pull requests) for the 'dev' branch!**
+* (any other): experimental branches to work on specific features or testing new
+ functionality or changes.
+
+## Help wanted
+
+We have several [ideas](docs/ideas.md) we would like to see in AFL++ to make it
+even better. However, we already work on so many things that we do not have the
+time for all the big ideas.
+
+This can be your way to support and contribute to AFL++ - extend it to do
+something cool.
+
+For everyone who wants to contribute (and send pull requests), please read our
+[contributing guidelines](CONTRIBUTING.md) before you submit.
+
+## Special thanks
+
+Many of the improvements to the original AFL and AFL++ wouldn't be possible
+without feedback, bug reports, or patches from our contributors.
+
+Thank you! (For people sending pull requests - please add yourself to this list
+:-)
+
+<details>
+
+ <summary>List of contributors</summary>
+
+ ```
+ Jann Horn Hanno Boeck
+ Felix Groebert Jakub Wilk
+ Richard W. M. Jones Alexander Cherepanov
+ Tom Ritter Hovik Manucharyan
+ Sebastian Roschke Eberhard Mattes
+ Padraig Brady Ben Laurie
+ @dronesec Luca Barbato
+ Tobias Ospelt Thomas Jarosch
+ Martin Carpenter Mudge Zatko
+ Joe Zbiciak Ryan Govostes
+ Michael Rash William Robinet
+ Jonathan Gray Filipe Cabecinhas
+ Nico Weber Jodie Cunningham
+ Andrew Griffiths Parker Thompson
+ Jonathan Neuschaefer Tyler Nighswander
+ Ben Nagy Samir Aguiar
+ Aidan Thornton Aleksandar Nikolich
+ Sam Hakim Laszlo Szekeres
+ David A. Wheeler Turo Lamminen
+ Andreas Stieger Richard Godbee
+ Louis Dassy teor2345
+ Alex Moneger Dmitry Vyukov
+ Keegan McAllister Kostya Serebryany
+ Richo Healey Martijn Bogaard
+ rc0r Jonathan Foote
+ Christian Holler Dominique Pelle
+ Jacek Wielemborek Leo Barnes
+ Jeremy Barnes Jeff Trull
+ Guillaume Endignoux ilovezfs
+ Daniel Godas-Lopez Franjo Ivancic
+ Austin Seipp Daniel Komaromy
+ Daniel Binderman Jonathan Metzman
+ Vegard Nossum Jan Kneschke
+ Kurt Roeckx Marcel Boehme
+ Van-Thuan Pham Abhik Roychoudhury
+ Joshua J. Drake Toby Hutton
+ Rene Freingruber Sergey Davidoff
+ Sami Liedes Craig Young
+ Andrzej Jackowski Daniel Hodson
+ Nathan Voss Dominik Maier
+ Andrea Biondo Vincent Le Garrec
+ Khaled Yakdan Kuang-che Wu
+ Josephine Calliotte Konrad Welc
+ Thomas Rooijakkers David Carlier
+ Ruben ten Hove Joey Jiao
+ fuzzah @intrigus-lgtm
+ ```
+
+</details>
+
+## Cite
+
+If you use AFL++ in scientific work, consider citing
+[our paper](https://www.usenix.org/conference/woot20/presentation/fioraldi)
+presented at WOOT'20:
+
+ Andrea Fioraldi, Dominik Maier, Heiko Eißfeldt, and Marc Heuse. “AFL++: Combining incremental steps of fuzzing research”. In 14th USENIX Workshop on Offensive Technologies (WOOT 20). USENIX Association, Aug. 2020.
+
+<details>
+
+<summary>BibTeX</summary>
+
+ ```bibtex
+ @inproceedings {AFLplusplus-Woot20,
+ author = {Andrea Fioraldi and Dominik Maier and Heiko Ei{\ss}feldt and Marc Heuse},
+ title = {{AFL++}: Combining Incremental Steps of Fuzzing Research},
+ booktitle = {14th {USENIX} Workshop on Offensive Technologies ({WOOT} 20)},
+ year = {2020},
+ publisher = {{USENIX} Association},
+ month = aug,
+ }
+ ```
+
+</details>
diff --git a/TODO.md b/TODO.md
new file mode 100644
index 00000000..99d2c419
--- /dev/null
+++ b/TODO.md
@@ -0,0 +1,35 @@
+# TODO list for AFL++
+
+## Should
+
+ - better documentation for custom mutators
+ - better autodetection of shifting runtime timeout values
+ - Update afl->pending_not_fuzzed for MOpt
+ - afl-plot to support multiple plot_data
+ - parallel builds for source-only targets
+ - get rid of check_binary, replace with more forkserver communication
+
+## Maybe
+
+ - forkserver tells afl-fuzz if cmplog is supported and if so enable
+ it by default, with AFL_CMPLOG_NO=1 (?) set to skip?
+ - afl_custom_fuzz_splice_optin()
+ - afl_custom_splice()
+ - cmdline option from-to range for mutations
+
+## Further down the road
+
+QEMU mode/FRIDA mode:
+ - non colliding instrumentation
+ - rename qemu specific envs to AFL_QEMU (AFL_ENTRYPOINT, AFL_CODE_START/END,
+ AFL_COMPCOV_LEVEL?)
+ - add AFL_QEMU_EXITPOINT (maybe multiple?), maybe pointless as there is
+ persistent mode
+
+## Ideas
+
+ - LTO/sancov: write current edge to prev_loc and use that information when
+ using cmplog or __sanitizer_cov_trace_cmp*. maybe we can deduct by follow up
+ edge numbers that both following cmp paths have been found and then disable
+ working on this edge id -> cmplog_intelligence branch
+ - use cmplog colorization taint result for havoc locations?
diff --git a/afl-cmin b/afl-cmin
new file mode 100755
index 00000000..853c9398
--- /dev/null
+++ b/afl-cmin
@@ -0,0 +1,542 @@
+#!/usr/bin/env sh
+export AFL_QUIET=1
+export ASAN_OPTIONS=detect_leaks=0
+THISPATH=`dirname ${0}`
+export PATH="${THISPATH}:$PATH"
+awk -f - -- ${@+"$@"} <<'EOF'
+#!/usr/bin/awk -f
+
+# awk script to minimize a test corpus of input files
+#
+# based on afl-cmin bash script written by Michal Zalewski
+# rewritten by Heiko Eißfeldt (hexcoder-)
+# tested with:
+# gnu awk (x86 Linux)
+# bsd awk (x86 *BSD)
+# mawk (arm32 raspbian)
+#
+# uses getopt.awk package from Arnold Robbins
+#
+# external tools used by this script:
+# test
+# grep
+# rm
+# mkdir
+# ln
+# cp
+# pwd
+# type
+# cd
+# find
+# stat
+# sort
+# cut
+# and afl-showmap from this project :-)
+
+# getopt.awk --- Do C library getopt(3) function in awk
+
+# External variables:
+# Optind -- index in ARGV of first nonoption argument
+# Optarg -- string value of argument to current option
+# Opterr -- if nonzero, print our own diagnostic
+# Optopt -- current option letter
+
+# Returns:
+# -1 at end of options
+# "?" for unrecognized option
+# <c> a character representing the current option
+
+# Private Data:
+# _opti -- index in multiflag option, e.g., -abc
+
+function getopt(argc, argv, options, thisopt, i)
+{
+ if (length(options) == 0) # no options given
+ return -1
+
+ if (argv[Optind] == "--") { # all done
+ Optind++
+ _opti = 0
+ return -1
+ } else if (argv[Optind] !~ /^-[^:\t ]/) {
+ _opti = 0
+ return -1
+ }
+ if (_opti == 0)
+ _opti = 2
+ thisopt = substr(argv[Optind], _opti, 1)
+ Optopt = thisopt
+ i = index(options, thisopt)
+ if (i == 0) {
+ if (Opterr)
+ printf("%c -- invalid option\n", thisopt) > "/dev/stderr"
+ if (_opti >= length(argv[Optind])) {
+ Optind++
+ _opti = 0
+ } else
+ _opti++
+ return "?"
+ }
+ if (substr(options, i + 1, 1) == ":") {
+ # get option argument
+ if (length(substr(argv[Optind], _opti + 1)) > 0)
+ Optarg = substr(argv[Optind], _opti + 1)
+ else
+ Optarg = argv[++Optind]
+ _opti = 0
+ } else
+ Optarg = ""
+ if (_opti == 0 || _opti >= length(argv[Optind])) {
+ Optind++
+ _opti = 0
+ } else
+ _opti++
+ return thisopt
+}
+
+function usage() {
+ print \
+"afl-cmin [ options ] -- /path/to/target_app [ ... ]\n" \
+"\n" \
+"Required parameters:\n" \
+" -i dir - input directory with starting corpus\n" \
+" -o dir - output directory for minimized files\n" \
+"\n" \
+"Execution control settings:\n" \
+" -f file - location read by the fuzzed program (stdin)\n" \
+" -m megs - memory limit for child process ("mem_limit" MB)\n" \
+" -t msec - run time limit for child process (none)\n" \
+" -O - use binary-only instrumentation (FRIDA mode)\n" \
+" -Q - use binary-only instrumentation (QEMU mode)\n" \
+" -U - use unicorn-based instrumentation (unicorn mode)\n" \
+"\n" \
+"Minimization settings:\n" \
+" -C - keep crashing inputs, reject everything else\n" \
+" -e - solve for edge coverage only, ignore hit counts\n" \
+"\n" \
+"For additional tips, please consult README.md\n" \
+"\n" \
+"Environment variables used:\n" \
+"AFL_ALLOW_TMP: allow unsafe use of input/output directories under {/var}/tmp\n" \
+"AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n" \
+"AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the forkserver to come up\n" \
+"AFL_KEEP_TRACES: leave the temporary <out_dir>/.traces directory\n" \
+"AFL_KILL_SIGNAL: Signal delivered to child processes on timeout (default: SIGKILL)\n" \
+"AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n" \
+"AFL_PATH: path for the afl-showmap binary if not found anywhere in PATH\n" \
+"AFL_PRINT_FILENAMES: If set, the filename currently processed will be " \
+ "printed to stdout\n" \
+"AFL_SKIP_BIN_CHECK: skip afl instrumentation checks for target binary\n"
+ exit 1
+}
+
+function exists_and_is_executable(binarypath) {
+ return 0 == system("test -f "binarypath" -a -x "binarypath)
+}
+
+BEGIN {
+ print "corpus minimization tool for afl++ (awk version)\n"
+
+ # defaults
+ extra_par = ""
+ AFL_CMIN_CRASHES_ONLY = ""
+
+ # process options
+ Opterr = 1 # default is to diagnose
+ Optind = 1 # skip ARGV[0]
+ while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eCOQU?")) != -1) {
+ if (_go_c == "i") {
+ if (!Optarg) usage()
+ if (in_dir) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
+ in_dir = Optarg
+ continue
+ } else
+ if (_go_c == "o") {
+ if (!Optarg) usage()
+ if (out_dir) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
+ out_dir = Optarg
+ continue
+ } else
+ if (_go_c == "f") {
+ if (!Optarg) usage()
+ if (stdin_file) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
+ stdin_file = Optarg
+ continue
+ } else
+ if (_go_c == "m") {
+ if (!Optarg) usage()
+ if (mem_limit) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
+ mem_limit = Optarg
+ mem_limit_given = 1
+ continue
+ } else
+ if (_go_c == "t") {
+ if (!Optarg) usage()
+ if (timeout) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
+ timeout = Optarg
+ continue
+ } else
+ if (_go_c == "C") {
+ AFL_CMIN_CRASHES_ONLY = "AFL_CMIN_CRASHES_ONLY=1 "
+ continue
+ } else
+ if (_go_c == "e") {
+ extra_par = extra_par " -e"
+ continue
+ } else
+ if (_go_c == "O") {
+ if (frida_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
+ extra_par = extra_par " -O"
+ frida_mode = 1
+ continue
+ } else
+ if (_go_c == "Q") {
+ if (qemu_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
+ extra_par = extra_par " -Q"
+ qemu_mode = 1
+ continue
+ } else
+ if (_go_c == "U") {
+ if (unicorn_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
+ extra_par = extra_par " -U"
+ unicorn_mode = 1
+ continue
+ } else
+ if (_go_c == "?") {
+ exit 1
+ } else
+ usage()
+ } # while options
+
+ if (!mem_limit) mem_limit = "none"
+ if (!timeout) timeout = "none"
+
+ # get program args
+ i = 0
+ prog_args_string = ""
+ for (; Optind < ARGC; Optind++) {
+ prog_args[i++] = ARGV[Optind]
+ if (i > 1)
+ prog_args_string = prog_args_string" '"ARGV[Optind]"'"
+ }
+
+ # sanity checks
+ if (!prog_args[0] || !in_dir || !out_dir) usage()
+
+ target_bin = prog_args[0]
+
+ # Do a sanity check to discourage the use of /tmp, since we can't really
+ # handle this safely from an awk script.
+
+ if (!ENVIRON["AFL_ALLOW_TMP"]) {
+ dirlist[0] = in_dir
+ dirlist[1] = target_bin
+ dirlist[2] = out_dir
+ dirlist[3] = stdin_file
+ "pwd" | getline dirlist[4] # current directory
+ for (dirind in dirlist) {
+ dir = dirlist[dirind]
+
+ if (dir ~ /^(\/var)?\/tmp/) {
+ print "[-] Error: do not use this script in /tmp or /var/tmp." > "/dev/stderr"
+ exit 1
+ }
+ }
+ delete dirlist
+ }
+
+ # If @@ is specified, but there's no -f, let's come up with a temporary input
+ # file name.
+
+ trace_dir = out_dir "/.traces"
+
+ if (!stdin_file) {
+ found_atat = 0
+ for (prog_args_ind in prog_args) {
+ if (match(prog_args[prog_args_ind], "@@") != 0) {
+ found_atat = 1
+ break
+ }
+ }
+ if (found_atat) {
+ stdin_file = trace_dir "/.cur_input"
+ }
+ }
+
+ # Check for obvious errors.
+
+ if (mem_limit && mem_limit != "none" && mem_limit < 5) {
+ print "[-] Error: dangerously low memory limit." > "/dev/stderr"
+ exit 1
+ }
+
+ if (timeout && timeout != "none" && timeout < 10) {
+ print "[-] Error: dangerously low timeout." > "/dev/stderr"
+ exit 1
+ }
+
+ if (target_bin && !exists_and_is_executable(target_bin)) {
+
+ "command -v "target_bin" 2>/dev/null" | getline tnew
+ if (!tnew || !exists_and_is_executable(tnew)) {
+ print "[-] Error: binary '"target_bin"' not found or not executable." > "/dev/stderr"
+ exit 1
+ }
+ target_bin = tnew
+ }
+
+ if (!ENVIRON["AFL_SKIP_BIN_CHECK"] && !qemu_mode && !frida_mode && !unicorn_mode) {
+ if (0 != system( "grep -q __AFL_SHM_ID "target_bin )) {
+ print "[-] Error: binary '"target_bin"' doesn't appear to be instrumented." > "/dev/stderr"
+ exit 1
+ }
+ }
+
+ if (0 != system( "test -d "in_dir )) {
+ print "[-] Error: directory '"in_dir"' not found." > "/dev/stderr"
+ exit 1
+ }
+
+ #if (0 == system( "test -d "in_dir"/default" )) {
+ # in_dir = in_dir "/default"
+ #}
+ #
+ #if (0 == system( "test -d "in_dir"/queue" )) {
+ # in_dir = in_dir "/queue"
+ #}
+
+ system("rm -rf "trace_dir" 2>/dev/null");
+ system("rm "out_dir"/id[:_]* 2>/dev/null")
+
+ "ls "out_dir"/* 2>/dev/null | wc -l" | getline noofentries
+ if (0 == system( "test -d "out_dir" -a "noofentries" -gt 0" )) {
+ print "[-] Error: directory '"out_dir"' exists and is not empty - delete it first." > "/dev/stderr"
+ exit 1
+ }
+
+ # Check for the more efficient way to copy files...
+ if (0 != system("mkdir -p -m 0700 "trace_dir)) {
+ print "[-] Error: Cannot create directory "trace_dir > "/dev/stderr"
+ exit 1
+ }
+
+ if (stdin_file) {
+ # truncate input file
+ printf "" > stdin_file
+ close( stdin_file )
+ }
+
+ # First we look in PATH
+ if (0 == system("command -v afl-showmap >/dev/null 2>&1")) {
+ "command -v afl-showmap 2>/dev/null" | getline showmap
+ } else {
+ # then we look in the current directory
+ if (0 == system("test -x ./afl-showmap")) {
+ showmap = "./afl-showmap"
+ } else {
+ if (ENVIRON["AFL_PATH"]) {
+ showmap = ENVIRON["AFL_PATH"] "/afl-showmap"
+ }
+ }
+ }
+
+ if (!showmap || 0 != system("test -x "showmap )) {
+ print "[-] Error: can't find 'afl-showmap' - please set AFL_PATH." > "/dev/stderr"
+ exit 1
+ }
+
+ # get list of input filenames sorted by size
+ i = 0
+ # yuck, gnu stat is option incompatible to bsd stat
+ # we use a heuristic to differentiate between
+ # GNU stat and other stats
+ "stat --version 2>/dev/null" | getline statversion
+ if (statversion ~ /GNU coreutils/) {
+ stat_format = "-c '%s %n'" # GNU
+ } else {
+ stat_format = "-f '%z %N'" # *BSD, MacOS
+ }
+ cmdline = "(cd "in_dir" && find . \\( ! -name \".*\" -a -type d \\) -o -type f -exec stat "stat_format" \\{\\} + | sort -k1n -k2r)"
+ #cmdline = "ls "in_dir" | (cd "in_dir" && xargs stat "stat_format" 2>/dev/null) | sort -k1n -k2r"
+ #cmdline = "(cd "in_dir" && stat "stat_format" *) | sort -k1n -k2r"
+ #cmdline = "(cd "in_dir" && ls | xargs stat "stat_format" ) | sort -k1n -k2r"
+ while (cmdline | getline) {
+ sub(/^[0-9]+ (\.\/)?/,"",$0)
+ infilesSmallToBigFull[i] = $0
+ sub(/.*\//, "", $0)
+ infilesSmallToBig[i] = $0
+ infilesSmallToBigMap[infilesSmallToBig[i]] = infilesSmallToBigFull[i]
+ infilesSmallToBigFullMap[infilesSmallToBigFull[i]] = infilesSmallToBig[i]
+ i++
+ }
+ in_count = i
+
+ first_file = infilesSmallToBigFull[0]
+
+ #if (0 == system("test -d ""\""in_dir"/"first_file"\"")) {
+ # print "[-] Error: The input directory is empty or contains subdirectories - please fix." > "/dev/stderr"
+ # exit 1
+ #}
+
+ system(">\""in_dir"/.afl-cmin.test\"")
+ if (0 == system("ln \""in_dir"/.afl-cmin.test\" "trace_dir"/.link_test")) {
+ cp_tool = "ln"
+ } else {
+ cp_tool = "cp"
+ }
+ system("rm -f \""in_dir"/.afl-cmin.test\"")
+
+ if (!ENVIRON["AFL_SKIP_BIN_CHECK"]) {
+ # Make sure that we can actually get anything out of afl-showmap before we
+ # waste too much time.
+
+ print "[*] Testing the target binary..."
+
+ if (!stdin_file) {
+ system( "AFL_CMIN_ALLOW_ANY=1 "AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"/.run_test\" -Z "extra_par" -- \""target_bin"\" "prog_args_string" <\""in_dir"/"first_file"\"")
+ } else {
+ system("cp \""in_dir"/"first_file"\" "stdin_file)
+ system( "AFL_CMIN_ALLOW_ANY=1 "AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"/.run_test\" -Z "extra_par" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null")
+ }
+
+ first_count = 0
+
+ runtest = trace_dir"/.run_test"
+ while ((getline < runtest) > 0) {
+ ++first_count
+ }
+
+ if (first_count) {
+ print "[+] OK, "first_count" tuples recorded."
+ } else {
+ print "[-] Error: no instrumentation output detected (perhaps crash or timeout)." > "/dev/stderr"
+ if (!ENVIRON["AFL_KEEP_TRACES"]) {
+ system("rm -rf "trace_dir" 2>/dev/null")
+ }
+ exit 1
+ }
+ }
+
+ # Let's roll!
+
+ #############################
+ # STEP 1: Collecting traces #
+ #############################
+
+ print "[*] Obtaining traces for "in_count" input files in '"in_dir"'."
+
+ cur = 0;
+ if (!stdin_file) {
+ print " Processing "in_count" files (forkserver mode)..."
+# print AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string
+ retval = system( AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string)
+ } else {
+ print " Processing "in_count" files (forkserver mode)..."
+# print AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null"
+ retval = system( AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null")
+ }
+
+ if (retval && !AFL_CMIN_CRASHES_ONLY) {
+ print "[!] Exit code "retval" != 0 received from afl-showmap, terminating..."
+
+ if (!ENVIRON["AFL_KEEP_TRACES"]) {
+ system("rm -rf "trace_dir" 2>/dev/null")
+ system("rmdir "out_dir)
+ }
+ exit retval
+ }
+
+ #######################################################
+ # STEP 2: register smallest input file for each tuple #
+ # STEP 3: copy that file (at most once) #
+ #######################################################
+
+ print "[*] Processing traces for input files in '"in_dir"'."
+
+ cur = 0
+ out_count = 0
+ tuple_count = 0
+
+ # from rare to frequent new tuples
+ # get the best (smallest) file for it
+ # and copy it
+ while (cur < in_count) {
+ fn = infilesSmallToBig[cur]
+ ++cur
+ printf "\r Processing file "cur"/"in_count
+ # create path for the trace file from afl-showmap
+ tracefile_path = trace_dir"/"fn
+ # gather all keys, and count them
+ while ((getline line < tracefile_path) > 0) {
+ key = line
+ if (!(key in key_count)) {
+ ++tuple_count
+ }
+ ++key_count[key]
+ if (! (key in best_file)) {
+ # this is the best file for this key
+ best_file[key] = fn
+#printf "BEST_FILE[%d]=\"%s\"\n",key,fn | "sort -t'[' -k2 > "trace_dir"/.candidate_script"
+ }
+#printf "%d %s\n",key,fn > trace_dir"/.candidate_list"
+ }
+ close(tracefile_path)
+ }
+ print ""
+
+ # sort keys
+ sortedKeys = trace_dir"/.all_uniq"
+ sortKeysCmd = "sort -k1n > "sortedKeys
+ for (key in key_count) {
+ printf "%7d %s\n",key_count[key],key | sortKeysCmd
+ }
+ close(sortKeysCmd)
+
+ # iterate over keys from rare to frequent and
+ # copy best file
+ while ((getline < sortedKeys) > 0) {
+
+ # split
+ nrFields = split($0, field, / +/)
+#print nrFields" Felder: '"field[0]"', '"field[1]"', '"field[2]"', '"field[3]"'"
+ key = field[nrFields]
+
+ ++tcnt;
+ printf "\r Processing tuple "tcnt"/"tuple_count" with count "key_count[key]"..."
+ if (key in keyAlreadyKnown) {
+ continue
+ }
+
+ fn = best_file[key]
+ # gather all tuples from the best file for this key
+ tracedfn = trace_dir"/"fn
+ while ((getline < tracedfn) > 0) {
+ keyAlreadyKnown[$0] = ""
+ }
+ close(tracedfn)
+
+ # copy file unless already done
+ if (! (fn in file_already_copied)) {
+ realfile = infilesSmallToBigMap[fn]
+ system(cp_tool" \""in_dir"/"realfile"\" \""out_dir"/"fn"\"")
+ file_already_copied[fn] = ""
+ ++out_count
+ #printf "tuple nr %d (%d cnt=%d) -> %s\n",tcnt,key,key_count[key],fn > trace_dir"/.log"
+ }
+ }
+ close(sortedKeys)
+ print ""
+ print "[+] Found "tuple_count" unique tuples across "in_count" files."
+
+ if (out_count == 1) {
+ print "[!] WARNING: All test cases had the same traces, check syntax!"
+ }
+ print "[+] Narrowed down to "out_count" files, saved in '"out_dir"'."
+
+ if (!ENVIRON["AFL_KEEP_TRACES"]) {
+ system("rm -rf "trace_dir" 2>/dev/null")
+ }
+
+ exit 0
+}
+EOF
diff --git a/afl-cmin.bash b/afl-cmin.bash
new file mode 100755
index 00000000..9ac65199
--- /dev/null
+++ b/afl-cmin.bash
@@ -0,0 +1,493 @@
+#!/usr/bin/env bash
+#
+# american fuzzy lop++ - corpus minimization tool
+# ---------------------------------------------
+#
+# Originally written by Michal Zalewski
+#
+# Copyright 2014, 2015 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# This tool tries to find the smallest subset of files in the input directory
+# that still trigger the full range of instrumentation data points seen in
+# the starting corpus. This has two uses:
+#
+# - Screening large corpora of input files before using them as a seed for
+# afl-fuzz. The tool will remove functionally redundant files and likely
+# leave you with a much smaller set.
+#
+# (In this case, you probably also want to consider running afl-tmin on
+# the individual files later on to reduce their size.)
+#
+# - Minimizing the corpus generated organically by afl-fuzz, perhaps when
+# planning to feed it to more resource-intensive tools. The tool achieves
+# this by removing all entries that used to trigger unique behaviors in the
+# past, but have been made obsolete by later finds.
+#
+# Note that the tool doesn't modify the files themselves. For that, you want
+# afl-tmin.
+#
+# This script must use bash because other shells may have hardcoded limits on
+# array sizes.
+#
+
+echo "corpus minimization tool for afl-fuzz by Michal Zalewski"
+echo
+
+#########
+# SETUP #
+#########
+
+# Process command-line options...
+
+MEM_LIMIT=none
+TIMEOUT=none
+
+unset IN_DIR OUT_DIR STDIN_FILE EXTRA_PAR MEM_LIMIT_GIVEN \
+ AFL_CMIN_CRASHES_ONLY AFL_CMIN_ALLOW_ANY QEMU_MODE UNICORN_MODE
+
+export AFL_QUIET=1
+
+while getopts "+i:o:f:m:t:eOQUCh" opt; do
+
+ case "$opt" in
+
+ "h")
+ ;;
+
+ "i")
+ IN_DIR="$OPTARG"
+ ;;
+
+ "o")
+ OUT_DIR="$OPTARG"
+ ;;
+ "f")
+ STDIN_FILE="$OPTARG"
+ ;;
+ "m")
+ MEM_LIMIT="$OPTARG"
+ MEM_LIMIT_GIVEN=1
+ ;;
+ "t")
+ TIMEOUT="$OPTARG"
+ ;;
+ "e")
+ EXTRA_PAR="$EXTRA_PAR -e"
+ ;;
+ "C")
+ export AFL_CMIN_CRASHES_ONLY=1
+ ;;
+ "O")
+ EXTRA_PAR="$EXTRA_PAR -O"
+ FRIDA_MODE=1
+ ;;
+ "Q")
+ EXTRA_PAR="$EXTRA_PAR -Q"
+ QEMU_MODE=1
+ ;;
+ "U")
+ EXTRA_PAR="$EXTRA_PAR -U"
+ UNICORN_MODE=1
+ ;;
+ "?")
+ exit 1
+ ;;
+
+ esac
+
+done
+
+shift $((OPTIND-1))
+
+TARGET_BIN="$1"
+
+if [ "$TARGET_BIN" = "" -o "$IN_DIR" = "" -o "$OUT_DIR" = "" ]; then
+
+ cat 1>&2 <<_EOF_
+Usage: $0 [ options ] -- /path/to/target_app [ ... ]
+
+Required parameters:
+
+ -i dir - input directory with the starting corpus
+ -o dir - output directory for minimized files
+
+Execution control settings:
+
+ -f file - location read by the fuzzed program (stdin)
+ -m megs - memory limit for child process ($MEM_LIMIT MB)
+ -t msec - run time limit for child process (none)
+ -O - use binary-only instrumentation (FRIDA mode)
+ -Q - use binary-only instrumentation (QEMU mode)
+ -U - use unicorn-based instrumentation (Unicorn mode)
+
+Minimization settings:
+
+ -C - keep crashing inputs, reject everything else
+ -e - solve for edge coverage only, ignore hit counts
+
+For additional tips, please consult README.md.
+
+Environment variables used:
+AFL_KEEP_TRACES: leave the temporary <out_dir>\.traces directory
+AFL_NO_FORKSRV: run target via execve instead of using the forkserver
+AFL_PATH: last resort location to find the afl-showmap binary
+AFL_SKIP_BIN_CHECK: skip check for target binary
+_EOF_
+ exit 1
+fi
+
+# Do a sanity check to discourage the use of /tmp, since we can't really
+# handle this safely from a shell script.
+
+#if [ "$AFL_ALLOW_TMP" = "" ]; then
+#
+# echo "$IN_DIR" | grep -qE '^(/var)?/tmp/'
+# T1="$?"
+#
+# echo "$TARGET_BIN" | grep -qE '^(/var)?/tmp/'
+# T2="$?"
+#
+# echo "$OUT_DIR" | grep -qE '^(/var)?/tmp/'
+# T3="$?"
+#
+# echo "$STDIN_FILE" | grep -qE '^(/var)?/tmp/'
+# T4="$?"
+#
+# echo "$PWD" | grep -qE '^(/var)?/tmp/'
+# T5="$?"
+#
+# if [ "$T1" = "0" -o "$T2" = "0" -o "$T3" = "0" -o "$T4" = "0" -o "$T5" = "0" ]; then
+# echo "[-] Error: do not use this script in /tmp or /var/tmp." 1>&2
+# exit 1
+# fi
+#
+#fi
+
+# If @@ is specified, but there's no -f, let's come up with a temporary input
+# file name.
+
+TRACE_DIR="$OUT_DIR/.traces"
+
+if [ "$STDIN_FILE" = "" ]; then
+
+ if echo "$*" | grep -qF '@@'; then
+ STDIN_FILE="$TRACE_DIR/.cur_input"
+ fi
+
+fi
+
+# Check for obvious errors.
+
+if [ ! "$MEM_LIMIT" = "none" ]; then
+
+ if [ "$MEM_LIMIT" -lt "5" ]; then
+ echo "[-] Error: dangerously low memory limit." 1>&2
+ exit 1
+ fi
+
+fi
+
+if [ ! "$TIMEOUT" = "none" ]; then
+
+ if [ "$TIMEOUT" -lt "10" ]; then
+ echo "[-] Error: dangerously low timeout." 1>&2
+ exit 1
+ fi
+
+fi
+
+if [ ! -f "$TARGET_BIN" -o ! -x "$TARGET_BIN" ]; then
+
+ TNEW="`which "$TARGET_BIN" 2>/dev/null`"
+
+ if [ ! -f "$TNEW" -o ! -x "$TNEW" ]; then
+ echo "[-] Error: binary '$TARGET_BIN' not found or not executable." 1>&2
+ exit 1
+ fi
+
+ TARGET_BIN="$TNEW"
+
+fi
+
+if [ "$AFL_SKIP_BIN_CHECK" = "" -a "$QEMU_MODE" = "" -a "$FRIDA_MODE" = "" -a "$UNICORN_MODE" = "" ]; then
+
+ if ! grep -qF "__AFL_SHM_ID" "$TARGET_BIN"; then
+ echo "[-] Error: binary '$TARGET_BIN' doesn't appear to be instrumented." 1>&2
+ exit 1
+ fi
+
+fi
+
+if [ ! -d "$IN_DIR" ]; then
+ echo "[-] Error: directory '$IN_DIR' not found." 1>&2
+ exit 1
+fi
+
+test -d "$IN_DIR/default" && IN_DIR="$IN_DIR/default"
+test -d "$IN_DIR/queue" && IN_DIR="$IN_DIR/queue"
+
+find "$OUT_DIR" -name 'id[:_]*' -maxdepth 1 -exec rm -- {} \; 2>/dev/null
+rm -rf "$TRACE_DIR" 2>/dev/null
+
+rmdir "$OUT_DIR" 2>/dev/null
+
+if [ -d "$OUT_DIR" ]; then
+ echo "[-] Error: directory '$OUT_DIR' exists and is not empty - delete it first." 1>&2
+ exit 1
+fi
+
+mkdir -m 700 -p "$TRACE_DIR" || exit 1
+
+if [ ! "$STDIN_FILE" = "" ]; then
+ rm -f "$STDIN_FILE" || exit 1
+ touch "$STDIN_FILE" || exit 1
+fi
+
+SHOWMAP=`command -v afl-showmap 2>/dev/null`
+
+if [ -z "$SHOWMAP" ]; then
+ TMP="${0%/afl-cmin.bash}/afl-showmap"
+ if [ -x "$TMP" ]; then
+ SHOWMAP=$TMP
+ fi
+fi
+
+if [ -z "$SHOWMAP" -a -x "./afl-showmap" ]; then
+ SHOWMAP="./afl-showmap"
+else
+ if [ -n "$AFL_PATH" ]; then
+ SHOWMAP="$AFL_PATH/afl-showmap"
+ fi
+fi
+
+if [ ! -x "$SHOWMAP" ]; then
+ echo "[-] Error: can't find 'afl-showmap' - please set AFL_PATH." 1>&2
+ rm -rf "$TRACE_DIR"
+ exit 1
+fi
+
+IN_COUNT=$((`ls -- "$IN_DIR" 2>/dev/null | wc -l`))
+
+if [ "$IN_COUNT" = "0" ]; then
+ echo "[+] Hmm, no inputs in the target directory. Nothing to be done."
+ rm -rf "$TRACE_DIR"
+ exit 1
+fi
+
+FIRST_FILE=`ls "$IN_DIR" | head -1`
+
+# Make sure that we're not dealing with a directory.
+
+if [ -d "$IN_DIR/$FIRST_FILE" ]; then
+ echo "[-] Error: The target directory contains subdirectories - please fix." 1>&2
+ rm -rf "$TRACE_DIR"
+ exit 1
+fi
+
+# Check for the more efficient way to copy files...
+
+if ln "$IN_DIR/$FIRST_FILE" "$TRACE_DIR/.link_test" 2>/dev/null; then
+ CP_TOOL=ln
+else
+ CP_TOOL=cp
+fi
+
+# Make sure that we can actually get anything out of afl-showmap before we
+# waste too much time.
+
+echo "[*] Testing the target binary..."
+
+if [ "$STDIN_FILE" = "" ]; then
+
+ AFL_CMIN_ALLOW_ANY=1 "$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/.run_test" -Z $EXTRA_PAR -- "$@" <"$IN_DIR/$FIRST_FILE"
+
+else
+
+ cp "$IN_DIR/$FIRST_FILE" "$STDIN_FILE"
+ AFL_CMIN_ALLOW_ANY=1 "$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/.run_test" -Z $EXTRA_PAR -H "$STDIN_FILE" -- "$@" </dev/null
+
+fi
+
+FIRST_COUNT=$((`grep -c . "$TRACE_DIR/.run_test"`))
+
+if [ "$FIRST_COUNT" -gt "0" ]; then
+
+ echo "[+] OK, $FIRST_COUNT tuples recorded."
+
+else
+
+ echo "[-] Error: no instrumentation output detected (perhaps crash or timeout)." 1>&2
+ test "$AFL_KEEP_TRACES" = "" && rm -rf "$TRACE_DIR"
+ exit 1
+
+fi
+
+# Let's roll!
+
+#############################
+# STEP 1: COLLECTING TRACES #
+#############################
+
+echo "[*] Obtaining traces for input files in '$IN_DIR'..."
+
+(
+
+ CUR=0
+
+ if [ "$STDIN_FILE" = "" ]; then
+
+ ls "$IN_DIR" | while read -r fn; do
+
+ CUR=$((CUR+1))
+ printf "\\r Processing file $CUR/$IN_COUNT... "
+
+ "$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/$fn" -Z $EXTRA_PAR -- "$@" <"$IN_DIR/$fn"
+
+ done
+
+ else
+
+ ls "$IN_DIR" | while read -r fn; do
+
+ CUR=$((CUR+1))
+ printf "\\r Processing file $CUR/$IN_COUNT... "
+
+ cp "$IN_DIR/$fn" "$STDIN_FILE"
+
+ "$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/$fn" -Z $EXTRA_PAR -H "$STDIN_FILE" -- "$@" </dev/null
+
+ done
+
+
+ fi
+
+)
+
+echo
+
+##########################
+# STEP 2: SORTING TUPLES #
+##########################
+
+# With this out of the way, we sort all tuples by popularity across all
+# datasets. The reasoning here is that we won't be able to avoid the files
+# that trigger unique tuples anyway, so we will want to start with them and
+# see what's left.
+
+echo "[*] Sorting trace sets (this may take a while)..."
+
+ls "$IN_DIR" | sed "s#^#$TRACE_DIR/#" | tr '\n' '\0' | xargs -0 -n 1 cat | \
+ sort | uniq -c | sort -k 1,1 -n >"$TRACE_DIR/.all_uniq"
+
+TUPLE_COUNT=$((`grep -c . "$TRACE_DIR/.all_uniq"`))
+
+echo "[+] Found $TUPLE_COUNT unique tuples across $IN_COUNT files."
+
+#####################################
+# STEP 3: SELECTING CANDIDATE FILES #
+#####################################
+
+# The next step is to find the best candidate for each tuple. The "best"
+# part is understood simply as the smallest input that includes a particular
+# tuple in its trace. Empirical evidence suggests that this produces smaller
+# datasets than more involved algorithms that could be still pulled off in
+# a shell script.
+
+echo "[*] Finding best candidates for each tuple..."
+
+CUR=0
+
+ls -rS "$IN_DIR" | while read -r fn; do
+
+ CUR=$((CUR+1))
+ printf "\\r Processing file $CUR/$IN_COUNT... "
+
+ sed "s#\$# $fn#" "$TRACE_DIR/$fn" >>"$TRACE_DIR/.candidate_list"
+
+done
+
+echo
+
+##############################
+# STEP 4: LOADING CANDIDATES #
+##############################
+
+# At this point, we have a file of tuple-file pairs, sorted by file size
+# in ascending order (as a consequence of ls -rS). By doing sort keyed
+# only by tuple (-k 1,1) and configured to output only the first line for
+# every key (-s -u), we end up with the smallest file for each tuple.
+
+echo "[*] Sorting candidate list (be patient)..."
+
+sort -k1,1 -s -u "$TRACE_DIR/.candidate_list" | \
+ sed 's/^/BEST_FILE[/;s/ /]="/;s/$/"/' >"$TRACE_DIR/.candidate_script"
+
+if [ ! -s "$TRACE_DIR/.candidate_script" ]; then
+ echo "[-] Error: no traces obtained from test cases, check syntax!" 1>&2
+ test "$AFL_KEEP_TRACES" = "" && rm -rf "$TRACE_DIR"
+ exit 1
+fi
+
+# The sed command converted the sorted list to a shell script that populates
+# BEST_FILE[tuple]="fname". Let's load that!
+
+. "$TRACE_DIR/.candidate_script"
+
+##########################
+# STEP 5: WRITING OUTPUT #
+##########################
+
+# The final trick is to grab the top pick for each tuple, unless said tuple is
+# already set due to the inclusion of an earlier candidate; and then put all
+# tuples associated with the newly-added file to the "already have" list. The
+# loop works from least popular tuples and toward the most common ones.
+
+echo "[*] Processing candidates and writing output files..."
+
+CUR=0
+
+touch "$TRACE_DIR/.already_have"
+
+while read -r cnt tuple; do
+
+ CUR=$((CUR+1))
+ printf "\\r Processing tuple $CUR/$TUPLE_COUNT with count $cnt... "
+
+ # If we already have this tuple, skip it.
+
+ grep -q "^$tuple\$" "$TRACE_DIR/.already_have" && continue
+
+ FN=${BEST_FILE[tuple]}
+
+# echo "tuple nr $CUR ($tuple cnt=$cnt) -> $FN" >> "$TRACE_DIR/.log"
+ $CP_TOOL "$IN_DIR/$FN" "$OUT_DIR/$FN"
+
+ if [ "$((CUR % 5))" = "0" ]; then
+ sort -u "$TRACE_DIR/$FN" "$TRACE_DIR/.already_have" >"$TRACE_DIR/.tmp"
+ mv -f "$TRACE_DIR/.tmp" "$TRACE_DIR/.already_have"
+ else
+ cat "$TRACE_DIR/$FN" >>"$TRACE_DIR/.already_have"
+ fi
+
+done <"$TRACE_DIR/.all_uniq"
+
+echo
+
+OUT_COUNT=`ls -- "$OUT_DIR" | wc -l`
+
+if [ "$OUT_COUNT" = "1" ]; then
+ echo "[!] WARNING: All test cases had the same traces, check syntax!"
+fi
+
+echo "[+] Narrowed down to $OUT_COUNT files, saved in '$OUT_DIR'."
+echo
+
+test "$AFL_KEEP_TRACES" = "" && rm -rf "$TRACE_DIR"
+
+exit 0
diff --git a/afl-persistent-config b/afl-persistent-config
new file mode 100755
index 00000000..fd453cbc
--- /dev/null
+++ b/afl-persistent-config
@@ -0,0 +1,133 @@
+#!/bin/bash
+# written by jhertz
+#
+
+test "$1" = "-h" -o "$1" = "-hh" && {
+ echo 'afl-persistent-config'
+ echo
+ echo $0
+ echo
+ echo afl-persistent-config has no command line options
+ echo
+ echo afl-persistent-config permanently reconfigures the system to a high performance fuzzing state.
+ echo "WARNING: this reduces the security of the system!"
+ echo
+ echo Note that there is also afl-system-config which sets additional runtime
+ echo configuration options.
+ exit 0
+}
+
+echo
+echo "WARNING: This scripts makes permanent configuration changes to the system to"
+echo " increase the performance for fuzzing. As a result, the system also"
+echo " becomes less secure against attacks! If you use this script, setup"
+echo " strong firewall rules and only make SSH available as a network"
+echo " service!"
+echo
+echo -n "Type \"YES\" to continue: "
+read ANSWER
+if [[ "$ANSWER" != "YES" ]]; then
+ echo Input was not YES, aborting ...
+ exit 1
+fi
+
+echo
+PLATFORM=`uname -s`
+
+# check that we're on Mac
+if [[ "$PLATFORM" = "Darwin" ]] ; then
+
+ # check if UID == 0
+ if [[ "$EUID" -ne 0 ]]; then
+ echo "You need to be root to do this. E.g. use \"sudo\""
+ exit 1
+ fi
+
+ # check if SIP is disabled
+ if [[ ! $(csrutil status | grep "disabled") ]]; then
+ echo "SIP needs to be disabled. Restart and press Command-R at reboot, Utilities => Terminal => enter \"csrutil disable\""
+ exit 1
+ fi
+
+ echo "Checks passed."
+
+ echo "Installing /Library/LaunchDaemons/shm_setup.plist"
+
+ cat << EOF > /Library/LaunchDaemons/shm_setup.plist
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+ <dict>
+ <key>Label</key>
+ <string>shmemsetup</string>
+ <key>UserName</key>
+ <string>root</string>
+ <key>GroupName</key>
+ <string>wheel</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/sbin/sysctl</string>
+ <string>-w</string>
+ <string>kern.sysv.shmmax=524288000</string>
+ <string>kern.sysv.shmmin=1</string>
+ <string>kern.sysv.shmmni=128</string>
+ <string>kern.sysv.shmseg=48</string>
+ <string>kern.sysv.shmall=131072000</string>
+ </array>
+ <key>KeepAlive</key>
+ <false/>
+ <key>RunAtLoad</key>
+ <true/>
+ </dict>
+</plist>
+EOF
+
+ echo
+ echo "Reboot and enjoy your fuzzing"
+ exit 0
+fi
+
+if [[ "$PLATFORM" = "Linux" ]] ; then
+
+ # check if UID == 0
+ if [[ "$EUID" -ne 0 ]]; then
+ echo "You need to be root to do this. E.g. use \"sudo\""
+ exit 1
+ fi
+
+ echo "Checks passed."
+
+ test -d /etc/sysctl.d || echo Error: /etc/sysctl.d directory not found, cannot install shmem config
+ test -d /etc/sysctl.d -a '!' -e /etc/sysctl.d/99-fuzzing && {
+ echo "Installing /etc/sysctl.d/99-fuzzing"
+ cat << EOF > /etc/sysctl.d/99-fuzzing
+kernel.core_uses_pid=0
+kernel.core_pattern=core
+kernel.randomize_va_space=0
+kernel.sched_child_runs_first=1
+kernel.sched_autogroup_enabled=1
+kernel.sched_migration_cost_ns=50000000
+kernel.sched_latency_ns=250000000
+EOF
+ }
+
+ egrep -q '^GRUB_CMDLINE_LINUX_DEFAULT=' /etc/default/grub 2>/dev/null || echo Error: /etc/default/grub with GRUB_CMDLINE_LINUX_DEFAULT is not present, cannot set boot options
+ egrep -q '^GRUB_CMDLINE_LINUX_DEFAULT=' /etc/default/grub 2>/dev/null && {
+ egrep '^GRUB_CMDLINE_LINUX_DEFAULT=' /etc/default/grub | egrep -q hardened_usercopy=off || {
+ echo "Configuring performance boot options"
+ LINE=`egrep '^GRUB_CMDLINE_LINUX_DEFAULT=' /etc/default/grub | sed 's/^GRUB_CMDLINE_LINUX_DEFAULT=//' | tr -d '"'`
+ OPTIONS="$LINE ibpb=off ibrs=off kpti=off l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off srbds=off noexec=off noexec32=off tsx=on tsx=on tsx_async_abort=off mitigations=off audit=0 hardened_usercopy=off ssbd=force-off"
+ echo Setting boot options in /etc/default/grub to GRUB_CMDLINE_LINUX_DEFAULT=\"$OPTIONS\"
+ sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=.*|GRUB_CMDLINE_LINUX_DEFAULT=\"$OPTIONS\"|" /etc/default/grub
+ }
+ }
+
+ echo
+ echo "Reboot and enjoy your fuzzing"
+ exit 0
+fi
+
+
+
+echo "Error: Unknown platform \"$PLATFORM\", currently supported are Linux and MacOS."
+exit 1
diff --git a/afl-plot b/afl-plot
new file mode 100755
index 00000000..90a46d24
--- /dev/null
+++ b/afl-plot
@@ -0,0 +1,328 @@
+#!/bin/sh
+#
+# american fuzzy lop++ - Advanced Persistent Graphing
+# -------------------------------------------------
+#
+# Originally written by Michal Zalewski
+# Based on a design & prototype by Michael Rash.
+#
+# Copyright 2014, 2015 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+
+get_abs_path() {
+ echo $(cd "`dirname "$1"`" && pwd)/"`basename "$1"`"
+}
+
+echo "progress plotting utility for afl-fuzz by Michal Zalewski"
+echo
+
+GRAPHICAL="0"
+
+if [ "$1" = "-g" ] || [ "$1" = "--graphical" ]; then
+GRAPHICAL="1"
+shift
+fi
+
+if [ "$#" != "2" ]; then
+
+ cat 1>&2 <<_EOF_
+$0 [ -g | --graphical ] afl_state_dir graph_output_dir
+
+This program generates gnuplot images from afl-fuzz output data.
+
+Usage:
+
+ afl_state_dir should point to an existing state directory for any
+ active or stopped instance of afl-fuzz
+ graph_output_dir should point to an empty directory where this
+ tool can write the resulting plots to
+ -g, --graphical (optional) display the plots in a graphical window
+ (you should have built afl-plot-ui to use this option)
+
+The program will put index.html and three PNG images in the output directory;
+you should be able to view it with any web browser of your choice.
+_EOF_
+
+ exit 1
+
+fi
+
+inputdir=`get_abs_path "$1"`
+outputdir=`get_abs_path "$2"`
+
+#if [ "$AFL_ALLOW_TMP" = "" ]; then
+#
+# echo "$inputdir" | grep -qE '^(/var)?/tmp/'
+# T1="$?"
+#
+# echo "$outputdir" | grep -qE '^(/var)?/tmp/'
+# T2="$?"
+#
+# if [ "$T1" = "0" -o "$T2" = "0" ]; then
+#
+# echo "[-] Error: this script shouldn't be used with shared /tmp directories." 1>&2
+# exit 1
+#
+# fi
+#
+#fi
+
+if [ ! -f "$inputdir/plot_data" ]; then
+
+ echo "[-] Error: input directory is not valid (missing 'plot_data')." 1>&2
+ exit 1
+
+fi
+
+LINES=`cat "$inputdir/plot_data" | wc -l`
+
+if [ "$LINES" -lt 3 ]; then
+
+ echo "[-] Error: plot_data carries too little data, let it run longer." 1>&2
+ exit 1
+
+fi
+
+BANNER="`cat "$inputdir/fuzzer_stats" 2> /dev/null | grep '^afl_banner ' | cut -d: -f2- | cut -b2-`"
+
+test "$BANNER" = "" && BANNER="(none)"
+
+GNUPLOT=`command -v gnuplot 2>/dev/null`
+
+if [ "$GNUPLOT" = "" ]; then
+
+ echo "[-] Error: can't find 'gnuplot' in your \$PATH." 1>&2
+ exit 1
+
+fi
+
+mkdir "$outputdir" 2>/dev/null
+
+if [ ! -d "$outputdir" ]; then
+
+ echo "[-] Error: unable to create the output directory - pick another location." 1>&2
+ exit 1
+
+fi
+
+rm -f "$outputdir/high_freq.png" "$outputdir/low_freq.png" "$outputdir/exec_speed.png" "$outputdir/edges.png"
+mv -f "$outputdir/index.html" "$outputdir/index.html.orig" 2>/dev/null
+
+GNUPLOT_SETUP="
+#set xdata time
+#set timefmt '%s'
+#set format x \"%b %d\n%H:%M\"
+set tics font 'small'
+unset mxtics
+unset mytics
+
+set grid xtics linetype 0 linecolor rgb '#e0e0e0'
+set grid ytics linetype 0 linecolor rgb '#e0e0e0'
+set border linecolor rgb '#50c0f0'
+set tics textcolor rgb '#000000'
+set key outside
+
+set autoscale xfixmin
+set autoscale xfixmax
+
+set xlabel \"relative time in seconds\" font \"small\"
+"
+
+PLOT_HF="
+set terminal png truecolor enhanced size 1000,300 butt
+set output '$outputdir/high_freq.png'
+
+$GNUPLOT_SETUP
+
+plot '$inputdir/plot_data' using 1:4 with filledcurve x1 title 'corpus count' linecolor rgb '#000000' fillstyle transparent solid 0.2 noborder, \\
+ '' using 1:3 with filledcurve x1 title 'current fuzz item' linecolor rgb '#f0f0f0' fillstyle transparent solid 0.5 noborder, \\
+ '' using 1:5 with lines title 'pending items' linecolor rgb '#0090ff' linewidth 3, \\
+ '' using 1:6 with lines title 'pending favs' linecolor rgb '#c00080' linewidth 3, \\
+ '' using 1:2 with lines title 'cycles done' linecolor rgb '#c000f0' linewidth 3
+"
+
+PLOT_LF="
+set terminal png truecolor enhanced size 1000,200 butt
+set output '$outputdir/low_freq.png'
+
+$GNUPLOT_SETUP
+
+plot '$inputdir/plot_data' using 1:8 with filledcurve x1 title '' linecolor rgb '#c00080' fillstyle transparent solid 0.2 noborder, \\
+ '' using 1:8 with lines title ' uniq crashes' linecolor rgb '#c00080' linewidth 3, \\
+ '' using 1:9 with lines title 'uniq hangs' linecolor rgb '#c000f0' linewidth 3, \\
+ '' using 1:10 with lines title 'levels' linecolor rgb '#0090ff' linewidth 3
+"
+
+PLOT_ES="
+set terminal png truecolor enhanced size 1000,200 butt
+set output '$outputdir/exec_speed.png'
+
+$GNUPLOT_SETUP
+
+plot '$inputdir/plot_data' using 1:11 with filledcurve x1 title '' linecolor rgb '#0090ff' fillstyle transparent solid 0.2 noborder, \\
+ '$inputdir/plot_data' using 1:11 with lines title ' execs/sec' linecolor rgb '#0090ff' linewidth 3 smooth bezier;
+"
+
+PLOT_EG="
+set terminal png truecolor enhanced size 1000,300 butt
+set output '$outputdir/edges.png'
+
+$GNUPLOT_SETUP
+
+plot '$inputdir/plot_data' using 1:13 with lines title ' edges' linecolor rgb '#0090ff' linewidth 3
+"
+
+if [ "$#" = "2" ] && [ "$GRAPHICAL" = "1" ]; then
+
+afl-plot-ui -h > /dev/null 2>&1
+
+if [ "$?" != "0" ]; then
+
+cat 1>&2 <<_EOF_
+You do not seem to have the afl-plot-ui utility installed. If you have installed afl-plot-ui, make sure the afl-plot-ui executable is in your PATH.
+If you are still facing any problems, please open an issue at https://github.com/AFLplusplus/AFLplusplus/issues.
+
+No plots have been generated. Please rerun without the "-g" or "--graphical" flag to generate the plots.
+_EOF_
+
+exit 1
+
+fi
+
+rm -rf "$outputdir/.tmp"
+mkdir -p "$outputdir/.tmp"
+mkfifo "$outputdir/.tmp/win_ids" || exit 1
+
+afl-plot-ui > "$outputdir/.tmp/win_ids" &
+W_IDS=$(cat "$outputdir/.tmp/win_ids")
+
+rm -rf "$outputdir/.tmp"
+
+W_ID1=$(echo "$W_IDS" | head -n 1)
+W_ID2=$(echo "$W_IDS" | head -n 2 | tail -n 1)
+W_ID3=$(echo "$W_IDS" | head -n 3 | tail -n 1)
+W_ID4=$(echo "$W_IDS" | tail -n 1)
+
+echo "[*] Generating plots..."
+
+(
+
+cat << _EOF_
+
+$PLOT_HF
+set term x11 window "$W_ID3"
+set output
+replot
+pause mouse close
+
+_EOF_
+
+) | gnuplot 2> /dev/null &
+
+(
+
+cat << _EOF_
+
+$PLOT_LF
+set term x11 window "$W_ID4"
+set output
+replot
+pause mouse close
+
+_EOF_
+
+) | gnuplot 2> /dev/null &
+
+(
+
+cat << _EOF_
+
+$PLOT_ES
+set term x11 window "$W_ID2"
+set output
+replot
+pause mouse close
+
+_EOF_
+
+) | gnuplot 2> /dev/null &
+
+(
+
+cat << _EOF_
+
+$PLOT_EG
+set term x11 window "$W_ID1"
+set output
+replot
+pause mouse close
+
+_EOF_
+
+) | gnuplot 2> /dev/null &
+
+sleep 1
+
+else
+
+echo "[*] Generating plots..."
+
+(
+
+cat << _EOF_
+
+$PLOT_HF
+
+$PLOT_LF
+
+$PLOT_ES
+
+$PLOT_EG
+
+_EOF_
+
+) | gnuplot
+
+echo "[?] You can also use -g flag to view the plots in an GUI window, and interact with the plots (if you have built afl-plot-ui). Run \"afl-plot-h\" to know more."
+
+fi
+
+if [ ! -s "$outputdir/exec_speed.png" ]; then
+
+ echo "[-] Error: something went wrong! Perhaps you have an ancient version of gnuplot?" 1>&2
+ exit 1
+
+fi
+
+echo "[*] Generating index.html..."
+
+cat >"$outputdir/index.html" <<_EOF_
+<table style="font-family: 'Trebuchet MS', 'Tahoma', 'Arial', 'Helvetica'">
+<tr><td style="width: 18ex"><b>Banner:</b></td><td>$BANNER</td></tr>
+<tr><td><b>Directory:</b></td><td>$inputdir</td></tr>
+<tr><td><b>Generated on:</b></td><td>`date`</td></tr>
+</table>
+<p>
+<img src="edges.png" width=1000 height=300>
+<img src="high_freq.png" width=1000 height=300><p>
+<img src="low_freq.png" width=1000 height=200><p>
+<img src="exec_speed.png" width=1000 height=200>
+
+_EOF_
+
+# Make it easy to remotely view results when outputting directly to a directory
+# served by Apache or other HTTP daemon. Since the plots aren't horribly
+# sensitive, this seems like a reasonable trade-off.
+
+chmod 755 "$outputdir"
+chmod 644 "$outputdir/high_freq.png" "$outputdir/low_freq.png" "$outputdir/exec_speed.png" "$outputdir/edges.png" "$outputdir/index.html"
+
+echo "[+] All done - enjoy your charts!"
+
+exit 0
diff --git a/afl-system-config b/afl-system-config
new file mode 100755
index 00000000..ef343704
--- /dev/null
+++ b/afl-system-config
@@ -0,0 +1,137 @@
+#!/bin/sh
+test "$1" = "-h" -o "$1" = "-hh" && {
+ echo 'afl-system-config by Marc Heuse <mh@mh-sec.de>'
+ echo
+ echo $0
+ echo
+ echo afl-system-config has no command line options
+ echo
+ echo afl-system-config reconfigures the system to a high performance fuzzing state.
+ echo "WARNING: this reduces the security of the system!"
+ echo
+ echo Note that there is also afl-persistent-config which sets additional permanent
+ echo configuration options.
+ exit 0
+}
+
+DONE=
+PLATFORM=`uname -s`
+echo This reconfigures the system to have a better fuzzing performance.
+echo "WARNING: this reduces the security of the system!"
+echo
+if [ '!' "$EUID" = 0 ] && [ '!' `id -u` = 0 ] ; then
+ echo "Warning: you need to be root to run this!"
+ # we do not exit as other mechanisms exist that allows to do this than
+ # being root. let the errors speak for themselves.
+fi
+sleep 1
+if [ "$PLATFORM" = "Linux" ] ; then
+{
+ sysctl -w kernel.core_uses_pid=0
+ # Arch Linux requires core_pattern to be empty :(
+ test -e /etc/arch-release && sysctl -w kernel.core_pattern=
+ test -e /etc/arch-release || sysctl -w kernel.core_pattern=core
+ sysctl -w kernel.randomize_va_space=0
+ sysctl -w kernel.sched_child_runs_first=1
+ sysctl -w kernel.sched_autogroup_enabled=1
+ sysctl -w kernel.sched_migration_cost_ns=50000000 2>/dev/null
+ sysctl -w kernel.sched_latency_ns=250000000 2>/dev/null
+ echo never > /sys/kernel/mm/transparent_hugepage/enabled
+ test -e /sys/devices/system/cpu/cpufreq/scaling_governor && echo performance | tee /sys/devices/system/cpu/cpufreq/scaling_governor
+ test -e /sys/devices/system/cpu/cpufreq/policy0/scaling_governor && echo performance | tee /sys/devices/system/cpu/cpufreq/policy*/scaling_governor
+ test -e /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor && echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
+ test -e /sys/devices/system/cpu/intel_pstate/no_turbo && echo 0 > /sys/devices/system/cpu/intel_pstate/no_turbo
+ test -e /sys/devices/system/cpu/cpufreq/boost && echo 1 > /sys/devices/system/cpu/cpufreq/boost
+ test -e /sys/devices/system/cpu/intel_pstate/max_perf_pct && echo 100 > /sys/devices/system/cpu/intel_pstate/max_perf_pct
+ test -n "$(which auditctl)" && auditctl -a never,task >/dev/null 2>&1
+} > /dev/null
+ echo Settings applied.
+ echo
+ dmesg | egrep -q 'nospectre_v2|spectre_v2=off' || {
+ echo It is recommended to boot the kernel with lots of security off - if you are running a machine that is in a secured network - so set this:
+ echo ' /etc/default/grub:GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=0 l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off srbds=off noexec=off noexec32=off tsx=on tsx_async_abort=off arm64.nopauth audit=0 hardened_usercopy=off ssbd=force-off"'
+ echo
+ }
+ echo If you run fuzzing instances in docker, run them with \"--security-opt seccomp=unconfined\" for more speed.
+ echo
+ DONE=1
+fi
+if [ "$PLATFORM" = "FreeBSD" ] ; then
+{
+ sysctl kern.elf32.aslr.enable=0
+ sysctl kern.elf64.aslr.enable=0
+} > /dev/null
+ echo Settings applied.
+ echo
+ cat <<EOF
+In order to suppress core file generation during fuzzing it is recommended to set
+me:\\
+ :coredumpsize=0:
+in the ~/.login_conf file for the user used for fuzzing.
+EOF
+ echo It is recommended to boot the kernel with lots of security off - if you are running a machine that is in a secured network - so set this:
+ echo ' sysctl hw.ibrs_disable=1'
+ echo 'Setting kern.pmap.pg_ps_enabled=0 into /boot/loader.conf might be helpful too.'
+ echo
+ DONE=1
+fi
+if [ "$PLATFORM" = "OpenBSD" ] ; then
+ doas sysctl vm.malloc_conf=
+ echo 'Freecheck on allocation in particular can be detrimental to performance.'
+ echo 'Also we might not want necessarily to abort at any allocation failure.'
+ echo 'System security features cannot be disabled on OpenBSD.'
+ echo
+ DONE=1
+fi
+if [ "$PLATFORM" = "DragonFly" ] ; then
+ #/sbin/sysctl kern.corefile=/dev/null
+ #echo Settings applied.
+ cat <<EOF
+In order to suppress core file generation during fuzzing it is recommended to set
+me:\\
+ :coredumpsize=0:
+in the ~/.login_conf file for the user used for fuzzing.
+EOF
+ echo
+ DONE=1
+fi
+if [ "$PLATFORM" = "NetBSD" ] ; then
+{
+ /sbin/sysctl -w security.models.extensions.user_set_cpu_affinity=1
+} > /dev/null
+ echo Settings applied.
+ echo
+ DONE=1
+fi
+if [ "$PLATFORM" = "Darwin" ] ; then
+ sysctl kern.sysv.shmmax=524288000
+ sysctl kern.sysv.shmmin=1
+ sysctl kern.sysv.shmseg=48
+ sysctl kern.sysv.shmall=131072000
+ echo Settings applied.
+ echo
+ if [ $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') ] ; then
+ echo
+ echo Unloading the default crash reporter
+ SL=/System/Library; PL=com.apple.ReportCrash
+ launchctl unload -w ${SL}/LaunchAgents/${PL}.plist >/dev/null 2>&1
+ sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist >/dev/null 2>&1
+ echo
+ fi
+ echo It is recommended to disable System Integration Protection for increased performance.
+ echo
+ DONE=1
+fi
+if [ "$PLATFORM" = "Haiku" ] ; then
+ DEBUG_SERVER_DIR=~/config/settings/system/debug_server
+ [ ! -d ${DEBUG_SERVER_DIR} ] && mkdir -p ${DEBUG_SERVER_DIR}
+ SETTINGS=${DEBUG_SERVER_DIR}/settings
+ [ -r ${SETTINGS} ] && grep -qE "default_action\s+kill" ${SETTINGS} && { echo "Nothing to do"; } || { \
+ echo We change the debug_server default_action from user to silently kill; \
+ [ ! -r ${SETTINGS} ] && echo "default_action kill" >${SETTINGS} || { mv ${SETTINGS} s.tmp; sed -e "s/default_action\s\s*user/default_action kill/" s.tmp > ${SETTINGS}; rm s.tmp; }; \
+ echo Settings applied.; echo; \
+ }
+ DONE=1
+fi
+test -z "$DONE" && echo Error: Unknown platform: $PLATFORM
+exit 0
diff --git a/afl-whatsup b/afl-whatsup
new file mode 100755
index 00000000..160a8c74
--- /dev/null
+++ b/afl-whatsup
@@ -0,0 +1,307 @@
+#!/bin/sh
+#
+# american fuzzy lop++ - status check tool
+# ----------------------------------------
+#
+# Originally written by Michal Zalewski
+#
+# Copyright 2015 Google Inc. All rights reserved.
+# Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# This tool summarizes the status of any locally-running synchronized
+# instances of afl-fuzz.
+#
+
+echo "$0 status check tool for afl-fuzz by Michal Zalewski"
+echo
+test "$1" = "-h" -o "$1" = "-hh" && {
+ echo "Usage: $0 [-s] [-d] afl_output_directory"
+ echo
+ echo Options:
+ echo " -s - skip details and output summary results only"
+ echo " -d - include dead fuzzer stats"
+ echo
+ exit 1
+}
+
+unset SUMMARY_ONLY
+unset PROCESS_DEAD
+
+while [ "$1" = "-s" -o "$1" = "-d" ]; do
+
+ if [ "$1" = "-s" ]; then
+ SUMMARY_ONLY=1
+ fi
+
+ if [ "$1" = "-d" ]; then
+ PROCESS_DEAD=1
+ fi
+
+ shift
+
+done
+
+DIR="$1"
+
+if [ "$DIR" = "" ]; then
+
+ echo "Usage: $0 [-s] [-d] afl_output_directory" 1>&2
+ echo 1>&2
+ echo Options: 1>&2
+ echo " -s - skip details and output summary results only" 1>&2
+ echo " -d - include dead fuzzer stats" 1>&2
+ echo 1>&2
+ exit 1
+
+fi
+
+cd "$DIR" || exit 1
+
+if [ -d queue ]; then
+
+ echo "[-] Error: parameter is an individual output directory, not a sync dir." 1>&2
+ exit 1
+
+fi
+
+RED=`tput setaf 9 1 1`
+GREEN=`tput setaf 2 1 1`
+BLUE=`tput setaf 4 1 1`
+YELLOW=`tput setaf 11 1 1`
+NC=`tput sgr0`
+RESET="$NC"
+
+CUR_TIME=`date +%s`
+
+TMP=`mktemp -t .afl-whatsup-XXXXXXXX` || TMP=`mktemp -p /data/local/tmp .afl-whatsup-XXXXXXXX` || TMP=`mktemp -p /data/local/tmp .afl-whatsup-XXXXXXXX` || exit 1
+
+ALIVE_CNT=0
+DEAD_CNT=0
+
+TOTAL_TIME=0
+TOTAL_EXECS=0
+TOTAL_EPS=0
+TOTAL_CRASHES=0
+TOTAL_PFAV=0
+TOTAL_PENDING=0
+
+# Time since last find / crash / hang, formatted as string
+FMT_TIME="0 days 0 hours"
+FMT_FIND="${RED}none seen yet${NC}"
+FMT_CRASH="none seen yet"
+FMT_HANG="none seen yet"
+
+if [ "$SUMMARY_ONLY" = "" ]; then
+
+ echo "Individual fuzzers"
+ echo "=================="
+ echo
+
+fi
+
+fmt_duration()
+{
+ DUR_STRING=
+ if [ $1 -le 0 ]; then
+ return 1
+ fi
+
+ local duration=$((CUR_TIME - $1))
+ local days=$((duration / 60 / 60 / 24))
+ local hours=$(((duration / 60 / 60) % 24))
+ local minutes=$(((duration / 60) % 60))
+ local seconds=$((duration % 60))
+
+ if [ $duration -le 0 ]; then
+ DUR_STRING="0 seconds"
+ elif [ $duration -eq 1 ]; then
+ DUR_STRING="1 second"
+ elif [ $days -gt 0 ]; then
+ DUR_STRING="$days days, $hours hours"
+ elif [ $hours -gt 0 ]; then
+ DUR_STRING="$hours hours, $minutes minutes"
+ elif [ $minutes -gt 0 ]; then
+ DUR_STRING="$minutes minutes, $seconds seconds"
+ else
+ DUR_STRING="$seconds seconds"
+ fi
+}
+
+FIRST=true
+TOTAL_WCOP=
+TOTAL_LAST_FIND=0
+
+for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
+
+ sed 's/^command_line.*$/_skip:1/;s/[ ]*:[ ]*/="/;s/$/"/' "$i" >"$TMP"
+ . "$TMP"
+
+ RUN_UNIX=$run_time
+ RUN_DAYS=$((RUN_UNIX / 60 / 60 / 24))
+ RUN_HRS=$(((RUN_UNIX / 60 / 60) % 24))
+
+ test -n "$cycles_wo_finds" && {
+ test -z "$FIRST" && TOTAL_WCOP="${TOTAL_WCOP}/"
+ TOTAL_WCOP="${TOTAL_WCOP}${cycles_wo_finds}"
+ FIRST=
+ }
+
+ if [ "$SUMMARY_ONLY" = "" ]; then
+
+ echo ">>> $afl_banner ($RUN_DAYS days, $RUN_HRS hrs) fuzzer PID: $fuzzer_pid <<<"
+ echo
+
+ fi
+
+ if ! kill -0 "$fuzzer_pid" 2>/dev/null; then
+
+ if [ "$SUMMARY_ONLY" = "" ]; then
+
+ echo " Instance is dead or running remotely, skipping."
+ echo
+
+ fi
+
+ DEAD_CNT=$((DEAD_CNT + 1))
+ last_find=0
+
+ if [ "$PROCESS_DEAD" = "" ]; then
+
+ continue
+
+ fi
+
+ fi
+
+ ALIVE_CNT=$((ALIVE_CNT + 1))
+
+ EXEC_SEC=0
+ test -z "$RUN_UNIX" -o "$RUN_UNIX" = 0 || EXEC_SEC=$((execs_done / RUN_UNIX))
+ PATH_PERC=$((cur_item * 100 / corpus_count))
+
+ TOTAL_TIME=$((TOTAL_TIME + RUN_UNIX))
+ TOTAL_EPS=$((TOTAL_EPS + EXEC_SEC))
+ TOTAL_EXECS=$((TOTAL_EXECS + execs_done))
+ TOTAL_CRASHES=$((TOTAL_CRASHES + saved_crashes))
+ TOTAL_PENDING=$((TOTAL_PENDING + pending_total))
+ TOTAL_PFAV=$((TOTAL_PFAV + pending_favs))
+
+ if [ "$last_find" -gt "$TOTAL_LAST_FIND" ]; then
+ TOTAL_LAST_FIND=$last_find
+ fi
+
+ if [ "$SUMMARY_ONLY" = "" ]; then
+
+ # Warnings in red
+ TIMEOUT_PERC=$((exec_timeout * 100 / execs_done))
+ if [ $TIMEOUT_PERC -ge 10 ]; then
+ echo " ${RED}timeout_ratio $TIMEOUT_PERC%${NC}"
+ fi
+
+ if [ $EXEC_SEC -eq 0 ]; then
+ echo " ${YELLOW}no data yet, 0 execs/sec${NC}"
+ elif [ $EXEC_SEC -lt 100 ]; then
+ echo " ${RED}slow execution, $EXEC_SEC execs/sec${NC}"
+ fi
+
+ fmt_duration $last_find && FMT_FIND=$DUR_STRING
+ fmt_duration $last_crash && FMT_CRASH=$DUR_STRING
+ fmt_duration $last_hang && FMT_HANG=$DUR_STRING
+ FMT_CWOP="not available"
+ test -n "$cycles_wo_finds" && {
+ test "$cycles_wo_finds" = 0 && FMT_CWOP="$cycles_wo_finds"
+ test "$cycles_wo_finds" -gt 10 && FMT_CWOP="${YELLOW}$cycles_wo_finds${NC}"
+ test "$cycles_wo_finds" -gt 50 && FMT_CWOP="${RED}$cycles_wo_finds${NC}"
+ }
+
+ echo " last_find : $FMT_FIND"
+ echo " last_crash : $FMT_CRASH"
+ echo " last_hang : $FMT_HANG"
+ echo " cycles_wo_finds : $FMT_CWOP"
+
+ CPU_USAGE=$(ps aux | grep $fuzzer_pid | grep -v grep | awk '{print $3}')
+ MEM_USAGE=$(ps aux | grep $fuzzer_pid | grep -v grep | awk '{print $4}')
+
+ echo " cpu usage $CPU_USAGE%, memory usage $MEM_USAGE%"
+ echo " cycles $((cycles_done + 1)), lifetime speed $EXEC_SEC execs/sec, items $cur_item/$corpus_count (${PATH_PERC}%)"
+
+ if [ "$saved_crashes" = "0" ]; then
+ echo " pending $pending_favs/$pending_total, coverage $bitmap_cvg, no crashes yet"
+ else
+ echo " pending $pending_favs/$pending_total, coverage $bitmap_cvg, crashes saved $saved_crashes (!)"
+ fi
+
+ echo
+
+ fi
+
+done
+
+# Formatting for total time, time since last find, crash, and hang
+fmt_duration $((CUR_TIME - TOTAL_TIME)) && FMT_TIME=$DUR_STRING
+# Formatting for total execution
+FMT_EXECS="0 millions"
+EXECS_MILLION=$((TOTAL_EXECS / 1000 / 1000))
+EXECS_THOUSAND=$((TOTAL_EXECS / 1000 % 1000))
+if [ $EXECS_MILLION -gt 9 ]; then
+ FMT_EXECS="$EXECS_MILLION millions"
+elif [ $EXECS_MILLION -gt 0 ]; then
+ FMT_EXECS="$EXECS_MILLION millions, $EXECS_THOUSAND thousands"
+else
+ FMT_EXECS="$EXECS_THOUSAND thousands"
+fi
+
+rm -f "$TMP"
+
+TOTAL_DAYS=$((TOTAL_TIME / 60 / 60 / 24))
+TOTAL_HRS=$(((TOTAL_TIME / 60 / 60) % 24))
+
+test -z "$TOTAL_WCOP" && TOTAL_WCOP="not available"
+fmt_duration $TOTAL_LAST_FIND && TOTAL_LAST_FIND=$DUR_STRING
+
+test "$TOTAL_TIME" = "0" && TOTAL_TIME=1
+
+if [ "$PROCESS_DEAD" = "" ]; then
+
+ TXT="excluded from stats"
+
+else
+
+ TXT="included in stats"
+ ALIVE_CNT=$(($ALIVE_CNT - $DEAD_CNT))
+
+fi
+
+echo "Summary stats"
+echo "============="
+echo
+echo " Fuzzers alive : $ALIVE_CNT"
+
+if [ ! "$DEAD_CNT" = "0" ]; then
+ echo " Dead or remote : $DEAD_CNT ($TXT)"
+fi
+
+echo " Total run time : $FMT_TIME"
+echo " Total execs : $FMT_EXECS"
+echo " Cumulative speed : $TOTAL_EPS execs/sec"
+if [ "$ALIVE_CNT" -gt "0" ]; then
+ echo " Average speed : $((TOTAL_EPS / ALIVE_CNT)) execs/sec"
+fi
+echo " Pending items : $TOTAL_PFAV faves, $TOTAL_PENDING total"
+
+if [ "$ALIVE_CNT" -gt "1" ]; then
+ echo " Pending per fuzzer : $((TOTAL_PFAV/ALIVE_CNT)) faves, $((TOTAL_PENDING/ALIVE_CNT)) total (on average)"
+fi
+
+echo " Crashes saved : $TOTAL_CRASHES"
+echo "Cycles without finds : $TOTAL_WCOP"
+echo " Time without finds : $TOTAL_LAST_FIND"
+echo
+
+exit 0
diff --git a/afl-wine-trace b/afl-wine-trace
new file mode 100755
index 00000000..63ff896b
--- /dev/null
+++ b/afl-wine-trace
@@ -0,0 +1,80 @@
+#!/usr/bin/env python3
+
+import os
+import sys
+import pefile
+import shutil
+import subprocess
+
+if len(sys.argv) < 2:
+ print("[afl-wine-trace] usage: ./afl-wine-trace binary [args...]\n")
+ exit(1)
+
+if os.getenv("AFL_PATH"):
+ my_dir = os.getenv("AFL_PATH")
+else:
+ my_dir = os.path.dirname(os.path.abspath(__file__))
+
+os.environ["WINELOADERNOEXEC"] = "1"
+
+pe = pefile.PE(sys.argv[1])
+
+if "AFL_ENTRYPOINT" not in os.environ:
+ os.environ["AFL_ENTRYPOINT"] = "0x%x" % (pe.OPTIONAL_HEADER.ImageBase + pe.OPTIONAL_HEADER.AddressOfEntryPoint)
+if not os.getenv("AFL_INST_LIBS"):
+ if "AFL_CODE_START" not in os.environ:
+ os.environ["AFL_CODE_START"] = "0x%x" % (pe.OPTIONAL_HEADER.ImageBase + pe.OPTIONAL_HEADER.BaseOfCode)
+ if "AFL_CODE_END" not in os.environ:
+ os.environ["AFL_CODE_END"] = "0x%x" % (pe.OPTIONAL_HEADER.ImageBase + pe.OPTIONAL_HEADER.BaseOfCode + pe.OPTIONAL_HEADER.SizeOfCode)
+
+if pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_AMD64"] or pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_IA64"]:
+ os.environ["QEMU_SET_ENV"] = "LD_PRELOAD=" + os.path.join(my_dir, "qemu_mode/unsigaction/unsigaction64.so") + ",WINEARCH=win64"
+else:
+ os.environ["QEMU_SET_ENV"] = "LD_PRELOAD=" + os.path.join(my_dir, "qemu_mode/unsigaction/unsigaction32.so") + ",WINEARCH=win32"
+
+if os.getenv("WINECOV_QEMU_PATH"):
+ qemu_path = os.getenv("WINECOV_QEMU_PATH")
+elif os.path.exists(os.path.join(my_dir, "afl-qemu-trace")):
+ qemu_path = os.path.join(my_dir, "afl-qemu-trace")
+else:
+ qemu_path = "qemu-"
+ if pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_AMD64"] or pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_IA64"]:
+ qemu_path += "x86_64"
+ elif pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_I386"]:
+ qemu_path += "i386"
+ else:
+ print ("[afl-wine-trace] unsuppoted architecture\n")
+ exit(1)
+ qemu_path = shutil.which(qemu_path)
+
+wine_path = None
+if os.getenv("AFL_WINE_PATH"):
+ wine_path = os.getenv("AFL_WINE_PATH")
+else:
+ if not wine_path and shutil.which("wine"):
+ wine_path = shutil.which("wine")
+ if not wine_path and os.path.exists("/usr/bin/wine"):
+ wine_path = "/usr/bin/wine"
+ if not wine_path and os.path.exists("/usr/lib/wine/wine"):
+ wine_path = "/usr/lib/wine/wine"
+ if pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_AMD64"] or pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_IA64"]:
+ wine_path += "64"
+ elif pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_I386"]:
+ pass
+ else:
+ print ("[afl-wine-trace] unsopported architecture\n")
+ exit(1)
+
+argv = sys.argv[1:]
+for i in range(len(argv)):
+ if ".cur_input" in argv[i]:
+ # Get the Wine translated path using the winepath tool
+ arg_translated = subprocess.run([os.path.join(os.path.dirname(wine_path), "winepath"), "--windows", argv[i]], universal_newlines=True, stdout=subprocess.PIPE).stdout
+ # Remove the spurious LF at the end of the path
+ if len(arg_translated) > 0 and arg_translated[-1] == '\n':
+ arg_translated = arg_translated[:-1]
+ argv[i] = arg_translated
+ break
+
+print("[afl-wine-trace] exec:", " ".join([qemu_path, wine_path] + argv))
+os.execve(qemu_path, [qemu_path, wine_path] + argv, os.environ)
diff --git a/config.h b/config.h
new file mode 120000
index 00000000..046ab52a
--- /dev/null
+++ b/config.h
@@ -0,0 +1 @@
+include/config.h \ No newline at end of file
diff --git a/dictionaries/README.md b/dictionaries/README.md
new file mode 100644
index 00000000..ab0a6798
--- /dev/null
+++ b/dictionaries/README.md
@@ -0,0 +1,42 @@
+# AFL++ dictionaries
+
+For the general instruction manual, see [docs/README.md](../docs/README.md).
+
+This subdirectory contains a set of dictionaries that can be used in conjunction
+with the -x option to allow the fuzzer to effortlessly explore the grammar of
+some of the more verbose data formats or languages.
+
+These sets were done by Michal Zalewski, various contributors, and imported from
+oss-fuzz, go-fuzz and libfuzzer.
+
+Custom dictionaries can be added at will. They should consist of a
+reasonably-sized set of rudimentary syntax units that the fuzzer will then try
+to clobber together in various ways. Snippets between 2 and 16 bytes are usually
+the sweet spot.
+
+Custom dictionaries can be created in two ways:
+
+ - By creating a new directory and placing each token in a separate file, in
+ which case, there is no need to escape or otherwise format the data.
+
+ - By creating a flat text file where tokens are listed one per line in the
+ format of name="value". The alphanumeric name is ignored and can be omitted,
+ although it is a convenient way to document the meaning of a particular
+ token. The value must appear in quotes, with hex escaping (\xNN) applied to
+ all non-printable, high-bit, or otherwise problematic characters (\\ and \"
+ shorthands are recognized, too).
+
+The fuzzer auto-selects the appropriate mode depending on whether the -x
+parameter is a file or a directory.
+
+In the file mode, every name field can be optionally followed by @<num>, e.g.:
+
+ `keyword_foo@1 = "foo"`
+
+Such entries will be loaded only if the requested dictionary level is equal or
+higher than this number. The default level is zero; a higher value can be set by
+appending @<num> to the dictionary file name, like so:
+
+ `-x path/to/dictionary.dct@2`
+
+Good examples of dictionaries can be found in xml.dict and png.dict. \ No newline at end of file
diff --git a/dictionaries/aff.dict b/dictionaries/aff.dict
new file mode 100644
index 00000000..09dae5de
--- /dev/null
+++ b/dictionaries/aff.dict
@@ -0,0 +1,73 @@
+# https://www.systutorials.com/docs/linux/man/4-hunspell/
+
+# Affix keywords
+"AF"
+"AM"
+"BREAK"
+"CHECKCOMPOUNDCASE"
+"CHECKCOMPOUNDDUP"
+"CHECKCOMPOUNDPATTERN"
+"CHECKCOMPOUNDREP"
+"CHECKCOMPOUNDTRIPLE"
+"COMPLEXPREFIXES"
+"COMPOUNDBEGIN"
+"COMPOUNDFLAG"
+"COMPOUNDFORBIDFLAG"
+"COMPOUNDLAST"
+"COMPOUNDMIDDLE"
+"COMPOUNDMIN"
+"COMPOUNDPERMITFLAG"
+"COMPOUNDROOT"
+"COMPOUNDRULE"
+"COMPOUNDSYLLABLE"
+"COMPOUNDWORDMAX"
+"FLAG"
+"FORBIDWARN"
+"FORCEUCASE"
+"IGNORE"
+"KEY"
+"LANG"
+"MAP"
+"MAXCODSUGS"
+"MAXDIFF"
+"MAXNGRAMSUGS"
+"NOSPLITSUGS"
+"NOSUGGEST"
+"ONLYINCOMPOUND"
+"ONLYMAXDIFF"
+"PFX"
+"PHONE"
+"REP"
+"SET"
+"SFX"
+"SIMPLIFIEDTRIPLE"
+"SUGWITHDOTS"
+"SYLLABLENUM"
+"TRY"
+"WARN"
+"CIRCUMFIX"
+"FORBIDDENWORD"
+"FULLSTRIP"
+"KEEPCASE"
+"ICONV"
+"OCONV"
+"LEMMA_PRESENT"
+"NEEDAFFIX"
+"PSEUDOROOT"
+"SUBSTANDARD"
+"WORDCHARS"
+"CHECKSHARPS"
+
+# Optional data fields
+"ph:"
+"st:"
+"al:"
+"po:"
+"ds:"
+"is:"
+"ts:"
+"sp:"
+"pa:"
+"dp:"
+"ip:"
+"tp:"
diff --git a/dictionaries/ass.dict b/dictionaries/ass.dict
new file mode 100644
index 00000000..aa4f9b43
--- /dev/null
+++ b/dictionaries/ass.dict
@@ -0,0 +1,112 @@
+"0x"
+"\\1a"
+"\\2a"
+"\\2c"
+"\\3a"
+"\\3c"
+"\\4a"
+"\\4c"
+"\\a"
+"\\alpha"
+"\\an"
+"Arial"
+"\\b"
+"Banner;"
+"\\be"
+"\\blur"
+"\\bord"
+"\\c"
+"CFF"
+"CID Type 1"
+"\\clip"
+"clip"
+"Courier"
+"Courier New"
+"Default"
+"Dialogue:"
+"[Events]"
+"\\fade"
+"\\fax"
+"\\fay"
+"\\fe"
+"\\fn"
+"fontname:"
+"[Fonts]"
+"Format:"
+"\\frx"
+"\\fry"
+"\\frz"
+"\\fs"
+"\\fsc"
+"\\fscx"
+"\\fscy"
+"\\fsp"
+"&h"
+"Helvetica"
+"\\i"
+"\\iclip"
+"iclip"
+"\\k"
+"Kerning:"
+"Kerning"
+"\\kf"
+"\\ko"
+"Language:"
+"monospace"
+"\\move"
+"move"
+"none"
+"\\org"
+"org"
+"OverrideStyle"
+"\\p"
+"p"
+"\\pbo"
+"pbo"
+"pc.240m"
+"pc.601"
+"pc.709"
+"pc.fcc"
+"PlayResX:"
+"PlayResX"
+"PlayResY:"
+"PlayResY"
+"\\pos"
+"pos"
+"\\q"
+"\\r"
+"\\s"
+"sans-serif"
+"ScaledBorderAndShadow:"
+"ScaledBorderAndShadow"
+"[Script Info]"
+"Scroll down;"
+"Scroll up;"
+"serif"
+"\\shad"
+"Style:"
+"\\t"
+"Text"
+"Timer:"
+"Timer"
+"Times"
+"Times New Roman"
+"tv.240m"
+"tv.601"
+"tv.709"
+"tv.fcc"
+"Type 1"
+"Type 42"
+"\\u"
+"UTF-8"
+"[V4 Styles]"
+"[V4+ Styles]"
+"WrapStyle:"
+"WrapStyle"
+"\\xbord"
+"\\xshad"
+"\\ybord"
+"YCbCr Matrix:"
+"YCbCr Matrix"
+"yes"
+"\\yshad"
diff --git a/dictionaries/atom.dict b/dictionaries/atom.dict
new file mode 100644
index 00000000..e9e6884d
--- /dev/null
+++ b/dictionaries/atom.dict
@@ -0,0 +1,33 @@
+# https://validator.w3.org/feed/docs/atom.html
+# https://tools.ietf.org/html/rfc4287
+
+"<?xml version='1.0' encoding='utf-8'?>"
+"<feed xmlns='http://www.w3.org/2005/Atom'>"
+
+"<alternate>"
+"<author>"
+"<category>"
+"<content>"
+"<contributor>"
+"<email>"
+"<entry>"
+"<feed>"
+"<first>"
+"<generator>"
+"<icon>"
+"<id>"
+"<last>"
+"<link>"
+"<logo>"
+"<modified/>
+"<name>"
+"<next>"
+"<previous>"
+"<published>"
+"<rights>"
+"<source>"
+"<subtitle>"
+"<summary>"
+"<title>"
+"<updated>"
+"<uri>"
diff --git a/dictionaries/av1_dc.dict b/dictionaries/av1_dc.dict
new file mode 100644
index 00000000..fb163886
--- /dev/null
+++ b/dictionaries/av1_dc.dict
@@ -0,0 +1,5 @@
+# IVF Signature + version (bytes 0-5)
+kw1="DKIF\x00\x00"
+
+# AV1 codec fourCC (bytes 8-11)
+kw2="AV01"
diff --git a/dictionaries/bash.dict b/dictionaries/bash.dict
new file mode 100644
index 00000000..a70e9ff6
--- /dev/null
+++ b/dictionaries/bash.dict
@@ -0,0 +1,152 @@
+# Keywords taken from
+# - https://www.gnu.org/software/bash/manual/html_node/Bash-Variables.html
+# - https://www.gnu.org/software/bash/manual/html_node/Bourne-Shell-Builtins.html
+# - https://www.gnu.org/software/bash/manual/html_node/Bourne-Shell-Variables.html
+# - https://www.gnu.org/software/bash/manual/html_node/Reserved-Word-Index.html
+
+"!"
+"."
+":"
+"["
+"[["
+"]]"
+"{"
+"}"
+"BASH"
+"BASH_ALIASES"
+"BASH_ARGC"
+"BASH_ARGV"
+"BASH_ARGV0"
+"BASH_CMDS"
+"BASH_COMMAND"
+"BASH_COMPAT"
+"BASH_ENV"
+"BASH_EXECUTION_STRING"
+"BASH_LINENO"
+"BASH_LOADABLES_PATH"
+"BASHOPTS"
+"BASHPID"
+"BASH_REMATCH"
+"BASH_SOURCE"
+"BASH_SUBSHELL"
+"BASH_VERSINFO"
+"BASH_VERSION"
+"BASH_XTRACEFD"
+"break"
+"case"
+"cd"
+"CDPATH"
+"CHILD_MAX"
+"COLUMNS"
+"COMP_CWORD"
+"COMP_KEY"
+"COMP_LINE"
+"COMP_POINT"
+"COMPREPLY"
+"COMP_TYPE"
+"COMP_WORDBREAKS"
+"COMP_WORDS"
+"continue"
+"COPROC"
+"DIRSTACK"
+"do"
+"done"
+"elif"
+"else"
+"EMACS"
+"ENV"
+"EPOCHREALTIME"
+"EPOCHSECONDS"
+"esac"
+"EUID"
+"eval"
+"exec"
+"EXECIGNORE"
+"exit"
+"export"
+"FCEDIT"
+"fi"
+"FIGNORE"
+"for"
+"FUNCNAME"
+"FUNCNEST"
+"function"
+"getopts"
+"GLOBIGNORE"
+"GROUPS"
+"hash"
+"histchars"
+"HISTCMD"
+"HISTCONTROL"
+"HISTFILE"
+"HISTFILESIZE"
+"HISTIGNORE"
+"HISTSIZE"
+"HISTTIMEFORMAT"
+"HOME"
+"HOSTFILE"
+"HOSTNAME"
+"HOSTTYPE"
+"if"
+"IFS"
+"IGNOREEOF"
+"in"
+"INPUTRC"
+"INSIDE_EMACS"
+"LANG"
+"LC_ALL"
+"LC_COLLATE"
+"LC_CTYPE"
+"LC_MESSAGES"
+"LC_NUMERIC"
+"LC_TIME"
+"LINENO"
+"LINES"
+"MACHTYPE"
+"MAIL"
+"MAILCHECK"
+"MAILPATH"
+"MAPFILE"
+"OLDPWD"
+"OPTARG"
+"OPTERR"
+"OPTIND"
+"OSTYPE"
+"PATH"
+"PIPESTATUS"
+"POSIXLY_CORRECT"
+"PPID"
+"PROMPT_COMMAND"
+"PROMPT_DIRTRIM"
+"PS0"
+"PS1"
+"PS2"
+"PS3"
+"PS4"
+"pwd"
+"PWD"
+"RANDOM"
+"READLINE_LINE"
+"READLINE_POINT"
+"readonly"
+"REPLY"
+"return"
+"SECONDS"
+"select"
+"SHELL"
+"SHELLOPTS"
+"shift"
+"SHLVL"
+"test"
+"then"
+"time"
+"TIMEFORMAT"
+"times"
+"TMOUT"
+"TMPDIR"
+"trap"
+"UID"
+"umask"
+"unset"
+"until"
+"while"
diff --git a/dictionaries/bdf.dict b/dictionaries/bdf.dict
new file mode 100644
index 00000000..953d1f1b
--- /dev/null
+++ b/dictionaries/bdf.dict
@@ -0,0 +1,30 @@
+# https://en.wikipedia.org/wiki/Glyph_Bitmap_Distribution_Format
+# https://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5005.BDF_Spec.pdf
+
+"STARTFONT"
+"COMMENT"
+"CONTENTVERSION"
+"FONT"
+"SIZE"
+"FONTBOUNDINGBOX"
+"METRICSSET"
+"SWIDTH"
+"DWIDTH"
+"SWIDTH1"
+"DWIDTH1"
+"VVECTOR"
+"STARTPROPERTIES"
+"ENDPROPERTIES"
+"CHARS"
+"STARTCHAR"
+"ENCODING"
+"BBX"
+"BITMAP"
+"ENDCHAR"
+"ENDFONT"
+
+# misc
+"255"
+"-1"
+"0"
+"2.1"
diff --git a/dictionaries/bmp.dict b/dictionaries/bmp.dict
new file mode 100644
index 00000000..ae691044
--- /dev/null
+++ b/dictionaries/bmp.dict
@@ -0,0 +1,10 @@
+windows="BM"
+os2_bitmap="BA"
+os2_icon="CI"
+os2_pointer="CP"
+os2_struct="IC"
+os2_ptr="PT"
+windows_color_space="Win "
+srgb="sRGB"
+link="LINK"
+mbed="MBED"
diff --git a/dictionaries/bz2.dict b/dictionaries/bz2.dict
new file mode 100644
index 00000000..5d1564fe
--- /dev/null
+++ b/dictionaries/bz2.dict
@@ -0,0 +1,3 @@
+magic="BZ"
+compress_magic="\x31\x41\x59\x26\x53\x59"
+eos_magic="\x17\x72\x45\x38\x50\x90"
diff --git a/dictionaries/creole.dict b/dictionaries/creole.dict
new file mode 100644
index 00000000..65a9909a
--- /dev/null
+++ b/dictionaries/creole.dict
@@ -0,0 +1,14 @@
+# http://www.wikicreole.org/wiki/Creole1.0
+
+bold="**"
+italic="//"
+heading="=="
+link1="[[a|b]]"
+link2="[[a:b]]"
+hr="----"
+img=" {{a|b}}"
+table_heading="|=a |=b |"
+raw="{{{a}}}"
+escape="~"
+placeholder="<<<x>>>"
+line_break="\\\\"
diff --git a/dictionaries/css.dict b/dictionaries/css.dict
new file mode 100644
index 00000000..92fa536c
--- /dev/null
+++ b/dictionaries/css.dict
@@ -0,0 +1,354 @@
+# https://en.wikipedia.org/wiki/Cascading_Style_Sheets
+
+# selectors
+"::after"
+"::before"
+"::first-letter"
+"::first-line"
+"::placeholder"
+"::selection"
+":active"
+":checked"
+":default"
+":disabled"
+":empty"
+":enabled"
+":first-child"
+":first-of-type"
+":focus"
+":hover"
+":in-range"
+":indeterminate"
+":invalid"
+":lang("
+":last-child"
+":last-of-type"
+":link"
+":not("
+":nth-child("
+":nth-last-child("
+":nth-last-of-type("
+":nth-of-type("
+":only-child"
+":only-of-type"
+":optional"
+":out-of-range"
+":read-only"
+":read-write"
+":required"
+":root"
+":target"
+":valid"
+":visited"
+
+# units
+"ch"
+"cm"
+"em"
+"ex"
+"in"
+"mm"
+"pc"
+"pt"
+"px"
+"rem"
+"vh"
+"vmax"
+"vmin"
+"vw"
+
+# functions
+"attr("
+"calc("
+"cubic-bezier("
+"hsl("
+"hsls("
+"linear-gradient("
+"radial-gradient("
+"repeating-linear-gradient("
+"repeating-radial-gradient("
+"rgb("
+"rgba("
+"var("
+
+# prefixes
+"-moz"
+"-webkit"
+
+# properties
+"@charset"
+"@font-face"
+"@font-feature-values"
+"@import"
+"@keyframes"
+"@media"
+"align-items"
+"align-self"
+"all"
+"animation"
+"animation-delay"
+"animation-direction"
+"animation-duration"
+"animation-fill-mode"
+"animation-iteration-count"
+"animation-name"
+"animation-play-state"
+"animation-timing-function"
+"backface-visibility"
+"background"
+"background-attachment"
+"background-blend-mode"
+"background-clip"
+"background-color"
+"background-image"
+"background-origin"
+"background-position"
+"background-repeat"
+"background-size"
+"border"
+"border-bottom"
+"border-bottom-color"
+"border-bottom-left-radius"
+"border-bottom-right-radius"
+"border-bottom-style"
+"border-bottom-width"
+"border-collapse"
+"border-color"
+"border-image"
+"border-image-outset"
+"border-image-repeat"
+"border-image-slice"
+"border-image-source"
+"border-image-width"
+"border-left"
+"border-left-color"
+"border-left-style"
+"border-left-width"
+"border-radius"
+"border-right"
+"border-right-color"
+"border-right-style"
+"border-right-width"
+"border-spacing"
+"border-style"
+"border-top"
+"border-top-color"
+"border-top-left-radius"
+"border-top-right-radius"
+"border-top-style"
+"border-top-width"
+"border-width"
+"bottom"
+"box-decoration-break"
+"box-shadow"
+"box-sizing"
+"break-after"
+"break-before"
+"break-inside"
+"caption-side"
+"caret-color"
+"clear"
+"clip"
+"color"
+"column-count"
+"column-fill"
+"column-gap"
+"column-rule"
+"column-rule-color"
+"column-rule-style"
+"column-rule-width"
+"column-span"
+"column-width"
+"columns"
+"content"
+"counter-increment"
+"counter-reset"
+"cursor"
+"direction"
+"display"
+"empty-cells"
+"filter"
+"flex"
+"flex-basis"
+"flex-direction"
+"flex-flow"
+"flex-grow"
+"flex-shrink"
+"flex-wrap"
+"float"
+"font"
+"font-family"
+"font-feature-settings"
+"font-kerning"
+"font-language-override"
+"font-size"
+"font-size-adjust"
+"font-stretch"
+"font-style"
+"font-synthesis"
+"font-variant"
+"font-variant-alternates"
+"font-variant-caps"
+"font-variant-east-asian"
+"font-variant-ligatures"
+"font-variant-numeric"
+"font-variant-position"
+"font-weight"
+"from"
+"grid"
+"grid-area"
+"grid-auto-columns"
+"grid-auto-flow"
+"grid-auto-rows"
+"grid-column"
+"grid-column-end"
+"grid-column-gap"
+"grid-column-start"
+"grid-gap"
+"grid-row"
+"grid-row-end"
+"grid-row-gap"
+"grid-row-start"
+"grid-template"
+"grid-template-areas"
+"grid-template-columns"
+"grid-template-rows"
+"hanging-punctuation"
+"height"
+"hyphens"
+"image-rendering"
+"isolation"
+"justify-content"
+"left"
+"letter-spacing"
+"line-break"
+"line-height"
+"list-style"
+"list-style-image"
+"list-style-position"
+"list-style-type"
+"margin"
+"margin-bottom"
+"margin-left"
+"margin-right"
+"margin-top"
+"max-height"
+"max-width"
+"min-height"
+"min-width"
+"mix-blend-mode"
+"object-fit"
+"object-position"
+"opacity"
+"order"
+"orphans"
+"outline"
+"outline-color"
+"outline-offset"
+"outline-style"
+"outline-width"
+"overflow"
+"overflow-wrap"
+"overflow-x"
+"overflow-y"
+"padding"
+"padding-bottom"
+"padding-left"
+"padding-right"
+"padding-top"
+"page-break-after"
+"page-break-before"
+"page-break-inside"
+"perspective"
+"perspective-origin"
+"pointer-events"
+"position"
+"quotes"
+"resize"
+"right"
+"scroll-behavior"
+"tab-size"
+"table-layout"
+"text-align"
+"text-align-last"
+"text-combine-upright"
+"text-decoration"
+"text-decoration-color"
+"text-decoration-line"
+"text-decoration-style"
+"text-indent"
+"text-justify"
+"text-orientation"
+"text-overflow"
+"text-shadow"
+"text-transform"
+"text-underline-position"
+"to"
+"top"
+"transform"
+"transform-origin"
+"transform-style"
+"transition"
+"transition-delay"
+"transition-duration"
+"transition-property"
+"transition-timing-function"
+"unicode-bidi"
+"user-select"
+"vertical-align"
+"visibility"
+"white-space"
+"widows"
+"width"
+"word-break"
+"word-spacing"
+"word-wrap"
+"writing-mode"
+"z-index"
+
+
+# aural - https://www.w3schools.com/cssref/css_ref_aural.asp
+"above"
+"azimuth"
+"below"
+"center"
+"code"
+"continuous"
+"cue"
+"cue-after"
+"cue-before"
+"elevation"
+"generic-voice"
+"left"
+"left-side"
+"leftwards"
+"lower"
+"medium"
+"mix"
+"none"
+"once"
+"pause"
+"pause-after"
+"pause-before"
+"pitch"
+"pitch-range"
+"play-during"
+"richness"
+"right"
+"right-side"
+"slower"
+"speak"
+"speak-header"
+"speak-numeral"
+"speak-punctuation"
+"speech-rate"
+"stress"
+"url"
+"voice-family"
+"volume"
+"x-fast"
+"x-high"
+"x-loud"
+"x-low"
+"x-slow"
+"x-soft"
diff --git a/dictionaries/csv.dict b/dictionaries/csv.dict
new file mode 100644
index 00000000..be61a7e6
--- /dev/null
+++ b/dictionaries/csv.dict
@@ -0,0 +1,6 @@
+"\x00"
+"\r\n"
+";;"
+",,"
+"\t;"
+"\n;"
diff --git a/dictionaries/dds.dict b/dictionaries/dds.dict
new file mode 100644
index 00000000..81cb473b
--- /dev/null
+++ b/dictionaries/dds.dict
@@ -0,0 +1,35 @@
+# See http://www.mindcontrol.org/~hplus/graphics/dds-info/
+
+magic="\x20\x53\x44\x44"
+
+# Headers
+"\x00\x00\x00\x01"
+"\x00\x00\x00\x02"
+"\x00\x00\x00\x04"
+"\x00\x00\x00\x08"
+"\x00\x00\x10\x00"
+"\x00\x02\x00\x00"
+"\x00\x08\x00\x00"
+"\x00\x80\x00\x00"
+"\x00\x00\x00\x01"
+"\x00\x00\x00\x04"
+"\x00\x00\x00\x20"
+"\x00\x00\x00\x40"
+"\x00\x00\x00\x08"
+"\x00\x00\x10\x00"
+"\x00\x40\x00\x00"
+"\x00\x00\x02\x00"
+"\x00\x00\x04\x00"
+"\x00\x00\x08\x00"
+"\x00\x00\x10\x00"
+"\x00\x00\x20\x00"
+"\x00\x00\x40\x00"
+"\x00\x00\x80\x00"
+"\x00\x20\x00\x00"
+
+#formats
+"1TXD"
+"2TXD"
+"3TXD"
+"4TXD"
+"5TXD"
diff --git a/dictionaries/djvu.dict b/dictionaries/djvu.dict
new file mode 100644
index 00000000..1fb8d3ba
--- /dev/null
+++ b/dictionaries/djvu.dict
@@ -0,0 +1,34 @@
+"ANTa"
+"ANTz"
+"BG2k"
+"BG44"
+"BGjp"
+"BM44"
+"CELX"
+"DIRM"
+"DJVI"
+"DJVM"
+"DJVU"
+"Djbz"
+"FAKE"
+"FG2k"
+"FG44"
+"FGbz"
+"FGjp"
+"FORM"
+"INCL"
+"INFO"
+"LINK"
+"METa"
+"METz"
+"NAVM"
+"NDIR"
+"PM44"
+"SINF"
+"Sjbz"
+"Smmr"
+"TH44"
+"THUM"
+"TXTa"
+"TXTz"
+"WMRM"
diff --git a/dictionaries/docommand.dict b/dictionaries/docommand.dict
new file mode 100644
index 00000000..2d88ebc0
--- /dev/null
+++ b/dictionaries/docommand.dict
@@ -0,0 +1,688 @@
+#SELECT WORD FROM INFORMATION_SCHEMA.KEYWORDS;
+ACCESSIBLE="ACCESSIBLE"
+ACCOUNT="ACCOUNT"
+ACTION="ACTION"
+ACTIVE="ACTIVE"
+ADD="ADD"
+ADMIN="ADMIN"
+AFTER="AFTER"
+AGAINST="AGAINST"
+AGGREGATE="AGGREGATE"
+ALGORITHM="ALGORITHM"
+ALL="ALL"
+ALTER="ALTER"
+ALWAYS="ALWAYS"
+ANALYZE="ANALYZE"
+AND="AND"
+ANY="ANY"
+AS="AS"
+ASC="ASC"
+ASCII="ASCII"
+ASENSITIVE="ASENSITIVE"
+AT="AT"
+AUTOEXTEND_SIZE="AUTOEXTEND_SIZE"
+AUTO_INCREMENT="AUTO_INCREMENT"
+AVG="AVG"
+AVG_ROW_LENGTH="AVG_ROW_LENGTH"
+BACKUP="BACKUP"
+BEFORE="BEFORE"
+BEGIN="BEGIN"
+BETWEEN="BETWEEN"
+BIGINT="BIGINT"
+BINARY="BINARY"
+BINLOG="BINLOG"
+BIT="BIT"
+BLOB="BLOB"
+BLOCK="BLOCK"
+BOOL="BOOL"
+BOOLEAN="BOOLEAN"
+BOTH="BOTH"
+BTREE="BTREE"
+BUCKETS="BUCKETS"
+BY="BY"
+BYTE="BYTE"
+CACHE="CACHE"
+CALL="CALL"
+CASCADE="CASCADE"
+CASCADED="CASCADED"
+CASE="CASE"
+CATALOG_NAME="CATALOG_NAME"
+CHAIN="CHAIN"
+CHANGE="CHANGE"
+CHANGED="CHANGED"
+CHANNEL="CHANNEL"
+CHAR="CHAR"
+CHARACTER="CHARACTER"
+CHARSET="CHARSET"
+CHECK="CHECK"
+CHECKSUM="CHECKSUM"
+CIPHER="CIPHER"
+CLASS_ORIGIN="CLASS_ORIGIN"
+CLIENT="CLIENT"
+CLONE="CLONE"
+CLOSE="CLOSE"
+COALESCE="COALESCE"
+CODE="CODE"
+COLLATE="COLLATE"
+COLLATION="COLLATION"
+COLUMN="COLUMN"
+COLUMNS="COLUMNS"
+COLUMN_FORMAT="COLUMN_FORMAT"
+COLUMN_NAME="COLUMN_NAME"
+COMMENT="COMMENT"
+COMMIT="COMMIT"
+COMMITTED="COMMITTED"
+COMPACT="COMPACT"
+COMPLETION="COMPLETION"
+COMPONENT="COMPONENT"
+COMPRESSED="COMPRESSED"
+COMPRESSION="COMPRESSION"
+CONCURRENT="CONCURRENT"
+CONDITION="CONDITION"
+CONNECTION="CONNECTION"
+CONSISTENT="CONSISTENT"
+CONSTRAINT="CONSTRAINT"
+CONSTRAINT_CATALOG="CONSTRAINT_CATALOG"
+CONSTRAINT_NAME="CONSTRAINT_NAME"
+CONSTRAINT_SCHEMA="CONSTRAINT_SCHEMA"
+CONTAINS="CONTAINS"
+CONTEXT="CONTEXT"
+CONTINUE="CONTINUE"
+CONVERT="CONVERT"
+CPU="CPU"
+CREATE="CREATE"
+CROSS="CROSS"
+CUBE="CUBE"
+CUME_DIST="CUME_DIST"
+CURRENT="CURRENT"
+CURRENT_DATE="CURRENT_DATE"
+CURRENT_TIME="CURRENT_TIME"
+CURRENT_TIMESTAMP="CURRENT_TIMESTAMP"
+CURRENT_USER="CURRENT_USER"
+CURSOR="CURSOR"
+CURSOR_NAME="CURSOR_NAME"
+DATA="DATA"
+DATABASE="DATABASE"
+DATABASES="DATABASES"
+DATAFILE="DATAFILE"
+DATE="DATE"
+DATETIME="DATETIME"
+DAY="DAY"
+DAY_HOUR="DAY_HOUR"
+DAY_MICROSECOND="DAY_MICROSECOND"
+DAY_MINUTE="DAY_MINUTE"
+DAY_SECOND="DAY_SECOND"
+DEALLOCATE="DEALLOCATE"
+DEC="DEC"
+DECIMAL="DECIMAL"
+DECLARE="DECLARE"
+DEFAULT="DEFAULT"
+DEFAULT_AUTH="DEFAULT_AUTH"
+DEFINER="DEFINER"
+DEFINITION="DEFINITION"
+DELAYED="DELAYED"
+DELAY_KEY_WRITE="DELAY_KEY_WRITE"
+DELETE="DELETE"
+DENSE_RANK="DENSE_RANK"
+DESC="DESC"
+DESCRIBE="DESCRIBE"
+DESCRIPTION="DESCRIPTION"
+DETERMINISTIC="DETERMINISTIC"
+DIAGNOSTICS="DIAGNOSTICS"
+DIRECTORY="DIRECTORY"
+DISABLE="DISABLE"
+DISCARD="DISCARD"
+DISK="DISK"
+DISTINCT="DISTINCT"
+DISTINCTROW="DISTINCTROW"
+DIV="DIV"
+DO="DO"
+DOUBLE="DOUBLE"
+DROP="DROP"
+DUAL="DUAL"
+DUMPFILE="DUMPFILE"
+DUPLICATE="DUPLICATE"
+DYNAMIC="DYNAMIC"
+EACH="EACH"
+ELSE="ELSE"
+ELSEIF="ELSEIF"
+EMPTY="EMPTY"
+ENABLE="ENABLE"
+ENCLOSED="ENCLOSED"
+ENCRYPTION="ENCRYPTION"
+END="END"
+ENDS="ENDS"
+ENFORCED="ENFORCED"
+ENGINE="ENGINE"
+ENGINES="ENGINES"
+ENUM="ENUM"
+ERROR="ERROR"
+ERRORS="ERRORS"
+ESCAPE="ESCAPE"
+ESCAPED="ESCAPED"
+EVENT="EVENT"
+EVENTS="EVENTS"
+EVERY="EVERY"
+EXCEPT="EXCEPT"
+EXCHANGE="EXCHANGE"
+EXCLUDE="EXCLUDE"
+EXECUTE="EXECUTE"
+EXISTS="EXISTS"
+EXIT="EXIT"
+EXPANSION="EXPANSION"
+EXPIRE="EXPIRE"
+EXPLAIN="EXPLAIN"
+EXPORT="EXPORT"
+EXTENDED="EXTENDED"
+EXTENT_SIZE="EXTENT_SIZE"
+FALSE="FALSE"
+FAST="FAST"
+FAULTS="FAULTS"
+FETCH="FETCH"
+FIELDS="FIELDS"
+FILE="FILE"
+FILE_BLOCK_SIZE="FILE_BLOCK_SIZE"
+FILTER="FILTER"
+FIRST="FIRST"
+FIRST_VALUE="FIRST_VALUE"
+FIXED="FIXED"
+FLOAT="FLOAT"
+FLOAT4="FLOAT4"
+FLOAT8="FLOAT8"
+FLUSH="FLUSH"
+FOLLOWING="FOLLOWING"
+FOLLOWS="FOLLOWS"
+FOR="FOR"
+FORCE="FORCE"
+FOREIGN="FOREIGN"
+FORMAT="FORMAT"
+FOUND="FOUND"
+FROM="FROM"
+FULL="FULL"
+FULLTEXT="FULLTEXT"
+FUNCTION="FUNCTION"
+GENERAL="GENERAL"
+GENERATED="GENERATED"
+GEOMCOLLECTION="GEOMCOLLECTION"
+GEOMETRY="GEOMETRY"
+GEOMETRYCOLLECTION="GEOMETRYCOLLECTION"
+GET="GET"
+GET_FORMAT="GET_FORMAT"
+GET_MASTER_PUBLIC_KEY="GET_MASTER_PUBLIC_KEY"
+GLOBAL="GLOBAL"
+GRANT="GRANT"
+GRANTS="GRANTS"
+GROUP="GROUP"
+GROUPING="GROUPING"
+GROUPS="GROUPS"
+GROUP_REPLICATION="GROUP_REPLICATION"
+HANDLER="HANDLER"
+HASH="HASH"
+HAVING="HAVING"
+HELP="HELP"
+HIGH_PRIORITY="HIGH_PRIORITY"
+HISTOGRAM="HISTOGRAM"
+HISTORY="HISTORY"
+HOST="HOST"
+HOSTS="HOSTS"
+HOUR="HOUR"
+HOUR_MICROSECOND="HOUR_MICROSECOND"
+HOUR_MINUTE="HOUR_MINUTE"
+HOUR_SECOND="HOUR_SECOND"
+IDENTIFIED="IDENTIFIED"
+IF="IF"
+IGNORE="IGNORE"
+IGNORE_SERVER_IDS="IGNORE_SERVER_IDS"
+IMPORT="IMPORT"
+IN="IN"
+INACTIVE="INACTIVE"
+INDEX="INDEX"
+INDEXES="INDEXES"
+INFILE="INFILE"
+INITIAL_SIZE="INITIAL_SIZE"
+INNER="INNER"
+INOUT="INOUT"
+INSENSITIVE="INSENSITIVE"
+INSERT="INSERT"
+INSERT_METHOD="INSERT_METHOD"
+INSTALL="INSTALL"
+INSTANCE="INSTANCE"
+INT="INT"
+INT1="INT1"
+INT2="INT2"
+INT3="INT3"
+INT4="INT4"
+INT8="INT8"
+INTEGER="INTEGER"
+INTERVAL="INTERVAL"
+INTO="INTO"
+INVISIBLE="INVISIBLE"
+INVOKER="INVOKER"
+IO="IO"
+IO_AFTER_GTIDS="IO_AFTER_GTIDS"
+IO_BEFORE_GTIDS="IO_BEFORE_GTIDS"
+IO_THREAD="IO_THREAD"
+IPC="IPC"
+IS="IS"
+ISOLATION="ISOLATION"
+ISSUER="ISSUER"
+ITERATE="ITERATE"
+JOIN="JOIN"
+JSON="JSON"
+JSON_TABLE="JSON_TABLE"
+KEY="KEY"
+KEYS="KEYS"
+KEY_BLOCK_SIZE="KEY_BLOCK_SIZE"
+KILL="KILL"
+LAG="LAG"
+LANGUAGE="LANGUAGE"
+LAST="LAST"
+LAST_VALUE="LAST_VALUE"
+LATERAL="LATERAL"
+LEAD="LEAD"
+LEADING="LEADING"
+LEAVE="LEAVE"
+LEAVES="LEAVES"
+LEFT="LEFT"
+LESS="LESS"
+LEVEL="LEVEL"
+LIKE="LIKE"
+LIMIT="LIMIT"
+LINEAR="LINEAR"
+LINES="LINES"
+LINESTRING="LINESTRING"
+LIST="LIST"
+LOAD="LOAD"
+LOCAL="LOCAL"
+LOCALTIME="LOCALTIME"
+LOCALTIMESTAMP="LOCALTIMESTAMP"
+LOCK="LOCK"
+LOCKED="LOCKED"
+LOCKS="LOCKS"
+LOGFILE="LOGFILE"
+LOGS="LOGS"
+LONG="LONG"
+LONGBLOB="LONGBLOB"
+LONGTEXT="LONGTEXT"
+LOOP="LOOP"
+LOW_PRIORITY="LOW_PRIORITY"
+MASTER="MASTER"
+MASTER_AUTO_POSITION="MASTER_AUTO_POSITION"
+MASTER_BIND="MASTER_BIND"
+MASTER_CONNECT_RETRY="MASTER_CONNECT_RETRY"
+MASTER_DELAY="MASTER_DELAY"
+MASTER_HEARTBEAT_PERIOD="MASTER_HEARTBEAT_PERIOD"
+MASTER_HOST="MASTER_HOST"
+MASTER_LOG_FILE="MASTER_LOG_FILE"
+MASTER_LOG_POS="MASTER_LOG_POS"
+MASTER_PASSWORD="MASTER_PASSWORD"
+MASTER_PORT="MASTER_PORT"
+MASTER_PUBLIC_KEY_PATH="MASTER_PUBLIC_KEY_PATH"
+MASTER_RETRY_COUNT="MASTER_RETRY_COUNT"
+MASTER_SERVER_ID="MASTER_SERVER_ID"
+MASTER_SSL="MASTER_SSL"
+MASTER_SSL_CA="MASTER_SSL_CA"
+MASTER_SSL_CAPATH="MASTER_SSL_CAPATH"
+MASTER_SSL_CERT="MASTER_SSL_CERT"
+MASTER_SSL_CIPHER="MASTER_SSL_CIPHER"
+MASTER_SSL_CRL="MASTER_SSL_CRL"
+MASTER_SSL_CRLPATH="MASTER_SSL_CRLPATH"
+MASTER_SSL_KEY="MASTER_SSL_KEY"
+MASTER_SSL_VERIFY_SERVER_CERT="MASTER_SSL_VERIFY_SERVER_CERT"
+MASTER_TLS_VERSION="MASTER_TLS_VERSION"
+MASTER_USER="MASTER_USER"
+MATCH="MATCH"
+MAXVALUE="MAXVALUE"
+MAX_CONNECTIONS_PER_HOUR="MAX_CONNECTIONS_PER_HOUR"
+MAX_QUERIES_PER_HOUR="MAX_QUERIES_PER_HOUR"
+MAX_ROWS="MAX_ROWS"
+MAX_SIZE="MAX_SIZE"
+MAX_UPDATES_PER_HOUR="MAX_UPDATES_PER_HOUR"
+MAX_USER_CONNECTIONS="MAX_USER_CONNECTIONS"
+MEDIUM="MEDIUM"
+MEDIUMBLOB="MEDIUMBLOB"
+MEDIUMINT="MEDIUMINT"
+MEDIUMTEXT="MEDIUMTEXT"
+MEMORY="MEMORY"
+MERGE="MERGE"
+MESSAGE_TEXT="MESSAGE_TEXT"
+MICROSECOND="MICROSECOND"
+MIDDLEINT="MIDDLEINT"
+MIGRATE="MIGRATE"
+MINUTE="MINUTE"
+MINUTE_MICROSECOND="MINUTE_MICROSECOND"
+MINUTE_SECOND="MINUTE_SECOND"
+MIN_ROWS="MIN_ROWS"
+MOD="MOD"
+MODE="MODE"
+MODIFIES="MODIFIES"
+MODIFY="MODIFY"
+MONTH="MONTH"
+MULTILINESTRING="MULTILINESTRING"
+MULTIPOINT="MULTIPOINT"
+MULTIPOLYGON="MULTIPOLYGON"
+MUTEX="MUTEX"
+MYSQL_ERRNO="MYSQL_ERRNO"
+NAME="NAME"
+NAMES="NAMES"
+NATIONAL="NATIONAL"
+NATURAL="NATURAL"
+NCHAR="NCHAR"
+NDB="NDB"
+NDBCLUSTER="NDBCLUSTER"
+NESTED="NESTED"
+NETWORK_NAMESPACE="NETWORK_NAMESPACE"
+NEVER="NEVER"
+NEW="NEW"
+NEXT="NEXT"
+NO="NO"
+NODEGROUP="NODEGROUP"
+NONE="NONE"
+NOT="NOT"
+NOWAIT="NOWAIT"
+NO_WAIT="NO_WAIT"
+NO_WRITE_TO_BINLOG="NO_WRITE_TO_BINLOG"
+NTH_VALUE="NTH_VALUE"
+NTILE="NTILE"
+NULL="NULL"
+NULLS="NULLS"
+NUMBER="NUMBER"
+NUMERIC="NUMERIC"
+NVARCHAR="NVARCHAR"
+OF="OF"
+OFFSET="OFFSET"
+OJ="OJ"
+OLD="OLD"
+ON="ON"
+ONE="ONE"
+ONLY="ONLY"
+OPEN="OPEN"
+OPTIMIZE="OPTIMIZE"
+OPTIMIZER_COSTS="OPTIMIZER_COSTS"
+OPTION="OPTION"
+OPTIONAL="OPTIONAL"
+OPTIONALLY="OPTIONALLY"
+OPTIONS="OPTIONS"
+OR="OR"
+ORDER="ORDER"
+ORDINALITY="ORDINALITY"
+ORGANIZATION="ORGANIZATION"
+OTHERS="OTHERS"
+OUT="OUT"
+OUTER="OUTER"
+OUTFILE="OUTFILE"
+OVER="OVER"
+OWNER="OWNER"
+PACK_KEYS="PACK_KEYS"
+PAGE="PAGE"
+PARSER="PARSER"
+PARTIAL="PARTIAL"
+PARTITION="PARTITION"
+PARTITIONING="PARTITIONING"
+PARTITIONS="PARTITIONS"
+PASSWORD="PASSWORD"
+PATH="PATH"
+PERCENT_RANK="PERCENT_RANK"
+PERSIST="PERSIST"
+PERSIST_ONLY="PERSIST_ONLY"
+PHASE="PHASE"
+PLUGIN="PLUGIN"
+PLUGINS="PLUGINS"
+PLUGIN_DIR="PLUGIN_DIR"
+POINT="POINT"
+POLYGON="POLYGON"
+PORT="PORT"
+PRECEDES="PRECEDES"
+PRECEDING="PRECEDING"
+PRECISION="PRECISION"
+PREPARE="PREPARE"
+PRESERVE="PRESERVE"
+PREV="PREV"
+PRIMARY="PRIMARY"
+PRIVILEGES="PRIVILEGES"
+PROCEDURE="PROCEDURE"
+PROCESS="PROCESS"
+PROCESSLIST="PROCESSLIST"
+PROFILE="PROFILE"
+PROFILES="PROFILES"
+PROXY="PROXY"
+PURGE="PURGE"
+QUARTER="QUARTER"
+QUERY="QUERY"
+QUICK="QUICK"
+RANGE="RANGE"
+RANK="RANK"
+READ="READ"
+READS="READS"
+READ_ONLY="READ_ONLY"
+READ_WRITE="READ_WRITE"
+REAL="REAL"
+REBUILD="REBUILD"
+RECOVER="RECOVER"
+RECURSIVE="RECURSIVE"
+REDO_BUFFER_SIZE="REDO_BUFFER_SIZE"
+REDUNDANT="REDUNDANT"
+REFERENCE="REFERENCE"
+REFERENCES="REFERENCES"
+REGEXP="REGEXP"
+RELAY="RELAY"
+RELAYLOG="RELAYLOG"
+RELAY_LOG_FILE="RELAY_LOG_FILE"
+RELAY_LOG_POS="RELAY_LOG_POS"
+RELAY_THREAD="RELAY_THREAD"
+RELEASE="RELEASE"
+RELOAD="RELOAD"
+REMOVE="REMOVE"
+RENAME="RENAME"
+REORGANIZE="REORGANIZE"
+REPAIR="REPAIR"
+REPEAT="REPEAT"
+REPEATABLE="REPEATABLE"
+REPLACE="REPLACE"
+REPLICATE_DO_DB="REPLICATE_DO_DB"
+REPLICATE_DO_TABLE="REPLICATE_DO_TABLE"
+REPLICATE_IGNORE_DB="REPLICATE_IGNORE_DB"
+REPLICATE_IGNORE_TABLE="REPLICATE_IGNORE_TABLE"
+REPLICATE_REWRITE_DB="REPLICATE_REWRITE_DB"
+REPLICATE_WILD_DO_TABLE="REPLICATE_WILD_DO_TABLE"
+REPLICATE_WILD_IGNORE_TABLE="REPLICATE_WILD_IGNORE_TABLE"
+REPLICATION="REPLICATION"
+REQUIRE="REQUIRE"
+RESET="RESET"
+RESIGNAL="RESIGNAL"
+RESOURCE="RESOURCE"
+RESPECT="RESPECT"
+RESTART="RESTART"
+RESTORE="RESTORE"
+RESTRICT="RESTRICT"
+RESUME="RESUME"
+RETAIN="RETAIN"
+RETURN="RETURN"
+RETURNED_SQLSTATE="RETURNED_SQLSTATE"
+RETURNS="RETURNS"
+REUSE="REUSE"
+REVERSE="REVERSE"
+REVOKE="REVOKE"
+RIGHT="RIGHT"
+RLIKE="RLIKE"
+ROLE="ROLE"
+ROLLBACK="ROLLBACK"
+ROLLUP="ROLLUP"
+ROTATE="ROTATE"
+ROUTINE="ROUTINE"
+ROW="ROW"
+ROWS="ROWS"
+ROW_COUNT="ROW_COUNT"
+ROW_FORMAT="ROW_FORMAT"
+ROW_NUMBER="ROW_NUMBER"
+RTREE="RTREE"
+SAVEPOINT="SAVEPOINT"
+SCHEDULE="SCHEDULE"
+SCHEMA="SCHEMA"
+SCHEMAS="SCHEMAS"
+SCHEMA_NAME="SCHEMA_NAME"
+SECOND="SECOND"
+SECONDARY="SECONDARY"
+SECONDARY_ENGINE="SECONDARY_ENGINE"
+SECONDARY_LOAD="SECONDARY_LOAD"
+SECONDARY_UNLOAD="SECONDARY_UNLOAD"
+SECOND_MICROSECOND="SECOND_MICROSECOND"
+SECURITY="SECURITY"
+SELECT="SELECT"
+SENSITIVE="SENSITIVE"
+SEPARATOR="SEPARATOR"
+SERIAL="SERIAL"
+SERIALIZABLE="SERIALIZABLE"
+SERVER="SERVER"
+SESSION="SESSION"
+SET="SET"
+SHARE="SHARE"
+SHOW="SHOW"
+SHUTDOWN="SHUTDOWN"
+SIGNAL="SIGNAL"
+SIGNED="SIGNED"
+SIMPLE="SIMPLE"
+SKIP="SKIP"
+SLAVE="SLAVE"
+SLOW="SLOW"
+SMALLINT="SMALLINT"
+SNAPSHOT="SNAPSHOT"
+SOCKET="SOCKET"
+SOME="SOME"
+SONAME="SONAME"
+SOUNDS="SOUNDS"
+SOURCE="SOURCE"
+SPATIAL="SPATIAL"
+SPECIFIC="SPECIFIC"
+SQL="SQL"
+SQLEXCEPTION="SQLEXCEPTION"
+SQLSTATE="SQLSTATE"
+SQLWARNING="SQLWARNING"
+SQL_AFTER_GTIDS="SQL_AFTER_GTIDS"
+SQL_AFTER_MTS_GAPS="SQL_AFTER_MTS_GAPS"
+SQL_BEFORE_GTIDS="SQL_BEFORE_GTIDS"
+SQL_BIG_RESULT="SQL_BIG_RESULT"
+SQL_BUFFER_RESULT="SQL_BUFFER_RESULT"
+SQL_CALC_FOUND_ROWS="SQL_CALC_FOUND_ROWS"
+SQL_NO_CACHE="SQL_NO_CACHE"
+SQL_SMALL_RESULT="SQL_SMALL_RESULT"
+SQL_THREAD="SQL_THREAD"
+SQL_TSI_DAY="SQL_TSI_DAY"
+SQL_TSI_HOUR="SQL_TSI_HOUR"
+SQL_TSI_MINUTE="SQL_TSI_MINUTE"
+SQL_TSI_MONTH="SQL_TSI_MONTH"
+SQL_TSI_QUARTER="SQL_TSI_QUARTER"
+SQL_TSI_SECOND="SQL_TSI_SECOND"
+SQL_TSI_WEEK="SQL_TSI_WEEK"
+SQL_TSI_YEAR="SQL_TSI_YEAR"
+SRID="SRID"
+SSL="SSL"
+STACKED="STACKED"
+START="START"
+STARTING="STARTING"
+STARTS="STARTS"
+STATS_AUTO_RECALC="STATS_AUTO_RECALC"
+STATS_PERSISTENT="STATS_PERSISTENT"
+STATS_SAMPLE_PAGES="STATS_SAMPLE_PAGES"
+STATUS="STATUS"
+STOP="STOP"
+STORAGE="STORAGE"
+STORED="STORED"
+STRAIGHT_JOIN="STRAIGHT_JOIN"
+STRING="STRING"
+SUBCLASS_ORIGIN="SUBCLASS_ORIGIN"
+SUBJECT="SUBJECT"
+SUBPARTITION="SUBPARTITION"
+SUBPARTITIONS="SUBPARTITIONS"
+SUPER="SUPER"
+SUSPEND="SUSPEND"
+SWAPS="SWAPS"
+SWITCHES="SWITCHES"
+SYSTEM="SYSTEM"
+TABLE="TABLE"
+TABLES="TABLES"
+TABLESPACE="TABLESPACE"
+TABLE_CHECKSUM="TABLE_CHECKSUM"
+TABLE_NAME="TABLE_NAME"
+TEMPORARY="TEMPORARY"
+TEMPTABLE="TEMPTABLE"
+TERMINATED="TERMINATED"
+TEXT="TEXT"
+THAN="THAN"
+THEN="THEN"
+THREAD_PRIORITY="THREAD_PRIORITY"
+TIES="TIES"
+TIME="TIME"
+TIMESTAMP="TIMESTAMP"
+TIMESTAMPADD="TIMESTAMPADD"
+TIMESTAMPDIFF="TIMESTAMPDIFF"
+TINYBLOB="TINYBLOB"
+TINYINT="TINYINT"
+TINYTEXT="TINYTEXT"
+TO="TO"
+TRAILING="TRAILING"
+TRANSACTION="TRANSACTION"
+TRIGGER="TRIGGER"
+TRIGGERS="TRIGGERS"
+TRUE="TRUE"
+TRUNCATE="TRUNCATE"
+TYPE="TYPE"
+TYPES="TYPES"
+UNBOUNDED="UNBOUNDED"
+UNCOMMITTED="UNCOMMITTED"
+UNDEFINED="UNDEFINED"
+UNDO="UNDO"
+UNDOFILE="UNDOFILE"
+UNDO_BUFFER_SIZE="UNDO_BUFFER_SIZE"
+UNICODE="UNICODE"
+UNINSTALL="UNINSTALL"
+UNION="UNION"
+UNIQUE="UNIQUE"
+UNKNOWN="UNKNOWN"
+UNLOCK="UNLOCK"
+UNSIGNED="UNSIGNED"
+UNTIL="UNTIL"
+UPDATE="UPDATE"
+UPGRADE="UPGRADE"
+USAGE="USAGE"
+USE="USE"
+USER="USER"
+USER_RESOURCES="USER_RESOURCES"
+USE_FRM="USE_FRM"
+USING="USING"
+UTC_DATE="UTC_DATE"
+UTC_TIME="UTC_TIME"
+UTC_TIMESTAMP="UTC_TIMESTAMP"
+VALIDATION="VALIDATION"
+VALUE="VALUE"
+VALUES="VALUES"
+VARBINARY="VARBINARY"
+VARCHAR="VARCHAR"
+VARCHARACTER="VARCHARACTER"
+VARIABLES="VARIABLES"
+VARYING="VARYING"
+VCPU="VCPU"
+VIEW="VIEW"
+VIRTUAL="VIRTUAL"
+VISIBLE="VISIBLE"
+WAIT="WAIT"
+WARNINGS="WARNINGS"
+WEEK="WEEK"
+WEIGHT_STRING="WEIGHT_STRING"
+WHEN="WHEN"
+WHERE="WHERE"
+WHILE="WHILE"
+WINDOW="WINDOW"
+WITH="WITH"
+WITHOUT="WITHOUT"
+WORK="WORK"
+WRAPPER="WRAPPER"
+WRITE="WRITE"
+X509="X509"
+XA="XA"
+XID="XID"
+XML="XML"
+XOR="XOR"
+YEAR="YEAR"
+YEAR_MONTH="YEAR_MONTH"
+ZEROFILL="ZEROFILL"
diff --git a/dictionaries/exif.dict b/dictionaries/exif.dict
new file mode 100644
index 00000000..08c71bbc
--- /dev/null
+++ b/dictionaries/exif.dict
@@ -0,0 +1,222 @@
+"\x00\x01"
+"\x00\x02"
+"\x00\x10"
+"\x00\x90"
+"\x00\xa0"
+"\x00\xa3"
+"\x00\xa5"
+"\x00\xfe"
+"\x01\x00"
+"\x01\x01"
+"\x01\x02"
+"\x01\x03"
+"\x01\x06"
+"\x01\x0a"
+"\x01\x0d"
+"\x01\x0e"
+"\x01\x0f"
+"\x01\x10"
+"\x01\x11"
+"\x01\x12"
+"\x01\x15"
+"\x01\x16"
+"\x01\x17"
+"\x01\x1a"
+"\x01\x1b"
+"\x01\x1c"
+"\x01\x28"
+"\x01\x2d"
+"\x01\x31"
+"\x01\x32"
+"\x01\x3b"
+"\x01\x3e"
+"\x01\x3f"
+"\x01\x4a"
+"\x01\x56"
+"\x01\x91"
+"\x01\x92"
+"\x01\xa0"
+"\x01\xa3"
+"\x01\xa4"
+"\x02\x00"
+"\x02\x01"
+"\x02\x02"
+"\x02\x10"
+"\x02\x11"
+"\x02\x12"
+"\x02\x13"
+"\x02\x14"
+"\x02\x91"
+"\x02\x92"
+"\x02\xa0"
+"\x02\xa3"
+"\x02\xa4"
+"\x02\xbc"
+"\x03\x01"
+"\x03\x90"
+"\x03\x92"
+"\x03\xa0"
+"\x03\xa4"
+"\x04\x90"
+"\x04\x92"
+"\x04\xa0"
+"\x04\xa4"
+"\x05\x92"
+"\x05\xa0"
+"\x05\xa4"
+"\x06\x01"
+"\x06\x92"
+"\x06\xa4"
+"\x07\x92"
+"\x07\xa4"
+"\x08\x92"
+"\x08\xa4"
+"\x09\x92"
+"\x09\xa4"
+"\x0a\x01"
+"\x0a\x92"
+"\x0a\xa4"
+"\x0b\xa2"
+"\x0b\xa4"
+"\x0c\xa2"
+"\x0c\xa4"
+"\x0d\x01"
+"\x0e\x01"
+"\x0e\xa2"
+"\x0f\x01"
+"\x0f\xa2"
+"\x10\x00"
+"\x10\x01"
+"\x10\x02"
+"\x10\xa2"
+"\x11\x01"
+"\x11\x02"
+"\x12\x01"
+"\x12\x02"
+"\x13\x02"
+"\x14\x02"
+"\x14\x92"
+"\x14\xa2"
+"\x15\x01"
+"\x15\xa2"
+"\x16\x01"
+"\x16\x92"
+"\x17\x01"
+"\x17\xa2"
+"\x1a\x01"
+"\x1b\x01"
+"\x1c\x01"
+"\x1c\xea"
+"\x20\xa4"
+"\x22\x88"
+"\x24\x88"
+"\x25\x88"
+"\x27\x88"
+"\x28\x01"
+"\x28\x88"
+"\x2a\x88"
+"\x2d\x01"
+"\x31\x01"
+"\x32\x01"
+"\x3b\x01"
+"\x3e\x01"
+"\x3f\x01"
+"\x49\x86"
+"\x4a\x01"
+"\x56\x01"
+"\x69\x87"
+"\x73\x87"
+"\x7c\x92"
+"\x82\x8d"
+"\x82\x8e"
+"\x82\x8f"
+"\x82\x98"
+"\x82\x9a"
+"\x82\x9d"
+"\x83\xbb"
+"\x86\x49"
+"\x86\x92"
+"\x87\x69"
+"\x87\x73"
+"\x88\x22"
+"\x88\x24"
+"\x88\x25"
+"\x88\x27"
+"\x88\x28"
+"\x88\x2a"
+"\x8d\x82"
+"\x8e\x82"
+"\x8f\x82"
+"\x90\x00"
+"\x90\x03"
+"\x90\x04"
+"\x90\x92"
+"\x91\x01"
+"\x91\x02"
+"\x91\x92"
+"\x92\x01"
+"\x92\x02"
+"\x92\x03"
+"\x92\x04"
+"\x92\x05"
+"\x92\x06"
+"\x92\x07"
+"\x92\x08"
+"\x92\x09"
+"\x92\x0a"
+"\x92\x14"
+"\x92\x16"
+"\x92\x7c"
+"\x92\x86"
+"\x92\x90"
+"\x92\x91"
+"\x92\x92"
+"\x98\x82"
+"\x9a\x82"
+"\x9b\x9c"
+"\x9c\x9b"
+"\x9c\x9c"
+"\x9c\x9d"
+"\x9c\x9e"
+"\x9c\x9f"
+"\x9d\x82"
+"\x9d\x9c"
+"\x9e\x9c"
+"\x9f\x9c"
+"\xa0\x00"
+"\xa0\x01"
+"\xa0\x02"
+"\xa0\x03"
+"\xa0\x04"
+"\xa0\x05"
+"\xa2\x0b"
+"\xa2\x0c"
+"\xa2\x0e"
+"\xa2\x0f"
+"\xa2\x10"
+"\xa2\x14"
+"\xa2\x15"
+"\xa2\x17"
+"\xa3\x00"
+"\xa3\x01"
+"\xa3\x02"
+"\xa4\x01"
+"\xa4\x02"
+"\xa4\x03"
+"\xa4\x04"
+"\xa4\x05"
+"\xa4\x06"
+"\xa4\x07"
+"\xa4\x08"
+"\xa4\x09"
+"\xa4\x0a"
+"\xa4\x0b"
+"\xa4\x0c"
+"\xa4\x20"
+"\xa5\x00"
+"\xa5\xc4"
+"\xbb\x83"
+"\xbc\x02"
+"\xc4\xa5"
+"\xea\x1c"
+"\xfe\x00"
diff --git a/dictionaries/fbs.dict b/dictionaries/fbs.dict
new file mode 100644
index 00000000..7ce6690e
--- /dev/null
+++ b/dictionaries/fbs.dict
@@ -0,0 +1,42 @@
+# spec: https://google.github.io/flatbuffers/flatbuffers_grammar.html
+
+attribute="attribute"
+bool="bool"
+byte="byte"
+double="double"
+enum="enum"
+false="false"
+file_extension="file_extension"
+float32="float32"
+float64="float64"
+float="float"
+include="include"
+inf="inf"
+infinity="infinity"
+int16="int16"
+int32="int32"
+int64="int64"
+int8="int8"
+int="int"
+long="long"
+namespace="namespace"
+nan="nan"
+root_type="root_type"
+root_type="root_type"
+rpc_service="rpc_service"
+short="short"
+string="string"
+struct="struct"
+table="table"
+true="true"
+ubyte="ubyte"
+uint16="uint16"
+uint32="uint32"
+uint64="uint64"
+uint="uint"
+ulong="ulong"
+union="union"
+ushort="ushort"
+
+separator=":"
+eol=";"
diff --git a/dictionaries/ftp.dict b/dictionaries/ftp.dict
new file mode 100644
index 00000000..2f253ac8
--- /dev/null
+++ b/dictionaries/ftp.dict
@@ -0,0 +1,124 @@
+# from https://github.com/antonio-morales/Fuzzing/Dictionaries/FTP/Example.dict.txt
+#Parameters
+#tls = {0,1,2,3}
+
+#Input1
+"user"
+"pass"
+"syst"
+"acct"
+"feat"
+"noop"
+"help"
+"stat"
+"stru"
+"adat"
+"site"
+
+#Input2
+"mkd"
+"cwd"
+"pwd"
+"cdup"
+
+#Input3
+"port"
+"list"
+"mlst"
+"nlst"
+"mlsd"
+
+#Input4
+"rmd"
+
+#Input5
+"stor"
+
+#Input6
+"retr"
+
+#Input7
+"dele"
+
+#Input8
+"pasv"
+
+#Input9
+"epsv"
+
+#Input10
+"type"
+"size"
+
+#Input11
+"mode"
+
+#Input12
+"rnfr"
+"rnto"
+
+#Input13
+"appe"
+
+#Input14
+"allo"
+"quit"
+
+#Input15
+"connect"
+
+#Input16
+"esta"
+"estp"
+
+#Input17
+"mdtm"
+"opts"
+"eprt"
+
+#Input18
+"mfmt"
+"pret"
+"stou"
+"rest"
+
+
+#-------------------------------------
+"\x00"
+"\x0d\x0a"
+"\x0d"
+"\x0a"
+"-"
+"-a "
+"-C "
+"-d "
+"-F "
+"-l "
+"-r "
+"-R "
+"-S "
+"-t"
+" "
+"fuzzing"
+"test"
+"teste"
+".txt"
+"test.txt"
+" UTC"
+"C"
+"E"
+"P"
+"S"
+"abor"
+
+#ifdef WITH_TLS
+"pbsz"
+"auth"
+"prot"
+"ccc"
+
+#ifdef DEBUG
+"xdbg"
+
+# ifdef WITH_DIRALIASES
+"alias"
diff --git a/dictionaries/gif.dict b/dictionaries/gif.dict
new file mode 100644
index 00000000..441b3b8d
--- /dev/null
+++ b/dictionaries/gif.dict
@@ -0,0 +1,18 @@
+#
+# AFL dictionary for GIF images
+# -----------------------------
+#
+# Created by Michal Zalewski
+#
+
+header_87a="87a"
+header_89a="89a"
+header_gif="GIF"
+
+marker_2c=","
+marker_3b=";"
+
+section_2101="!\x01\x12"
+section_21f9="!\xf9\x04"
+section_21fe="!\xfe"
+section_21ff="!\xff\x11"
diff --git a/dictionaries/graphviz.dict b/dictionaries/graphviz.dict
new file mode 100644
index 00000000..0b034b36
--- /dev/null
+++ b/dictionaries/graphviz.dict
@@ -0,0 +1,373 @@
+# Semi-manually curated list of interesting words within a graphviz input file.
+# TODO(robhart): Consider expanding from:
+# - htmllex.c
+# - ?
+# Not included exhaustive list of colortables, fontnames, etc. that are unlikely
+# to influence core graphviz behaviour.
+
+# Attributes (from http://www.graphviz.org/doc/info/attrs.html)
+"Damping"
+"K"
+"URL"
+"_background"
+"area"
+"arrowhead"
+"arrowsize"
+"arrowtail"
+"bb"
+"bgcolor"
+"colorList"
+"center"
+"charset"
+"clusterrank"
+"color"
+"colorList"
+"colorscheme"
+"comment"
+"compound"
+"concentrate"
+"constraint"
+"decorate"
+"defaultdist"
+"dim"
+"dimen"
+"dir"
+"diredgeconstraints"
+"distortion"
+"dpi"
+"edgeURL"
+"edgehref"
+"edgetarget"
+"edgetooltip"
+"epsilon"
+"esep"
+"fillcolor"
+"fixedsize"
+"fontcolor"
+"fontname"
+"fontnames"
+"fontpath"
+"fontsize"
+"forcelabels"
+"gradientangle"
+"group"
+"headURL"
+"head_lp"
+"headclip"
+"headhref"
+"headlabel"
+"headport"
+"headtarget"
+"headtooltip"
+"height"
+"href"
+"id"
+"image"
+"imagepath"
+"imagescale"
+"inputscale"
+"label"
+"labelURL"
+"label_scheme"
+"labelangle"
+"labeldistance"
+"labelfloat"
+"labelfontcolor"
+"labelfontname"
+"labelfontsize"
+"labelhref"
+"labeljust"
+"labelloc"
+"labeltarget"
+"labeltooltip"
+"landscape"
+"layer"
+"layerlistsep"
+"layers"
+"layerselect"
+"layersep"
+"layout"
+"len"
+"levels"
+"levelsgap"
+"lhead"
+"lheight"
+"lp"
+"ltail"
+"lwidth"
+"margin"
+"maxiter"
+"mclimit"
+"mindist"
+"minlen"
+"mode"
+"model"
+"mosek"
+"newrank"
+"nodesep"
+"nojustify"
+"normalize"
+"notranslate"
+"nslimit "
+"nslimit1"
+"ordering"
+"orientation"
+"OrientationGraph"
+"outputorder"
+"overlap"
+"overlap_scaling"
+"overlap_shrink"
+"pack"
+"packmode"
+"pad"
+"point"
+"page"
+"point"
+"pagedir"
+"pencolor"
+"penwidth"
+"peripheries"
+"pin"
+"pos"
+"splineType"
+"quadtree"
+"quantum"
+"rank"
+"rankdir"
+"ranksep"
+"ratio"
+"string"
+"rects"
+"regular"
+"remincross"
+"RemoveOverlaps"
+"repulsiveforce"
+"resolution"
+"root"
+"rotate"
+"rotation"
+"samehead"
+"sametail"
+"samplepoints"
+"scale"
+"searchsize"
+"sep"
+"setlinewidth"
+"shape"
+"shapefile"
+"showboxes"
+"sides"
+"size"
+"skew"
+"smoothing"
+"sortv"
+"splines"
+"string"
+"start"
+"style"
+"stylesheet"
+"tailURL"
+"tail_lp"
+"tailclip"
+"tailhref"
+"taillabel"
+"tailport"
+"tailtarget"
+"tailtooltip"
+"target"
+"tooltip"
+"truecolor"
+"vertices"
+"viewport"
+"voro_margin"
+"weight"
+"width"
+"xdotversion"
+"xlabel"
+"xlp"
+"z"
+
+# Shapes (from shapes.c)
+"box"
+"polygon"
+"ellipse"
+"oval"
+"circle"
+"point"
+"egg"
+"triangle"
+"none"
+"plaintext"
+"plain"
+"diamond"
+"trapezium"
+"parallelogram"
+"house"
+"pentagon"
+"hexagon"
+"septagon"
+"octagon"
+"note"
+"tab"
+"folder"
+"box3d"
+"component"
+"cylinder"
+"rect"
+"rectangle"
+"square"
+"doublecircle"
+"doubleoctagon"
+"tripleoctagon"
+"invtriangle"
+"invtrapezium"
+"invhouse"
+"underline"
+"Mdiamond"
+"Msquare"
+"Mcircle"
+"DotGraphs"
+
+"promoter"
+"cds"
+"terminator"
+"utr"
+"insulator"
+"ribosite"
+"rnastab"
+"proteasesite"
+"proteinstab"
+
+"primersite"
+"restrictionsite"
+"fivepoverhang"
+"threepoverhang"
+"noverhang"
+"assembly"
+"signature"
+"rpromoter"
+"larrow"
+"rarrow"
+"lpromoter"
+
+"record"
+"Mrecord"
+"epsf"
+"star"
+
+# styles
+"bold"
+"dashed"
+"diagonals"
+"dotted"
+"filled"
+"invis"
+"radial"
+"rounded"
+"solid"
+"striped"
+"tapered"
+"wedged"
+
+
+# misc -- https://graphviz.gitlab.io/_pages/doc/info/lang.html
+"node"
+"edge"
+"digraph"
+"subgraph"
+"strict"
+"same"
+"->"
+"--"
+" {A B} "
+" a -- b "
+# Special value for the "shape" attribute
+"epsf"
+
+# html
+"=\""
+"<table"
+"<tr"
+"<td"
+"<font"
+"<br"
+"<img"
+"<i"
+"<b"
+"<u"
+"<o"
+"<sub"
+"<sup"
+"<s"
+"<hr"
+"<vr"
+
+# html attributes
+"align"
+"balign"
+"bgcolor"
+"border"
+"cellborder"
+"cellpadding"
+"cellspacing"
+"color"
+"colspan"
+"columns"
+"face"
+"fixedsize"
+"gradientangle"
+"height"
+"href"
+"id"
+"point-size"
+"port"
+"rows"
+"rowspan"
+"scale"
+"sides"
+"src"
+"style"
+"target"
+"title"
+"tooltip"
+"valign"
+"width"
+
+# arrow spaces
+"box"
+"crow"
+"curve"
+"icurve"
+"diamond"
+"dot"
+"inv"
+"none"
+"normal"
+"tee"
+"vee"
+
+
+# Examples of parameters
+"%f"
+"50,50,.5,'2.8 BSD'"
+"100,100,2,450,-1"
+"none"
+"avg_dist"
+"graph_dist"
+"power_dist"
+"rng"
+"spring"
+"triangle"
+"same"
+"min"
+"source"
+"max"
+"sink"
+"node"
+"clust"
+"graph"
+"array_flags"
+"%2x"
+"%s"
+"%99$p"
+"%n"
diff --git a/dictionaries/heif.dict b/dictionaries/heif.dict
new file mode 100644
index 00000000..ec279df7
--- /dev/null
+++ b/dictionaries/heif.dict
@@ -0,0 +1,76 @@
+# https://standards.iso.org/ittf/PubliclyAvailableStandards/c066067_ISO_IEC_23008-12_2017.zip
+
+"altr"
+"auxC"
+"auxc"
+"auxi"
+"auxv"
+"avcC"
+"avci"
+"avcs"
+"ccst"
+"cdsc"
+"clap"
+"colr"
+"dimg"
+"dinf"
+"dref"
+"elst"
+"equi"
+"free"
+"frma"
+"ftyp"
+"grid"
+"grp1"
+"hdlr"
+"heic"
+"heim"
+"heis"
+"heix"
+"hevc"
+"hevx"
+"hvc1"
+"hvc2"
+"hvcC"
+"idat"
+"iden"
+"iinf"
+"iloc"
+"imir"
+"infe"
+"iovl"
+"ipro"
+"iprp"
+"iref"
+"irot"
+"ispe"
+"jpeg"
+"jpgC"
+"jpgs"
+"lhv1"
+"lhvC"
+"lsel"
+"mdat"
+"meta"
+"mif1"
+"mime"
+"mjpg"
+"msf1"
+"oinf"
+"pasp"
+"pict"
+"pitm"
+"pixi"
+"refs"
+"rloc"
+"schi"
+"schm"
+"sgpd"
+"sinf"
+"skip"
+"stsz"
+"subs"
+"thmb"
+"tkhd"
+"tols"
+"trak"
diff --git a/dictionaries/hoextdown.dict b/dictionaries/hoextdown.dict
new file mode 100644
index 00000000..b06783c9
--- /dev/null
+++ b/dictionaries/hoextdown.dict
@@ -0,0 +1,49 @@
+asterisk="*"
+attr_generic=" a=\"1\""
+attr_href=" href=\"1\""
+attr_xml_lang=" xml:lang=\"1\""
+attr_xmlns=" xmlns=\"1\""
+backslash="\\"
+backtick="`"
+colon=":"
+dashes="---"
+double_quote="\""
+entity_builtin="&lt;"
+entity_decimal="&#1;"
+entity_external="&a;"
+entity_hex="&#x1;"
+equals="==="
+exclamation="!"
+greater_than=">"
+hash="#"
+hyphen="-"
+indent=" "
+left_bracket="["
+left_paren="("
+less_than="<"
+plus="+"
+right_bracket="]"
+right_paren=")"
+single_quote="'"
+string_any="ANY"
+string_brackets="[]"
+string_cdata="CDATA"
+string_dashes="--"
+string_empty_dblquotes="\"\""
+string_empty_quotes="''"
+string_idrefs="IDREFS"
+string_parentheses="()"
+string_pcdata="#PCDATA"
+tag_cdata="<![CDATA["
+tag_close="</a>"
+tag_doctype="<!DOCTYPE"
+tag_element="<!ELEMENT"
+tag_entity="<!ENTITY"
+tag_notation="<!NOTATION"
+tag_open="<a>"
+tag_open_close="<a />"
+tag_open_exclamation="<!"
+tag_open_q="<?"
+tag_sq2_close="]]>"
+tag_xml_q="<?xml?>"
+underscore="_"
diff --git a/dictionaries/html_tags.dict b/dictionaries/html_tags.dict
new file mode 100644
index 00000000..2805de90
--- /dev/null
+++ b/dictionaries/html_tags.dict
@@ -0,0 +1,160 @@
+#
+# AFL dictionary for HTML parsers (tags only)
+# -------------------------------------------
+#
+# A basic collection of HTML tags likely to matter to HTML parsers. Does *not*
+# include any attributes or attribute values.
+#
+# Created by Michal Zalewski
+#
+
+tag_a="<a>"
+tag_abbr="<abbr>"
+tag_acronym="<acronym>"
+tag_address="<address>"
+tag_annotation_xml="<annotation-xml>"
+tag_applet="<applet>"
+tag_area="<area>"
+tag_article="<article>"
+tag_aside="<aside>"
+tag_audio="<audio>"
+tag_b="<b>"
+tag_base="<base>"
+tag_basefont="<basefont>"
+tag_bdi="<bdi>"
+tag_bdo="<bdo>"
+tag_bgsound="<bgsound>"
+tag_big="<big>"
+tag_blink="<blink>"
+tag_blockquote="<blockquote>"
+tag_body="<body>"
+tag_br="<br>"
+tag_button="<button>"
+tag_canvas="<canvas>"
+tag_caption="<caption>"
+tag_center="<center>"
+tag_cite="<cite>"
+tag_code="<code>"
+tag_col="<col>"
+tag_colgroup="<colgroup>"
+tag_data="<data>"
+tag_datalist="<datalist>"
+tag_dd="<dd>"
+tag_del="<del>"
+tag_desc="<desc>"
+tag_details="<details>"
+tag_dfn="<dfn>"
+tag_dir="<dir>"
+tag_div="<div>"
+tag_dl="<dl>"
+tag_dt="<dt>"
+tag_em="<em>"
+tag_embed="<embed>"
+tag_fieldset="<fieldset>"
+tag_figcaption="<figcaption>"
+tag_figure="<figure>"
+tag_font="<font>"
+tag_footer="<footer>"
+tag_foreignobject="<foreignobject>"
+tag_form="<form>"
+tag_frame="<frame>"
+tag_frameset="<frameset>"
+tag_h1="<h1>"
+tag_h2="<h2>"
+tag_h3="<h3>"
+tag_h4="<h4>"
+tag_h5="<h5>"
+tag_h6="<h6>"
+tag_head="<head>"
+tag_header="<header>"
+tag_hgroup="<hgroup>"
+tag_hr="<hr>"
+tag_html="<html>"
+tag_i="<i>"
+tag_iframe="<iframe>"
+tag_image="<image>"
+tag_img="<img>"
+tag_input="<input>"
+tag_ins="<ins>"
+tag_isindex="<isindex>"
+tag_kbd="<kbd>"
+tag_keygen="<keygen>"
+tag_label="<label>"
+tag_legend="<legend>"
+tag_li="<li>"
+tag_link="<link>"
+tag_listing="<listing>"
+tag_main="<main>"
+tag_malignmark="<malignmark>"
+tag_map="<map>"
+tag_mark="<mark>"
+tag_marquee="<marquee>"
+tag_math="<math>"
+tag_menu="<menu>"
+tag_menuitem="<menuitem>"
+tag_meta="<meta>"
+tag_meter="<meter>"
+tag_mglyph="<mglyph>"
+tag_mi="<mi>"
+tag_mn="<mn>"
+tag_mo="<mo>"
+tag_ms="<ms>"
+tag_mtext="<mtext>"
+tag_multicol="<multicol>"
+tag_nav="<nav>"
+tag_nextid="<nextid>"
+tag_nobr="<nobr>"
+tag_noembed="<noembed>"
+tag_noframes="<noframes>"
+tag_noscript="<noscript>"
+tag_object="<object>"
+tag_ol="<ol>"
+tag_optgroup="<optgroup>"
+tag_option="<option>"
+tag_output="<output>"
+tag_p="<p>"
+tag_param="<param>"
+tag_plaintext="<plaintext>"
+tag_pre="<pre>"
+tag_progress="<progress>"
+tag_q="<q>"
+tag_rb="<rb>"
+tag_rp="<rp>"
+tag_rt="<rt>"
+tag_rtc="<rtc>"
+tag_ruby="<ruby>"
+tag_s="<s>"
+tag_samp="<samp>"
+tag_script="<script>"
+tag_section="<section>"
+tag_select="<select>"
+tag_small="<small>"
+tag_source="<source>"
+tag_spacer="<spacer>"
+tag_span="<span>"
+tag_strike="<strike>"
+tag_strong="<strong>"
+tag_style="<style>"
+tag_sub="<sub>"
+tag_summary="<summary>"
+tag_sup="<sup>"
+tag_svg="<svg>"
+tag_table="<table>"
+tag_tbody="<tbody>"
+tag_td="<td>"
+tag_template="<template>"
+tag_textarea="<textarea>"
+tag_tfoot="<tfoot>"
+tag_th="<th>"
+tag_thead="<thead>"
+tag_time="<time>"
+tag_title="<title>"
+tag_tr="<tr>"
+tag_track="<track>"
+tag_tt="<tt>"
+tag_u="<u>"
+tag_ul="<ul>"
+tag_var="<var>"
+tag_video="<video>"
+tag_wbr="<wbr>"
+tag_xmp="<xmp>"
diff --git a/dictionaries/http.dict b/dictionaries/http.dict
new file mode 100644
index 00000000..092697d9
--- /dev/null
+++ b/dictionaries/http.dict
@@ -0,0 +1,119 @@
+# Sources: https://en.wikipedia.org/wiki/List_of_HTTP_header_fields
+
+# misc
+"HTTP/1.1"
+
+# verbs
+"CONNECT"
+"DELETE"
+"GET"
+"HEAD"
+"OPTIONS"
+"PATCH"
+"POST"
+"PUT"
+"TRACE"
+
+
+# Fields
+"A-IM"
+"Accept"
+"Accept-Charset"
+"Accept-Datetime"
+"Accept-Encoding"
+"Accept-Language"
+"Accept-Patch"
+"Accept-Ranges"
+"Access-Control-Allow-Credentials"
+"Access-Control-Allow-Headers"
+"Access-Control-Allow-Methods"
+"Access-Control-Allow-Origin"
+"Access-Control-Expose-Headers"
+"Access-Control-Max-Age"
+"Access-Control-Request-Headers"
+"Access-Control-Request-Method"
+"Age"
+"Allow"
+"Alt-Svc"
+"Authorization"
+"Cache-Control"
+"Connection"
+"Connection:"
+"Content-Disposition"
+"Content-Encoding"
+"Content-Language"
+"Content-Length"
+"Content-Location"
+"Content-MD5"
+"Content-Range"
+"Content-Security-Policy"
+"Content-Type"
+"Cookie"
+"DNT"
+"Date"
+"Delta-Base"
+"ETag"
+"Expect"
+"Expires"
+"Forwarded"
+"From"
+"Front-End-Https"
+"HTTP2-Settings"
+"Host"
+"IM"
+"If-Match"
+"If-Modified-Since"
+"If-None-Match"
+"If-Range"
+"If-Unmodified-Since"
+"Last-Modified"
+"Link"
+"Location"
+"Max-Forwards"
+"Origin"
+"P3P"
+"Pragma"
+"Proxy-Authenticate"
+"Proxy-Authorization"
+"Proxy-Connection"
+"Public-Key-Pins"
+"Range"
+"Referer"
+"Refresh"
+"Retry-After"
+"Save-Data"
+"Server"
+"Set-Cookie"
+"Status"
+"Strict-Transport-Security"
+"TE"
+"Timing-Allow-Origin"
+"Tk"
+"Trailer"
+"Transfer-Encoding"
+"Upgrade"
+"Upgrade-Insecure-Requests"
+"User-Agent"
+"Vary"
+"Via"
+"WWW-Authenticate"
+"Warning"
+"X-ATT-DeviceId"
+"X-Content-Duration"
+"X-Content-Security-Policy"
+"X-Content-Type-Options"
+"X-Correlation-ID"
+"X-Csrf-Token"
+"X-Forwarded-For"
+"X-Forwarded-Host"
+"X-Forwarded-Proto"
+"X-Frame-Options"
+"X-Http-Method-Override"
+"X-Powered-By"
+"X-Request-ID"
+"X-Requested-With"
+"X-UA-Compatible"
+"X-UIDH"
+"X-Wap-Profile"
+"X-WebKit-CSP"
+"X-XSS-Protection"
diff --git a/dictionaries/icc.dict b/dictionaries/icc.dict
new file mode 100644
index 00000000..058704c0
--- /dev/null
+++ b/dictionaries/icc.dict
@@ -0,0 +1,591 @@
+# See http://www.color.org/specification/ICC.2-2019.pdf
+
+magic="acsp"
+
+# spectral encoding
+"rs"
+"ts"
+"es"
+"bs"
+"sm"
+"mc"
+
+# Profile classes
+"scnr"
+"mntr"
+"prtr"
+"link"
+"spac"
+"abst"
+"nmcl"
+"cenc"
+"mod "
+"mlnk"
+"mvis"
+
+# Data colour space field
+"XYZ "
+"Lab "
+"Luv "
+"YVbr"
+"Yxy "
+"LMS "
+"RGB "
+"GRAY"
+"HSV "
+"HLS "
+"CMYK"
+"CMY "
+"2CLR"
+"3CLR"
+"4CLR"
+"5CLR"
+"6CLR"
+"7CLR"
+"8CLR"
+"9CLR"
+"ACLR"
+"BCLR"
+"CCLR"
+"DCLR"
+"ECLR"
+"FCLR"
+"nc"
+"YCC"
+
+# primary platforms
+"APPL"
+"MSFT"
+"SGI "
+"SUNW"
+
+
+# Tags
+"A2B0"
+"A2B1"
+"A2B2"
+"A2B3"
+"A2M0"
+"bcp0"
+"bcp1"
+"bcp2"
+"bcp3"
+"bsp0"
+"bsp1"
+"bsp2"
+"bsp3"
+"bAB0"
+"bAB1"
+"bAB2"
+"bAB3"
+"bBA0"
+"bBA1"
+"bBA2"
+"bBA3"
+"bBD0"
+"bBD1"
+"bBD2"
+"bBD3"
+"bDB0"
+"bDB1"
+"bDB2"
+"bDB3"
+"bMB0"
+"bMB1"
+"bMB2"
+"bMB3"
+"bMS0"
+"bMS1"
+"bMS2"
+"bMS3"
+"B2A0"
+"B2A1"
+"B2A2"
+"B2A3"
+"B2D0"
+"B2D1"
+"B2D2"
+"B2D3"
+"calt"
+"targ"
+"cept"
+"csnm"
+"clro"
+"cloo"
+"clin"
+"clio"
+"ciis"
+"cprt"
+"c2sp"
+"cxF "
+"dmnd"
+"dmdd"
+"dAB0"
+"dAB2"
+"dAB3"
+"dAB4"
+"dBA0"
+"dBA1"
+"dBA2"
+"dBA3"
+"dBD0"
+"dBD1"
+"dBD2"
+"dBD3"
+"dDB0"
+"dDB1"
+"dDB2"
+"dDB3"
+"d2B0"
+"d2B1"
+"d2B2"
+"d2B3"
+"gbd0"
+"gbd1"
+"gbd2"
+"gbd3"
+"mdv "
+"mcta"
+"minf"
+"miin"
+"wtpt"
+"meta"
+"M2A0"
+"M2B0"
+"M2B1"
+"M2B2"
+"M2B3"
+"M2S0"
+"M2S1"
+"M2S2"
+"M2S3"
+"nmcl"
+"rig0"
+"desc"
+"psin"
+"rfnm"
+"rig2"
+"svcn"
+"swpt"
+"s2cp"
+"smap"
+"tech"
+
+# tag types
+"clro"
+"curv"
+"data"
+"dtim"
+"dict"
+"ehim"
+"enim"
+"fl16"
+"fl32"
+"fl64"
+"gbd "
+"mAB "
+"mBA "
+"meas"
+"mluc"
+"mpet"
+"para"
+"sf32"
+"sig "
+"smat"
+"tary"
+"tstr"
+"ui32"
+"ui64"
+"ui08"
+"ut16"
+"utf8"
+"zut8"
+"zxml"
+
+# Function operands
+"calc"
+"func"
+"true"
+"ndef"
+"env "
+"in "
+"out "
+"tget"
+"tput"
+"tsav"
+"curv"
+"mtx "
+"clut"
+"tint"
+"elem"
+"copy"
+"rotl"
+"rotr"
+"posd"
+"flip"
+"pop "
+"solv"
+"tran"
+"sum "
+"prod"
+"min "
+"max "
+"and "
+"or "
+"pi "
+"+INF"
+"-INF"
+"NaN "
+"add "
+"sub "
+"mul "
+"dic "
+"mod "
+"pow "
+"gama"
+"sadd"
+"ssub"
+"sdiv"
+"smul"
+"sq "
+"sqrt"
+"cb "
+"cbrt"
+"abs "
+"neg "
+"rond"
+"flor"
+"ceil"
+"trnc"
+"sign"
+"exp "
+"log "
+"ln "
+"sin "
+"cos "
+"tan "
+"asin"
+"acos"
+"atan"
+"atn2"
+"ctop"
+"ptoc"
+"rnum"
+"lt "
+"le "
+"eq"
+"near"
+"ge "
+"gt "
+"vmin"
+"vmax"
+"vand"
+"vor "
+"tLab"
+"tXYZ"
+"if "
+"else"
+"sel "
+"case"
+"dflt"
+"cvst"
+"sngf"
+"curf"
+"parf"
+"smaf"
+"clut"
+"eclt"
+"emtx"
+"eobs"
+"xclt"
+"iemx"
+"JtoX"
+"matf"
+"smet"
+"rclt"
+"robs"
+"tint"
+"XtoJ"
+"bACS"
+"eACS"
+"brdf"
+"type"
+"func"
+"nump"
+"xfrm"
+"BPh0"
+"BPh1"
+"CT10"
+"CT20"
+"CT30"
+"CT11"
+"CT21"
+"CT31"
+"War0"
+"War1"
+"La10"
+"La20"
+"La30"
+"La11"
+"La21"
+"La31"
+"name"
+"lcnm"
+"pcs "
+"spec"
+"spcb"
+"spcg"
+"ncol"
+"pinf"
+
+# from oss-fuzz, some duplicates
+# Fuzzing dictionary for icc
+# Extracted from lcms2.h of Little-CMS project 2.8.
+
+magic="acsp"
+sig="lcms"
+
+# Base ICC type definitions
+"chrm"
+"clro"
+"clrt"
+"crdi"
+"curv"
+"data"
+"dict"
+"dtim"
+"devs"
+"mft2"
+"mft1"
+"mAB "
+"mBA "
+"meas"
+"mluc"
+"mpet"
+"ncol"
+"ncl2"
+"para"
+"pseq"
+"psid"
+"rcs2"
+"sf32"
+"scrn"
+"sig "
+"text"
+"desc"
+"uf32"
+"bfd "
+"ui16"
+"ui32"
+"ui64"
+"ui08"
+"vcgt"
+"view"
+"XYZ "
+
+# Base ICC tag definitions
+"A2B0"
+"A2B1"
+"A2B2"
+"bXYZ"
+"bXYZ"
+"bTRC"
+"B2A0"
+"B2A1"
+"B2A2"
+"calt"
+"targ"
+"chad"
+"chrm"
+"clro"
+"clrt"
+"clot"
+"ciis"
+"cprt"
+"crdi"
+"data"
+"dtim"
+"dmnd"
+"dmdd"
+"devs"
+"D2B0"
+"D2B1"
+"D2B2"
+"D2B3"
+"B2D0"
+"B2D1"
+"B2D2"
+"B2D3"
+"gamt"
+"kTRC"
+"gXYZ"
+"gXYZ"
+"gTRC"
+"lumi"
+"meas"
+"bkpt"
+"wtpt"
+"ncol"
+"ncl2"
+"resp"
+"rig0"
+"pre0"
+"pre1"
+"pre2"
+"desc"
+"dscm"
+"pseq"
+"psid"
+"psd0"
+"psd1"
+"psd2"
+"psd3"
+"ps2s"
+"ps2i"
+"rXYZ"
+"rXYZ"
+"rTRC"
+"rig2"
+"scrd"
+"scrn"
+"tech"
+"bfd "
+"vued"
+"view"
+"vcgt"
+"meta"
+"arts"
+
+# ICC Technology tag
+"dcam"
+"fscn"
+"rscn"
+"ijet"
+"twax"
+"epho"
+"esta"
+"dsub"
+"rpho"
+"fprn"
+"vidm"
+"vidc"
+"pjtv"
+"CRT "
+"PMD "
+"AMD "
+"KPCD"
+"imgs"
+"grav"
+"offs"
+"silk"
+"flex"
+"mpfs"
+"mpfr"
+"dmpc"
+"dcpj"
+
+# ICC Color spaces
+"XYZ "
+"Lab "
+"Luv "
+"YCbr"
+"Yxy "
+"RGB "
+"GRAY"
+"HSV "
+"HLS "
+"CMYK"
+"CMY "
+"MCH1"
+"MCH2"
+"MCH3"
+"MCH4"
+"MCH5"
+"MCH6"
+"MCH7"
+"MCH8"
+"MCH9"
+"MCHA"
+"MCHB"
+"MCHC"
+"MCHD"
+"MCHE"
+"MCHF"
+"nmcl"
+"1CLR"
+"2CLR"
+"3CLR"
+"4CLR"
+"5CLR"
+"6CLR"
+"7CLR"
+"8CLR"
+"9CLR"
+"ACLR"
+"BCLR"
+"CCLR"
+"DCLR"
+"ECLR"
+"FCLR"
+"LuvK"
+
+# ICC Profile Class
+"scnr"
+"mntr"
+"prtr"
+"link"
+"abst"
+"spac"
+"nmcl"
+
+# ICC Platforms
+"APPL"
+"MSFT"
+"SUNW"
+"SGI "
+"TGNT"
+"*nix"
+
+# Reference gamut
+"prmg"
+
+# For cmsSigColorimetricIntentImageStateTag
+"scoe"
+"sape"
+"fpce"
+"rhoc"
+"rpoc"
+
+# Multi process elements types
+"cvst"
+"matf"
+"clut"
+"bACS"
+"eACS"
+"l2x "
+"x2l "
+"ncl "
+"2 4 "
+"4 2 "
+"idn "
+"d2l "
+"l2d "
+"d2x "
+"x2d "
+"clp "
+
+# Types of CurveElements
+"parf"
+"samf"
+"curf"
+
+# Used in ResponseCurveType
+"StaA"
+"StaE"
+"StaI"
+"StaT"
+"StaM"
+"DN "
+"DN P"
+"DNN "
+"DNNP"
diff --git a/dictionaries/iccprofile.dict b/dictionaries/iccprofile.dict
new file mode 100644
index 00000000..26dd973e
--- /dev/null
+++ b/dictionaries/iccprofile.dict
@@ -0,0 +1,25 @@
+# Dict for ICC profiles parsed by skcms.
+
+"mft1"
+"mft2"
+"mAB "
+"rXYZ"
+"gXYZ"
+"bXYZ"
+"rTRC"
+"gTRC"
+"bTRC"
+"kTRC"
+"A2B0"
+"curv"
+"para"
+"mluc"
+"XYZ "
+"Lab "
+"RGB "
+"CMYK"
+"GRAY"
+"mntr"
+"scnr"
+"prtr"
+"spac"
diff --git a/dictionaries/icns.dict b/dictionaries/icns.dict
new file mode 100644
index 00000000..211f26c2
--- /dev/null
+++ b/dictionaries/icns.dict
@@ -0,0 +1,43 @@
+# https://en.wikipedia.org/wiki/Apple_Icon_Image_format
+
+"ICN#"
+"ICON"
+"TOC "
+"h8mk"
+"ic04"
+"ic05"
+"ic07"
+"ic08"
+"ic09"
+"ic10"
+"ic11"
+"ic12"
+"ic13"
+"ic14"
+"ich#"
+"ich4"
+"ich8"
+"icl4"
+"icl8"
+"icm#"
+"icm4"
+"icm8"
+"icnV"
+"icns"
+"icp4"
+"icp5"
+"icp6"
+"ics#"
+"ics4"
+"ics8"
+"icsB"
+"icsb"
+"ih32"
+"il32"
+"info"
+"is32"
+"it32"
+"l8mk"
+"name"
+"s8mk"
+"t8mk"
diff --git a/dictionaries/initfile.dict b/dictionaries/initfile.dict
new file mode 100644
index 00000000..2d88ebc0
--- /dev/null
+++ b/dictionaries/initfile.dict
@@ -0,0 +1,688 @@
+#SELECT WORD FROM INFORMATION_SCHEMA.KEYWORDS;
+ACCESSIBLE="ACCESSIBLE"
+ACCOUNT="ACCOUNT"
+ACTION="ACTION"
+ACTIVE="ACTIVE"
+ADD="ADD"
+ADMIN="ADMIN"
+AFTER="AFTER"
+AGAINST="AGAINST"
+AGGREGATE="AGGREGATE"
+ALGORITHM="ALGORITHM"
+ALL="ALL"
+ALTER="ALTER"
+ALWAYS="ALWAYS"
+ANALYZE="ANALYZE"
+AND="AND"
+ANY="ANY"
+AS="AS"
+ASC="ASC"
+ASCII="ASCII"
+ASENSITIVE="ASENSITIVE"
+AT="AT"
+AUTOEXTEND_SIZE="AUTOEXTEND_SIZE"
+AUTO_INCREMENT="AUTO_INCREMENT"
+AVG="AVG"
+AVG_ROW_LENGTH="AVG_ROW_LENGTH"
+BACKUP="BACKUP"
+BEFORE="BEFORE"
+BEGIN="BEGIN"
+BETWEEN="BETWEEN"
+BIGINT="BIGINT"
+BINARY="BINARY"
+BINLOG="BINLOG"
+BIT="BIT"
+BLOB="BLOB"
+BLOCK="BLOCK"
+BOOL="BOOL"
+BOOLEAN="BOOLEAN"
+BOTH="BOTH"
+BTREE="BTREE"
+BUCKETS="BUCKETS"
+BY="BY"
+BYTE="BYTE"
+CACHE="CACHE"
+CALL="CALL"
+CASCADE="CASCADE"
+CASCADED="CASCADED"
+CASE="CASE"
+CATALOG_NAME="CATALOG_NAME"
+CHAIN="CHAIN"
+CHANGE="CHANGE"
+CHANGED="CHANGED"
+CHANNEL="CHANNEL"
+CHAR="CHAR"
+CHARACTER="CHARACTER"
+CHARSET="CHARSET"
+CHECK="CHECK"
+CHECKSUM="CHECKSUM"
+CIPHER="CIPHER"
+CLASS_ORIGIN="CLASS_ORIGIN"
+CLIENT="CLIENT"
+CLONE="CLONE"
+CLOSE="CLOSE"
+COALESCE="COALESCE"
+CODE="CODE"
+COLLATE="COLLATE"
+COLLATION="COLLATION"
+COLUMN="COLUMN"
+COLUMNS="COLUMNS"
+COLUMN_FORMAT="COLUMN_FORMAT"
+COLUMN_NAME="COLUMN_NAME"
+COMMENT="COMMENT"
+COMMIT="COMMIT"
+COMMITTED="COMMITTED"
+COMPACT="COMPACT"
+COMPLETION="COMPLETION"
+COMPONENT="COMPONENT"
+COMPRESSED="COMPRESSED"
+COMPRESSION="COMPRESSION"
+CONCURRENT="CONCURRENT"
+CONDITION="CONDITION"
+CONNECTION="CONNECTION"
+CONSISTENT="CONSISTENT"
+CONSTRAINT="CONSTRAINT"
+CONSTRAINT_CATALOG="CONSTRAINT_CATALOG"
+CONSTRAINT_NAME="CONSTRAINT_NAME"
+CONSTRAINT_SCHEMA="CONSTRAINT_SCHEMA"
+CONTAINS="CONTAINS"
+CONTEXT="CONTEXT"
+CONTINUE="CONTINUE"
+CONVERT="CONVERT"
+CPU="CPU"
+CREATE="CREATE"
+CROSS="CROSS"
+CUBE="CUBE"
+CUME_DIST="CUME_DIST"
+CURRENT="CURRENT"
+CURRENT_DATE="CURRENT_DATE"
+CURRENT_TIME="CURRENT_TIME"
+CURRENT_TIMESTAMP="CURRENT_TIMESTAMP"
+CURRENT_USER="CURRENT_USER"
+CURSOR="CURSOR"
+CURSOR_NAME="CURSOR_NAME"
+DATA="DATA"
+DATABASE="DATABASE"
+DATABASES="DATABASES"
+DATAFILE="DATAFILE"
+DATE="DATE"
+DATETIME="DATETIME"
+DAY="DAY"
+DAY_HOUR="DAY_HOUR"
+DAY_MICROSECOND="DAY_MICROSECOND"
+DAY_MINUTE="DAY_MINUTE"
+DAY_SECOND="DAY_SECOND"
+DEALLOCATE="DEALLOCATE"
+DEC="DEC"
+DECIMAL="DECIMAL"
+DECLARE="DECLARE"
+DEFAULT="DEFAULT"
+DEFAULT_AUTH="DEFAULT_AUTH"
+DEFINER="DEFINER"
+DEFINITION="DEFINITION"
+DELAYED="DELAYED"
+DELAY_KEY_WRITE="DELAY_KEY_WRITE"
+DELETE="DELETE"
+DENSE_RANK="DENSE_RANK"
+DESC="DESC"
+DESCRIBE="DESCRIBE"
+DESCRIPTION="DESCRIPTION"
+DETERMINISTIC="DETERMINISTIC"
+DIAGNOSTICS="DIAGNOSTICS"
+DIRECTORY="DIRECTORY"
+DISABLE="DISABLE"
+DISCARD="DISCARD"
+DISK="DISK"
+DISTINCT="DISTINCT"
+DISTINCTROW="DISTINCTROW"
+DIV="DIV"
+DO="DO"
+DOUBLE="DOUBLE"
+DROP="DROP"
+DUAL="DUAL"
+DUMPFILE="DUMPFILE"
+DUPLICATE="DUPLICATE"
+DYNAMIC="DYNAMIC"
+EACH="EACH"
+ELSE="ELSE"
+ELSEIF="ELSEIF"
+EMPTY="EMPTY"
+ENABLE="ENABLE"
+ENCLOSED="ENCLOSED"
+ENCRYPTION="ENCRYPTION"
+END="END"
+ENDS="ENDS"
+ENFORCED="ENFORCED"
+ENGINE="ENGINE"
+ENGINES="ENGINES"
+ENUM="ENUM"
+ERROR="ERROR"
+ERRORS="ERRORS"
+ESCAPE="ESCAPE"
+ESCAPED="ESCAPED"
+EVENT="EVENT"
+EVENTS="EVENTS"
+EVERY="EVERY"
+EXCEPT="EXCEPT"
+EXCHANGE="EXCHANGE"
+EXCLUDE="EXCLUDE"
+EXECUTE="EXECUTE"
+EXISTS="EXISTS"
+EXIT="EXIT"
+EXPANSION="EXPANSION"
+EXPIRE="EXPIRE"
+EXPLAIN="EXPLAIN"
+EXPORT="EXPORT"
+EXTENDED="EXTENDED"
+EXTENT_SIZE="EXTENT_SIZE"
+FALSE="FALSE"
+FAST="FAST"
+FAULTS="FAULTS"
+FETCH="FETCH"
+FIELDS="FIELDS"
+FILE="FILE"
+FILE_BLOCK_SIZE="FILE_BLOCK_SIZE"
+FILTER="FILTER"
+FIRST="FIRST"
+FIRST_VALUE="FIRST_VALUE"
+FIXED="FIXED"
+FLOAT="FLOAT"
+FLOAT4="FLOAT4"
+FLOAT8="FLOAT8"
+FLUSH="FLUSH"
+FOLLOWING="FOLLOWING"
+FOLLOWS="FOLLOWS"
+FOR="FOR"
+FORCE="FORCE"
+FOREIGN="FOREIGN"
+FORMAT="FORMAT"
+FOUND="FOUND"
+FROM="FROM"
+FULL="FULL"
+FULLTEXT="FULLTEXT"
+FUNCTION="FUNCTION"
+GENERAL="GENERAL"
+GENERATED="GENERATED"
+GEOMCOLLECTION="GEOMCOLLECTION"
+GEOMETRY="GEOMETRY"
+GEOMETRYCOLLECTION="GEOMETRYCOLLECTION"
+GET="GET"
+GET_FORMAT="GET_FORMAT"
+GET_MASTER_PUBLIC_KEY="GET_MASTER_PUBLIC_KEY"
+GLOBAL="GLOBAL"
+GRANT="GRANT"
+GRANTS="GRANTS"
+GROUP="GROUP"
+GROUPING="GROUPING"
+GROUPS="GROUPS"
+GROUP_REPLICATION="GROUP_REPLICATION"
+HANDLER="HANDLER"
+HASH="HASH"
+HAVING="HAVING"
+HELP="HELP"
+HIGH_PRIORITY="HIGH_PRIORITY"
+HISTOGRAM="HISTOGRAM"
+HISTORY="HISTORY"
+HOST="HOST"
+HOSTS="HOSTS"
+HOUR="HOUR"
+HOUR_MICROSECOND="HOUR_MICROSECOND"
+HOUR_MINUTE="HOUR_MINUTE"
+HOUR_SECOND="HOUR_SECOND"
+IDENTIFIED="IDENTIFIED"
+IF="IF"
+IGNORE="IGNORE"
+IGNORE_SERVER_IDS="IGNORE_SERVER_IDS"
+IMPORT="IMPORT"
+IN="IN"
+INACTIVE="INACTIVE"
+INDEX="INDEX"
+INDEXES="INDEXES"
+INFILE="INFILE"
+INITIAL_SIZE="INITIAL_SIZE"
+INNER="INNER"
+INOUT="INOUT"
+INSENSITIVE="INSENSITIVE"
+INSERT="INSERT"
+INSERT_METHOD="INSERT_METHOD"
+INSTALL="INSTALL"
+INSTANCE="INSTANCE"
+INT="INT"
+INT1="INT1"
+INT2="INT2"
+INT3="INT3"
+INT4="INT4"
+INT8="INT8"
+INTEGER="INTEGER"
+INTERVAL="INTERVAL"
+INTO="INTO"
+INVISIBLE="INVISIBLE"
+INVOKER="INVOKER"
+IO="IO"
+IO_AFTER_GTIDS="IO_AFTER_GTIDS"
+IO_BEFORE_GTIDS="IO_BEFORE_GTIDS"
+IO_THREAD="IO_THREAD"
+IPC="IPC"
+IS="IS"
+ISOLATION="ISOLATION"
+ISSUER="ISSUER"
+ITERATE="ITERATE"
+JOIN="JOIN"
+JSON="JSON"
+JSON_TABLE="JSON_TABLE"
+KEY="KEY"
+KEYS="KEYS"
+KEY_BLOCK_SIZE="KEY_BLOCK_SIZE"
+KILL="KILL"
+LAG="LAG"
+LANGUAGE="LANGUAGE"
+LAST="LAST"
+LAST_VALUE="LAST_VALUE"
+LATERAL="LATERAL"
+LEAD="LEAD"
+LEADING="LEADING"
+LEAVE="LEAVE"
+LEAVES="LEAVES"
+LEFT="LEFT"
+LESS="LESS"
+LEVEL="LEVEL"
+LIKE="LIKE"
+LIMIT="LIMIT"
+LINEAR="LINEAR"
+LINES="LINES"
+LINESTRING="LINESTRING"
+LIST="LIST"
+LOAD="LOAD"
+LOCAL="LOCAL"
+LOCALTIME="LOCALTIME"
+LOCALTIMESTAMP="LOCALTIMESTAMP"
+LOCK="LOCK"
+LOCKED="LOCKED"
+LOCKS="LOCKS"
+LOGFILE="LOGFILE"
+LOGS="LOGS"
+LONG="LONG"
+LONGBLOB="LONGBLOB"
+LONGTEXT="LONGTEXT"
+LOOP="LOOP"
+LOW_PRIORITY="LOW_PRIORITY"
+MASTER="MASTER"
+MASTER_AUTO_POSITION="MASTER_AUTO_POSITION"
+MASTER_BIND="MASTER_BIND"
+MASTER_CONNECT_RETRY="MASTER_CONNECT_RETRY"
+MASTER_DELAY="MASTER_DELAY"
+MASTER_HEARTBEAT_PERIOD="MASTER_HEARTBEAT_PERIOD"
+MASTER_HOST="MASTER_HOST"
+MASTER_LOG_FILE="MASTER_LOG_FILE"
+MASTER_LOG_POS="MASTER_LOG_POS"
+MASTER_PASSWORD="MASTER_PASSWORD"
+MASTER_PORT="MASTER_PORT"
+MASTER_PUBLIC_KEY_PATH="MASTER_PUBLIC_KEY_PATH"
+MASTER_RETRY_COUNT="MASTER_RETRY_COUNT"
+MASTER_SERVER_ID="MASTER_SERVER_ID"
+MASTER_SSL="MASTER_SSL"
+MASTER_SSL_CA="MASTER_SSL_CA"
+MASTER_SSL_CAPATH="MASTER_SSL_CAPATH"
+MASTER_SSL_CERT="MASTER_SSL_CERT"
+MASTER_SSL_CIPHER="MASTER_SSL_CIPHER"
+MASTER_SSL_CRL="MASTER_SSL_CRL"
+MASTER_SSL_CRLPATH="MASTER_SSL_CRLPATH"
+MASTER_SSL_KEY="MASTER_SSL_KEY"
+MASTER_SSL_VERIFY_SERVER_CERT="MASTER_SSL_VERIFY_SERVER_CERT"
+MASTER_TLS_VERSION="MASTER_TLS_VERSION"
+MASTER_USER="MASTER_USER"
+MATCH="MATCH"
+MAXVALUE="MAXVALUE"
+MAX_CONNECTIONS_PER_HOUR="MAX_CONNECTIONS_PER_HOUR"
+MAX_QUERIES_PER_HOUR="MAX_QUERIES_PER_HOUR"
+MAX_ROWS="MAX_ROWS"
+MAX_SIZE="MAX_SIZE"
+MAX_UPDATES_PER_HOUR="MAX_UPDATES_PER_HOUR"
+MAX_USER_CONNECTIONS="MAX_USER_CONNECTIONS"
+MEDIUM="MEDIUM"
+MEDIUMBLOB="MEDIUMBLOB"
+MEDIUMINT="MEDIUMINT"
+MEDIUMTEXT="MEDIUMTEXT"
+MEMORY="MEMORY"
+MERGE="MERGE"
+MESSAGE_TEXT="MESSAGE_TEXT"
+MICROSECOND="MICROSECOND"
+MIDDLEINT="MIDDLEINT"
+MIGRATE="MIGRATE"
+MINUTE="MINUTE"
+MINUTE_MICROSECOND="MINUTE_MICROSECOND"
+MINUTE_SECOND="MINUTE_SECOND"
+MIN_ROWS="MIN_ROWS"
+MOD="MOD"
+MODE="MODE"
+MODIFIES="MODIFIES"
+MODIFY="MODIFY"
+MONTH="MONTH"
+MULTILINESTRING="MULTILINESTRING"
+MULTIPOINT="MULTIPOINT"
+MULTIPOLYGON="MULTIPOLYGON"
+MUTEX="MUTEX"
+MYSQL_ERRNO="MYSQL_ERRNO"
+NAME="NAME"
+NAMES="NAMES"
+NATIONAL="NATIONAL"
+NATURAL="NATURAL"
+NCHAR="NCHAR"
+NDB="NDB"
+NDBCLUSTER="NDBCLUSTER"
+NESTED="NESTED"
+NETWORK_NAMESPACE="NETWORK_NAMESPACE"
+NEVER="NEVER"
+NEW="NEW"
+NEXT="NEXT"
+NO="NO"
+NODEGROUP="NODEGROUP"
+NONE="NONE"
+NOT="NOT"
+NOWAIT="NOWAIT"
+NO_WAIT="NO_WAIT"
+NO_WRITE_TO_BINLOG="NO_WRITE_TO_BINLOG"
+NTH_VALUE="NTH_VALUE"
+NTILE="NTILE"
+NULL="NULL"
+NULLS="NULLS"
+NUMBER="NUMBER"
+NUMERIC="NUMERIC"
+NVARCHAR="NVARCHAR"
+OF="OF"
+OFFSET="OFFSET"
+OJ="OJ"
+OLD="OLD"
+ON="ON"
+ONE="ONE"
+ONLY="ONLY"
+OPEN="OPEN"
+OPTIMIZE="OPTIMIZE"
+OPTIMIZER_COSTS="OPTIMIZER_COSTS"
+OPTION="OPTION"
+OPTIONAL="OPTIONAL"
+OPTIONALLY="OPTIONALLY"
+OPTIONS="OPTIONS"
+OR="OR"
+ORDER="ORDER"
+ORDINALITY="ORDINALITY"
+ORGANIZATION="ORGANIZATION"
+OTHERS="OTHERS"
+OUT="OUT"
+OUTER="OUTER"
+OUTFILE="OUTFILE"
+OVER="OVER"
+OWNER="OWNER"
+PACK_KEYS="PACK_KEYS"
+PAGE="PAGE"
+PARSER="PARSER"
+PARTIAL="PARTIAL"
+PARTITION="PARTITION"
+PARTITIONING="PARTITIONING"
+PARTITIONS="PARTITIONS"
+PASSWORD="PASSWORD"
+PATH="PATH"
+PERCENT_RANK="PERCENT_RANK"
+PERSIST="PERSIST"
+PERSIST_ONLY="PERSIST_ONLY"
+PHASE="PHASE"
+PLUGIN="PLUGIN"
+PLUGINS="PLUGINS"
+PLUGIN_DIR="PLUGIN_DIR"
+POINT="POINT"
+POLYGON="POLYGON"
+PORT="PORT"
+PRECEDES="PRECEDES"
+PRECEDING="PRECEDING"
+PRECISION="PRECISION"
+PREPARE="PREPARE"
+PRESERVE="PRESERVE"
+PREV="PREV"
+PRIMARY="PRIMARY"
+PRIVILEGES="PRIVILEGES"
+PROCEDURE="PROCEDURE"
+PROCESS="PROCESS"
+PROCESSLIST="PROCESSLIST"
+PROFILE="PROFILE"
+PROFILES="PROFILES"
+PROXY="PROXY"
+PURGE="PURGE"
+QUARTER="QUARTER"
+QUERY="QUERY"
+QUICK="QUICK"
+RANGE="RANGE"
+RANK="RANK"
+READ="READ"
+READS="READS"
+READ_ONLY="READ_ONLY"
+READ_WRITE="READ_WRITE"
+REAL="REAL"
+REBUILD="REBUILD"
+RECOVER="RECOVER"
+RECURSIVE="RECURSIVE"
+REDO_BUFFER_SIZE="REDO_BUFFER_SIZE"
+REDUNDANT="REDUNDANT"
+REFERENCE="REFERENCE"
+REFERENCES="REFERENCES"
+REGEXP="REGEXP"
+RELAY="RELAY"
+RELAYLOG="RELAYLOG"
+RELAY_LOG_FILE="RELAY_LOG_FILE"
+RELAY_LOG_POS="RELAY_LOG_POS"
+RELAY_THREAD="RELAY_THREAD"
+RELEASE="RELEASE"
+RELOAD="RELOAD"
+REMOVE="REMOVE"
+RENAME="RENAME"
+REORGANIZE="REORGANIZE"
+REPAIR="REPAIR"
+REPEAT="REPEAT"
+REPEATABLE="REPEATABLE"
+REPLACE="REPLACE"
+REPLICATE_DO_DB="REPLICATE_DO_DB"
+REPLICATE_DO_TABLE="REPLICATE_DO_TABLE"
+REPLICATE_IGNORE_DB="REPLICATE_IGNORE_DB"
+REPLICATE_IGNORE_TABLE="REPLICATE_IGNORE_TABLE"
+REPLICATE_REWRITE_DB="REPLICATE_REWRITE_DB"
+REPLICATE_WILD_DO_TABLE="REPLICATE_WILD_DO_TABLE"
+REPLICATE_WILD_IGNORE_TABLE="REPLICATE_WILD_IGNORE_TABLE"
+REPLICATION="REPLICATION"
+REQUIRE="REQUIRE"
+RESET="RESET"
+RESIGNAL="RESIGNAL"
+RESOURCE="RESOURCE"
+RESPECT="RESPECT"
+RESTART="RESTART"
+RESTORE="RESTORE"
+RESTRICT="RESTRICT"
+RESUME="RESUME"
+RETAIN="RETAIN"
+RETURN="RETURN"
+RETURNED_SQLSTATE="RETURNED_SQLSTATE"
+RETURNS="RETURNS"
+REUSE="REUSE"
+REVERSE="REVERSE"
+REVOKE="REVOKE"
+RIGHT="RIGHT"
+RLIKE="RLIKE"
+ROLE="ROLE"
+ROLLBACK="ROLLBACK"
+ROLLUP="ROLLUP"
+ROTATE="ROTATE"
+ROUTINE="ROUTINE"
+ROW="ROW"
+ROWS="ROWS"
+ROW_COUNT="ROW_COUNT"
+ROW_FORMAT="ROW_FORMAT"
+ROW_NUMBER="ROW_NUMBER"
+RTREE="RTREE"
+SAVEPOINT="SAVEPOINT"
+SCHEDULE="SCHEDULE"
+SCHEMA="SCHEMA"
+SCHEMAS="SCHEMAS"
+SCHEMA_NAME="SCHEMA_NAME"
+SECOND="SECOND"
+SECONDARY="SECONDARY"
+SECONDARY_ENGINE="SECONDARY_ENGINE"
+SECONDARY_LOAD="SECONDARY_LOAD"
+SECONDARY_UNLOAD="SECONDARY_UNLOAD"
+SECOND_MICROSECOND="SECOND_MICROSECOND"
+SECURITY="SECURITY"
+SELECT="SELECT"
+SENSITIVE="SENSITIVE"
+SEPARATOR="SEPARATOR"
+SERIAL="SERIAL"
+SERIALIZABLE="SERIALIZABLE"
+SERVER="SERVER"
+SESSION="SESSION"
+SET="SET"
+SHARE="SHARE"
+SHOW="SHOW"
+SHUTDOWN="SHUTDOWN"
+SIGNAL="SIGNAL"
+SIGNED="SIGNED"
+SIMPLE="SIMPLE"
+SKIP="SKIP"
+SLAVE="SLAVE"
+SLOW="SLOW"
+SMALLINT="SMALLINT"
+SNAPSHOT="SNAPSHOT"
+SOCKET="SOCKET"
+SOME="SOME"
+SONAME="SONAME"
+SOUNDS="SOUNDS"
+SOURCE="SOURCE"
+SPATIAL="SPATIAL"
+SPECIFIC="SPECIFIC"
+SQL="SQL"
+SQLEXCEPTION="SQLEXCEPTION"
+SQLSTATE="SQLSTATE"
+SQLWARNING="SQLWARNING"
+SQL_AFTER_GTIDS="SQL_AFTER_GTIDS"
+SQL_AFTER_MTS_GAPS="SQL_AFTER_MTS_GAPS"
+SQL_BEFORE_GTIDS="SQL_BEFORE_GTIDS"
+SQL_BIG_RESULT="SQL_BIG_RESULT"
+SQL_BUFFER_RESULT="SQL_BUFFER_RESULT"
+SQL_CALC_FOUND_ROWS="SQL_CALC_FOUND_ROWS"
+SQL_NO_CACHE="SQL_NO_CACHE"
+SQL_SMALL_RESULT="SQL_SMALL_RESULT"
+SQL_THREAD="SQL_THREAD"
+SQL_TSI_DAY="SQL_TSI_DAY"
+SQL_TSI_HOUR="SQL_TSI_HOUR"
+SQL_TSI_MINUTE="SQL_TSI_MINUTE"
+SQL_TSI_MONTH="SQL_TSI_MONTH"
+SQL_TSI_QUARTER="SQL_TSI_QUARTER"
+SQL_TSI_SECOND="SQL_TSI_SECOND"
+SQL_TSI_WEEK="SQL_TSI_WEEK"
+SQL_TSI_YEAR="SQL_TSI_YEAR"
+SRID="SRID"
+SSL="SSL"
+STACKED="STACKED"
+START="START"
+STARTING="STARTING"
+STARTS="STARTS"
+STATS_AUTO_RECALC="STATS_AUTO_RECALC"
+STATS_PERSISTENT="STATS_PERSISTENT"
+STATS_SAMPLE_PAGES="STATS_SAMPLE_PAGES"
+STATUS="STATUS"
+STOP="STOP"
+STORAGE="STORAGE"
+STORED="STORED"
+STRAIGHT_JOIN="STRAIGHT_JOIN"
+STRING="STRING"
+SUBCLASS_ORIGIN="SUBCLASS_ORIGIN"
+SUBJECT="SUBJECT"
+SUBPARTITION="SUBPARTITION"
+SUBPARTITIONS="SUBPARTITIONS"
+SUPER="SUPER"
+SUSPEND="SUSPEND"
+SWAPS="SWAPS"
+SWITCHES="SWITCHES"
+SYSTEM="SYSTEM"
+TABLE="TABLE"
+TABLES="TABLES"
+TABLESPACE="TABLESPACE"
+TABLE_CHECKSUM="TABLE_CHECKSUM"
+TABLE_NAME="TABLE_NAME"
+TEMPORARY="TEMPORARY"
+TEMPTABLE="TEMPTABLE"
+TERMINATED="TERMINATED"
+TEXT="TEXT"
+THAN="THAN"
+THEN="THEN"
+THREAD_PRIORITY="THREAD_PRIORITY"
+TIES="TIES"
+TIME="TIME"
+TIMESTAMP="TIMESTAMP"
+TIMESTAMPADD="TIMESTAMPADD"
+TIMESTAMPDIFF="TIMESTAMPDIFF"
+TINYBLOB="TINYBLOB"
+TINYINT="TINYINT"
+TINYTEXT="TINYTEXT"
+TO="TO"
+TRAILING="TRAILING"
+TRANSACTION="TRANSACTION"
+TRIGGER="TRIGGER"
+TRIGGERS="TRIGGERS"
+TRUE="TRUE"
+TRUNCATE="TRUNCATE"
+TYPE="TYPE"
+TYPES="TYPES"
+UNBOUNDED="UNBOUNDED"
+UNCOMMITTED="UNCOMMITTED"
+UNDEFINED="UNDEFINED"
+UNDO="UNDO"
+UNDOFILE="UNDOFILE"
+UNDO_BUFFER_SIZE="UNDO_BUFFER_SIZE"
+UNICODE="UNICODE"
+UNINSTALL="UNINSTALL"
+UNION="UNION"
+UNIQUE="UNIQUE"
+UNKNOWN="UNKNOWN"
+UNLOCK="UNLOCK"
+UNSIGNED="UNSIGNED"
+UNTIL="UNTIL"
+UPDATE="UPDATE"
+UPGRADE="UPGRADE"
+USAGE="USAGE"
+USE="USE"
+USER="USER"
+USER_RESOURCES="USER_RESOURCES"
+USE_FRM="USE_FRM"
+USING="USING"
+UTC_DATE="UTC_DATE"
+UTC_TIME="UTC_TIME"
+UTC_TIMESTAMP="UTC_TIMESTAMP"
+VALIDATION="VALIDATION"
+VALUE="VALUE"
+VALUES="VALUES"
+VARBINARY="VARBINARY"
+VARCHAR="VARCHAR"
+VARCHARACTER="VARCHARACTER"
+VARIABLES="VARIABLES"
+VARYING="VARYING"
+VCPU="VCPU"
+VIEW="VIEW"
+VIRTUAL="VIRTUAL"
+VISIBLE="VISIBLE"
+WAIT="WAIT"
+WARNINGS="WARNINGS"
+WEEK="WEEK"
+WEIGHT_STRING="WEIGHT_STRING"
+WHEN="WHEN"
+WHERE="WHERE"
+WHILE="WHILE"
+WINDOW="WINDOW"
+WITH="WITH"
+WITHOUT="WITHOUT"
+WORK="WORK"
+WRAPPER="WRAPPER"
+WRITE="WRITE"
+X509="X509"
+XA="XA"
+XID="XID"
+XML="XML"
+XOR="XOR"
+YEAR="YEAR"
+YEAR_MONTH="YEAR_MONTH"
+ZEROFILL="ZEROFILL"
diff --git a/dictionaries/jbig2.dict b/dictionaries/jbig2.dict
new file mode 100644
index 00000000..97f31b39
--- /dev/null
+++ b/dictionaries/jbig2.dict
@@ -0,0 +1,98 @@
+# AFL dictionary for jbig2 images
+# by Sebastian Rasmussen <sebras@gmail.com>
+
+id_string="\x97\x4a\x42\x32\x0d\x0a\x1a\x0a"
+
+# segments
+
+noretain_allpages_symbol_dictionary="\x00"
+noretain_allpages_intermediate_text_region="\x04"
+noretain_allpages_immediate_text_region="\x06"
+noretain_allpages_immediate_lossless_text_region="\x07"
+noretain_allpages_pattern_dictionary="\x10"
+noretain_allpages_intermediate_halftone_region="\x14"
+noretain_allpages_immediate_halftone_region="\x16"
+noretain_allpages_immediate_lossless_halftone_region="\x17"
+noretain_allpages_intermediate_generic_region="\x24"
+noretain_allpages_immediate_generic_region="\x26"
+noretain_allpages_immediate_lossless_generic_region="\x27"
+noretain_allpages_intermediate_generic_refinement_region="\x28"
+noretain_allpages_immediate_generic_refinement_region="\x2a"
+noretain_allpages_immediate_lossless_generic_refinement_region="\x2b"
+noretain_allpages_page_information="\x30"
+noretain_allpages_end_of_page="\x31"
+noretain_allpages_end_of_stripe="\x32"
+noretain_allpages_end_of_file="\x33"
+noretain_allpages_profiles="\x34"
+noretain_allpages_tables="\x35"
+noretain_allpages_color_palette="\x36"
+noretain_allpages_extension="\x3e"
+
+noretain_specificpage_symbol_dictionary="\x40"
+noretain_specificpage_intermediate_text_region="\x44"
+noretain_specificpage_immediate_text_region="\x46"
+noretain_specificpage_immediate_lossless_text_region="\x47"
+noretain_specificpage_pattern_dictionary="\x50"
+noretain_specificpage_intermediate_halftone_region="\x54"
+noretain_specificpage_immediate_halftone_region="\x56"
+noretain_specificpage_immediate_lossless_halftone_region="\x57"
+noretain_specificpage_intermediate_generic_region="\x64"
+noretain_specificpage_immediate_generic_region="\x66"
+noretain_specificpage_immediate_lossless_generic_region="\x67"
+noretain_specificpage_intermediate_generic_refinement_region="\x68"
+noretain_specificpage_immediate_generic_refinement_region="\x6a"
+noretain_specificpage_immediate_lossless_generic_refinement_regio6="\x6b"
+noretain_specificpage_page_information="\x70"
+noretain_specificpage_end_of_page="\x71"
+noretain_specificpage_end_of_stripe="\x72"
+noretain_specificpage_end_of_file="\x73"
+noretain_specificpage_profiles="\x74"
+noretain_specificpage_tables="\x75"
+noretain_specificpage_color_palette="\x76"
+noretain_specificpage_extension="\x7e"
+
+retain_allpages_symbol_dictionary="\x80"
+retain_allpages_intermediate_text_region="\x84"
+retain_allpages_immediate_text_region="\x86"
+retain_allpages_immediate_lossless_text_region="\x87"
+retain_allpages_pattern_dictionary="\x90"
+retain_allpages_intermediate_halftone_region="\x94"
+retain_allpages_immediate_halftone_region="\x96"
+retain_allpages_immediate_lossless_halftone_region="\x97"
+retain_allpages_intermediate_generic_region="\xa4"
+retain_allpages_immediate_generic_region="\xa6"
+retain_allpages_immediate_lossless_generic_region="\xa7"
+retain_allpages_intermediate_generic_refinement_region="\xa8"
+retain_allpages_immediate_generic_refinement_region="\xaa"
+retain_allpages_immediate_lossless_generic_refinement_regio6="\xab"
+retain_allpages_page_information="\xb0"
+retain_allpages_end_of_page="\xb1"
+retain_allpages_end_of_stripe="\xb2"
+retain_allpages_end_of_file="\xb3"
+retain_allpages_profiles="\xb4"
+retain_allpages_tables="\xb5"
+retain_allpages_color_palette="\xb6"
+retain_allpages_extension="\xbe"
+
+retain_specificpage_symbol_dictionary="\xc0"
+retain_specificpage_intermediate_text_region="\xc4"
+retain_specificpage_immediate_text_region="\xc6"
+retain_specificpage_immediate_lossless_text_region="\xc7"
+retain_specificpage_pattern_dictionary="\xd0"
+retain_specificpage_intermediate_halftone_region="\xd4"
+retain_specificpage_immediate_halftone_region="\xd6"
+retain_specificpage_immediate_lossless_halftone_region="\xd7"
+retain_specificpage_intermediate_generic_region="\xe4"
+retain_specificpage_immediate_generic_region="\xe6"
+retain_specificpage_immediate_lossless_generic_region="\xe7"
+retain_specificpage_intermediate_generic_refinement_region="\xe8"
+retain_specificpage_immediate_generic_refinement_region="\xea"
+retain_specificpage_immediate_lossless_generic_refinement_regio6="\xeb"
+retain_specificpage_page_information="\xf0"
+retain_specificpage_end_of_page="\xf1"
+retain_specificpage_end_of_stripe="\xf2"
+retain_specificpage_end_of_file="\xf3"
+retain_specificpage_profiles="\xf4"
+retain_specificpage_tables="\xf5"
+retain_specificpage_color_palette="\xf6"
+retain_specificpage_extension="\xfe"
diff --git a/dictionaries/jpeg.dict b/dictionaries/jpeg.dict
new file mode 100644
index 00000000..40282f1a
--- /dev/null
+++ b/dictionaries/jpeg.dict
@@ -0,0 +1,22 @@
+#
+# AFL dictionary for JPEG images
+# ------------------------------
+#
+# Created by Michal Zalewski
+#
+
+header_jfif="JFIF\x00"
+header_jfxx="JFXX\x00"
+
+section_ffc0="\xff\xc0"
+section_ffc2="\xff\xc2"
+section_ffc4="\xff\xc4"
+section_ffd0="\xff\xd0"
+section_ffd8="\xff\xd8"
+section_ffd9="\xff\xd9"
+section_ffda="\xff\xda"
+section_ffdb="\xff\xdb"
+section_ffdd="\xff\xdd"
+section_ffe0="\xff\xe0"
+section_ffe1="\xff\xe1"
+section_fffe="\xff\xfe"
diff --git a/dictionaries/jpeg2000.dict b/dictionaries/jpeg2000.dict
new file mode 100644
index 00000000..18cc2125
--- /dev/null
+++ b/dictionaries/jpeg2000.dict
@@ -0,0 +1,22 @@
+type="jP "
+ftyp="ftyp"
+subtype1="jp2 "
+subtype2="jp20"
+subtype3="jpm "
+subtype4="jpx "
+subtype5="jp2h"
+subtype6="jpxb"
+subtype7="mjp2"
+subtype8="mj2s"
+subtype9="jp2c"
+subtype10="jpch"
+subtype11="jplh"
+codestream="\xFF\x4F\xFF\x51"
+signature="\x0d\x0a\x87\x0a"
+tag1="hdr"
+tag2="colr"
+tag3="url"
+tag4="req"
+tag5="res"
+tag6="page"
+tag7="obj"
diff --git a/dictionaries/js.dict b/dictionaries/js.dict
new file mode 100644
index 00000000..7926364c
--- /dev/null
+++ b/dictionaries/js.dict
@@ -0,0 +1,107 @@
+#
+# AFL dictionary for JavaScript
+# -----------------------------
+#
+# Contains basic reserved keywords and syntax building blocks.
+#
+# Created by Michal Zalewski
+#
+
+keyword_arguments="arguments"
+keyword_break="break"
+keyword_case="case"
+keyword_catch="catch"
+keyword_const="const"
+keyword_continue="continue"
+keyword_debugger="debugger"
+keyword_decodeURI="decodeURI"
+keyword_default="default"
+keyword_delete="delete"
+keyword_do="do"
+keyword_else="else"
+keyword_escape="escape"
+keyword_eval="eval"
+keyword_export="export"
+keyword_finally="finally"
+keyword_for="for (a=0;a<2;a++)"
+keyword_function="function"
+keyword_if="if"
+keyword_in="in"
+keyword_instanceof="instanceof"
+keyword_isNaN="isNaN"
+keyword_let="let"
+keyword_new="new"
+keyword_parseInt="parseInt"
+keyword_return="return"
+keyword_switch="switch"
+keyword_this="this"
+keyword_throw="throw"
+keyword_try="try"
+keyword_typeof="typeof"
+keyword_var="var"
+keyword_void="void"
+keyword_while="while"
+keyword_with="with"
+
+misc_1=" 1"
+misc_a="a"
+misc_array=" [1]"
+misc_assign=" a=1"
+misc_code_block=" {1}"
+misc_colon_num=" 1:"
+misc_colon_string=" 'a':"
+misc_comma=" ,"
+misc_comment_block=" /* */"
+misc_comment_line=" //"
+misc_cond=" 1?2:3"
+misc_dec=" --"
+misc_div=" /"
+misc_equals=" ="
+misc_fn=" a()"
+misc_identical=" ==="
+misc_inc=" ++"
+misc_minus=" -"
+misc_modulo=" %"
+misc_parentheses=" ()"
+misc_parentheses_1=" (1)"
+misc_parentheses_1x4=" (1,1,1,1)"
+misc_parentheses_a=" (a)"
+misc_period="."
+misc_plus=" +"
+misc_plus_assign=" +="
+misc_regex=" /a/g"
+misc_rol=" <<<"
+misc_semicolon=" ;"
+misc_serialized_object=" {'a': 1}"
+misc_string=" 'a'"
+misc_unicode=" '\\u0001'"
+
+object_Array=" Array"
+object_Boolean=" Boolean"
+object_Date=" Date"
+object_Function=" Function"
+object_Infinity=" Infinity"
+object_Int8Array=" Int8Array"
+object_Math=" Math"
+object_NaN=" NaN"
+object_Number=" Number"
+object_Object=" Object"
+object_RegExp=" RegExp"
+object_String=" String"
+object_Symbol=" Symbol"
+object_false=" false"
+object_null=" null"
+object_true=" true"
+
+prop_charAt=".charAt"
+prop_concat=".concat"
+prop_constructor=".constructor"
+prop_destructor=".destructor"
+prop_length=".length"
+prop_match=".match"
+prop_proto=".__proto__"
+prop_prototype=".prototype"
+prop_slice=".slice"
+prop_toCode=".toCode"
+prop_toString=".toString"
+prop_valueOf=".valueOf"
diff --git a/dictionaries/json.dict b/dictionaries/json.dict
new file mode 100644
index 00000000..b7604fb9
--- /dev/null
+++ b/dictionaries/json.dict
@@ -0,0 +1,61 @@
+#
+# AFL dictionary for JSON
+# -----------------------
+#
+# Just the very basics.
+#
+# Inspired by a dictionary by Jakub Wilk <jwilk@jwilk.net>
+#
+
+"0"
+",0"
+":0"
+"0:"
+"-1.2e+3"
+
+"true"
+"false"
+"null"
+
+"\"\""
+",\"\""
+":\"\""
+"\"\":"
+
+"{}"
+",{}"
+":{}"
+"{\"\":0}"
+"{{}}"
+
+"[]"
+",[]"
+":[]"
+"[0]"
+"[[]]"
+
+"''"
+"\\"
+"\\b"
+"\\f"
+"\\n"
+"\\r"
+"\\t"
+"\\u0000"
+"\\x00"
+"\\0"
+"\\uD800\\uDC00"
+"\\uDBFF\\uDFFF"
+
+"\"\":0"
+"//"
+"/**/"
+
+"$ref"
+"type"
+"coordinates"
+"@context"
+"@id"
+
+","
+":"
diff --git a/dictionaries/jsonnet.dict b/dictionaries/jsonnet.dict
new file mode 100644
index 00000000..d209328a
--- /dev/null
+++ b/dictionaries/jsonnet.dict
@@ -0,0 +1,60 @@
+# https://jsonnet.org/ref/spec.html
+
+# Keywords
+"assert"
+"else"
+"error"
+"false"
+"for"
+"function"
+"if"
+"import"
+"importstr"
+"in"
+"local"
+"null"
+"self"
+"super"
+"tailstrict"
+"then"
+"true"
+"super"
+"local"
+
+# operators
+"|||"
+"@\""
+"@'"
+"!="
+"=="
+"[::]"
+"+:::"
+
+# functions
+"std.acos("
+"std.asin("
+"std.atan("
+"std.ceil("
+"std.char("
+"std.codepoint("
+"std.cos("
+"std.equals("
+"std.exp("
+"std.exponent("
+"std.floor("
+"std.join("
+"std.length("
+"std.log("
+"std.makeArray("
+"std.mantissa("
+"std.mod"
+"std.modulo("
+"std.objectFiledsEx("
+"std.objectsHasEx("
+"std.pow("
+"std.primitiveEquals("
+"std.sin("
+"std.slice("
+"std.sqrt("
+"std.tan("
+"std.type("
diff --git a/dictionaries/markdown.dict b/dictionaries/markdown.dict
new file mode 100644
index 00000000..be94db29
--- /dev/null
+++ b/dictionaries/markdown.dict
@@ -0,0 +1,28 @@
+strike="~~"
+list="2."
+link="[a]("
+link_without_ref="[a]["
+image="![b]("
+bold="**"
+separator="---"
+title="# "
+fence="```"
+link_bottom="[a]:"
+link_inline="<http://"
+link_bottom_title="[1]: http://a.com"
+checklist="- [x"
+toc="[TOC]"
+highlight_rst=":::python"
+
+
+# GFM - https://github.github.com/gfm/
+"| ---"
+leaf1="***"
+leaf2="___"
+code_hl="```html"
+task="- [ ]"
+
+
+# Extended syntax: https://www.markdownguide.org/extended-syntax/
+footnote="[^a]"
+title_id="#a {#b}"
diff --git a/dictionaries/math.dict b/dictionaries/math.dict
new file mode 100644
index 00000000..ca0e0ee8
--- /dev/null
+++ b/dictionaries/math.dict
@@ -0,0 +1,20 @@
+"{"
+"}"
+","
+"["
+"]"
+","
+":"
+"e"
+"e+"
+"e-"
+"E"
+"E+"
+"E-"
+"\""
+"\\"
+" "
+"null"
+"1"
+"1.234"
+"3e4"
diff --git a/dictionaries/mathml.dict b/dictionaries/mathml.dict
new file mode 100644
index 00000000..56c7a209
--- /dev/null
+++ b/dictionaries/mathml.dict
@@ -0,0 +1,279 @@
+#https://developer.mozilla.org/en-US/docs/Web/MathML/Element
+# https://www.w3.org/TR/MathML3/chapter4.html
+
+header="<math xmlns='http://www.w3.org/1998/Math/MathML'>"
+
+# presentation mathml
+"<annotation-xml>"
+"<annotation>"
+"<apply>"
+"<maction>"
+"<maligngroup>"
+"<malignmark>"
+"<math>"
+"<menclose>"
+"<merror>"
+"<mfenced> "
+"<mfrac>"
+"<mglyph>"
+"<mi>"
+"<mlabeledtr>"
+"<mlongdiv>"
+"<mmultiscripts>"
+"<mn>"
+"<mo>"
+"<mover>"
+"<mpadded>"
+"<mphantom>"
+"<mprescripts>"
+"<mroot>"
+"<mrow>"
+"<ms>"
+"<mscarries>"
+"<mscarry>"
+"<msgroup>"
+"<msline>"
+"<mspace>"
+"<msqrt>"
+"<msrow>"
+"<mstack>"
+"<mstyle>"
+"<msub>"
+"<msubsup>"
+"<msup>"
+"<mtable>"
+"<mtd>"
+"<mtext>"
+"<mtr>"
+"<munder>"
+"<munderover>"
+"<none>"
+"<semantics>"
+
+# attributes
+"accent"
+"accentunder"
+"actiontype"
+"align"
+"alignmentscope"
+"altimg"
+"altimg-height"
+"alttext"
+"bevelled"
+"charalign"
+"close"
+"columnalign"
+"columnlines"
+"columnspacing"
+"columnspan"
+"columnwidth"
+"crossout"
+"decimalpoint"
+"denomalign"
+"depth"
+"dir"
+"display"
+"displaystyle"
+"edge"
+"equalcolumns"
+"equalrows"
+"fence"
+"form"
+"frame"
+"framespacing"
+"groupalign"
+"height"
+"href"
+"id"
+"indentalign"
+"indentalignfirst"
+"indentalignlast"
+"indentshift"
+"indentshiftfirst"
+"indentshiftlast"
+"indenttarget"
+"infixlinebreakstyle"
+"largeop"
+"length"
+"linebreak"
+"linebreakmultchar"
+"linebreakstyle"
+"lineleading"
+"linethickness"
+"location"
+"longdivstyle"
+"lquote"
+"lspace"
+"mathbackground"
+"mathcolor"
+"mathsize"
+"mathvariant"
+"maxsize"
+"minlabelspacing"
+"minsize"
+"movablelimits"
+"notation"
+"numalign"
+"open"
+"overflow"
+"position"
+"rowalign"
+"rowlines"
+"rowspacing"
+"rowspan"
+"rquote"
+"rspace"
+"scriptlevel"
+"scriptminsize"
+"scriptsizemultiplier"
+"selection"
+"separator"
+"separators"
+"shift"
+"side"
+"src"
+"stackalign"
+"stretchy"
+"subscriptshift"
+"supscriptshift"
+"symmetric"
+"voffset"
+"width"
+"xlink:href"
+"xmlns"
+
+# content mathml
+"<interval>"
+"<inverse>"
+"<lambda>"
+"<compose/>"
+"<ident/>"
+"<domain/>"
+"<codomain/>"
+"<image/>"
+"<piecewise>"
+"<piece>"
+"<otherwise>"
+"<quotient/>"
+"<factorial/>"
+"<divide/>"
+"<max/>"
+"<min/>"
+"<minus/>"
+"<plus/>"
+"<power/>"
+"<rem/>"
+"<times/>"
+"<root/>"
+"<gcd/>"
+"<and/>"
+"<or/>"
+"<xor/>"
+"<not/>"
+"<implies/>"
+"<forall/>"
+"<exists/>"
+"<abs/>"
+"<conjugate/>"
+"<arg/>"
+"<real/>"
+"<imaginary/>"
+"<lcm/>"
+"<floor/>"
+"<ceiling/>"
+"Relations"
+"<eq/>"
+"<neq/>"
+"<gt/>"
+"<lt/>"
+"<geq/>"
+"<leq/>"
+"<equivalent/>"
+"<approx/>"
+"<factorof/>"
+"<int/>"
+"<diff/>"
+"<partialdiff/>"
+"<divergence/>"
+"<grad/>"
+"<curl/>"
+"<laplacian/>"
+"<set>"
+"<list>"
+"<union/>"
+"<intersect/>"
+"<in/>"
+"<notin/>"
+"<subset/>"
+"<prsubset/>"
+"<notsubset/>"
+"<notprsubset/>"
+"<setdiff/>"
+"<card/>"
+"<cartesianproduct/>"
+"<sum/>"
+"<product/>"
+"<limit/>"
+"<tendsto/>"
+"<sin/>"
+"<cos/>"
+"<tan/>"
+"<sec/>"
+"<csc/>"
+"<cot/>"
+"<arcsin/>"
+"<arccos/>"
+"<arctan/>"
+"<arcsec/>"
+"<arccsc/>"
+"<arccot/>"
+"<sinh/>"
+"<cosh/>"
+"<tanh/>"
+"<sech/>"
+"<csch/>"
+"<coth/>"
+"<arcsinh/>"
+"<arccosh/>"
+"<arctanh/>"
+"<arcsech/>"
+"<arccsch/>"
+"<arccoth/>"
+"<exp/>"
+"<ln/>"
+"<log/>"
+"<logbase>"
+"<mean/>"
+"<sdev/>"
+"<variance/>"
+"<median/>"
+"<mode/>"
+"<moment/>"
+"<momentabout>"
+"<vector>"
+"<matrix>"
+"<matrixrow>"
+"<determinant/>"
+"<transpose/>"
+"<selector/>"
+"<vectorproduct/>"
+"<scalarproduct/>"
+"<outerproduct/>"
+"<integers/>"
+"<reals/>"
+"<rationals/>"
+"<naturalnumbers/>"
+"<complexes/>"
+"<primes/>"
+"<exponentiale/>"
+"<imaginaryi/>"
+"<notanumber/>"
+"<true/>"
+"<false/>"
+"<emptyset/>"
+"<pi/>"
+"<eulergamma/>"
+"<infinity/>"
+"<declare>"
+"<reln>"
+"<fn>"
diff --git a/dictionaries/mp4.dict b/dictionaries/mp4.dict
new file mode 100644
index 00000000..1755faba
--- /dev/null
+++ b/dictionaries/mp4.dict
@@ -0,0 +1,82 @@
+# Taken from https://chromium.googlesource.com/chromium/src/+/master/media/test/mp4.dict
+
+FOURCC_NULL="\x00\x00\x00\x00"
+FOURCC_AC3 ="\x61\x63\x2d\x33"
+FOURCC_EAC3="\x65\x63\x2d\x33"
+FOURCC_AVC1="\x61\x76\x63\x31"
+FOURCC_AVC3="\x61\x76\x63\x33"
+FOURCC_AVCC="\x61\x76\x63\x43"
+FOURCC_BLOC="\x62\x6C\x6F\x63"
+FOURCC_CENC="\x63\x65\x6e\x63"
+FOURCC_CO64="\x63\x6f\x36\x34"
+FOURCC_CTTS="\x63\x74\x74\x73"
+FOURCC_DINF="\x64\x69\x6e\x66"
+FOURCC_EDTS="\x65\x64\x74\x73"
+FOURCC_EMSG="\x65\x6d\x73\x67"
+FOURCC_ELST="\x65\x6c\x73\x74"
+FOURCC_ENCA="\x65\x6e\x63\x61"
+FOURCC_ENCV="\x65\x6e\x63\x76"
+FOURCC_ESDS="\x65\x73\x64\x73"
+FOURCC_FREE="\x66\x72\x65\x65"
+FOURCC_FRMA="\x66\x72\x6d\x61"
+FOURCC_FTYP="\x66\x74\x79\x70"
+FOURCC_HDLR="\x68\x64\x6c\x72"
+FOURCC_HINT="\x68\x69\x6e\x74"
+FOURCC_HVC1="\x68\x76\x63\x31"
+FOURCC_HVCC="\x68\x76\x63\x43"
+FOURCC_IODS="\x69\x6f\x64\x73"
+FOURCC_MDAT="\x6d\x64\x61\x74"
+FOURCC_MDHD="\x6d\x64\x68\x64"
+FOURCC_MDIA="\x6d\x64\x69\x61"
+FOURCC_MECO="\x6d\x65\x63\x6f"
+FOURCC_MEHD="\x6d\x65\x68\x64"
+FOURCC_META="\x6d\x65\x74\x61"
+FOURCC_MFHD="\x6d\x66\x68\x64"
+FOURCC_MFRA="\x6d\x66\x72\x61"
+FOURCC_MINF="\x6d\x69\x6e\x66"
+FOURCC_MOOF="\x6d\x6f\x6f\x66"
+FOURCC_MOOV="\x6d\x6f\x6f\x76"
+FOURCC_MP4A="\x6d\x70\x34\x61"
+FOURCC_MP4V="\x6d\x70\x34\x76"
+FOURCC_MVEX="\x6d\x76\x65\x78"
+FOURCC_MVHD="\x6d\x76\x68\x64"
+FOURCC_PASP="\x70\x61\x73\x70"
+FOURCC_PDIN="\x70\x64\x69\x6e"
+FOURCC_PRFT="\x70\x72\x66\x74"
+FOURCC_PSSH="\x70\x73\x73\x68"
+FOURCC_SAIO="\x73\x61\x69\x6f"
+FOURCC_SAIZ="\x73\x61\x69\x7a"
+FOURCC_SBGP="\x73\x62\x67\x70"
+FOURCC_SCHI="\x73\x63\x68\x69"
+FOURCC_SCHM="\x73\x63\x68\x6d"
+FOURCC_SDTP="\x73\x64\x74\x70"
+FOURCC_SEIG="\x73\x65\x69\x67"
+FOURCC_SENC="\x73\x65\x6e\x63"
+FOURCC_SGPD="\x73\x67\x70\x64"
+FOURCC_SIDX="\x73\x69\x64\x78"
+FOURCC_SINF="\x73\x69\x6e\x66"
+FOURCC_SKIP="\x73\x6b\x69\x70"
+FOURCC_SMHD="\x73\x6d\x68\x64"
+FOURCC_SOUN="\x73\x6f\x75\x6e"
+FOURCC_SSIX="\x73\x73\x69\x78"
+FOURCC_STBL="\x73\x74\x62\x6c"
+FOURCC_STCO="\x73\x74\x63\x6f"
+FOURCC_STSC="\x73\x74\x73\x63"
+FOURCC_STSD="\x73\x74\x73\x64"
+FOURCC_STSS="\x73\x74\x73\x73"
+FOURCC_STSZ="\x73\x74\x73\x7a"
+FOURCC_STTS="\x73\x74\x74\x73"
+FOURCC_STYP="\x73\x74\x79\x70"
+FOURCC_TENC="\x74\x65\x6e\x63"
+FOURCC_TFDT="\x74\x66\x64\x74"
+FOURCC_TFHD="\x74\x66\x68\x64"
+FOURCC_TKHD="\x74\x6b\x68\x64"
+FOURCC_TRAF="\x74\x72\x61\x66"
+FOURCC_TRAK="\x74\x72\x61\x6b"
+FOURCC_TREX="\x74\x72\x65\x78"
+FOURCC_TRUN="\x74\x72\x75\x6e"
+FOURCC_UDTA="\x75\x64\x74\x61"
+FOURCC_UUID="\x75\x75\x69\x64"
+FOURCC_VIDE="\x76\x69\x64\x65"
+FOURCC_VMHD="\x76\x6d\x68\x64"
+FOURCC_WIDE="\x77\x69\x64\x65"
diff --git a/dictionaries/mysqld.dict b/dictionaries/mysqld.dict
new file mode 100644
index 00000000..33c97f6e
--- /dev/null
+++ b/dictionaries/mysqld.dict
@@ -0,0 +1 @@
+user="root"
diff --git a/dictionaries/ogg.dict b/dictionaries/ogg.dict
new file mode 100644
index 00000000..27a08e45
--- /dev/null
+++ b/dictionaries/ogg.dict
@@ -0,0 +1,36 @@
+# https://xiph.org/vorbis/doc/Vorbis_I_spec.html
+
+header="OggS"
+
+# Codecs
+"BBCD\x00"
+"\x7fFLAC"
+"\x80theora"
+"\x01vorbis"
+"CELT "
+"CMML\x00\x00\x00\x00"
+"\x8bJNG\x0d\x0a\x1a\x0a"
+"\x80kate\x00\x00\x00"
+"OggMIDI\x00"
+"\x8aMNG\x0d\x0a\x1a\x0a"
+"PCM "
+"\x89PNG\x0d\x0a\x1a\x0a"
+"Speex "
+"YUV4MPEG"
+
+# Metadata
+"TITLE="
+"VERSION="
+"ALBUM="
+"TRACKNUMBER="
+"ARTIST="
+"PERFORMER="
+"COPYRIGHT="
+"LICENSE="
+"ORGANIZATION="
+"DESCRIPTION="
+"GENRE="
+"DATE="
+"LOCATION="
+"CONTACT="
+"ISRC="
diff --git a/dictionaries/openexr.dict b/dictionaries/openexr.dict
new file mode 100644
index 00000000..05c90ca1
--- /dev/null
+++ b/dictionaries/openexr.dict
@@ -0,0 +1,57 @@
+# specs:
+# - https://www.openexr.com/documentation/openexrfilelayout.pdf
+# - https://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/OpenEXR.html
+
+lay="_lay"
+ver="_ver"
+adoptNeutral="AdoptNeutral"
+altitude="altitude"
+aperture="aperture"
+box2f="box2f"
+box2i="box2i"
+capdate="capDate"
+channels="channels"
+chlist="chlist"
+chromaticities="chromaticities"
+comments="comments"
+compression="compression"
+dataWindow="dataWindow"
+displayWindow="displayWindow"
+double="double"
+envmap="envmap"
+expTime="expTime"
+focus="focus"
+framesPerSecond="framesPerSecond"
+float="float"
+header="\x76\x2F\x31\x01"
+int="int"
+isoSpeed="isoSpeed"
+keycode="keyCode"
+latitude="latitude"
+lineOrder="lineOrder"
+longitude="longitude"
+lookModTransform="lookModTransform"
+m33f="m33f"
+m44f="m44f"
+owner="owner"
+pixelAspectRatio="pixelAspectRatio"
+preview="preview"
+renderingTransform="renderingTransform"
+rational="rational"
+screenWindowCenter="screenWindowCenter"
+screenWindowWidth="screenWindowWidth"
+string="string"
+stringvector="stringvector"
+tiles="tiles"
+tiledesc="tileDesc"
+timecode="timeCode"
+utcOffset="itcOffset"
+whiteLuminance="whiteLuminance"
+worldToCamera="worldToCamera"
+worldToNDC="worldToNDC"
+v2f="v2f"
+v2i="v2i"
+v3f="v3f"
+v3i="v3i"
+wrapmodes="wrapmodes"
+xDensity="xDensity"
diff --git a/dictionaries/otf.dict b/dictionaries/otf.dict
new file mode 100644
index 00000000..b5b603e5
--- /dev/null
+++ b/dictionaries/otf.dict
@@ -0,0 +1,963 @@
+# https://docs.microsoft.com/en-us/typography/opentype/spec/
+
+# magic
+"ttcf"
+
+# feature tags
+"aalt"
+"abvf"
+"abvm"
+"abvs"
+"afrc"
+"akhn"
+"blwf"
+"blwm"
+"blws"
+"calt"
+"case"
+"ccmp"
+"cfar"
+"cjct"
+"clig"
+"cpct"
+"cpsp"
+"cswh"
+"curs"
+"cv01"
+"c2pc"
+"c2sc"
+"dist"
+"dlig"
+"dnom"
+"dtls"
+"expt"
+"falt"
+"fin2"
+"fin3"
+"fina"
+"flac"
+"frac"
+"fwid"
+"half"
+"haln"
+"halt"
+"hist"
+"hkna"
+"hlig"
+"hngl"
+"hojo"
+"hwid"
+"init"
+"isol"
+"ital"
+"jalt"
+"jp78"
+"jp83"
+"jp90"
+"jp04"
+"kern"
+"lfbd"
+"liga"
+"ljmo"
+"lnum"
+"locl"
+"ltra"
+"ltrm"
+"mark"
+"med2"
+"medi"
+"mgrk"
+"mkmk"
+"mset"
+"nalt"
+"nlck"
+"nukt"
+"numr"
+"onum"
+"opbd"
+"ordn"
+"ornm"
+"palt"
+"pcap"
+"pkna"
+"pnum"
+"pref"
+"pres"
+"pstf"
+"psts"
+"pwid"
+"qwid"
+"rand"
+"rclt"
+"rlig"
+"rkrf"
+"rphf"
+"rtbd"
+"rtla"
+"rtlm"
+"ruby"
+"rvrn"
+"salt"
+"sinf"
+"size"
+"smcp"
+"smpl"
+"ss01"
+"ssty"
+"stch"
+"subs"
+"sups"
+"swsh"
+"titl"
+"tjmo"
+"tnam"
+"tnum"
+"trad"
+"twid"
+"unic"
+"valt"
+"vatu"
+"vert"
+"vhal"
+"vjmo"
+"vkna"
+"vkrn"
+"vpal"
+"vrt2"
+"vrtr"
+"zero"
+
+# baseline tags
+"hang"
+"icfb"
+"ictf"
+"ideo"
+"idtp"
+"math"
+"romn"
+
+# axis tags
+"ital"
+"opsz"
+"slnt"
+"wdth"
+"wght"
+
+# tables
+"BASE"
+"CBDT"
+"CBLC"
+"CFF"
+"CFF2"
+"COLR"
+"CPAL"
+"DSIG"
+"EBDT"
+"EBLC"
+"EBSC"
+"GDEF"
+"GPOS"
+"GSUB"
+"HVAR"
+"JSTF"
+"LTSH"
+"MATH"
+"MERG"
+"MVAR"
+"OTTO"
+"PCLT"
+"STAT"
+"SVG"
+"VDMX"
+"VORG"
+"VVAR"
+"avar"
+"cmap"
+"cmat"
+"cvar"
+"cvt"
+"fpgm"
+"fvar"
+"gasp"
+"glyf"
+"gvar"
+"hdmx"
+"head"
+"hhea"
+"hmtx"
+"kern"
+"loca"
+"maxp"
+"meta"
+"name"
+"post"
+"prep"
+"sbix"
+"vhea"
+"vmtx"
+
+# script tags
+"adlm"
+"ahom"
+"hluw"
+"arab"
+"armn"
+"avst"
+"bali"
+"bamu"
+"bass"
+"batk"
+"beng"
+"bng2"
+"bhks"
+"bopo"
+"brah"
+"brai"
+"bugi"
+"buhd"
+"byzm"
+"cans"
+"cari"
+"aghb"
+"cakm"
+"cham"
+"cher"
+"hani"
+"copt"
+"cprt"
+"cyrl"
+"dsrt"
+"deva"
+"dev2"
+"dogr"
+"dupl"
+"egyp"
+"elba"
+"ethi"
+"geor"
+"glag"
+"goth"
+"gran"
+"grek"
+"gujr"
+"gjr2"
+"gong"
+"guru"
+"gur2"
+"hang"
+"jamo"
+"rohg"
+"hano"
+"hatr"
+"hebr"
+"kana"
+"armi"
+"phli"
+"prti"
+"java"
+"kthi"
+"knda"
+"knd2"
+"kana"
+"kali"
+"khar"
+"khmr"
+"khoj"
+"sind"
+"lao "
+"latn"
+"lepc"
+"limb"
+"lina"
+"linb"
+"lisu"
+"lyci"
+"lydi"
+"mahj"
+"maka"
+"mlym"
+"mlm2"
+"mand"
+"mani"
+"marc"
+"gonm"
+"math"
+"medf"
+"mtei"
+"mend"
+"merc"
+"mero"
+"plrd"
+"modi"
+"mong"
+"mroo"
+"mult"
+"musc"
+"mymr"
+"mym2"
+"nbat"
+"newa"
+"talu"
+"nko "
+"nshu"
+"orya"
+"ory2"
+"ogam"
+"olck"
+"ital"
+"hung"
+"narb"
+"perm"
+"xpeo"
+"sogo"
+"sarb"
+"orkh"
+"osge"
+"osma"
+"hmng"
+"palm"
+"pauc"
+"phag"
+"phnx"
+"phlp"
+"rjng"
+"runr"
+"samr"
+"saur"
+"shrd"
+"shaw"
+"sidd"
+"sgnw"
+"sinh"
+"sogd"
+"sora"
+"soyo"
+"xsux"
+"sund"
+"sylo"
+"syrc"
+"tglg"
+"tagb"
+"tale"
+"lana"
+"tavt"
+"takr"
+"taml"
+"tml2"
+"tang"
+"telu"
+"tel2"
+"thaa"
+"thai"
+"tibt"
+"tfng"
+"tirh"
+"ugar"
+"vai "
+"wara"
+"yi "
+"zanb"
+
+# language tags
+"ABA "
+"ABK "
+"ACH "
+"ACR "
+"ADY "
+"AFK "
+"AFR "
+"AGW "
+"AIO "
+"AKA "
+"ALS "
+"ALT "
+"AMH "
+"ANG "
+"APPH"
+"ARA "
+"ARG "
+"ARI "
+"ARK "
+"ASM "
+"AST "
+"ATH "
+"AVR "
+"AWA "
+"AYM "
+"AZB "
+"AZE "
+"BAD "
+"BAD0"
+"BAG "
+"BAL "
+"BAN "
+"BAR "
+"BAU "
+"BBC "
+"BBR "
+"BCH "
+"BCR "
+"BDY "
+"BEL "
+"BEM "
+"BEN "
+"BGC "
+"BGQ "
+"BGR "
+"BHI "
+"BHO "
+"BIK "
+"BIL "
+"BIS "
+"BJJ "
+"BKF "
+"BLI "
+"BLK "
+"BLN "
+"BLT "
+"BMB "
+"BML "
+"BOS "
+"BPY "
+"BRE "
+"BRH "
+"BRI "
+"BRM "
+"BRX "
+"BSH "
+"BSK "
+"BTI "
+"BTS "
+"BUG "
+"BYV "
+"CAK "
+"CAT "
+"CBK "
+"CCHN"
+"CEB "
+"CHE "
+"CHG "
+"CHH "
+"CHI "
+"CHK "
+"CHK0"
+"CHO "
+"CHP "
+"CHR "
+"CHA "
+"CHU "
+"CHY "
+"CGG "
+"CJA "
+"CJM "
+"CMR "
+"COP "
+"COR "
+"COS "
+"CPP "
+"CRE "
+"CRR "
+"CRT "
+"CSB "
+"CSL "
+"CSY "
+"CTG "
+"CUK "
+"DAN "
+"DAR "
+"DAX "
+"DCR "
+"DEU "
+"DGO "
+"DGR "
+"DHG "
+"DHV "
+"DIQ "
+"DIV "
+"DJR "
+"DJR0"
+"DNG "
+"DNJ "
+"DNK "
+"DRI "
+"DUJ "
+"DUN "
+"DZN "
+"EBI "
+"ECR "
+"EDO "
+"EFI "
+"ELL "
+"EMK "
+"ENG "
+"ERZ "
+"ESP "
+"ESU "
+"ETI "
+"EUQ "
+"EVK "
+"EVN "
+"EWE "
+"FAN "
+"FAN0"
+"FAR "
+"FAT "
+"FIN "
+"FJI "
+"FLE "
+"FMP "
+"FNE "
+"FON "
+"FOS "
+"FRA "
+"FRC "
+"FRI "
+"FRL "
+"FRP "
+"FTA "
+"FUL "
+"FUV "
+"GAD "
+"GAE "
+"GAG "
+"GAL "
+"GAR "
+"GAW "
+"GEZ "
+"GIH "
+"GIL "
+"GIL0"
+"GKP "
+"GLK "
+"GMZ "
+"GNN "
+"GOG "
+"GON "
+"GRN "
+"GRO "
+"GUA "
+"GUC "
+"GUF "
+"GUJ "
+"GUZ "
+"HAI "
+"HAL "
+"HAR "
+"HAU "
+"HAW "
+"HAY "
+"HAZ "
+"HBN "
+"HER "
+"HIL "
+"HIN "
+"HMA "
+"HMN "
+"HMO "
+"HND "
+"HO "
+"HRI "
+"HRV "
+"HUN "
+"HYE "
+"HYE0"
+"IBA "
+"IBB "
+"IBO "
+"IJO "
+"IDO "
+"ILE "
+"ILO "
+"INA "
+"IND "
+"ING "
+"INU "
+"IPK "
+"IPPH"
+"IRT "
+"ISL "
+"ISM "
+"ITA "
+"IWR "
+"JAM "
+"JAN "
+"JAV "
+"JBO "
+"JCT "
+"JII "
+"JUD "
+"JUL "
+"KAB "
+"KAB0"
+"KAC "
+"KAL "
+"KAN "
+"KAR "
+"KAT "
+"KAZ "
+"KDE "
+"KEA "
+"KEB "
+"KEK "
+"KGE "
+"KHA "
+"KHK "
+"KHM "
+"KHS "
+"KHT "
+"KHV "
+"KHW "
+"KIK "
+"KIR "
+"KIS "
+"KIU "
+"KJD "
+"KJP "
+"KJZ "
+"KKN "
+"KLM "
+"KMB "
+"KMN "
+"KMO "
+"KMS "
+"KMZ "
+"KNR "
+"KOD "
+"KOH "
+"KOK "
+"KON "
+"KOM "
+"KON0"
+"KOP "
+"KOR "
+"KOS "
+"KOZ "
+"KPL "
+"KRI "
+"KRK "
+"KRL "
+"KRM "
+"KRN "
+"KRT "
+"KSH "
+"KSH0"
+"KSI "
+"KSM "
+"KSW "
+"KUA "
+"KUI "
+"KUL "
+"KUM "
+"KUR "
+"KUU "
+"KUY "
+"KYK "
+"KYU "
+"LAD "
+"LAH "
+"LAK "
+"LAM "
+"LAO "
+"LAT "
+"LAZ "
+"LCR "
+"LDK "
+"LEZ "
+"LIJ "
+"LIM "
+"LIN "
+"LIS "
+"LJP "
+"LKI "
+"LMA "
+"LMB "
+"LMO "
+"LMW "
+"LOM "
+"LRC "
+"LSB "
+"LSM "
+"LTH "
+"LTZ "
+"LUA "
+"LUB "
+"LUG "
+"LUH "
+"LUO "
+"LVI "
+"MAD "
+"MAG "
+"MAH "
+"MAJ "
+"MAK "
+"MAL "
+"MAM "
+"MAN "
+"MAP "
+"MAR "
+"MAW "
+"MBN "
+"MBO "
+"MCH "
+"MCR "
+"MDE "
+"MDR "
+"MEN "
+"MER "
+"MFA "
+"MFE "
+"MIN "
+"MIZ "
+"MKD "
+"MKR "
+"MKW "
+"MLE "
+"MLG "
+"MLN "
+"MLR "
+"MLY "
+"MND "
+"MNG "
+"MNI "
+"MNK "
+"MNX "
+"MOH "
+"MOK "
+"MOL "
+"MON "
+"MOR "
+"MOS "
+"MRI "
+"MTH "
+"MTS "
+"MUN "
+"MUS "
+"MWL "
+"MWW "
+"MYN "
+"MZN "
+"NAG "
+"NAH "
+"NAN "
+"NAP "
+"NAS "
+"NAU "
+"NAV "
+"NCR "
+"NDB "
+"NDC "
+"NDG "
+"NDS "
+"NEP "
+"NEW "
+"NGA "
+"NGR "
+"NHC "
+"NIS "
+"NIU "
+"NKL "
+"NKO "
+"NLD "
+"NOE "
+"NOG "
+"NOR "
+"NOV "
+"NSM "
+"NSO "
+"NTA "
+"NTO "
+"NYM "
+"NYN "
+"NZA "
+"OCI "
+"OCR "
+"OJB "
+"ORI "
+"ORO "
+"OSS "
+"PAA "
+"PAG "
+"PAL "
+"PAM "
+"PAN "
+"PAP "
+"PAP0"
+"PAS "
+"PAU "
+"PCC "
+"PCD "
+"PDC "
+"PGR "
+"PHK "
+"PIH "
+"PIL "
+"PLG "
+"PLK "
+"PMS "
+"PNB "
+"POH "
+"PON "
+"PRO "
+"PTG "
+"PWO "
+"QIN "
+"QUC "
+"QUH "
+"QUZ "
+"QVI "
+"QWH "
+"RAJ "
+"RAR "
+"RBU "
+"RCR "
+"REJ "
+"RIA "
+"RIF "
+"RIT "
+"RKW "
+"RMS "
+"RMY "
+"ROM "
+"ROY "
+"RSY "
+"RTM "
+"RUA "
+"RUN "
+"RUP "
+"RUS "
+"SAD "
+"SAN "
+"SAS "
+"SAT "
+"SAY "
+"SCN "
+"SCO "
+"SEK "
+"SEL "
+"SGA "
+"SGO "
+"SGS "
+"SHI "
+"SHN "
+"SIB "
+"SID "
+"SIG "
+"SKS "
+"SKY "
+"SCS "
+"SLA "
+"SLV "
+"SML "
+"SMO "
+"SNA "
+"SNA0"
+"SND "
+"SNH "
+"SNK "
+"SOG "
+"SOP "
+"SOT "
+"SQI "
+"SRB "
+"SRD "
+"SRK "
+"SRR "
+"SSL "
+"SSM "
+"STQ "
+"SUK "
+"SUN "
+"SUR "
+"SVA "
+"SVE "
+"SWA "
+"SWK "
+"SWZ "
+"SXT "
+"SXU "
+"SYL "
+"SYR "
+"SYRE"
+"SYRJ"
+"SYRN"
+"SZL "
+"TAB "
+"TAJ "
+"TAM "
+"TAT "
+"TCR "
+"TDD "
+"TEL "
+"TET "
+"TGL "
+"TGN "
+"TGR "
+"TGY "
+"THA "
+"THT "
+"TIB "
+"TIV "
+"TKM "
+"TMH "
+"TMN "
+"TNA "
+"TNE "
+"TNG "
+"TOD "
+"TOD0"
+"TPI "
+"TRK "
+"TSG "
+"TSJ "
+"TUA "
+"TUM "
+"TUL "
+"TUV "
+"TVL "
+"TWI "
+"TYZ "
+"TZM "
+"TZO "
+"UDM "
+"UKR "
+"UMB "
+"URD "
+"USB "
+"UYG "
+"UZB "
+"VEC "
+"VEN "
+"VIT "
+"VOL "
+"VRO "
+"WA "
+"WAG "
+"WAR "
+"WCR "
+"WEL "
+"WLN "
+"WLF "
+"WTM "
+"XBD "
+"XKF "
+"XHS "
+"XJB "
+"XOG "
+"XPE "
+"YAK "
+"YAO "
+"YAP "
+"YBA "
+"YCR "
+"YIC "
+"YIM "
+"ZEA "
+"ZGH "
+"ZHA "
+"ZHH "
+"ZHP "
+"ZHS "
+"ZHT "
+"ZND "
+"ZUL "
+"ZZA "
diff --git a/dictionaries/pbm.dict b/dictionaries/pbm.dict
new file mode 100644
index 00000000..98d61cab
--- /dev/null
+++ b/dictionaries/pbm.dict
@@ -0,0 +1,29 @@
+# https://en.wikipedia.org/wiki/Netpbm_format
+header1="P1"
+header2="P2"
+header3="P3"
+header4="P4"
+header5="P5"
+header6="P6"
+zero="0"
+one="1"
+comment="#"
+max="255"
+overflow="256"
+
+# PAM - https://en.wikipedia.org/wiki/Netpbm#PAM_graphics_format
+header7="P7"
+width="WIDTH"
+height="HEIGHT"
+depth="DEPTH"
+maxval="MAXVAL"
+enhdr="ENDHDR"
+tupltype="TUPLTYPE"
+tupltype1="RGB_ALPHA"
+tupltype2="RGB"
+typltype3="BLACKANDWHITE"
+typltype4="BLACKANDWHITE_ALPHA"
+typltype5="GRAYSCALE"
+typltype6="GRAYSCALE_ALPHA"
+maxval_num="65535"
+maxval_overlfow="65536"
diff --git a/dictionaries/pcap.dict b/dictionaries/pcap.dict
new file mode 100644
index 00000000..0ac622b8
--- /dev/null
+++ b/dictionaries/pcap.dict
@@ -0,0 +1,10 @@
+# https://www.tcpdump.org/pcap/pcap.html
+
+# Headers
+"\xa1\xb2\xc3\xd4"
+"\xd4\xc3\xb2\xa1"
+"\xa1\xb2\x3c\x4d"
+"\x4d\x3c\xb2\xa1"
+
+
+current_version="\x02\x00\x04\x00"
diff --git a/dictionaries/pdf.dict b/dictionaries/pdf.dict
new file mode 100644
index 00000000..a6c48d59
--- /dev/null
+++ b/dictionaries/pdf.dict
@@ -0,0 +1,1466 @@
+#
+# AFL dictionary for PDF
+# ----------------------
+#
+# This is a pretty big PDF dictionary constructed by Ben by manually reviewing
+# the spec and combining that with the data pulled out of a corpus of sample
+# PDFs.
+#
+# Contributed by Ben Nagy <ben@iagu.net>
+#
+
+"#"
+"%"
+"%%"
+"%%EOF"
+"%FDF-1.7"
+"%PDF-1.7"
+"("
+"(/xdp:xdp)"
+"(\\001)"
+"(config)"
+"(datasets)"
+"(template)"
+"(xdp:xdp)"
+")"
+"-1"
+"-1.0"
+".."
+"/"
+"/#23clipboard"
+"/.notdef"
+"/1"
+"/1.0"
+"/1.3"
+"/3D"
+"/3DA"
+"/3DAnimationStyle"
+"/3DB"
+"/3DD"
+"/3DI"
+"/3DLightingScheme"
+"/3DRenderMode"
+"/3DV"
+"/3DView"
+"/90pv-RKSJ-H"
+"/A"
+"/A0"
+"/A85"
+"/AA"
+"/AAIC"
+"/AAPL"
+"/ABCDEF+ACaslonPro-Regular"
+"/ABCDEF+AJensonPro-LtIt"
+"/ABCDEF+AdobeCorpID-MinionRg"
+"/ABCDEF+Arial,Bold"
+"/ABCDEF+BankGothicMdBT"
+"/ABCDEF+Bauhaus-Heavy"
+"/ABCDEF+BluesClues"
+"/ABCDEF+BodegaSans"
+"/ABCDEF+BodoniMTCondensed"
+"/ABCDEF+BookAntiqua"
+"/ABCDEF+CMBX10"
+"/ABCDEF+CaflischScriptPro-Regular"
+"/ABCDEF+CityBlueprint"
+"/ABCDEF+CourierNewPSMT"
+"/ABCDEF+FixedsysExcelsior2.00"
+"/ABCDEF+MSTT31854bd45bo188067S00"
+"/ABCDEF+MinionPro-BoldCnIt"
+"/ABCDEF+MyriadMM-It_400_300_"
+"/ABCDEF+Wingdings"
+"/ABCDEF+ZapfDingbats"
+"/AC"
+"/ADBE"
+"/ADB_DEVICE_DEFAULT_STYLE"
+"/ADB_DefaultStyle"
+"/ADB_NO_TRAP_STYLE"
+"/AE"
+"/AESV2"
+"/AGaramond"
+"/AH"
+"/AI8DstIndex"
+"/AI8SrcIndex"
+"/AIMetaData"
+"/AIPDFPrivateData1"
+"/AIS"
+"/AL"
+"/AN"
+"/AP"
+"/AS"
+"/ASCII85Decode"
+"/ASCIIHexDecode"
+"/ASomewhatLongerName"
+"/AU"
+"/Aacute"
+"/Acc.#20Prod.#202501#20#2F2#20#20"
+"/Accounts#20payable"
+"/AccurateScreens"
+"/Acircumflex"
+"/AcroForm"
+"/Action"
+"/Actual"
+"/Add"
+"/Adieresis"
+"/Adobe"
+"/Adobe#20PDF#20Library"
+"/Adobe.PPKLite"
+"/AdobeCorpID-Acrobat"
+"/AdobeCorpID-MinionRg"
+"/AdobePhotoshop"
+"/Agrave"
+"/All"
+"/AllKO"
+"/AllOn"
+"/Alt"
+"/Alternate"
+"/AlternatePresentations"
+"/Alternates"
+"/Amex"
+"/And"
+"/Angle"
+"/Annot"
+"/Annots"
+"/AntiAlias"
+"/AnyOn"
+"/Apag_PDFX_Checkup"
+"/App"
+"/Architecture-Normal"
+"/Arial"
+"/Aring"
+"/Art"
+"/ArtBox"
+"/Article"
+"/Artifact"
+"/Artwork"
+"/Ascent"
+"/Aspect"
+"/Assistant"
+"/Atilde"
+"/AuthEvent"
+"/Author"
+"/Avenir-Heavy"
+"/Avenir-MediumOblique"
+"/AvgWidth"
+"/BBox"
+"/BC"
+"/BCL"
+"/BDC"
+"/BDL"
+"/BE"
+"/BFSOL"
+"/BG"
+"/BG2"
+"/BM"
+"/BMC"
+"/BS"
+"/BW"
+"/Bank"
+"/BaseEncoding"
+"/BaseFont"
+"/BaseState"
+"/BaseVersion"
+"/Birch"
+"/BitsPerComponent"
+"/BitsPerCoordinate"
+"/BitsPerFlag"
+"/BitsPerSample"
+"/Bl"
+"/BlCDel"
+"/BlMiNu"
+"/Black"
+"/BlackIs1"
+"/BlackOP"
+"/BlackPoint"
+"/BleedBox"
+"/Blend"
+"/Block"
+"/Blue"
+"/BluesClues"
+"/Bookshelf"
+"/Border"
+"/Bounds"
+"/BoxColorInfo"
+"/Btn"
+"/BulmerMT-BoldDisplay"
+"/ByteRange"
+"/C"
+"/C0"
+"/C0_0"
+"/C1"
+"/C2W"
+"/C3"
+"/CALS_AIS"
+"/CALS_BM"
+"/CALS_HT"
+"/CALS_SMASK"
+"/CALS_ca"
+"/CAM"
+"/CB"
+"/CC"
+"/CCH"
+"/CCITTFaxDecode"
+"/CD"
+"/CDL"
+"/CEN"
+"/CF"
+"/CFM"
+"/CI"
+"/CIDFontType0"
+"/CIDFontType0C"
+"/CIDFontType2"
+"/CIDInit"
+"/CIDSet"
+"/CIDSystemInfo"
+"/CIDToGIDMap"
+"/CMV_LabBar"
+"/CMV_LabControl"
+"/CMYK"
+"/CMYK#20#2880,#208,#2034,#200#29"
+"/CMap"
+"/CMapName"
+"/CMapType"
+"/CMapVersion"
+"/CO"
+"/CP"
+"/CS"
+"/CS0"
+"/CT"
+"/CV"
+"/CalGray"
+"/CalRGB"
+"/CapHeight"
+"/Caption"
+"/Caslon540BT-Roman"
+"/CaslonBT-Bold"
+"/CaslonBT-BoldItalic"
+"/Catalog"
+"/Category"
+"/Ccedilla"
+"/CenturySchoolbookBT-Roman"
+"/Ch"
+"/Chair"
+"/Chap"
+"/Chaparral-Display"
+"/CharProcs"
+"/CharSet"
+"/CheckSum"
+"/Circle"
+"/ClarendonBT-Black"
+"/ClassMap"
+"/Clearface-Black"
+"/Clip"
+"/ClippedText"
+"/Cn"
+"/Collection"
+"/CollectionItem"
+"/CollectionSchema"
+"/CollectionSubitem"
+"/Color"
+"/ColorBurn"
+"/ColorDodge"
+"/ColorMatch"
+"/ColorSpace"
+"/ColorTransform"
+"/ColorType"
+"/Colorants"
+"/Colors"
+"/Columns"
+"/ComicSansMS,Bold"
+"/Comment"
+"/Comments"
+"/Company"
+"/Compatibility"
+"/Compatible"
+"/Components"
+"/CompressArt"
+"/Condensed"
+"/Configs"
+"/Consultant"
+"/ContainerVersion"
+"/Contents"
+"/Coords"
+"/Copy"
+"/Copy#20center"
+"/Cor"
+"/Corner#20surface"
+"/CosineDot"
+"/Count"
+"/Cour"
+"/Courier"
+"/Create"
+"/CreationDate"
+"/Creator"
+"/CreatorInfo"
+"/CreatorVersion"
+"/CropBox"
+"/CropFixed"
+"/CropRect"
+"/Crypt"
+"/CryptFilter"
+"/CryptFilterDecodeParms"
+"/Cs12"
+"/Cs3"
+"/Cyan"
+"/D"
+"/DA"
+"/DCTDecode"
+"/DIC#202525p*"
+"/DIS"
+"/DL"
+"/DOS"
+"/DP"
+"/DR"
+"/DS"
+"/DSz"
+"/DV"
+"/DW"
+"/DamagedRowsBeforeError"
+"/Darken"
+"/Data"
+"/Date"
+"/Decode"
+"/DecodeParms"
+"/DefEmbeddedFile"
+"/Default"
+"/DefaultCryptFilter"
+"/DefaultForPrinting"
+"/DefaultRGB"
+"/Delete"
+"/Delta"
+"/DescendantFonts"
+"/Descent"
+"/Description"
+"/Design"
+"/Dest"
+"/DestOutputProfile"
+"/DestOutputProfileRef"
+"/Dests"
+"/DeviceCMYK"
+"/DeviceGray"
+"/DeviceN"
+"/DeviceRGB"
+"/Difference"
+"/Differences"
+"/DigestLocation"
+"/DigestMethod"
+"/DigestValue"
+"/Dimmed"
+"/Direction"
+"/DisplayDocTitle"
+"/Dissolve"
+"/Div"
+"/Dm"
+"/DocMDP"
+"/DocOpen"
+"/Document"
+"/Documents"
+"/Domain"
+"/Door"
+"/DotGain"
+"/Draw"
+"/Dt"
+"/Dur"
+"/Dynamic#20connector"
+"/E"
+"/EF"
+"/EFF"
+"/EMC"
+"/Eacute"
+"/EarlyChange"
+"/Ecircumflex"
+"/Edieresis"
+"/Editable"
+"/Egrave"
+"/EmbedFonts"
+"/EmbedICCProfile"
+"/Embedded"
+"/EmbeddedFile"
+"/EmbeddedFiles"
+"/Encode"
+"/EncodedByteAlign"
+"/Encoding"
+"/Encrypt"
+"/EncryptMetadata"
+"/EndIndent"
+"/EndOfBlock"
+"/EndOfLine"
+"/Euro"
+"/Euro.037"
+"/Event"
+"/ExData"
+"/Exchange-Pro"
+"/Exclude"
+"/Exclusion"
+"/Executive"
+"/Export"
+"/ExportCrispy"
+"/ExportState"
+"/ExtGState"
+"/Extend"
+"/Extends"
+"/ExtensionLevel"
+"/Extensions"
+"/F1"
+"/F1.0"
+"/F12"
+"/F13"
+"/F3"
+"/F5"
+"/F6"
+"/F7"
+"/F8"
+"/FB"
+"/FD"
+"/FDecodeParms"
+"/FFilter"
+"/FICL"
+"/FM"
+"/FOV"
+"/FRM"
+"/FS"
+"/FT"
+"/Facilities"
+"/Fade"
+"/False"
+"/Feature"
+"/FedEx#20Orange"
+"/FedEx#20Purple"
+"/Field"
+"/Fields"
+"/Figure"
+"/File"
+"/Files"
+"/Filespec"
+"/FillIn"
+"/Filter"
+"/First"
+"/FirstChar"
+"/FirstPage"
+"/Fit"
+"/FitB"
+"/FitBH"
+"/FitBV"
+"/FitH"
+"/FitR"
+"/FitV"
+"/FitWindow"
+"/FixedPrint"
+"/Flags"
+"/FlateDecode"
+"/Fm0"
+"/Fm4"
+"/Fo"
+"/Focoltone#201047"
+"/Font"
+"/FontBBox"
+"/FontDescriptor"
+"/FontFamily"
+"/FontFile"
+"/FontFile2"
+"/FontMatrix"
+"/FontName"
+"/FontStretch"
+"/FontWeight"
+"/Form"
+"/FormEx"
+"/FormType"
+"/FreeText"
+"/FreeTextCallout"
+"/Frequency"
+"/FullSave"
+"/FullScreen"
+"/Function"
+"/FunctionType"
+"/Functions"
+"/Futura-Bold"
+"/Futura-CondensedExtraBold"
+"/G"
+"/G02"
+"/GLGR"
+"/GS0"
+"/GS1"
+"/GS2"
+"/GTS"
+"/GTS_PDFA1"
+"/GTS_PDFX"
+"/GTS_PDFXConformance"
+"/GTS_PDFXVersion"
+"/GWG#20Green"
+"/Gamma"
+"/Garamond"
+"/Georgia,Bold"
+"/GoTo"
+"/GoTo3DView"
+"/GoToE"
+"/GoToR"
+"/Gold"
+"/Goudy"
+"/Gray"
+"/Green"
+"/GreymantleMVB"
+"/GrotesqueMT"
+"/Group"
+"/H"
+"/HDAG_Tools"
+"/HKana"
+"/HT"
+"/HT2"
+"/Halftone"
+"/HalftoneName"
+"/HalftoneType"
+"/HardLight"
+"/HeBo"
+"/Head1"
+"/Headlamp"
+"/Height"
+"/HeiseiMin"
+"/Helv"
+"/Helvetica"
+"/Helvetica-Bold"
+"/Helvetica-BoldOblique"
+"/Helvetica-Condensed"
+"/HelveticaNeue-Black"
+"/Hide"
+"/HonMincho-M"
+"/Horizontal"
+"/Hue"
+"/I"
+"/I0"
+"/IC"
+"/ICCBased"
+"/ICCVersion"
+"/ID"
+"/IDS"
+"/IDTree"
+"/IEC"
+"/IF"
+"/IN"
+"/ISO32000Registry"
+"/ISO_PDFE1"
+"/ISO_PDFEVersion"
+"/IT"
+"/ITO"
+"/ITP"
+"/IV"
+"/IX"
+"/Icircumflex"
+"/Icon"
+"/Identity"
+"/Identity-H"
+"/IgnEP"
+"/Illustrator"
+"/Illustrator8.0"
+"/Im0"
+"/Im1"
+"/Im2"
+"/Im3"
+"/Im4"
+"/Image"
+"/Image1"
+"/ImageB"
+"/ImageC"
+"/ImageI"
+"/ImageMask"
+"/ImageResources"
+"/ImageType"
+"/Import"
+"/ImportData"
+"/ImpressBT-Regular"
+"/Index"
+"/Indexed"
+"/Info"
+"/Information#20services"
+"/Ink"
+"/InkList"
+"/InsertPages"
+"/Insignia"
+"/IntegerItem"
+"/Intent"
+"/Interpolate"
+"/ItalicAngle"
+"/ItcKabel-Ultra"
+"/Item1"
+"/Item2"
+"/JBIG2Decode"
+"/JBIG2Globals"
+"/JPXDecode"
+"/JS"
+"/JT"
+"/JTC"
+"/JTF"
+"/JTFile"
+"/JTM"
+"/JavaScript"
+"/JobTicketContents"
+"/Justify"
+"/Keywords"
+"/Kids"
+"/L"
+"/L1"
+"/L1a"
+"/L1b"
+"/L2R"
+"/L50188"
+"/LBody"
+"/LI"
+"/LL"
+"/LLE"
+"/LLO"
+"/LS"
+"/LSP"
+"/LZW"
+"/LZWDecode"
+"/Lab"
+"/Lang"
+"/Last"
+"/LastChar"
+"/LastItem"
+"/LastModified"
+"/Lateral#20file"
+"/Launch"
+"/Layout"
+"/Lbl"
+"/Leading"
+"/Legal"
+"/Length"
+"/Length1"
+"/Length2"
+"/Length3"
+"/LetterspaceFlags"
+"/Lighten"
+"/Limits"
+"/Line"
+"/LineDimension"
+"/LineHeight"
+"/Linear"
+"/Linearized"
+"/Link"
+"/Locked"
+"/LogoGreen"
+"/LrTb"
+"/Lslash"
+"/Luminosity"
+"/M"
+"/MB"
+"/MC"
+"/MC0"
+"/MCD"
+"/MCID"
+"/MCR"
+"/MD5"
+"/MH"
+"/MIT"
+"/MK"
+"/MMType1"
+"/MP"
+"/MR"
+"/MS"
+"/MUX#20#2F#20DEMUX"
+"/Mac"
+"/MacRomanEncoding"
+"/Magenta"
+"/Manager"
+"/MarkInfo"
+"/Marked"
+"/MarkedPDF"
+"/Marker#20board"
+"/Markup3D"
+"/Mask"
+"/Mastercard"
+"/Matrix"
+"/Max"
+"/MaxLen"
+"/MaxWidth"
+"/Me"
+"/Measure"
+"/MediaBox"
+"/MetaData"
+"/Min"
+"/MinionMM"
+"/MissingWidth"
+"/MixedContainer"
+"/MixingHints"
+"/ModDate"
+"/Mode"
+"/Modify"
+"/Movie"
+"/Msg"
+"/MurrayHillBT-Bold"
+"/MxGeom"
+"/MxLaNu"
+"/MxPts"
+"/MyriadPro-Black"
+"/NA"
+"/NChannel"
+"/ND"
+"/NL"
+"/NM"
+"/NR"
+"/Name"
+"/Name1"
+"/Named"
+"/Names"
+"/NeedsRendering"
+"/NewCenturySchlbk-Italic"
+"/NewWindow"
+"/Next"
+"/NextPage"
+"/No"
+"/NonEFontNoWarn"
+"/NonStruct"
+"/None"
+"/Normal"
+"/Not"
+"/NotDefSpecial"
+"/NumBlock"
+"/Nums"
+"/OB"
+"/OBJR"
+"/OC"
+"/OC2"
+"/OC3"
+"/OC4"
+"/OCG"
+"/OCGs"
+"/OCL"
+"/OCMD"
+"/OCProperties"
+"/OE"
+"/OFF"
+"/OLN"
+"/ON"
+"/OOL"
+"/OPBG"
+"/OPBS"
+"/OPI"
+"/OPM"
+"/OS"
+"/OT"
+"/Oacute"
+"/Obj"
+"/ObjStm"
+"/Ocircumflex"
+"/Odieresis"
+"/Ograve"
+"/Omega"
+"/OneColumn"
+"/Online"
+"/Open"
+"/OpenAction"
+"/Operation"
+"/Opt"
+"/OptionSet"
+"/Options"
+"/Or"
+"/Orange"
+"/Order"
+"/Ordering"
+"/OriginalLayerName"
+"/Oslash"
+"/Otilde"
+"/Outlines"
+"/OutputCondition"
+"/OutputConditionIdentifier"
+"/OutputIntent"
+"/OutputIntents"
+"/Overlay"
+"/P0"
+"/P1"
+"/P2"
+"/P2,#2300ff007900000000,PANTONE#20151#20C"
+"/PANTONE"
+"/PANTONE#20158-5#20CVS"
+"/PANTONE#20221#20CVU"
+"/PANTONE#203405#20C"
+"/PANTONE#20399#20CVC"
+"/PANTONE#20Blue#20072#20C"
+"/PANTONE#20Orange#20021#20C"
+"/PANTONE#20Orange#20021#20CVC"
+"/PANTONE#20Yellow#20C"
+"/PC"
+"/PDFDocEncoding"
+"/PIX"
+"/PO"
+"/PS"
+"/PUBLISHER"
+"/PZ"
+"/Pa0"
+"/Page"
+"/PageElement"
+"/PageLabels"
+"/PageLayout"
+"/PageMode"
+"/PageRange"
+"/Pages"
+"/PaintType"
+"/Palatino,Bold"
+"/Pale#20Brown.c"
+"/Panose"
+"/Paper#20tray"
+"/Para"
+"/Params"
+"/Parent"
+"/ParentTree"
+"/ParentTreeNextKey"
+"/Part"
+"/Pattern"
+"/PatternType"
+"/PcZ"
+"/Perceptual"
+"/Perms"
+"/Pg"
+"/Pgf"
+"/PieceInfo"
+"/PitStop"
+"/Placement"
+"/Play"
+"/Polygon"
+"/PolygonCloud"
+"/Popup"
+"/Position"
+"/PowerUpPDF"
+"/PrOut"
+"/PrRGBGra"
+"/PrRGBIma"
+"/Predictor"
+"/PresSteps"
+"/PreserveRB"
+"/Prev"
+"/PrevPage"
+"/Preview"
+"/Print"
+"/PrintRecord"
+"/PrintScaling"
+"/PrintState"
+"/PrintStyle"
+"/Printed"
+"/PrintingOrder"
+"/Private"
+"/ProcSet"
+"/Process"
+"/ProcessBlue"
+"/ProcessGreen"
+"/ProcessRed"
+"/Producer"
+"/ProfileCS"
+"/ProfileName"
+"/Prop_Build"
+"/Properties"
+"/Proportional"
+"/PubSec"
+"/Q"
+"/QuadPoints"
+"/R1"
+"/RBGroups"
+"/RC"
+"/RD"
+"/REC"
+"/REx"
+"/RF"
+"/RGB"
+"/RI"
+"/RICMYKGra"
+"/RICMYKIma"
+"/RICalGra"
+"/RICalIma"
+"/RIDefault"
+"/RIDevNGra"
+"/RIDevNIma"
+"/RIRGBGra"
+"/RIRGBIma"
+"/RL"
+"/RM"
+"/RV"
+"/Range"
+"/Rect"
+"/Red"
+"/Redact"
+"/Ref"
+"/Reference"
+"/Registry"
+"/RegistryName"
+"/RelativeColorimetric"
+"/Rendition"
+"/Renditions"
+"/Requirements"
+"/ResetForm"
+"/Resolution"
+"/Resources"
+"/ReversedChars"
+"/RoleMap"
+"/Root"
+"/Rotate"
+"/Round"
+"/RoundTrip"
+"/RoundtripVersion"
+"/Router"
+"/Rows"
+"/RunLengthDecode"
+"/Ryumin"
+"/SA"
+"/SBDraft"
+"/SC"
+"/SE"
+"/SFSSL"
+"/SFTWS"
+"/SI"
+"/SL"
+"/SLA"
+"/SM"
+"/SMask"
+"/SMaskInData"
+"/SP"
+"/SPS"
+"/STL"
+"/SU"
+"/SW"
+"/Saturation"
+"/SaveAs"
+"/SaveContents"
+"/SaveResource"
+"/SavedBy"
+"/Scaron"
+"/Schema"
+"/Screen"
+"/Sect"
+"/SemiCondensed"
+"/SemiExpanded"
+"/Separation"
+"/SeparationInfo"
+"/SetOCGState"
+"/SettingsFileName"
+"/Sh0"
+"/Sh1"
+"/Shading"
+"/ShadingType"
+"/Shape"
+"/Sig"
+"/SigFlags"
+"/SigRef"
+"/Signature"
+"/Signed"
+"/SinglePage"
+"/Size"
+"/SlideShow"
+"/SoftLight"
+"/Solid"
+"/Solidities"
+"/SomeName"
+"/Sort"
+"/Sound"
+"/Space"
+"/SpaceAfter"
+"/SpaceBefore"
+"/Span"
+"/SpawnTemplate"
+"/SpdrArt"
+"/SpiderInfo"
+"/Split"
+"/Spot"
+"/Spot1"
+"/Spot2"
+"/SpotFunction"
+"/SpotMap"
+"/St"
+"/Stamp"
+"/StandardImageFileData"
+"/Star"
+"/Start"
+"/StartIndent"
+"/StartResource"
+"/State"
+"/StdCF"
+"/StemH"
+"/StemV"
+"/Stm"
+"/StmF"
+"/Stop"
+"/Story"
+"/StrF"
+"/StrikeOut"
+"/StringItem"
+"/StructElem"
+"/StructParent"
+"/StructParents"
+"/StructTreeRoot"
+"/Style"
+"/SubFilter"
+"/SubType"
+"/Subdictionary"
+"/Subform"
+"/Subj"
+"/Subject"
+"/SubmitForm"
+"/SubmitStandalone"
+"/SubsetFontsBelow"
+"/SubsetFontsRatio"
+"/Supplement"
+"/Swiss721BT-Black"
+"/Switch"
+"/T"
+"/T1"
+"/T1_0"
+"/TB"
+"/TC"
+"/TCS"
+"/TF"
+"/TID"
+"/TK"
+"/TM"
+"/TO"
+"/TOC"
+"/TOCI"
+"/TOYO#200004pc"
+"/TP"
+"/TR"
+"/TR2"
+"/TRUMATCH#206-e"
+"/TS"
+"/TSV"
+"/TT"
+"/TT0"
+"/TTRefMan"
+"/TU"
+"/TV"
+"/TW"
+"/TWS"
+"/TWY"
+"/Tabs"
+"/TagSuspect"
+"/TargetCS"
+"/Technical"
+"/Template"
+"/TemplateInstantiated"
+"/Templates"
+"/Text"
+"/TextAlign"
+"/TextBox"
+"/TextIndent"
+"/The"
+"/This"
+"/Thorn"
+"/Thread"
+"/Threads"
+"/Thumb"
+"/Thumbnail"
+"/Thumbs"
+"/Ti"
+"/TiBI"
+"/TilingType"
+"/Times-BoldItalic"
+"/Times-Roman"
+"/Title"
+"/ToUnicode"
+"/Toggle"
+"/Trans"
+"/TransferFunction"
+"/TransformMethod"
+"/TransformParams"
+"/Transparency"
+"/TrapInfo"
+"/TrapMagicNumber"
+"/TrapRegions"
+"/TrapSet"
+"/Trapped"
+"/Trapping"
+"/TrappingDetails"
+"/TrappingParameters"
+"/TrimBox"
+"/True"
+"/TrueType"
+"/TrustedMode"
+"/TwoColumnLeft"
+"/Tx"
+"/Type"
+"/Type0"
+"/U3D"
+"/UA"
+"/UCR"
+"/UCR2"
+"/UIDOffset"
+"/UR"
+"/UR3"
+"/URI"
+"/URL"
+"/URLs"
+"/Uacute"
+"/Ucircumflex"
+"/Udieresis"
+"/Ugrave"
+"/Univers-BoldExt"
+"/Unix"
+"/Unknown"
+"/Usage"
+"/UseAttachments"
+"/UseNone"
+"/UseOC"
+"/UseOutlines"
+"/UseThumbs"
+"/UsedCMYK"
+"/UserProperties"
+"/UserUnit"
+"/V2"
+"/VA"
+"/VE"
+"/VP"
+"/Verdana,Bold"
+"/Version"
+"/Vertical"
+"/VeryLastItem"
+"/View"
+"/ViewerPreferences"
+"/Visa"
+"/Visible"
+"/Volume"
+"/W2"
+"/WAI"
+"/WAN"
+"/WMode"
+"/WP"
+"/WarnockPro-BoldIt"
+"/Watermark"
+"/WebCapture"
+"/Which"
+"/WhiteBG"
+"/WhitePoint"
+"/Widget"
+"/Width"
+"/Widths"
+"/Win"
+"/WinAnsiEncoding"
+"/Window"
+"/Windows"
+"/Work#20surface"
+"/Workbook"
+"/Worksheet"
+"/WritingMode"
+"/X"
+"/X1"
+"/XFA"
+"/XHeight"
+"/XML"
+"/XN"
+"/XObject"
+"/XRef"
+"/XRefStm"
+"/XStep"
+"/XUID"
+"/XYZ"
+"/Y"
+"/YStep"
+"/Yacute"
+"/Ydieresis"
+"/Yellow"
+"/Z"
+"/Z7KNXbN"
+"/ZaDb"
+"/ZapfDingbats"
+"/Zcaron"
+"/Zoom"
+"/_No_paragraph_style_"
+"/a1"
+"/acute"
+"/adbe.pkcs7.detached"
+"/ampersand"
+"/apple"
+"/approxequal"
+"/asciicircum"
+"/asciitilde"
+"/asterisk"
+"/at"
+"/audio#2Fmpeg"
+"/b"
+"/backslash"
+"/bar"
+"/blank"
+"/braceleft"
+"/braceright"
+"/bracketleft"
+"/bracketright"
+"/breve"
+"/brokenbar"
+"/bullet"
+"/c108"
+"/cCompKind"
+"/cCompQuality"
+"/cCompression"
+"/cRes"
+"/cResolution"
+"/ca"
+"/caron"
+"/cedilla"
+"/cent"
+"/circumflex"
+"/colon"
+"/comma"
+"/copyright"
+"/currency"
+"/dagger"
+"/daggerdbl"
+"/degree"
+"/deviceNumber"
+"/dieresis"
+"/divide"
+"/dollar"
+"/dotaccent"
+"/dotlessi"
+"/dotlessj"
+"/eight"
+"/ellipsis"
+"/emdash"
+"/endash"
+"/equal"
+"/eth"
+"/exclam"
+"/exclamdown"
+"/f"
+"/ff"
+"/ffi"
+"/ffl"
+"/fi"
+"/five"
+"/fl"
+"/florin"
+"/four"
+"/fraction"
+"/gCompKind"
+"/gCompQuality"
+"/gCompression"
+"/gRes"
+"/gResolution"
+"/germandbls"
+"/go1"
+"/grave"
+"/greater"
+"/greaterequal"
+"/guillemotleft"
+"/guillemotright"
+"/guilsinglleft"
+"/guilsinglright"
+"/hungarumlaut"
+"/hyphen"
+"/iacute"
+"/idieresis"
+"/igrave"
+"/infinity"
+"/integral"
+"/j"
+"/k"
+"/less"
+"/lessequal"
+"/logicalnot"
+"/lozenge"
+"/lt#20blue"
+"/mCompKind"
+"/mCompression"
+"/mRes"
+"/mResolution"
+"/macron"
+"/minus"
+"/mu"
+"/multiply"
+"/n"
+"/n0"
+"/nine"
+"/notequal"
+"/ntilde"
+"/numbersign"
+"/o"
+"/ogonek"
+"/one"
+"/onehalf"
+"/onequarter"
+"/onesuperior"
+"/op"
+"/ordfeminine"
+"/ordmasculine"
+"/p"
+"/pageH"
+"/pageV"
+"/paragraph"
+"/parenleft"
+"/parenright"
+"/partialdiff"
+"/pdf"
+"/pdfx"
+"/percent"
+"/period"
+"/periodcentered"
+"/perthousand"
+"/pi"
+"/plus"
+"/plusminus"
+"/pms#208400"
+"/printX"
+"/product"
+"/question"
+"/questiondown"
+"/quotedbl"
+"/quotedblbase"
+"/quotedblleft"
+"/quotedblright"
+"/quoteleft"
+"/quoteright"
+"/quotesinglbase"
+"/quotesingle"
+"/r"
+"/radical"
+"/registered"
+"/ring"
+"/s"
+"/s1"
+"/sd1"
+"/sd2"
+"/section"
+"/semicolon"
+"/seven"
+"/six"
+"/slash"
+"/sterling"
+"/summation"
+"/thinspace"
+"/three"
+"/threequarters"
+"/threesuperior"
+"/tilde"
+"/trademark"
+"/two"
+"/twosuperior"
+"/u"
+"/underscore"
+"/v"
+"/w"
+"/y1"
+"/yen"
+"/yes"
+"/zero"
+"0 R"
+"1"
+"1.0"
+"<"
+"<<"
+">"
+">>"
+"Adobe.PPKLite"
+"Adobe.PubSec"
+"B*"
+"BDC"
+"BI"
+"BMC"
+"BT"
+"BX"
+"CS"
+"DP"
+"Do"
+"EI"
+"EMC"
+"ET"
+"EX"
+"Entrust.PPKEF"
+"ID"
+"MP"
+"R"
+"T*"
+"TJ"
+"TL"
+"Tc"
+"Td"
+"Tf"
+"Tj"
+"Tm"
+"Tr"
+"Ts"
+"Tw"
+"W*"
+"["
+"[0.0 0.0 0.0 0.0 0.0 0.0]"
+"[1 1 1]"
+"[1.0 -1.0 1.0 -1.0]"
+"[1.0 -1.0]"
+"\\"
+"]"
+"abs"
+"adbe.pkcs7.s3"
+"adbe.pkcs7.s4"
+"adbe.pkcs7.s5"
+"add"
+"and"
+"atan"
+"begin"
+"beginarrangedfont"
+"beginbfchar"
+"begincidrange"
+"begincmap"
+"begincodespacerange"
+"beginnotdefchar"
+"beginnotdefrange"
+"beginusematrix"
+"bitshift"
+"ceiling"
+"cm"
+"copy"
+"cos"
+"cvi"
+"cvr"
+"d0"
+"d1"
+"div"
+"dup"
+"end"
+"endarrangedfont"
+"endbfchar"
+"endcidrange"
+"endcmap"
+"endcodespacerange"
+"endnotdefchar"
+"endnotdefrange"
+"endobj"
+"endstream"
+"endusematrix"
+"eq"
+"exch"
+"exp"
+"f*"
+"false"
+"findresource"
+"floor"
+"ge"
+"gs"
+"gt"
+"idiv"
+"if"
+"ifelse"
+"index"
+"le"
+"ln"
+"log"
+"lt"
+"mod"
+"mul"
+"ne"
+"neg"
+"not"
+"null"
+"obj"
+"or"
+"page"
+"pop"
+"re"
+"rg"
+"ri"
+"roll"
+"round"
+"sin"
+"sqrt"
+"startxref"
+"stream"
+"sub"
+"trailer"
+"true"
+"truncate"
+"usecmap"
+"usefont"
+"xor"
+"xref"
+"{"
+"}"
diff --git a/dictionaries/perl.dict b/dictionaries/perl.dict
new file mode 100644
index 00000000..580a2248
--- /dev/null
+++ b/dictionaries/perl.dict
@@ -0,0 +1,16 @@
+
+#
+# AFL dictionary for fuzzing Perl
+# --------------------------------
+#
+# Created by @RandomDhiraj
+#
+
+"<:crlf"
+"fwrite()"
+"fread()"
+":raw:utf8"
+":raw:eol(LF)"
+"Perl_invert()"
+":raw:eol(CRLF)"
+"Perl_PerlIO_eof()"
diff --git a/dictionaries/png.dict b/dictionaries/png.dict
new file mode 100644
index 00000000..ad9ea328
--- /dev/null
+++ b/dictionaries/png.dict
@@ -0,0 +1,38 @@
+#
+# AFL dictionary for PNG images
+# -----------------------------
+#
+# Just the basic, standard-originating sections; does not include vendor
+# extensions.
+#
+# Created by Michal Zalewski
+#
+
+header_png="\x89PNG\x0d\x0a\x1a\x0a"
+
+section_IDAT="IDAT"
+section_IEND="IEND"
+section_IHDR="IHDR"
+section_PLTE="PLTE"
+section_bKGD="bKGD"
+section_cHRM="cHRM"
+section_fRAc="fRAc"
+section_gAMA="gAMA"
+section_gIFg="gIFg"
+section_gIFt="gIFt"
+section_gIFx="gIFx"
+section_hIST="hIST"
+section_iCCP="iCCP"
+section_iTXt="iTXt"
+section_oFFs="oFFs"
+section_pCAL="pCAL"
+section_pHYs="pHYs"
+section_sBIT="sBIT"
+section_sCAL="sCAL"
+section_sPLT="sPLT"
+section_sRGB="sRGB"
+section_sTER="sTER"
+section_tEXt="tEXt"
+section_tIME="tIME"
+section_tRNS="tRNS"
+section_zTXt="zTXt"
diff --git a/dictionaries/proj4.dict b/dictionaries/proj4.dict
new file mode 100644
index 00000000..8dc05562
--- /dev/null
+++ b/dictionaries/proj4.dict
@@ -0,0 +1,249 @@
+# Dictionary developed for proj4 standard_fuzzer.cpp
+
+# valid proj types (lines 1,2), generated from seeds
+# $ grep -hoe 'proj=\w*' -o seeds/* | sort -u
+"+proj=aea"
+"+proj=aeqd"
+"+proj=calcofi"
+"+proj=cass"
+"+proj=cea"
+"+proj=comill"
+"+proj=eck4"
+"+proj=eck6"
+"+proj=eqc"
+"+proj=eqdc"
+"+proj=etmerc"
+"+proj=gall"
+"+proj=geocent"
+"+proj=geos"
+"+proj=gstmerc"
+"+proj=hammer"
+"+proj=healpix"
+"+proj=helmert"
+"+proj=kav5"
+"+proj=krovak"
+"+proj=labrd"
+"+proj=laea"
+"+proj=latlong"
+"+proj=lcc"
+"+proj=longlat"
+"+proj=merc"
+"+proj=mill"
+"+proj=misrsom"
+"+proj=moll"
+"+proj=natearth"
+"+proj=natearth2"
+"+proj=nzmg"
+"+proj=ob_tran"
+"+proj=omerc"
+"+proj=omerc"
+"+proj=patterson"
+"+proj=pconic"
+"+proj=poly"
+"+proj=qsc"
+"+proj=rhealpix"
+"+proj=robin"
+"+proj=sch"
+"+proj=sinu"
+"+proj=somerc"
+"+proj=stere"
+"+proj=sterea"
+"+proj=tmerc"
+"+proj=utm"
+"+proj=vandg"
+
+# valid datum types (lines 1,2), generated from seeds
+# $ grep -hoe 'datum=\w*' -o seeds/* | sort -u
+"+datum=GGRS87"
+"+datum=NAD27"
+"+datum=NAD83"
+"+datum=OSGB36"
+"+datum=WGS84"
+"+datum=carthage"
+"+datum=hermannskogel"
+"+datum=ire65"
+"+datum=nzgd49"
+"+datum=potsdam"
+
+# valid ellps types
+# $ grep -hoe 'elps=\w*' -o seeds/* | sort -u
+"+ellps=GRS67"
+"+ellps=GRS80"
+"+ellps=WGS66"
+"+ellps=WGS72"
+"+ellps=WGS84"
+"+ellps=airy"
+"+ellps=aust_SA"
+"+ellps=bess_nam"
+"+ellps=bessel"
+"+ellps=clrk66"
+"+ellps=clrk80"
+"+ellps=everest"
+"+ellps=evrstSS"
+"+ellps=fschr60m"
+"+ellps=helmert"
+"+ellps=intl"
+"+ellps=krass"
+"+ellps=mod_airy"
+"+ellps=sphere"
+
+# other various valid types
+"+epoch=1988"
+"+gamma=53d7"
+"+geoidgrids=egm08_25"
+"+geoidgrids=g2012a_conus"
+"+lastupdate=1993"
+"+lat_0=44d00"
+"+lat_0=46"
+"+lat_1=18d49"
+"+lat_2=40d43"
+"+lat_ts=33"
+"+llps=bessel"
+"+llps=clrk66"
+"+lon_0=7"
+"+lon_1=62"
+"+lon_2=53"
+"+lonc=78d00"
+"+lpha=55d40"
+"+nadgrids=MD"
+"+nadgrids=chenyx06etrs"
+"+nadgrids=conus"
+"+nadgrids=ntf_r93"
+"+nadgrids=ntv1_can"
+"+nadgrids=ntv2_0"
+"+nadgrids=null"
+"+north=0"
+"+north_square=0"
+"+o_lat_p=LAT_POLE"
+"+o_lon_p=LON_POLE"
+"+o_proj=moll"
+"+origin=EPSG"
+"+origin=Esri"
+"+origin=IGNF"
+"+origin=Swisstopo"
+"+origin=ftp"
+"+origin=http"
+"+pm=jakarta"
+"+pm=lisbon"
+"+pm=madrid"
+"+pm=oslo"
+"+pm=paris"
+"+pm=rome"
+"+pm=stockholm"
+"+title=Amsterdam"
+"+towgs84=103"
+"+units=ft"
+"+units=km"
+"+units=link"
+"+units=m"
+"+units=us"
+"+vunits=m"
+"+vunits=us"
+
+# binary prefix for line 3
+"BINARY2D:"
+"BINARY3D:"
+
+# floating point numbers
+"-0.100000 "
+"0.000000 "
+"0.100000 "
+"1.100000 "
+"4294967295.000000 "
+"9007199254740992.000000 "
+"\x9a\x99\x99\x99\x99\x99\xf1\xbf"
+"\x9a\x99\x99\x99\x99\x99\xb9\xbf"
+"\x00\x00\x00\x00\x00\x00\x00\x00"
+"\x9a\x99\x99\x99\x99\x99\xb9\x3f"
+"\x9a\x99\x99\x99\x99\x99\xf1\x3f"
+"\x00\x00\xe0\xff\xff\xff\xef\x41"
+"\x00\x00\x00\x00\x00\x00\x40\x43"
+
+
+# valid prefixes
+"+R="
+"+RES="
+"+W="
+"+a="
+"+alpha="
+"+axis="
+"+azi="
+"+b="
+"+bs="
+"+d="
+"+datum="
+"+depmode="
+"+dest="
+"+dir="
+"+drx="
+"+dry="
+"+drz="
+"+ds="
+"+dx="
+"+dy="
+"+dz="
+"+e="
+"+ellps="
+"+epoch="
+"+es="
+"+f="
+"+files="
+"+flg="
+"+gamma="
+"+geoidgrids="
+"+h="
+"+has_opt="
+"+init="
+"+k="
+"+k_0="
+"+lastupdate="
+"+lat_0="
+"+lat_1="
+"+lat_2="
+"+lat_ts="
+"+lib="
+"+list="
+"+lon_0="
+"+lon_1="
+"+lon_2="
+"+lon_wrap="
+"+lonc="
+"+nadgrids="
+"+north="
+"+north_square="
+"+o_lat_p="
+"+o_lon_p="
+"+o_proj="
+"+origin="
+"+path="
+"+phdg_0="
+"+plat_0="
+"+plon_0="
+"+pm="
+"+prefix="
+"+proj="
+"+r_a="
+"+rf="
+"+rx="
+"+ry="
+"+rz="
+"+s="
+"+skip_next="
+"+south="
+"+south_square="
+"+srcdirstrip="
+"+sweep="
+"+target_option="
+"+title="
+"+to_meter="
+"+topsrcdirstrip="
+"+towgs84="
+"+units="
+"+version="
+"+vunits="
+"+x="
+"+x_0="
+"+y="
+"+y_0="
+"+z="
+"+zone="
diff --git a/dictionaries/protobuf.dict b/dictionaries/protobuf.dict
new file mode 100644
index 00000000..28a506f6
--- /dev/null
+++ b/dictionaries/protobuf.dict
@@ -0,0 +1,40 @@
+# Keywords taken from https://developers.google.com/protocol-buffers/docs/reference/proto2-spec
+
+bool="bool"
+bytes="bytes"
+double="double"
+enum="enum"
+extend="extend"
+extension="extension"
+false="false"
+fixed32="fixed32"
+fixed64="fixed64"
+float="float"
+group="group"
+import="import"
+inner="inner"
+int32="int32"
+int64="int64"
+map="map<"
+message="message"
+option="option"
+optional="optional"
+package="package"
+public="public"
+repeated="repeated"
+required="required"
+reserved="reserved"
+returns="returns"
+rpc="rpc"
+service="service"
+sfixed32="sfixed32"
+sfixed64="sfixed64"
+sint32="sint32"
+sint64="sint64"
+stream="stream"
+string="string"
+syntax="syntax"
+true="true"
+uint32="uint32"
+uint64="uint64"
+weak="weak"
diff --git a/dictionaries/ps.dict b/dictionaries/ps.dict
new file mode 100644
index 00000000..bac3c0a0
--- /dev/null
+++ b/dictionaries/ps.dict
@@ -0,0 +1,433 @@
+# https://web.archive.org/web/20170218093716/https://www.adobe.com/products/postscript/pdfs/PLRM.pdf
+# TODO(jvoisin) Add more, starting from page 318
+
+
+header="%!PS"
+
+#types
+"array"
+"packedarray"
+"dict"
+"string"
+"userdict"
+"$error"
+"statusdict"
+"FontDirectory"
+"globaldict"
+"systemdict"
+"GlobalFontDirectory"
+"Order"
+"DateSource"
+"BitsPerSample"
+"Encode"
+"Decode"
+"Size"
+
+# Stack operators
+"dup"
+"exch"
+"pop"
+"copy"
+"roll"
+"index"
+"mark"
+"clear"
+"count"
+"counttomark"
+"cleartomark"
+
+# maths
+"add"
+"sub"
+"mul"
+"div"
+"idiv"
+"mod"
+"abs"
+"neg"
+"ceiling"
+"floor"
+"round"
+"truncate"
+"sqrt"
+"exp"
+"ln"
+"log"
+"rand"
+"srang"
+"rrand"
+
+# arrays
+"get"
+"put"
+"copy"
+"length"
+"forall"
+"getinterval"
+"putinterval"
+"aload"
+"astore"
+"mark"
+"setpacking"
+"currentpacking"
+"begin"
+"end"
+"def"
+"store"
+"load"
+"where"
+"countdictstack"
+"cleardictstack"
+"dictstack"
+"known"
+"maxlength"
+"undef"
+"<<"
+">>"
+"search"
+"anchorsearch"
+"token"
+
+# relational operators
+"eq"
+"ne"
+"gt"
+"ge"
+"lt"
+"le"
+"and"
+"or"
+"xor"
+"true"
+"false"
+"bitshift"
+
+
+#control operators
+"if"
+"else"
+"ifelse"
+"exec"
+"for"
+"repeat"
+"loop"
+"forall"
+"pathforall"
+"kshow"
+"exit"
+"countexecstack"
+"execstack"
+"stop"
+"errordict"
+"stopped"
+
+
+# type
+"type"
+"xcheck"
+"rcheck"
+"wcheck"
+"cvlit"
+"cvx"
+"readonly"
+"executeonly"
+"noacces"
+"cvi"
+"cvr"
+"cns"
+"cvs"
+"cvrs"
+
+#misc
+"print"
+"invalidaccess"
+"gcheck"
+"showpage"
+"currentgstate"
+"currentfile"
+"status"
+"byteavailable"
+"setdevparams"
+"currentdevparams"
+"Predictor"
+"Columns"
+"Colors"
+"BitsPerComponent"
+"Uncompressed"
+"EndOfLine"
+"EncodedByteAlign"
+"EndOfBlock"
+"Blackls1"
+"DamagedRowsBeforeError"
+"CloseTarget"
+"HuffTables"
+"ColorTransform"
+
+
+# vm
+"load"
+"save"
+"restore"
+"setglobal"
+"grestoreall"
+"invalidrestore"
+"startjob"
+"exitserver"
+
+# User objects
+"defineuserobject"
+"undefineuserobject"
+"execuserobject"
+"UserObjects"
+
+#i/o
+"read"
+"write"
+"readstring"
+"readline"
+"writestring"
+"readhexstring"
+"writehexstring"
+"token"
+"flush"
+"flushfile"
+
+
+# files
+"file"
+"deletefile"
+"renamefile"
+"status"
+"filenameforall"
+"setfileposition"
+"fileposition"
+"%stdin"
+"%stdout"
+"%stderr"
+"%statementedit"
+"%lineedit"
+
+# Filters
+"ASCII85Decode"
+"ASCII85Encode"
+"ASCIIHexDecode"
+"ASCIIHexEncode"
+"Decode"
+"Encode"
+"RunLengthEncode"
+"RunLengthDecode"
+"CCITTFaxEncode"
+"CCITTFaxDecode"
+"DCTEncode"
+"DCTDecode"
+"ReusableStreamDecode"
+"NullEncode"
+"SubFileDecode"
+"filter"
+"LWZEncode"
+"LWZDecode"
+"FlateEncode"
+"FlateDecode"
+"EODCount"
+"EODString"
+"CloseSource"
+
+
+# Resources
+"findresource"
+"resourcestatus"
+"resourceforall"
+"definerresource"
+"undefineresource"
+"findfont"
+"definefont"
+"resourcestatsu"
+"Font"
+"CIDFont"
+"CMap"
+"FontSet"
+"Encoding"
+"Form"
+"Pattern"
+"ProcSet"
+"ColorSpace"
+"Halftone"
+"ColorRendering"
+"IdiomSet"
+"Inkparam"
+"TrapParams"
+"OutputDevice"
+"Controllangue"
+"Localization"
+"PDL"
+"HWOptions"
+"Filter"
+"ColorSpaceFamily"
+"Emulator"
+"IODevice"
+"ColorRenderingType"
+"FMapType"
+"FontType"
+"FormType"
+"HalftoneType"
+"ImageType"
+"PatternType"
+"FunctionType"
+"ShadingType"
+"TrappingType"
+"Category"
+"Generic"
+"BitMapFontInit"
+"CIDInit"
+"ColorRendering"
+"FontSetInit"
+"Trapping"
+"ColorSpace"
+"ColorSpaceFamily"
+"sethalftone"
+"DefineResource"
+"UndefineResource"
+"FindResource"
+"ResourceStatus"
+"ResourceForAll"
+"Category"
+"InstaceType"
+"ResourceFileName"
+"Intent"
+"AsyncRead"
+"Times-Roman"
+
+
+# Error handling
+"errorname"
+"errorinfo"
+"command"
+"newerror"
+"ostack"
+"estack"
+"dstack"
+"recordstacks"
+"binary"
+"bind"
+"average"
+
+
+# Image models
+"CTM"
+"DeviceGray"
+"arc"
+"arcn"
+"artct"
+"clip"
+"cliprestore"
+"clipsave"
+"closepath"
+"currentlinewidth"
+"curveto"
+"fill"
+"grestone"
+"gsave"
+"image"
+"ineofill"
+"infill"
+"instroke"
+"inueofill"
+"inustroke"
+"lineto"
+"moveto"
+"newpath"
+"nocurrentpoint"
+"path"
+"position"
+"rcurveto"
+"rlineto"
+"setbox"
+"setlinewidth"
+"show"
+"stroke"
+"ucache"
+"ufill"
+"ustroke"
+"cvlit"
+"ufill"
+"ueofill"
+"rectfill"
+"rectstoke"
+"rectclip"
+"execform"
+"FormType"
+"XIUD"
+"BBox"
+"Matrix"
+"PaintProc"
+"Implementation"
+
+
+# Colorspace
+"setcolorspace"
+"setgray"
+"setrgbcolor"
+"setcmykcolor"
+"image"
+"colorimage"
+"sethsbcolor"
+"CIEBasedABC"
+"CIEBasedA"
+"CIEBaseDEF"
+"CIEBaseDEFG"
+"Pattern"
+"Indexed"
+"Separation"
+"DeviceN"
+"setpattern"
+"currentgray"
+"currentrgbcolor"
+"currentcmykcolor"
+"setcachedevice"
+"setcachedevice2"
+"BuildGlyph"
+"BuildChar"
+"CharString"
+"shfill"
+"setundercolorremoval"
+"settransfer"
+"setscreen"
+"sethalftone"
+"setcolortransfer"
+"DeviceRGB"
+"DeviceCMYK"
+"DeviceGray"
+"RangeABC"
+"DecodeABC"
+"MatrixABC"
+"RangeLMN"
+"DecodeLMN"
+"MatrixLMN"
+"WhitePoint"
+"BlackPoint"
+
+
+# Patterns
+"PatternType"
+"XUID"
+"PaintProc"
+"BBox"
+"XStep"
+"YStep"
+"PaintType"
+"TilingType"
+"Implementation"
+"Shading"
+"ShadingType"
+"AntiAlias"
+"Coords"
+"BitsPerFlag"
+"BitsPerCoordinate"
+"MultipleDataSources"
+
+
+# Misc things
+"[-1, 1, -1, 1]"
+"[-1 1]"
+"1337"
+"<</"
diff --git a/dictionaries/psd.dict b/dictionaries/psd.dict
new file mode 100644
index 00000000..fefb8869
--- /dev/null
+++ b/dictionaries/psd.dict
@@ -0,0 +1,180 @@
+# https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/
+
+"8BPS"
+"8BIM"
+"8B64"
+
+# blend mode keys
+"pass"
+"norm"
+"diss"
+"dark"
+"mul "
+"idiv"
+"lbrn"
+"dkCl"
+"lite"
+"scrn"
+"deiv"
+"lddg"
+"lgCl"
+"over"
+"sLit"
+"hLit"
+"vLit"
+"lLit"
+"pLit"
+"hMix"
+"diff"
+"smud"
+"fsub"
+"fdiv"
+"hue "
+"sat "
+"colr"
+"lum "
+
+# adjustment layers
+"SoCo"
+"GdFl"
+"PtFl"
+"brit"
+"levl"
+"curv"
+"expA"
+"vibA"
+"hue "
+"hue2"
+"blnc"
+"blwh"
+"phfl"
+"mixr"
+"clrL"
+"nvrt"
+"post"
+"thrs"
+"grdm"
+"selc"
+
+# effect signatures
+"cmnS"
+"dsdw"
+"isdw"
+"oglw"
+"iglw"
+"bevl"
+"sofi"
+
+# keys
+"Layr"
+"Lr16"
+"Lr32"
+"TySh"
+"tySt"
+"lrFX"
+"luni"
+"lyid"
+"lfx2"
+"Patt"
+"Pat2"
+"Pat3"
+"Anno"
+"clbl"
+"infx"
+"knko"
+"lspf"
+"lclr"
+"fxrp"
+"grdm"
+"lsct"
+"brst"
+"SoCo"
+"PtFl"
+"GdFl"
+"vmsk"
+"vsms"
+"vscg"
+"ffxi"
+"lnsr"
+"shpa"
+"shmd"
+"lyvr"
+"tsly"
+"lmgm"
+"vmgm"
+"brit"
+"mixr"
+"clrL"
+"plLd"
+"lnkD"
+"lnk2"
+"lnk3"
+"phfl"
+"blwh"
+"CgEd"
+"Txt2"
+"vibA"
+"pths"
+"anFX"
+"FMsk"
+"SoLd"
+"vstk"
+"vscg"
+"sn2P"
+"vogk"
+"PxSc"
+"cinf"
+"PxSD"
+"artb"
+"artd"
+"abdd"
+"SoLE"
+"Mtrn"
+"Mt16"
+"Mt32"
+"LMsk"
+"expA"
+"FXid"
+"FEid"
+
+# color handling
+"conv"
+"avod"
+"lumi"
+
+# descriptor structure
+"obj "
+"Objc"
+"VlLs"
+"doub"
+"UntF"
+"TEXT"
+"enum"
+"long"
+"comp"
+"bool"
+"GlbO"
+"type"
+"GlbC"
+"alis"
+"tdta"
+
+# reference structure
+"prop"
+"Clss"
+"Enmr"
+"rele"
+"Idnt"
+"indx"
+"name"
+
+# misc
+"txtA"
+"sndA"
+"txtC"
+"sndM"
+"plcL"
+"liFD"
+"liFE"
+"lifA"
+"soLD"
diff --git a/dictionaries/regexp.dict b/dictionaries/regexp.dict
new file mode 100644
index 00000000..07b890a0
--- /dev/null
+++ b/dictionaries/regexp.dict
@@ -0,0 +1,244 @@
+#
+# AFL dictionary for regex
+# --------------------------
+#
+# Contains various regular expressions.
+#
+# Created by Yang Guo <yangguo@chromium.org>
+#
+# Contributed by Dhiraj Mishra <dhiraj@inputzero.io>
+#
+"()"
+"(?<!)"
+"(?<=)"
+"(?=)"
+"?"
+"[\\[\\]\\{\\}\\(\\)\\%\\^\\#\\ ]"
+"[]"
+"\\[\\]\\{\\}\\(\\)\\%\\^\\#\\ "
+"]"
+"{"
+"{,}"
+"{}"
+"}"
+"[\\0]"
+"[\\00011]"
+"[\\011]"
+"\\011"
+"?:\\1"
+"[\\11]"
+"\\11"
+"[\\111]"
+"\\111"
+"[\\1111]"
+"\\1111"
+"\\1112"
+"[\\118]"
+"\\118"
+"[\\11a]"
+"\\11a"
+"{12,"
+"[-123]"
+"[^123]"
+"{12,3b"
+"\\1\\2(a(?:\\1\\2))\\2)\\1"
+"\\1\\2(a(?:\\1(b\\1\\2))\\2)\\1"
+"\\1\\2(b\\1\\2))\\2)\\1"
+"\\1(a)"
+"(\\1a)"
+"(?!\\1(a\\1)\\1)\\1"
+"\\1(b\\1\\2))\\2)\\1"
+"{1z}"
+"(\\2)(\\1)"
+"\\8"
+"\\9"
+"{93}"
+"(?:a*)*"
+"(?:a*)+"
+"(?:a+)*"
+"(?:a+)+"
+"(?:a+)?"
+"(?:a?)*"
+"(?:a?)+"
+"(?:a?)?"
+"(?:a?)??"
+"(?<!a)"
+"(?<=a)"
+"(?<a>)"
+"(?<a>.)"
+"(a)"
+"a"
+"a*?"
+"a+"
+"a+?"
+"a."
+"a?"
+"a??"
+"a{"
+"a{,}"
+"a{}"
+"a$"
+"a{0}"
+"(?:a+){0,0}"
+"a{0,1}?"
+"(?=a){0,10}a"
+"(?!(a))\\1"
+"(a)\\1"
+"(a\\1)"
+"(?=a){1,10}a"
+"a{1,2}?"
+"a{12,"
+"a{12,3b"
+"a{12z}"
+"a{12za?)?"
+"(?:a{5,1000000}){3,1000000}"
+"(?=a){9,10}a"
+"(?!a)?a"
+"a[^a]"
+"a[a]"
+"(?!a)?a\\1"
+"(?:(?=a))a\\1"
+"a[a-z]"
+"(?:ab)"
+"(?:ab)+"
+"(?:ab)?"
+"(ab)"
+"a(?!b)"
+"a(?:b)"
+"a(?=b)"
+"a*b"
+"a+b"
+"a\\b!"
+"a|b"
+"a*b\\+\\|[0-9]\\|\\d{1,9}"
+"(ab)\\1"
+"(?:ab){4,7}"
+"a\\Bb"
+"a(?!bbb|bb)c"
+"a(?=bbb|bb)c"
+"ab\\b\\d\\bcd"
+"[a-b-c]"
+"a(?=b)c"
+"a*b|c"
+"a+b|c"
+"a\\bc"
+"a||bc"
+"a|bc"
+"ab|c"
+"abc"
+"abc+"
+"abc+?"
+"a[bc]d"
+"(?:ab)|cde"
+"(?:ab|cde)"
+"(ab|cde)"
+"(ab|cde)\\1"
+"abc|def"
+"abc|def|ghi"
+"a\\D"
+"a\\fb\\nc\\rd\\te\\vf"
+"(?<a>.)\\k<a>"
+"a\\n"
+"a\\nb\\bc"
+"a\\q"
+"a\\s"
+"a\\S"
+"a\\sc"
+"a\\Sc"
+"a\\w"
+"a\\W"
+"a?)"xyz{93}"
+"a{z}"
+"[a-zA-Z0-9]"
+"[\\c!]"
+"[\\c_]"
+"[\\c~]"
+"\\c!"
+"\\c"
+"\\c_"
+"\\c~"
+"[\\c1]"
+"[\\ca]"
+"[\\cA]"
+"\\cA"
+"\\cj\\cJ\\ci\\cI\\ck\\cK"
+"[\\cz]"
+"[\\cZ]"
+"/^\\d*\\./"
+"/\\d{1,2}\\/\\d{1,2}\\/\\d{4}/"
+"\\[DataMember\\((.+?)\\)\\]"
+"[\\d-\\d]"
+"[\\d-z]"
+"(?: foo )"
+"(?:foo)"
+"foo(?=bar)bar)az"
+"foo(?=bar)bar)baz"
+"foo(?!bar)baz"
+"foo(?<!bar)baz"
+"foo(?<=bar)baz"
+"foo(?=bar)baz"
+"foo|(bar|baz)|quux"
+"fo(?o(?o(?o(?=bar)baz"
+"foo[z]*"
+"\\P{Any}"
+"\\p{Changes_When_NFKC_Casefolded}"
+"\\P{Decimal_Number}"
+"\\P{gc=Decimal_Number}"
+"\\p{gc=Nd}"
+"\\p{General_Category=Decimal_Number}"
+"\\p{Nd}"
+"\\P{sc=Greek}"
+"\\p{Script_Extensions=Greek}"
+"\\p{Script=Greek}"
+"\\P{scx=Greek}"
+"\\q"
+"\\u0034"
+"\\u003z"
+"\\u0060"
+"\\u{12345}"
+"\\u{12345}*"
+"\\u{12345}{3}"
+"\\u{12345}\\u{23456}"
+"\\ud808\\udf45*"
+"[\\ud808\\udf45-\\ud809\\udccc]"
+"\\w|\\d"
+"[x]"
+"\x01"
+"\x0f"
+"\\x3z"
+"\\x60"
+"[\x8f]"
+"[\x92\xa9-\xf4\x8f\xbf\xbf]"
+"[x\\dz]"
+"[\xe2\x81\xa3]"
+"\xe2\x81\xa3"
+"\xed\xa0\x80"
+"((\xed\xa0\x80))\x02"
+"\xed\xb0\x80"
+"(\xed\xb0\x80)\x01"
+"[-\xf0\x9f\x92\xa9]+"
+"\xf0\x9f\x92\xa9"
+"[\xf0\x9f\x92\xa9-\xf4\x8f\xbf\x92\xa9-\xf4\x8f\xbf\xbf]"
+"[\xf0\x9f\x92\xa9-\xf4\x8f\xbf\xbf]"
+"^xxx$"
+"(x)(x)(x)\\1"
+"(x)(x)(x)\\1*"
+"(x)(x)(x)\\2"
+"(x)(x)(x)\\3"
+"(x)(x)(x)\\3*"
+"(x)(x)(x)\\4"
+"(x)(x)(x)\\4*"
+"(x)(x)(x)(x)(x)(x)(x)(x)(x)(x)\\10"
+"(x)(x)(x)(x)(x)(x)(x)(x)(x)(x)\\11"
+"[xyz]"
+"xyz?"
+"xyz??"
+"xyz{0,1}"
+"xyz{0,1}?"
+"xyz{1,}"
+"xyz{1,}?"
+"xyz{1,32}"
+"xyz{1,32}?"
+"xyz{93}"
+"{z}"
+"[z-\\d]"
diff --git a/dictionaries/riff.dict b/dictionaries/riff.dict
new file mode 100644
index 00000000..627c72e7
--- /dev/null
+++ b/dictionaries/riff.dict
@@ -0,0 +1,17 @@
+# https://developers.google.com/speed/webp/docs/riff_container
+
+# FourCC
+"ALPH"
+"ANIM"
+"ANMF"
+"EXIF"
+"ICCP"
+"RIFF"
+"VP8 "
+"VP8L"
+"VP8X"
+"WEBP"
+"XMP "
+
+# VP8 signature
+"\x9D\x01\x2A"
diff --git a/dictionaries/rss.dict b/dictionaries/rss.dict
new file mode 100644
index 00000000..8dfb3340
--- /dev/null
+++ b/dictionaries/rss.dict
@@ -0,0 +1,31 @@
+# https://en.wikipedia.org/wiki/RSS
+
+"<?xml version='1.0' encoding='UTF-8' ?>"
+"<rss version='2.0'>"
+"<author>"
+"<category>"
+"<channel>"
+"<cloud>"
+"<comments>"
+"<copyright>"
+"<description>"
+"<docs>"
+"<enclosure>"
+"<generator>"
+"<guid>"
+"<image>"
+"<item>"
+"<language>"
+"<lastBuildDate>"
+"<link>"
+"<managingEditor>"
+"<pubDate>"
+"<rating>"
+"<skipDays>"
+"<skipHours>"
+"<source>"
+"<textInput>"
+"<title>"
+"<ttl>"
+"<url>"
+"<webMaster>"
diff --git a/dictionaries/rst.dict b/dictionaries/rst.dict
new file mode 100644
index 00000000..bdad2338
--- /dev/null
+++ b/dictionaries/rst.dict
@@ -0,0 +1,21 @@
+# https://docutils.readthedocs.io/en/sphinx-docs/ref/rst/restructuredtext.html
+
+bold="**"
+list1="1. "
+list2="(1) "
+list3="1) "
+list4="I. "
+list5="i. "
+list6="* "
+list7="- "
+list8="+ "
+end_of_paragraph="::"
+title="====="
+image=".. image:: "
+image_attr=" :a: 1"
+doctest=">>>"
+table1="+--+""
+table2="+==+""
+footnote_and_citation=".. [a] "
+hyperlink=".. _a: http://a "
+macro=".. |b| a"
diff --git a/dictionaries/rtf.dict b/dictionaries/rtf.dict
new file mode 100644
index 00000000..2d5019ef
--- /dev/null
+++ b/dictionaries/rtf.dict
@@ -0,0 +1,408 @@
+# http://latex2rtf.sourceforge.net/RTF-Spec-1.0.txt
+
+# charset
+"\\ansi"
+"\\mac"
+"\\pc"
+"\\pca"
+
+# font table
+"\\fnil"
+"\\fRoman"
+"\\fswiss"
+"\\fmodern"
+"\\fscript"
+"\\fdecor"
+"\\ftech"
+
+
+# stylesheet
+"\\sbasedon"
+"\\snext"
+"\\keycode"
+
+
+# colors
+"\\red"
+"\\green"
+"\\blue"
+"\\cf"
+"\\cb"
+
+# pictures
+"\\pict"
+"\\macpict"
+"\\pmmetafile"
+"\\wmetafile"
+"\\dibitmap"
+"\\wbitmap"
+"\\wbmbitspixel"
+"\\wbmplanes"
+"\\wbmwidthbytes"
+"\\picw"
+"\\pich"
+"\\picwgoal"
+"\\pichgoal"
+"\\picscalex"
+"\\picscaley"
+"\\picscaled"
+"\\piccropt"
+"\\piccropb"
+"\\piccropl"
+"\\piccropr"
+"\\bin"
+# these strings are probably not necessary
+"MM_TEXT"
+"MM_LOMETRIC"
+"MM_HIMETRIC"
+"MM_LOENGLISH"
+"MM_HIENGLISH"
+"MM_TWIPS"
+"MM_ISOTROPIC"
+"MM_ANISOTROPIC"
+"PU_ARBITRARY"
+"PU_PELS"
+"PU_LOMETRIC"
+"PU_HIMETRIC"
+"PU_LOENGLISH"
+"PU_HIENGLISH"
+"PU_TWIPS"
+
+# headers and footers
+"\\headerl"
+"\\headerr"
+"\\headerf"
+"\\footerl"
+"\\footerr"
+"\\footerf"
+
+# misc
+"\\*\\footnote"
+"\\*\\annotation"
+"\\xe"
+"\\txe"
+"\\rxe"
+"\\bxe"
+"\\ixe"
+"\\tcf"
+"\\tcl"
+"\\*\\bkmkstart"
+"\\*\\bkmkend"
+"\\bkmkcolf"
+"\\bkmkcoll"
+
+# metadata
+"\\info"
+"\\title"
+"\\subject"
+"\\author"
+"\\operator"
+"\\keywords"
+"\\comment"
+"\\version"
+"\\doccomm"
+"\\vern"
+"\\creatim"
+"\\revtim"
+"\\printim"
+"\\buptim"
+"\\edmins"
+"\\yr"
+"\\mo"
+"\\dy"
+"\\hr"
+"\\min"
+"\\nofpages"
+"\\nofwords"
+"\\nofchars"
+"\\id"
+"\\field"
+"\\flddirty"
+"\\fldedit"
+"\\fldlock"
+"\\fldpriv"
+"\\*\\fldinst"
+"\\fldrslt"
+
+# objects
+"\\objemb"
+"\\objlink"
+"\\objautlink"
+"\\objsub"
+"\\objicemb"
+"\\linkself"
+"\\objlock"
+"\\objclass"
+"\\objname"
+"\\objh"
+"\\objw"
+"\\objsetsize"
+"\\objtransy"
+"\\objcropt"
+"\\objcropb"
+"\\objcropl"
+"\\objcropr"
+"\\objscalex"
+"\\objscaley"
+"\\objdata"
+"\\objalias"
+"\\objsect"
+"\\rsltrtf"
+"\\rsltpict"
+"\\rsltbmp"
+"\\rslttxt"
+"\\rsltmerge"
+"\\result"
+
+# macintosh editor
+"\\bkmkpub"
+"\\pubauto"
+
+# formating
+"\\deftab"
+"\\hyphhotz"
+"\\linestart"
+"\\fracwidth"
+"\\*\\nextfile"
+"\\*\\template"
+"\\makebackup"
+"\\defformat"
+"\\psover"
+"\\deflang"
+"\\ftnsep"
+"\\ftnsepc"
+"\\ftncn"
+"\\endnotes"
+"\\enddoc"
+"\\ftntj"
+"\\ftnbj"
+"\\ftnstart"
+"\\ftnrestart"
+"\\paperw"
+"\\paperh"
+"\\margl"
+"\\margr"
+"\\margt"
+"\\margb"
+"\\facingp"
+"\\gutter"
+"\\margmirror"
+"\\landscape"
+"\\pgnstart"
+"\\widowctrl"
+"\\revisions"
+"\\revprop"
+"\\revbar"
+"\\sectd"
+"\\endnhere"
+"\\binfsxn"
+"\\binsxn"
+"\\sbknone"
+"\\sbkcol"
+"\\sbkpage"
+"\\sbkeven"
+"\\sbkodd"
+"\\cols"
+"\\colsx"
+"\\linebetcol"
+"\\linemod"
+"\\linex"
+"\\linestarts"
+"\\linerestart"
+"\\lineppage"
+"\\linecont"
+"\\pgwsxn"
+"\\pghsxn"
+"\\marglsxn"
+"\\margrsxn"
+"\\margtsxn"
+"\\margbsxn"
+"\\guttersxn"
+"\\lndscpsxn"
+"\\titlepg"
+"\\headery"
+"\\footery"
+"\\pgnstarts"
+"\\pgncont"
+"\\pgnrestart"
+"\\pgnx"
+"\\pgny"
+"\\pgndec"
+"\\pgnucrm"
+"\\pgnlcrm"
+"\\pgnucltr"
+"\\pgnlcltr"
+"\\vertalt"
+"\\vertal"
+"\\vertalc"
+"\\vertalj"
+"\\pard"
+"\\s"
+"\\intbl"
+"\\keep"
+"\\keepn"
+"\\noline"
+"\\pagebb"
+"\\sbys"
+"\\ql"
+"\\qr"
+"\\qj"
+"\\qc"
+"\\fi"
+"\\li"
+"\\ri"
+"\\sb"
+"\\sa"
+"\\sl"
+"\\tx"
+"\\tqr"
+"\\tqc"
+"\\tqdec"
+"\\tb"
+"\\tldot"
+"\\tlhyph"
+"\\tlul"
+"\\tlth"
+"\\tleq"
+"\\brdrt"
+"\\brdrb"
+"\\brdrl"
+"\\brdrr"
+"\\brdrbtw"
+"\\brdrbar"
+"\\box"
+"\\brdrs"
+"\\brdrth"
+"\\brdrsh"
+"\\brdrdb"
+"\\brdrdot"
+"\\brdrhair"
+"\\brdrw"
+"\\brdrcf"
+"\\brsp"
+"\\shading"
+"\\bghoriz"
+"\\bgvert"
+"\\bgfdiag"
+"\\bgbdiag"
+"\\bgcross"
+"\\bgdcross"
+"\\bgdkhoriz"
+"\\bgdkvert"
+"\\bgdkfdiag"
+"\\bgdkbdiag"
+"\\bgdkcross"
+"\\bgdkdcross"
+"\\cfpat"
+"\\cbpat"
+"\\absw"
+"\\absh"
+"\\phmrg"
+"\\phpg"
+"\\phcol"
+"\\posx"
+"\\posxc"
+"\\posxi"
+"\\posxo"
+"\\posxr"
+"\\posxl"
+"\\pvmrg"
+"\\pvpg"
+"\\pvpara"
+"\\posy"
+"\\posyil"
+"\\posyt"
+"\\posyc"
+"\\posyb"
+"\\dxfrtext"
+"\\dyfrtext"
+
+#tables
+"\\trowd"
+"\\trgaph"
+"\\cellx"
+"\\clmgf"
+"\\clmrg"
+"\\clbrdrt"
+"\\clbrdrl"
+"\\clbrdrr"
+"\\trql"
+"\\trqr"
+"\\trqc"
+"\\trleft"
+"\\trrh"
+"\\clshdng"
+"\\clbghoriz"
+"\\clbgvert"
+"\\clbgfdiag"
+"\\clbgbdiag"
+"\\clbgcross"
+"\\clbgdcross"
+"\\clbgdkhor"
+"\\clbgdkvert"
+"\\clbgdkfdiag"
+"\\clbgdkbdiag"
+"\\clbgdkcross"
+"\\clbgdkdcross"
+"\\clcfpat"
+"\\clcbpat"
+
+# char format
+"\\plain"
+"\\b"
+"\\caps"
+"\\deleted"
+"\\dn"
+"\\expnd"
+"\\f"
+"\\fs"
+"\\i"
+"\\outl"
+"\\revised"
+"\\scaps"
+"\\shad"
+"\\strike"
+"\\ul"
+"\\uld"
+"\\uldb"
+"\\ulnone"
+"\\ulw"
+"\\up"
+"\\v"
+"\\lang"
+
+# special chars
+"\\chdate"
+"\\chdpl"
+"\\chdpa"
+"\\chtime"
+"\\chpgn"
+"\\chftn"
+"\\chatn"
+"\\chftnsep"
+"\\chftnsepc"
+"\\cell"
+"\\row"
+"\\par"
+"\\sect"
+"\\page"
+"\\column"
+"\\line"
+"\\tab"
+"\\emdash"
+"\\endash"
+"\\bullet"
+"\\lquote"
+"\\rquote"
+"\\ldblquote"
+"\\rdblquote"
+"\\|"
+"\\~"
+"\\-"
+"\\_"
+"\\:"
+"\\*"
+"\\'hh"
+"\\alt"
+"\\shift"
+"\\ctrl"
diff --git a/dictionaries/sas.dict b/dictionaries/sas.dict
new file mode 100644
index 00000000..2c8d14b2
--- /dev/null
+++ b/dictionaries/sas.dict
@@ -0,0 +1,37 @@
+" "
+"#"
+"$"
+"$CHAR"
+"%LET"
+"("
+")"
+"*/"
+"/*"
+";"
+"@"
+"ATTRIB"
+"CLEAR"
+"CONTENTS"
+"DATA"
+"DATE"
+"FILENAME"
+"FOOTNOTE"
+"FORMAT"
+"IF"
+"INFILE"
+"INPUT"
+"INVALUE"
+"LABEL"
+"LENGTH"
+"LIBNAME"
+"LIST"
+"MISSING"
+"OPTIONS"
+"OTHER"
+"PRINT"
+"PROC"
+"RUN"
+"VALUE"
+"_ALL_"
+"dlm"
+"firstobs"
diff --git a/dictionaries/spss.dict b/dictionaries/spss.dict
new file mode 100644
index 00000000..a9debe0e
--- /dev/null
+++ b/dictionaries/spss.dict
@@ -0,0 +1,46 @@
+"("
+"(NOMINAL)"
+"(ORDINAL)"
+"(SCALE)"
+")"
+"."
+"/"
+"/VARIABLES"
+"="
+" "
+"A"
+"ADATE"
+"COMMENT"
+"DATA"
+"DATASET"
+"DATE"
+"DELIMITERS"
+"DICTIONARY"
+"DISPLAY"
+"END"
+"EXECUTE"
+"F"
+"FILE"
+"FIRSTCASE"
+"FIXED"
+"FORMATS"
+"HANDLE"
+"IF"
+"INPUT"
+"LABEL"
+"LABELS"
+"LEVEL"
+"LIST"
+"NAME"
+"OUTFILE"
+"PROGRAM"
+"RECODE"
+"RECORD"
+"SAVE"
+"SELECT"
+"SET"
+"SYSMIS"
+"TABLE"
+"VALUE"
+"VARIABLE"
+"WINDOW"
diff --git a/dictionaries/sql.dict b/dictionaries/sql.dict
new file mode 100644
index 00000000..efa44ba8
--- /dev/null
+++ b/dictionaries/sql.dict
@@ -0,0 +1,282 @@
+#
+# AFL dictionary for SQL
+# ----------------------
+#
+# Modeled based on SQLite documentation, contains some number of SQLite
+# extensions. Other dialects of SQL may benefit from customized dictionaries.
+#
+# If you append @1 to the file name when loading this dictionary, afl-fuzz
+# will also additionally load a selection of pragma keywords that are very
+# specific to SQLite (and are probably less interesting from the security
+# standpoint, because they are usually not allowed in non-privileged
+# contexts).
+#
+# Created by Michal Zalewski
+#
+
+function_abs=" abs(1)"
+function_avg=" avg(1)"
+function_changes=" changes()"
+function_char=" char(1)"
+function_coalesce=" coalesce(1,1)"
+function_count=" count(1)"
+function_date=" date(1,1,1)"
+function_datetime=" datetime(1,1,1)"
+function_decimal=" decimal(1,1)"
+function_glob=" glob(1,1)"
+function_group_concat=" group_concat(1,1)"
+function_hex=" hex(1)"
+function_ifnull=" ifnull(1,1)"
+function_instr=" instr(1,1)"
+function_julianday=" julianday(1,1,1)"
+function_last_insert_rowid=" last_insert_rowid()"
+function_length=" length(1)"
+function_like=" like(1,1)"
+function_likelihood=" likelihood(1,1)"
+function_likely=" likely(1)"
+function_load_extension=" load_extension(1,1)"
+function_lower=" lower(1)"
+function_ltrim=" ltrim(1,1)"
+function_max=" max(1,1)"
+function_min=" min(1,1)"
+function_nullif=" nullif(1,1)"
+function_printf=" printf(1,1)"
+function_quote=" quote(1)"
+function_random=" random()"
+function_randomblob=" randomblob(1)"
+function_replace=" replace(1,1,1)"
+function_round=" round(1,1)"
+function_rtrim=" rtrim(1,1)"
+function_soundex=" soundex(1)"
+function_sqlite_compileoption_get=" sqlite_compileoption_get(1)"
+function_sqlite_compileoption_used=" sqlite_compileoption_used(1)"
+function_sqlite_source_id=" sqlite_source_id()"
+function_sqlite_version=" sqlite_version()"
+function_strftime=" strftime(1,1,1,1)"
+function_substr=" substr(1,1,1)"
+function_sum=" sum(1)"
+function_time=" time(1,1,1)"
+function_total=" total(1)"
+function_total_changes=" total_changes()"
+function_trim=" trim(1,1)"
+function_typeof=" typeof(1)"
+function_unicode=" unicode(1)"
+function_unlikely=" unlikely(1)"
+function_upper=" upper(1)"
+function_varchar=" varchar(1)"
+function_zeroblob=" zeroblob(1)"
+
+keyword_ABORT="ABORT"
+keyword_ACTION="ACTION"
+keyword_ADD="ADD"
+keyword_AFTER="AFTER"
+keyword_ALL="ALL"
+keyword_ALTER="ALTER"
+keyword_ANALYZE="ANALYZE"
+keyword_AND="AND"
+keyword_AS="AS"
+keyword_ASC="ASC"
+keyword_ATTACH="ATTACH"
+keyword_AUTOINCREMENT="AUTOINCREMENT"
+keyword_BEFORE="BEFORE"
+keyword_BEGIN="BEGIN"
+keyword_BETWEEN="BETWEEN"
+keyword_BY="BY"
+keyword_CASCADE="CASCADE"
+keyword_CASE="CASE"
+keyword_CAST="CAST"
+keyword_CHECK="CHECK"
+keyword_COLLATE="COLLATE"
+keyword_COLUMN="COLUMN"
+keyword_COMMIT="COMMIT"
+keyword_CONFLICT="CONFLICT"
+keyword_CONSTRAINT="CONSTRAINT"
+keyword_CREATE="CREATE"
+keyword_CROSS="CROSS"
+keyword_CURRENT_DATE="CURRENT_DATE"
+keyword_CURRENT_TIME="CURRENT_TIME"
+keyword_CURRENT_TIMESTAMP="CURRENT_TIMESTAMP"
+keyword_DATABASE="DATABASE"
+keyword_DEFAULT="DEFAULT"
+keyword_DEFERRABLE="DEFERRABLE"
+keyword_DEFERRED="DEFERRED"
+keyword_DELETE="DELETE"
+keyword_DESC="DESC"
+keyword_DETACH="DETACH"
+keyword_DISTINCT="DISTINCT"
+keyword_DROP="DROP"
+keyword_EACH="EACH"
+keyword_ELSE="ELSE"
+keyword_END="END"
+keyword_ESCAPE="ESCAPE"
+keyword_EXCEPT="EXCEPT"
+keyword_EXCLUSIVE="EXCLUSIVE"
+keyword_EXISTS="EXISTS"
+keyword_EXPLAIN="EXPLAIN"
+keyword_FAIL="FAIL"
+keyword_FOR="FOR"
+keyword_FOREIGN="FOREIGN"
+keyword_FROM="FROM"
+keyword_FULL="FULL"
+keyword_GLOB="GLOB"
+keyword_GROUP="GROUP"
+keyword_HAVING="HAVING"
+keyword_IF="IF"
+keyword_IGNORE="IGNORE"
+keyword_IMMEDIATE="IMMEDIATE"
+keyword_IN="IN"
+keyword_INDEX="INDEX"
+keyword_INDEXED="INDEXED"
+keyword_INITIALLY="INITIALLY"
+keyword_INNER="INNER"
+keyword_INSERT="INSERT"
+keyword_INSTEAD="INSTEAD"
+keyword_INTERSECT="INTERSECT"
+keyword_INTO="INTO"
+keyword_IS="IS"
+keyword_ISNULL="ISNULL"
+keyword_JOIN="JOIN"
+keyword_KEY="KEY"
+keyword_LEFT="LEFT"
+keyword_LIKE="LIKE"
+keyword_LIMIT="LIMIT"
+keyword_MATCH="MATCH"
+keyword_NATURAL="NATURAL"
+keyword_NO="NO"
+keyword_NOT="NOT"
+keyword_NOTNULL="NOTNULL"
+keyword_NULL="NULL"
+keyword_OF="OF"
+keyword_OFFSET="OFFSET"
+keyword_ON="ON"
+keyword_OR="OR"
+keyword_ORDER="ORDER"
+keyword_OUTER="OUTER"
+keyword_PLAN="PLAN"
+keyword_PRAGMA="PRAGMA"
+keyword_PRIMARY="PRIMARY"
+keyword_QUERY="QUERY"
+keyword_RAISE="RAISE"
+keyword_RECURSIVE="RECURSIVE"
+keyword_REFERENCES="REFERENCES"
+keyword_REGEXP="REGEXP"
+keyword_REINDEX="REINDEX"
+keyword_RELEASE="RELEASE"
+keyword_RENAME="RENAME"
+keyword_REPLACE="REPLACE"
+keyword_RESTRICT="RESTRICT"
+keyword_RIGHT="RIGHT"
+keyword_ROLLBACK="ROLLBACK"
+keyword_ROW="ROW"
+keyword_SAVEPOINT="SAVEPOINT"
+keyword_SELECT="SELECT"
+keyword_SET="SET"
+keyword_TABLE="TABLE"
+keyword_TEMP="TEMP"
+keyword_TEMPORARY="TEMPORARY"
+keyword_THEN="THEN"
+keyword_TO="TO"
+keyword_TRANSACTION="TRANSACTION"
+keyword_TRIGGER="TRIGGER"
+keyword_UNION="UNION"
+keyword_UNIQUE="UNIQUE"
+keyword_UPDATE="UPDATE"
+keyword_USING="USING"
+keyword_VACUUM="VACUUM"
+keyword_VALUES="VALUES"
+keyword_VIEW="VIEW"
+keyword_VIRTUAL="VIRTUAL"
+keyword_WHEN="WHEN"
+keyword_WHERE="WHERE"
+keyword_WITH="WITH"
+keyword_WITHOUT="WITHOUT"
+
+operator_concat=" || "
+operator_ebove_eq=" >="
+
+snippet_1eq1=" 1=1"
+snippet_at=" @1"
+snippet_backticks=" `a`"
+snippet_blob=" blob"
+snippet_brackets=" [a]"
+snippet_colon=" :1"
+snippet_comment=" /* */"
+snippet_date="2001-01-01"
+snippet_dollar=" $1"
+snippet_dotref=" a.b"
+snippet_fmtY="%Y"
+snippet_int=" int"
+snippet_neg1=" -1"
+snippet_pair=" a,b"
+snippet_parentheses=" (1)"
+snippet_plus2days="+2 days"
+snippet_qmark=" ?1"
+snippet_semicolon=" ;"
+snippet_star=" *"
+snippet_string_pair=" \"a\",\"b\""
+
+string_dbl_q=" \"a\""
+string_escaped_q=" 'a''b'"
+string_single_q=" 'a'"
+
+pragma_application_id@1=" application_id"
+pragma_auto_vacuum@1=" auto_vacuum"
+pragma_automatic_index@1=" automatic_index"
+pragma_busy_timeout@1=" busy_timeout"
+pragma_cache_size@1=" cache_size"
+pragma_cache_spill@1=" cache_spill"
+pragma_case_sensitive_like@1=" case_sensitive_like"
+pragma_checkpoint_fullfsync@1=" checkpoint_fullfsync"
+pragma_collation_list@1=" collation_list"
+pragma_compile_options@1=" compile_options"
+pragma_count_changes@1=" count_changes"
+pragma_data_store_directory@1=" data_store_directory"
+pragma_database_list@1=" database_list"
+pragma_default_cache_size@1=" default_cache_size"
+pragma_defer_foreign_keys@1=" defer_foreign_keys"
+pragma_empty_result_callbacks@1=" empty_result_callbacks"
+pragma_encoding@1=" encoding"
+pragma_foreign_key_check@1=" foreign_key_check"
+pragma_foreign_key_list@1=" foreign_key_list"
+pragma_foreign_keys@1=" foreign_keys"
+pragma_freelist_count@1=" freelist_count"
+pragma_full_column_names@1=" full_column_names"
+pragma_fullfsync@1=" fullfsync"
+pragma_ignore_check_constraints@1=" ignore_check_constraints"
+pragma_incremental_vacuum@1=" incremental_vacuum"
+pragma_index_info@1=" index_info"
+pragma_index_list@1=" index_list"
+pragma_integrity_check@1=" integrity_check"
+pragma_journal_mode@1=" journal_mode"
+pragma_journal_size_limit@1=" journal_size_limit"
+pragma_legacy_file_format@1=" legacy_file_format"
+pragma_locking_mode@1=" locking_mode"
+pragma_max_page_count@1=" max_page_count"
+pragma_mmap_size@1=" mmap_size"
+pragma_page_count@1=" page_count"
+pragma_page_size@1=" page_size"
+pragma_parser_trace@1=" parser_trace"
+pragma_query_only@1=" query_only"
+pragma_quick_check@1=" quick_check"
+pragma_read_uncommitted@1=" read_uncommitted"
+pragma_recursive_triggers@1=" recursive_triggers"
+pragma_reverse_unordered_selects@1=" reverse_unordered_selects"
+pragma_schema_version@1=" schema_version"
+pragma_secure_delete@1=" secure_delete"
+pragma_short_column_names@1=" short_column_names"
+pragma_shrink_memory@1=" shrink_memory"
+pragma_soft_heap_limit@1=" soft_heap_limit"
+pragma_stats@1=" stats"
+pragma_synchronous@1=" synchronous"
+pragma_table_info@1=" table_info"
+pragma_temp_store@1=" temp_store"
+pragma_temp_store_directory@1=" temp_store_directory"
+pragma_threads@1=" threads"
+pragma_user_version@1=" user_version"
+pragma_vdbe_addoptrace@1=" vdbe_addoptrace"
+pragma_vdbe_debug@1=" vdbe_debug"
+pragma_vdbe_listing@1=" vdbe_listing"
+pragma_vdbe_trace@1=" vdbe_trace"
+pragma_wal_autocheckpoint@1=" wal_autocheckpoint"
+pragma_wal_checkpoint@1=" wal_checkpoint"
+pragma_writable_schema@1=" writable_schema"
diff --git a/dictionaries/stata.dict b/dictionaries/stata.dict
new file mode 100644
index 00000000..2c619db8
--- /dev/null
+++ b/dictionaries/stata.dict
@@ -0,0 +1,22 @@
+" "
+")"
+"*/"
+"/*"
+"_column("
+"_firstlineoffile("
+"_line("
+"_lines("
+"_lrecl("
+"_newline"
+"_skip("
+"byte"
+"dictionary"
+"double"
+"float"
+"infile"
+"int"
+"long"
+"str"
+"using"
+"{"
+"}"
diff --git a/dictionaries/svg.dict b/dictionaries/svg.dict
new file mode 100644
index 00000000..ca38b6b3
--- /dev/null
+++ b/dictionaries/svg.dict
@@ -0,0 +1,170 @@
+# Keywords taken from
+# - https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Introduction
+# - https://css-tricks.com/svg-properties-and-css/
+
+"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+"standalone="
+"version="
+"encoding="
+"<?xml"
+"?>"
+"/>"
+"<![CDATA["
+
+# tags
+"<svg"
+"xmlns=\"http://www.w3.org/2000/svg\""
+"<a"
+"<animate"
+"<animateMotion"
+"<animateTransform"
+"<circle"
+"<clipPath"
+"<color-profile"
+"<defs"
+"<desc"
+"<discard"
+"<ellipse"
+"<feBlend"
+"<feColorMatrix"
+"<feComponentTransfer"
+"<feComposite"
+"<feConvolveMatrix"
+"<feDiffuseLighting"
+"<feDisplacementMap"
+"<feDistantLight"
+"<feDropShadow"
+"<feFlood"
+"<feFuncA"
+"<feFuncB"
+"<feFuncG"
+"<feFuncR"
+"<feGaussianBlur"
+"<feImage"
+"<feMerge"
+"<feMergeNode"
+"<feMorphology"
+"<feOffset"
+"<fePointLight"
+"<feSpecularLighting"
+"<feSpotLight"
+"<feTile"
+"<feTurbulence"
+"<filter"
+"<foreignObject"
+"<g"
+"<hatch"
+"<hatchpath"
+"<image"
+"<line"
+"<linearGradient"
+"<marker"
+"<mask"
+"<mesh"
+"<meshgradient"
+"<meshpatch"
+"<meshrow"
+"<metadata"
+"<mpath"
+"<path"
+"<pattern"
+"<polygon"
+"<polyline"
+"<radialGradient"
+"<rect"
+"<rect"
+"<script"
+"<script>"
+"<set"
+"<solidcolor"
+"<stop"
+"<style"
+"<svg"
+"<switch"
+"<symbol"
+"<text"
+"<textArea"
+"<textPath"
+"<title"
+"<title>"
+"<tspan"
+"<unknown"
+"<use"
+"<view"
+
+
+# attributes
+"alignment-baseline"
+"baseline-shift"
+"class"
+"color"
+"cursor"
+"cx"
+"cy"
+"direction"
+"display"
+"dominant-baseline"
+"editable"
+"fill"
+"fill-opacity"
+"font-family"
+"font-size"
+"font-size-adjust"
+"font-stretch"
+"font-style"
+"font-variant"
+"font-weight"
+"glyph-orientation-horizontal"
+"glyph-orientation-vertical"
+"gradientUnits"
+"height"
+"kerning""
+"letter-spacing"
+"offset"
+"overflow"
+"patternContentUnits"
+"pointer-events"
+"points"
+"rotate"
+"rx"
+"ry"
+"spreadMethod"
+"stop-color"
+"stop-opacity"
+"stroke"
+"stroke-dasharray"
+"stroke-linecap"
+"stroke-linejoin"
+"stroke-opacity"
+"stroke-width"
+"style"
+"text-anchor"
+"text-decoration"
+"textlength"
+"transform"
+"unicode-bidi"
+"visibility"
+"width"
+"word-spacing"
+"writing-mode"
+"x1"
+"x2"
+"y1"
+"y2"
+
+# attributes' values
+"bounding-Box"
+"repeat"
+"display"
+"transparent"
+"orange"
+"round"
+"butt"
+"userSpaceOnUse"
+"objectBoundingBox"
+"square"
+"miter"
+"bevel"
+"translate("
+"rotate("
+"matrix("
diff --git a/dictionaries/tex.dict b/dictionaries/tex.dict
new file mode 100644
index 00000000..ce40fff5
--- /dev/null
+++ b/dictionaries/tex.dict
@@ -0,0 +1,122 @@
+# main keywords
+
+"@article{"
+"@conference{"
+"@misc{"
+"\\@."
+"\\Huge"
+"\\LARGE"
+"\\LaTeX\\"
+"\\Large"
+"\\author{"
+"\\begin{"
+"\\caption"
+"\\centering"
+"\\chapter{"
+"\\citeA{"
+"\\citeNP"
+"\\citeN{"
+"\\citeyear{"
+"\\cite{"
+"\\cline{"
+"\\date{"
+"\\documentclass{"
+"\\emph{"
+"\\end{"
+"\\footnotesize"
+"\\footnote{"
+"\\frac{"
+"\\hline"
+"\\hspace{"
+"\\huge"
+"\\includegraphics"
+"\\item{"
+"\\kill"
+"\\label{"
+"\\large"
+"\\ldots"
+"\\leq"
+"\\linespread"
+"\\maketitle{}"
+"\\multicolumn{"
+"\\newcommand{"
+"\\noindent"
+"\\normalfont{"
+"\\normalsize"
+"\\pagebreak"
+"\\pageref{"
+"\\pagestyle{"
+"\\part{"
+"\\prod_{"
+"\\raggedleft"
+"\\raggedright"
+"\\ref{"
+"\\rule{"
+"\\scriptsize"
+"\\section{"
+"\\setcounter{"
+"\\shortciteA{"
+"\\shortciteNP"
+"\\shortciteN{"
+"\\shortcite{"
+"\\small"
+"\\sqrt{"
+"\\subsection{"
+"\\sum_{"
+"\\tableofcontents"
+"\\textbackslash"
+"\\textbar"
+"\\textbf{"
+"\\textgreater"
+"\\textit{"
+"\\textless"
+"\\textmd{"
+"\\textnormal{"
+"\\textrm{"
+"\\textsc{"
+"\\textsf{"
+"\\textsl{"
+"\\texttt{"
+"\\textup{"
+"\\tiny"
+"\\title{"
+"\\today"
+"\\underline{"
+"\\usepackage"
+"\\vspace{"
+
+
+# misc
+
+"abbrv"
+"addres"
+"article"
+"book"
+"center"
+"description"
+"document"
+"draft"
+"em"
+"enumerate"
+"equation"
+"figure"
+"flushleft"
+"flushright"
+"hyperref"
+"itemize"
+"landscape"
+"letter"
+"letterpaper"
+"plain"
+"publisher"
+"quotation"
+"quote"
+"report"
+"slides"
+"tabular*"
+"twocolumn"
+"twoside"
+"unsrt"
+"verbatim*"
+"verse"
+"year"
diff --git a/dictionaries/theme-load-fuzz.dict b/dictionaries/theme-load-fuzz.dict
new file mode 100644
index 00000000..928b2a79
--- /dev/null
+++ b/dictionaries/theme-load-fuzz.dict
@@ -0,0 +1,9 @@
+"{"
+"}"
+"\""
+";"
+"="
+"formats"
+"replaces"
+"abstracts"
+"timestamp"
diff --git a/dictionaries/tiff.dict b/dictionaries/tiff.dict
new file mode 100644
index 00000000..720e56ce
--- /dev/null
+++ b/dictionaries/tiff.dict
@@ -0,0 +1,51 @@
+#
+# AFL dictionary for TIFF images
+# ------------------------------
+#
+# Just the basic, standard-originating sections; does not include vendor
+# extensions.
+#
+# Created by Michal Zalewski
+#
+
+header_ii="II*\x00"
+header_mm="MM\x00*"
+
+section_100="\x00\x01"
+section_101="\x01\x01"
+section_102="\x02\x01"
+section_103="\x03\x01"
+section_106="\x06\x01"
+section_107="\x07\x01"
+section_10D="\x0d\x01"
+section_10E="\x0e\x01"
+section_10F="\x0f\x01"
+section_110="\x10\x01"
+section_111="\x11\x01"
+section_112="\x12\x01"
+section_115="\x15\x01"
+section_116="\x16\x01"
+section_117="\x17\x01"
+section_11A="\x1a\x01"
+section_11B="\x1b\x01"
+section_11C="\x1c\x01"
+section_11D="\x1d\x01"
+section_11E="\x1e\x01"
+section_11F="\x1f\x01"
+section_122="\"\x01"
+section_123="#\x01"
+section_124="$\x01"
+section_125="%\x01"
+section_128="(\x01"
+section_129=")\x01"
+section_12D="-\x01"
+section_131="1\x01"
+section_132="2\x01"
+section_13B=";\x01"
+section_13C="<\x01"
+section_13D="=\x01"
+section_13E=">\x01"
+section_13F="?\x01"
+section_140="@\x01"
+section_FE="\xfe\x00"
+section_FF="\xff\x00"
diff --git a/dictionaries/tokener_parse_ex.dict b/dictionaries/tokener_parse_ex.dict
new file mode 100644
index 00000000..23c6fa2c
--- /dev/null
+++ b/dictionaries/tokener_parse_ex.dict
@@ -0,0 +1,18 @@
+"{"
+"}"
+","
+"["
+"]"
+","
+":"
+"e"
+"e+"
+"e-"
+"E"
+"E+"
+"E-"
+"\""
+"null"
+"1"
+"1.234"
+"3e4"
diff --git a/dictionaries/toml.dict b/dictionaries/toml.dict
new file mode 100644
index 00000000..5fa58065
--- /dev/null
+++ b/dictionaries/toml.dict
@@ -0,0 +1,22 @@
+# https://github.com/toml-lang/toml
+
+key_value="a.b=\"c\""
+unicode="\\u1234"
+unicode_long="\\u12345678"
+true="true"
+false="false"
+multiline_literal="'''"
+multiline="\"\"\""
+integer="+1_2_3_4"
+negative_integer="-1"
+hex="0xde_ad"
+oct="0o6"
+bin="0b1"
+float="-6_3.6e-05"
+nan="nan"
+inf="inf"
+time="1979-05-27T07:32:00Z"
+array="[1,2]"
+table="[a]"
+inline_table="a={1=2,3=4}"
+array_table="[[a]]"
diff --git a/dictionaries/type42.dict b/dictionaries/type42.dict
new file mode 100644
index 00000000..f0aac6bc
--- /dev/null
+++ b/dictionaries/type42.dict
@@ -0,0 +1,25 @@
+# https://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5012.Type42_Spec.pdf
+# This format is a super-set of postscript, so don't forget to use ps.dict as well
+
+magic="%!PS-TrueTypeFont"
+"%%VMUsage:"
+"/FontType"
+"/FontMatrix"
+"/FontName"
+"/FontInfo"
+"/Encoding"
+"/FontBBox"
+"/UniqueID"
+"/XUID"
+"/PaintType"
+"/StrokeWidth"
+"/Metrics"
+"/Metrics2"
+"/CDevProc"
+"/CharStrings"
+"/sfnts"
+"/CIDMap"
+"/GDBytes"
+"/GlyphDirectory"
+"/MetricsCount"
+"/WMode"
diff --git a/dictionaries/url.dict b/dictionaries/url.dict
new file mode 100644
index 00000000..098f9053
--- /dev/null
+++ b/dictionaries/url.dict
@@ -0,0 +1,62 @@
+# https://en.wikipedia.org/wiki/Uniform_Resource_Identifier
+
+# scheme
+"aim"
+"callto"
+"cvs"
+"data"
+"facetime"
+"feed"
+"file"
+"ftp"
+"git"
+"gopher"
+"gtalk"
+"h323"
+"hdl"
+"http"
+"https"
+"imap"
+"irc"
+"irc6"
+"ircs"
+"itms"
+"javascript"
+"magnet"
+"mailto"
+"mms"
+"msnim"
+"news"
+"nntp"
+"prospero"
+"rsync"
+"rtsp"
+"rtspu"
+"sftp"
+"shttp"
+"sip"
+"sips"
+"skype"
+"smb"
+"snews"
+"ssh"
+"svn"
+"svn"
+"svn+ssh"
+"telnet"
+"tel"
+"wais"
+"ymsg"
+
+# encoded characters
+"%2f"
+"%40"
+"%26"
+
+# misc
+"://"
+"//"
+"\\"
+"../"
+";type=a"
+"xn--"
diff --git a/dictionaries/utf8.dict b/dictionaries/utf8.dict
new file mode 100644
index 00000000..ab0d6e35
--- /dev/null
+++ b/dictionaries/utf8.dict
@@ -0,0 +1,73 @@
+# https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
+
+
+# Defines byteorder and endianess
+byte_order="\xFE\xFF"
+
+# Reorder the display of text for RTL reading
+right_to_left="\x20\x2E"
+
+# Mongolian Vowel Separator: invisible and has the whitespace property
+invisible_separator="\x18\x03"
+
+# Invisible zero-width character.
+word_join="\x20\x60"
+
+# Reserved code point
+reserved="\xfe\xfe"
+
+# Invalid code point
+invalid1="\xff\xff"
+invalid2="\x01\xff\xff"
+invalid3="\xfdd0"
+
+# unassigned code point
+unassigned="\x0f\xed"
+
+# illegal low half-surrogate
+illegal_low="\xde\xad"
+
+# illegal high half-surrogate
+illegal_high="\xda\xad"
+
+# private use area code usbed by apple for its logo
+apple="\xf8\xff"
+
+# hostname normalization
+fullwidth_solidus="\xff\x0f"
+
+# numerical mapping and a value
+bold_eight="\x01\xd7\xd6"
+
+# # U+00DF normalizes to "ss" during IDNA2003's mapping phase,
+# different from its IDNA2008 mapping. See http://www.unicode.org/reports/tr46/
+weird="\x00\xdf"
+
+# U+FDFD expands by 11x (UTF-8) and 18x (UTF-16) under NFKC/NFKC
+expansion="\xfd\xfd"
+
+# U+0390 expands by 3x (UTF-8) under NFD
+expansion2="\x03\x90"
+
+# U+1F82 expands by 4x (UTF-16) under NFD
+expansion3= "\x1F\x82"
+
+# U+FB2C expands by 3x (UTF-16) under NFC
+expansion4="\xFB\x2C"
+
+# Lowecaser expansion: https://twitter.com/jifa/status/625776454479970304
+low_exp1="\x02\x3a"
+low_exp2="\x02\x3e"
+low_exp3="\x00\xdf"
+low_exp4="\x1e\x9e"
+
+# Null byte
+null="\x00\x00"
+"\xfc\x80\x80\x80\x80\x80"
+"fc\x80\x80\x80\x80\xaf"
+
+# Confusing new lines
+"\x00\x1b"
+"\x00\x85"
+"\x20\x28"
+"\x20\x29"
diff --git a/dictionaries/vcf.dict b/dictionaries/vcf.dict
new file mode 100644
index 00000000..3043f611
--- /dev/null
+++ b/dictionaries/vcf.dict
@@ -0,0 +1,119 @@
+# https://en.wikipedia.org/wiki/VCard
+
+# Properties
+"ADR;"
+"AGENT:"
+"ANNIVERSARY:"
+"BDAY:"
+"BEGIN:VCARD"
+"BIRTHPLACE;"
+"CALADRURI:"
+"CALURI:"
+"CATEGORIES:"
+"CLASS:"
+"CLIENTPIDMAP:"
+"DEATHDATE:"
+"DEATHPLACE;"
+"EMAIL:"
+"END:VCARD"
+"EXPERTISE;"
+"FBURL:"
+"FN:"
+"GENDER:"
+"GEO:"
+"HOBBY;"
+"IMPP:"
+"INTEREST;"
+"KEY"
+"KIND"
+"LABEL;"
+"LANG"
+"LOGO"
+"MAILER"
+"N:"
+"NAME:"
+"NICKNAME:"
+"NOTE:"
+"ORG:"
+"ORG-DIRECTORY:"
+"PHOTO;"
+"PRODID:"
+"PROFILE:VCARD"
+"RELATED;"
+"REV:"
+"ROLE:"
+"SHORT-STRING:"
+"SOUND;"
+"SOURCES:"
+"TEL;"
+"TITLE:"
+"TZ:"
+"UID:"
+"URL:"
+"VERSION:3.0"
+"XML:"
+
+# Extensions
+"X-ABUID"
+"X-AIM"
+"X-ANNIVERSARY"
+"X-ASSISTANT"
+"X-EVOLUTION-ANNIVERSARY"
+"X-EVOLUTION-ASSISTANT"
+"X-EVOLUTION-BLOG-URL"
+"X-EVOLUTION-CALLBACK"
+"X-EVOLUTION-FILE-AS"
+"X-EVOLUTION-LIST"
+"X-EVOLUTION-LIST-SHOW_ADDRESSES"
+"X-EVOLUTION-MANAGER"
+"X-EVOLUTION-RADIO"
+"X-EVOLUTION-SPOUSE"
+"X-EVOLUTION-TELEX"
+"X-EVOLUTION-TTYTDD"
+"X-EVOLUTION-VIDEO-URL"
+"X-GADUGADU"
+"X-GENDER"
+"X-GOOGLE-TALK,"
+"X-GROUPWISE"
+"X-ICQ"
+"X-JABBER"
+"X-KADDRESSBOOK-BlogFeed"
+"X-KADDRESSBOOK-OPENPGPFP"
+"X-KADDRESSBOOK-X-Anniversary"
+"X-KADDRESSBOOK-X-AssistantsName"
+"X-KADDRESSBOOK-X-IMAddress"
+"X-KADDRESSBOOK-X-ManagersName"
+"X-KADDRESSBOOK-X-Office"
+"X-KADDRESSBOOK-X-Profession"
+"X-KADDRESSBOOK-X-SpouseName"
+"X-MANAGER"
+"X-MOZILLA-HTML"
+"X-MOZILLA-PROPERTY"
+"X-MS-CARDPICTURE"
+"X-MS-IMADDRESS"
+"X-MS-OL-DESIGN"
+"X-MSN"
+"X-PHONETIC-FIRST-NAME,"
+"X-SKYPE,"
+"X-SPOUSE"
+"X-TWITTER"
+"X-WAB-GENDER"
+"X-WEBMONEY-ID"
+"X-YAHOO"
+
+# Misc
+"MEDIATYPE="
+"uri:tel"
+"TYPE=HOME,PREF:"
+"TYPE=PNG;"
+"TYPE=WORK,VOICE:"
+"x-qq:"
+"ENCODING=b:"
+"ENCODING=BASE64:"
+"MEDIATYPE="
+"data:"
+"application/gpg-keys;"
+"image/png;"
+"base64,"
+"audio/ogg"
+"LEVEL=expert:"
diff --git a/dictionaries/vhd.dict b/dictionaries/vhd.dict
new file mode 100644
index 00000000..100f17b3
--- /dev/null
+++ b/dictionaries/vhd.dict
@@ -0,0 +1,10 @@
+# https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-VHDX/%5bMS-VHDX%5d.pdf
+
+magic="\x65\x6C\x69\x66\x78\x64\x68\x76"
+head="\x64\x61\x65\x68"
+regi="\x69\x67\x65\x72"
+loge="\x65\x67\x6F\x6C"
+zero="\x6F\x72\x65\x7A"
+desc="\x63\x73\x65\x64"
+data="\x61\x74\x61\x64"
+metadata="\x61\x74\x61\x64\x61\x74\x65\x6D"
diff --git a/dictionaries/vpx_dec.dict b/dictionaries/vpx_dec.dict
new file mode 100644
index 00000000..c6dc1807
--- /dev/null
+++ b/dictionaries/vpx_dec.dict
@@ -0,0 +1,8 @@
+# IVF Signature + version (bytes 0-5)
+kw1="DKIF\x00\x00"
+
+# VP9 codec fourCC (bytes 8-11)
+kw2="VP90"
+
+# VP8 codec fourCC (bytes 8-11)
+kw3="VP80"
diff --git a/dictionaries/wav.dict b/dictionaries/wav.dict
new file mode 100644
index 00000000..c475d40f
--- /dev/null
+++ b/dictionaries/wav.dict
@@ -0,0 +1,25 @@
+header="RIFF"
+header_id="WAVE"
+
+fmt_chunk="fmt "
+fact_chunk="fact"
+data_chunk="data"
+cue_chunk="cue "
+playlist_chunk="plst"
+list_chunk="list"
+label_chunk="labl"
+note_chunk="note"
+labeled_text_chunk="ltxt"
+sampler_chunk="smpl"
+instrument_chunk="inst"
+
+# IFF extension: https://web.archive.org/web/20080114200405/http://www.borg.com/~jglatt/tech/aboutiff.htm
+"FORM"
+"LIST"
+"CAT "
+"ILBM"
+"AIFF"
+"ANIM"
+"CMAP"
+"MIDI"
+"MThd"
diff --git a/dictionaries/webm.dict b/dictionaries/webm.dict
new file mode 100644
index 00000000..7660ce80
--- /dev/null
+++ b/dictionaries/webm.dict
@@ -0,0 +1,152 @@
+# Element IDs.
+IdEbml = "\x1A\x45\xDF\xA3"
+IdEbmlVersion = "\x42\x86"
+IdEbmlReadVersion = "\x42\xF7"
+IdEbmlMaxIdLength = "\x42\xF2"
+IdEbmlMaxSizeLength = "\x42\xF3"
+IdDocType = "\x42\x82"
+IdDocTypeVersion = "\x42\x87"
+IdDocTypeReadVersion = "\x42\x85"
+IdVoid = "\xEC"
+IdSegment = "\x18\x53\x80\x67"
+IdSeekHead = "\x11\x4D\x9B\x74"
+IdSeek = "\x4D\xBB"
+IdSeekId = "\x53\xAB"
+IdSeekPosition = "\x53\xAC"
+IdInfo = "\x15\x49\xA9\x66"
+IdTimecodeScale = "\x2A\xD7\xB1"
+IdDuration = "\x44\x89"
+IdDateUtc = "\x44\x61"
+IdTitle = "\x7B\xA9"
+IdMuxingApp = "\x4D\x80"
+IdWritingApp = "\x57\x41"
+IdCluster = "\x1F\x43\xB6\x75"
+IdTimecode = "\xE7"
+IdPrevSize = "\xAB"
+IdSimpleBlock = "\xA3"
+IdBlockGroup = "\xA0"
+IdBlock = "\xA1"
+IdBlockVirtual = "\xA2"
+IdBlockAdditions = "\x75\xA1"
+IdBlockMore = "\xA6"
+IdBlockAddId = "\xEE"
+IdBlockAdditional = "\xA5"
+IdBlockDuration = "\x9B"
+IdReferenceBlock = "\xFB"
+IdDiscardPadding = "\x75\xA2"
+IdSlices = "\x8E"
+IdTimeSlice = "\xE8"
+IdLaceNumber = "\xCC"
+IdTracks = "\x16\x54\xAE\x6B"
+IdTrackEntry = "\xAE"
+IdTrackNumber = "\xD7"
+IdTrackUid = "\x73\xC5"
+IdTrackType = "\x83"
+IdFlagEnabled = "\xB9"
+IdFlagDefault = "\x88"
+IdFlagForced = "\x55\xAA"
+IdFlagLacing = "\x9C"
+IdDefaultDuration = "\x23\xE3\x83"
+IdName = "\x53\x6E"
+IdLanguage = "\x22\xB5\x9C"
+IdCodecId = "\x86"
+IdCodecPrivate = "\x63\xA2"
+IdCodecName = "\x25\x86\x88"
+IdCodecDelay = "\x56\xAA"
+IdSeekPreRoll = "\x56\xBB"
+IdVideo = "\xE0"
+IdFlagInterlaced = "\x9A"
+IdStereoMode = "\x53\xB8"
+IdAlphaMode = "\x53\xC0"
+IdPixelWidth = "\xB0"
+IdPixelHeight = "\xBA"
+IdPixelCropBottom = "\x54\xAA"
+IdPixelCropTop = "\x54\xBB"
+IdPixelCropLeft = "\x54\xCC"
+IdPixelCropRight = "\x54\xDD"
+IdDisplayWidth = "\x54\xB0"
+IdDisplayHeight = "\x54\xBA"
+IdDisplayUnit = "\x54\xB2"
+IdAspectRatioType = "\x54\xB3"
+IdFrameRate = "\x23\x83\xE3"
+IdColour = "\x55\xB0"
+IdMatrixCoefficients = "\x55\xB1"
+IdBitsPerChannel = "\x55\xB2"
+IdChromaSubsamplingHorz = "\x55\xB3"
+IdChromaSubsamplingVert = "\x55\xB4"
+IdCbSubsamplingHorz = "\x55\xB5"
+IdCbSubsamplingVert = "\x55\xB6"
+IdChromaSitingHorz = "\x55\xB7"
+IdChromaSitingVert = "\x55\xB8"
+IdRange = "\x55\xB9"
+IdTransferCharacteristics = "\x55\xBA"
+IdPrimaries = "\x55\xBB"
+IdMaxCll = "\x55\xBC"
+IdMaxFall = "\x55\xBD"
+IdMasteringMetadata = "\x55\xD0"
+IdPrimaryRChromaticityX = "\x55\xD1"
+IdPrimaryRChromaticityY = "\x55\xD2"
+IdPrimaryGChromaticityX = "\x55\xD3"
+IdPrimaryGChromaticityY = "\x55\xD4"
+IdPrimaryBChromaticityX = "\x55\xD5"
+IdPrimaryBChromaticityY = "\x55\xD6"
+IdWhitePointChromaticityX = "\x55\xD7"
+IdWhitePointChromaticityY = "\x55\xD8"
+IdLuminanceMax = "\x55\xD9"
+IdLuminanceMin = "\x55\xDA"
+IdProjection = "\x76\x70"
+IdProjectionType = "\x76\x71"
+IdProjectionPrivate = "\x76\x72"
+IdProjectionPoseYaw = "\x76\x73"
+IdProjectionPosePitch = "\x76\x74"
+IdProjectionPoseRoll = "\x76\x75"
+IdAudio = "\xE1"
+IdSamplingFrequency = "\xB5"
+IdOutputSamplingFrequency = "\x78\xB5"
+IdChannels = "\x9F"
+IdBitDepth = "\x62\x64"
+IdContentEncodings = "\x6D\x80"
+IdContentEncoding = "\x62\x40"
+IdContentEncodingOrder = "\x50\x31"
+IdContentEncodingScope = "\x50\x32"
+IdContentEncodingType = "\x50\x33"
+IdContentEncryption = "\x50\x35"
+IdContentEncAlgo = "\x47\xE1"
+IdContentEncKeyId = "\x47\xE2"
+IdContentEncAesSettings = "\x47\xE7"
+IdAesSettingsCipherMode = "\x47\xE8"
+IdCues = "\x1C\x53\xBB\x6B"
+IdCuePoint = "\xBB"
+IdCueTime = "\xB3"
+IdCueTrackPositions = "\xB7"
+IdCueTrack = "\xF7"
+IdCueClusterPosition = "\xF1"
+IdCueRelativePosition = "\xF0"
+IdCueDuration = "\xB2"
+IdCueBlockNumber = "\x53\x78"
+IdChapters = "\x10\x43\xA7\x70"
+IdEditionEntry = "\x45\xB9"
+IdChapterAtom = "\xB6"
+IdChapterUid = "\x73\xC4"
+IdChapterStringUid = "\x56\x54"
+IdChapterTimeStart = "\x91"
+IdChapterTimeEnd = "\x92"
+IdChapterDisplay = "\x80"
+IdChapString = "\x85"
+IdChapLanguage = "\x43\x7C"
+IdChapCountry = "\x43\x7E"
+IdTags = "\x12\x54\xC3\x67"
+IdTag = "\x73\x73"
+IdTargets = "\x63\xC0"
+IdTargetTypeValue = "\x68\xCA"
+IdTargetType = "\x63\xCA"
+IdTagTrackUid = "\x63\xC5"
+IdSimpleTag = "\x67\xC8"
+IdTagName = "\x45\xA3"
+IdTagLanguage = "\x44\x7A"
+IdTagDefault = "\x44\x84"
+IdTagString = "\x44\x87"
+IdTagBinary = "\x44\x85"
+
+# Interesting sizes.
+SizeUnknown = "\xFF"
diff --git a/dictionaries/webp.dict b/dictionaries/webp.dict
new file mode 100644
index 00000000..53aa28c7
--- /dev/null
+++ b/dictionaries/webp.dict
@@ -0,0 +1,20 @@
+#
+# AFL dictionary for WebP images
+# ------------------------------
+#
+# Created by Michal Zalewski
+#
+
+header_RIFF="RIFF"
+header_WEBP="WEBP"
+
+section_ALPH="ALPH"
+section_ANIM="ANIM"
+section_ANMF="ANMF"
+section_EXIF="EXIF"
+section_FRGM="FRGM"
+section_ICCP="ICCP"
+section_VP8="VP8 "
+section_VP8L="VP8L"
+section_VP8X="VP8X"
+section_XMP="XMP "
diff --git a/dictionaries/wkt.dict b/dictionaries/wkt.dict
new file mode 100644
index 00000000..68423b52
--- /dev/null
+++ b/dictionaries/wkt.dict
@@ -0,0 +1,35 @@
+# https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry
+
+"AFFINEPLACEMENT"
+"BREPSOLID"
+"CIRCLE"
+"CIRCULARSTRING"
+"CLOTHOID"
+"COMPOUNDCURVE"
+"CURVE"
+"CURVEPOLYGON"
+"ELLIPTICALCURVE"
+"EMPTY"
+"GEODESICSTRING"
+"GEOMETRY"
+"GEOMETRYCOLLECTION"
+"LINESTRING"
+"MULTICURVE"
+"MULTILINESTRING"
+"MULTIPOINT"
+"MULTIPOLYGON"
+"MULTISURFACE"
+"NURBSCURVE"
+"POINT"
+"PATCHES"
+"POLYGON"
+"POLYHEDRALSURFACE"
+"SPIRALCURVE"
+"SRID"
+"SURFACE"
+"TIN"
+"TRIANGLE"
+"ZM"
+
+# misc
+"(1,2)"
diff --git a/dictionaries/x86.dict b/dictionaries/x86.dict
new file mode 100644
index 00000000..0434b766
--- /dev/null
+++ b/dictionaries/x86.dict
@@ -0,0 +1,1885 @@
+# https://www.felixcloutier.com/x86/
+# https://en.wikipedia.org/wiki/X86_instruction_listings
+# https://www.nasm.us/doc/nasmdocb.html
+
+"AAA"
+"AAD"
+"AAM"
+"AAS"
+"ADC"
+"ADCX"
+"ADD"
+"ADDPD"
+"ADDPS"
+"ADDSD"
+"ADDSS"
+"ADDSUBPD"
+"ADDSUBPS"
+"ADOX"
+"AESDEC"
+"AESDECLAST"
+"AESENC"
+"AESENCLAST"
+"AESIMC"
+"AESKEYGENASSIST"
+"ALTINST"
+"AMD"
+"AND"
+"ANDN"
+"ANDNPD"
+"ANDNPS"
+"ANDPD"
+"ANDPS"
+"ARPL"
+"AVX"
+"BEXTR"
+"BLCFILL"
+"BLCI"
+"BLCIC"
+"BLCMSK"
+"BLCS"
+"BLENDPD"
+"BLENDPS"
+"BLENDVPD"
+"BLENDVPS"
+"BLSFILL"
+"BLSI"
+"BLSIC"
+"BLSMSK"
+"BLSR"
+"BNDCL"
+"BNDCN"
+"BNDCU"
+"BNDLDX"
+"BNDMK"
+"BNDMOV"
+"BNDSTX"
+"BOUND"
+"BSF"
+"BSR"
+"BSWAP"
+"BT"
+"BTC"
+"BTR"
+"BTS"
+"BZHI"
+"CALL"
+"CBW"
+"CDQ"
+"CDQE"
+"CLAC"
+"CLC"
+"CLD"
+"CLDEMOTE"
+"CLFLUSH"
+"CLFLUSHOPT"
+"CLGI"
+"CLI"
+"CLTS"
+"CLWB"
+"CLZERO"
+"CMC"
+"CMOVB"
+"CMOVcc"
+"CMP"
+"CMPEQPD"
+"CMPEQSS"
+"CMPLEPD"
+"CMPLESS"
+"CMPLTPD"
+"CMPLTSS"
+"CMPNEQPD"
+"CMPNEQSS"
+"CMPNLEPD"
+"CMPNLESS"
+"CMPNLTPD"
+"CMPNLTSS"
+"CMPORDPD"
+"CMPORDSS"
+"CMPPD"
+"CMPPS"
+"CMPS"
+"CMPSB"
+"CMPSD"
+"CMPSD*"
+"CMPSQ"
+"CMPSS"
+"CMPSW"
+"CMPUNORDPD"
+"CMPUNORDSS"
+"CMPXCHG"
+"CMPXCHG16B"
+"CMPXCHG486"
+"CMPXCHG8B"
+"COMISD"
+"COMISS"
+"CPUID"
+"CPU_READ"
+"CPU_WRITE"
+"CQO"
+"CRC32"
+"CVTDQ2PD"
+"CVTDQ2PS"
+"CVTPD2DQ"
+"CVTPD2PI"
+"CVTPD2PS"
+"CVTPI2PD"
+"CVTPI2PS"
+"CVTPS2DQ"
+"CVTPS2PD"
+"CVTPS2PI"
+"CVTSD2SI"
+"CVTSD2SS"
+"CVTSI2SD"
+"CVTSI2SS"
+"CVTSS2SD"
+"CVTSS2SI"
+"CVTTPD2DQ"
+"CVTTPD2PI"
+"CVTTPS2DQ"
+"CVTTPS2PI"
+"CVTTSD2SI"
+"CVTTSS2SI"
+"CWD"
+"CWDE"
+"DAA"
+"DAS"
+"DB"
+"DEC"
+"DIV"
+"DIVPD"
+"DIVPS"
+"DIVSD"
+"DIVSS"
+"DMINT"
+"DO"
+"DPPD"
+"DPPS"
+"EACCEPT"
+"EACCEPTCOPY"
+"EADD"
+"EAUG"
+"EBLOCK"
+"ECREATE"
+"EDBGRD"
+"EDBGWR"
+"EDECVIRTCHILD"
+"EENTER"
+"EEXIT"
+"EEXTEND"
+"EGETKEY"
+"EINCVIRTCHILD"
+"EINIT"
+"ELBUC"
+"ELDB"
+"ELDBC"
+"ELDU"
+"EMMS"
+"EMODPE"
+"EMODPR"
+"EMODT"
+"ENCLS"
+"ENCLU"
+"ENCLV"
+"ENTER"
+"EPA"
+"EQU"
+"ERDINFO"
+"EREMOVE"
+"EREPORT"
+"ERESUME"
+"ESC"
+"ESETCONTEXT"
+"ETRACK"
+"ETRACKC"
+"EWB]"
+"EXTRACTPS"
+"EXTRQ"
+"F2XM1"
+"FABS"
+"FADD"
+"FADDP"
+"FBLD"
+"FBSTP"
+"FCHS"
+"FCLEX"
+"FCMOV"
+"FCMOVB"
+"FCMOVBE"
+"FCMOVE"
+"FCMOVNB"
+"FCMOVNBE"
+"FCMOVNE"
+"FCMOVNU"
+"FCMOVU"
+"FCMOVcc"
+"FCOM"
+"FCOMI"
+"FCOMIP"
+"FCOMP"
+"FCOMPP"
+"FCOS"
+"FDECSTP"
+"FDISI"
+"FDIV"
+"FDIVP"
+"FDIVR"
+"FDIVRP"
+"FEMMS"
+"FENI"
+"FFREE"
+"FFREEP"
+"FIADD"
+"FICOM"
+"FICOMP"
+"FIDIV"
+"FIDIVR"
+"FILD"
+"FIMUL"
+"FINCSTP"
+"FINIT"
+"FIST"
+"FISTP"
+"FISTTP"
+"FISUB"
+"FISUBR"
+"FLD"
+"FLD1"
+"FLDCW"
+"FLDENV"
+"FLDENVD"
+"FLDENVW"
+"FLDL2E"
+"FLDL2T"
+"FLDLG2"
+"FLDLN2"
+"FLDPI"
+"FLDZ"
+"FMUL"
+"FMULP"
+"FNCLEX"
+"FNDISI"
+"FNENI"
+"FNINIT"
+"FNOP"
+"FNSAVE"
+"FNSAVEW"
+"FNSTCW"
+"FNSTENV"
+"FNSTENVW"
+"FNSTSW"
+"FPATAN"
+"FPREM"
+"FPREM1"
+"FPTAN"
+"FRNDINT"
+"FRSTOR"
+"FRSTORD"
+"FRSTORW"
+"FSAVE"
+"FSAVED"
+"FSAVEW"
+"FSCALE"
+"FSETPM"
+"FSIN"
+"FSINCOS"
+"FSQRT"
+"FST"
+"FSTCW"
+"FSTENV"
+"FSTENVD"
+"FSTENVW"
+"FSTP"
+"FSTSW"
+"FSUB"
+"FSUBP"
+"FSUBR"
+"FSUBRP"
+"FTST"
+"FUCOM"
+"FUCOMI"
+"FUCOMIP"
+"FUCOMP"
+"FUCOMPP"
+"FWAIT"
+"FXAM"
+"FXCH"
+"FXRSTOR"
+"FXRSTOR64"
+"FXSAVE"
+"FXSAVE64"
+"FXTRACT"
+"FYL2X"
+"FYL2XP1"
+"GF2P8AFFINEINVQB"
+"GF2P8AFFINEQB"
+"GF2P8MULB"
+"HADDPD"
+"HADDPS"
+"HINT"
+"HLT"
+"HSUBPD"
+"HSUBPS"
+"IBTS"
+"ICEBP"
+"IDIV"
+"IMUL"
+"IN"
+"INC"
+"INS"
+"INSB"
+"INSD"
+"INSERTPS"
+"INSERTQ"
+"INSW"
+"INT"
+"INT01"
+"INT03"
+"INT1"
+"INT3"
+"INTO"
+"INVD"
+"INVEPT"
+"INVLPG"
+"INVLPGA"
+"INVPCID"
+"INVVPID"
+"IRET"
+"IRETD"
+"IRETQ"
+"IRETW"
+"IRETx"
+"JCXZ"
+"JECXZ"
+"JMP"
+"JMPE"
+"JRCXZ"
+"Jcc"
+"KADDB"
+"KADDD"
+"KADDQ"
+"KADDW"
+"KANDB"
+"KANDD"
+"KANDNB"
+"KANDND"
+"KANDNQ"
+"KANDNW"
+"KANDQ"
+"KANDW"
+"KMOVB"
+"KMOVD"
+"KMOVQ"
+"KMOVW"
+"KNOTB"
+"KNOTD"
+"KNOTQ"
+"KNOTW"
+"KORB"
+"KORD"
+"KORQ"
+"KORTESTB"
+"KORTESTD"
+"KORTESTQ"
+"KORTESTW"
+"KORW"
+"KSHIFTLB"
+"KSHIFTLD"
+"KSHIFTLQ"
+"KSHIFTLW"
+"KSHIFTRB"
+"KSHIFTRD"
+"KSHIFTRQ"
+"KSHIFTRW"
+"KTESTB"
+"KTESTD"
+"KTESTQ"
+"KTESTW"
+"KUNPCKBW"
+"KUNPCKDQ"
+"KUNPCKWD"
+"KXNORB"
+"KXNORD"
+"KXNORQ"
+"KXNORW"
+"KXORB"
+"KXORD"
+"KXORQ"
+"KXORW"
+"LAHF"
+"LAR"
+"LDDQU"
+"LDMXCSR"
+"LDS"
+"LEA"
+"LEAVE"
+"LES"
+"LFENCE"
+"LFS"
+"LGDT"
+"LGS"
+"LIDT"
+"LLDT"
+"LLWPCB"
+"LMSW"
+"LOADALL"
+"LOADALL286"
+"LOADALLD"
+"LOCK"
+"LODS"
+"LODSB"
+"LODSD"
+"LODSQ"
+"LODSW"
+"LOOP"
+"LOOPD"
+"LOOPE"
+"LOOPNE"
+"LOOPNZ"
+"LOOPW"
+"LOOPZ"
+"LOOPcc"
+"LSL"
+"LSS"
+"LTR"
+"LWPINS"
+"LWPVAL"
+"LZCNT"
+"MASKMOVDQU"
+"MASKMOVQ"
+"MAXPD"
+"MAXPS"
+"MAXSD"
+"MAXSS"
+"MFENCE"
+"MINPD"
+"MINPS"
+"MINSD"
+"MINSS"
+"MONITOR"
+"MONITORX"
+"MOV"
+"MOVAPD"
+"MOVAPS"
+"MOVBE"
+"MOVD"
+"MOVDDUP"
+"MOVDIR64B"
+"MOVDIRI"
+"MOVDQ2Q"
+"MOVDQA"
+"MOVDQU"
+"MOVHLPS"
+"MOVHPD"
+"MOVHPS"
+"MOVLHPS"
+"MOVLPD"
+"MOVLPS"
+"MOVMSKPD"
+"MOVMSKPS"
+"MOVNTDQ"
+"MOVNTDQA"
+"MOVNTI"
+"MOVNTPD"
+"MOVNTPS"
+"MOVNTQ"
+"MOVNTSD"
+"MOVNTSS"
+"MOVQ"
+"MOVQ2DQ"
+"MOVS"
+"MOVSB"
+"MOVSD"
+"MOVSD*"
+"MOVSHDUP"
+"MOVSLDUP"
+"MOVSQ"
+"MOVSS"
+"MOVSW"
+"MOVSX"
+"MOVSXD"
+"MOVUPD"
+"MOVUPS"
+"MOVZX"
+"MPSADBW"
+"MUL"
+"MULPD"
+"MULPS"
+"MULSD"
+"MULSS"
+"MULX"
+"MWAIT"
+"MWAITX"
+"NEG"
+"NOP"
+"NOT"
+"OR"
+"ORPD"
+"ORPS"
+"OUT"
+"OUTS"
+"OUTSB"
+"OUTSD"
+"OUTSW"
+"PABSB"
+"PABSD"
+"PABSQ"
+"PABSW"
+"PACKSSDW"
+"PACKSSWB"
+"PACKUSDW"
+"PACKUSWB"
+"PADDB"
+"PADDD"
+"PADDQ"
+"PADDSB"
+"PADDSIW"
+"PADDSW"
+"PADDUSB"
+"PADDUSW"
+"PADDW"
+"PALIGNR"
+"PAND"
+"PANDN"
+"PAUSE"
+"PAVEB"
+"PAVGB"
+"PAVGUSB"
+"PAVGW"
+"PBLENDVB"
+"PBLENDW"
+"PCLMULHQHQDQ"
+"PCLMULHQLQDQ"
+"PCLMULQDQ"
+"PCMPEQB"
+"PCMPEQD"
+"PCMPEQQ"
+"PCMPEQW"
+"PCMPESTRI"
+"PCMPESTRM"
+"PCMPGTB"
+"PCMPGTD"
+"PCMPGTQ"
+"PCMPGTW"
+"PCMPISTRI"
+"PCMPISTRM"
+"PCOMMIT"
+"PCONFIG"
+"PDEP"
+"PDISTIB"
+"PEXT"
+"PEXTRB"
+"PEXTRD"
+"PEXTRQ"
+"PEXTRW"
+"PF2ID"
+"PF2IW"
+"PFACC"
+"PFADD"
+"PFCMPEQ"
+"PFCMPGE"
+"PFCMPGT"
+"PFMAX"
+"PFMIN"
+"PFMUL"
+"PFNACC"
+"PFPNACC"
+"PFRCP"
+"PFRCPIT1"
+"PFRCPIT2"
+"PFRCPV"
+"PFRSQIT1"
+"PFRSQRT"
+"PFRSQRTV"
+"PFSUB"
+"PFSUBR"
+"PHADDD"
+"PHADDSW"
+"PHADDW"
+"PHMINPOSUW"
+"PHSUBD"
+"PHSUBSW"
+"PHSUBW"
+"PI2FD"
+"PI2FW"
+"PINSRB"
+"PINSRD"
+"PINSRQ"
+"PINSRW"
+"PMACHRIW"
+"PMADDUBSW"
+"PMADDWD"
+"PMAGW"
+"PMAXSB"
+"PMAXSD"
+"PMAXSQ"
+"PMAXSW"
+"PMAXUB"
+"PMAXUD"
+"PMAXUQ"
+"PMAXUW"
+"PMINSB"
+"PMINSD"
+"PMINSQ"
+"PMINSW"
+"PMINUB"
+"PMINUD"
+"PMINUQ"
+"PMINUW"
+"PMOVMSKB"
+"PMOVSX"
+"PMOVSXBD"
+"PMOVSXBQ"
+"PMOVSXBW"
+"PMOVSXDQ"
+"PMOVSXWD"
+"PMOVSXWQ"
+"PMOVZX"
+"PMOVZXBD"
+"PMOVZXBQ"
+"PMOVZXBW"
+"PMOVZXDQ"
+"PMOVZXWD"
+"PMOVZXWQ"
+"PMULDQ"
+"PMULHRIW"
+"PMULHRSW"
+"PMULHRW"
+"PMULHRWA"
+"PMULHRWC"
+"PMULHUW"
+"PMULHW"
+"PMULLD"
+"PMULLQ"
+"PMULLW"
+"PMULUDQ"
+"PMVGEZB"
+"PMVLZB"
+"PMVNZB"
+"PMVZB"
+"POP"
+"POPA"
+"POPAD"
+"POPAW"
+"POPCNT"
+"POPF"
+"POPFD"
+"POPFQ"
+"POPFW"
+"POR"
+"PREFETCH"
+"PREFETCHNTA"
+"PREFETCHT0"
+"PREFETCHT1"
+"PREFETCHT2"
+"PREFETCHW"
+"PREFETCHWT1"
+"PREFETCHh"
+"PSADBW"
+"PSHUFB"
+"PSHUFD"
+"PSHUFHW"
+"PSHUFLW"
+"PSHUFW"
+"PSIGNB"
+"PSIGND"
+"PSIGNW"
+"PSLLD"
+"PSLLDQ"
+"PSLLQ"
+"PSLLW"
+"PSRAD"
+"PSRAQ"
+"PSRAW"
+"PSRLD"
+"PSRLDQ"
+"PSRLQ"
+"PSRLW"
+"PSUBB"
+"PSUBD"
+"PSUBQ"
+"PSUBSB"
+"PSUBSIW"
+"PSUBSW"
+"PSUBUSB"
+"PSUBUSW"
+"PSUBW"
+"PSWAPD"
+"PTEST"
+"PTWRITE"
+"PUNPCKHBW"
+"PUNPCKHDQ"
+"PUNPCKHQDQ"
+"PUNPCKHWD"
+"PUNPCKLBW"
+"PUNPCKLDQ"
+"PUNPCKLQDQ"
+"PUNPCKLWD"
+"PUSH"
+"PUSHA"
+"PUSHAD"
+"PUSHAW"
+"PUSHF"
+"PUSHFD"
+"PUSHFQ"
+"PUSHFW"
+"PXOR"
+"RCL"
+"RCPPS"
+"RCPSS"
+"RCR"
+"RDFSBASE"
+"RDGSBASE"
+"RDM"
+"RDMSR"
+"RDPID"
+"RDPKRU"
+"RDPMC"
+"RDRAND"
+"RDSEED"
+"RDSHR"
+"RDTSC"
+"RDTSCP"
+"REP"
+"REPE"
+"REPNE"
+"REPNZ"
+"REPZ"
+"REPxx"
+"RESO"
+"RESW"
+"RESZ"
+"RET"
+"RETD"
+"RETF"
+"RETFD"
+"RETFQ"
+"RETFW"
+"RETN"
+"RETND"
+"RETNQ"
+"RETNW"
+"RETQ"
+"RETW"
+"ROL"
+"ROR"
+"RORX"
+"ROUNDPD"
+"ROUNDPS"
+"ROUNDSD"
+"ROUNDSS"
+"RSDC"
+"RSLDT"
+"RSM"
+"RSQRTPS"
+"RSQRTSS"
+"RSTS"
+"SAHF"
+"SAL"
+"SALC"
+"SAR"
+"SARX"
+"SBB"
+"SCAS"
+"SCASB"
+"SCASD"
+"SCASQ"
+"SCASW"
+"SETcc"
+"SETALC"
+"SFENCE"
+"SGDT"
+"SGX"
+"SHA1MSG1"
+"SHA1MSG2"
+"SHA1NEXTE"
+"SHA1RNDS4"
+"SHA256MSG1"
+"SHA256MSG2"
+"SHA256RNDS2"
+"SHL"
+"SHLD"
+"SHLX"
+"SHR"
+"SHRD"
+"SHRX"
+"SHUFPD"
+"SHUFPS"
+"SIDT"
+"SKINIT"
+"SLDT"
+"SLWPCB"
+"SMI"
+"SMINT"
+"SMINTOLD"
+"SMSW"
+"SMX"
+"SQRTPD"
+"SQRTPS"
+"SQRTSD"
+"SQRTSS"
+"SSE2"
+"STAC"
+"STC"
+"STD"
+"STGI"
+"STI"
+"STMXCSR"
+"STOS"
+"STOSB"
+"STOSD"
+"STOSQ"
+"STOSW"
+"STR"
+"SUB"
+"SUBPD"
+"SUBPS"
+"SUBSD"
+"SUBSS"
+"SVDC"
+"SVLDT"
+"SVTS"
+"SWAPGS"
+"SYSCALL"
+"SYSENTER"
+"SYSEXIT"
+"SYSRET"
+"T1MSKC"
+"TEST"
+"TPAUSE"
+"TZCNT"
+"TZMSK"
+"UCOMISD"
+"UCOMISS"
+"UD"
+"UD0"
+"UD1"
+"UD2"
+"UD2A"
+"UD2B"
+"UMONITOR"
+"UMOV"
+"UMWAIT"
+"UNPCKHPD"
+"UNPCKHPS"
+"UNPCKLPD"
+"UNPCKLPS"
+"V4DPWSSDS"
+"V4FMADDPS"
+"V4FMADDSS"
+"V4FNMADDPS"
+"V4FNMADDSS"
+"VADDPD"
+"VADDPS"
+"VADDSD"
+"VADDSS"
+"VADDSUBPD"
+"VADDSUBPS"
+"VAESDEC"
+"VAESDECLAST"
+"VAESENC"
+"VAESENCLAST"
+"VAESIMC"
+"VALIGND"
+"VALIGNQ"
+"VANDNPD"
+"VANDNPS"
+"VANDPD"
+"VANDPS"
+"VBLENDMPD"
+"VBLENDMPS"
+"VBLENDPD"
+"VBLENDPS"
+"VBLENDVPD"
+"VBLENDVPS"
+"VBROADCAST"
+"VBROADCASTF32X2"
+"VBROADCASTF32X4"
+"VBROADCASTF32X8"
+"VBROADCASTF64X2"
+"VBROADCASTF64X4"
+"VBROADCASTI128"
+"VBROADCASTI32X2"
+"VBROADCASTI32X4"
+"VBROADCASTI32X8"
+"VBROADCASTI64X2"
+"VBROADCASTI64X4"
+"VBROADCASTSD"
+"VBROADCASTSS"
+"VCMPEQPD"
+"VCMPEQPS"
+"VCMPEQSS"
+"VCMPEQ_OSPD"
+"VCMPEQ_OSPS"
+"VCMPEQ_OSSD"
+"VCMPEQ_UQPD"
+"VCMPEQ_UQPS"
+"VCMPEQ_UQSD"
+"VCMPEQ_USPD"
+"VCMPEQ_USPS"
+"VCMPEQ_USSD"
+"VCMPFALSEPD"
+"VCMPFALSEPS"
+"VCMPFALSESD"
+"VCMPFALSE_OQPD"
+"VCMPFALSE_OQPS"
+"VCMPFALSE_OQSS"
+"VCMPFALSE_OSPD"
+"VCMPFALSE_OSPS"
+"VCMPFALSE_OSSS"
+"VCMPGEPD"
+"VCMPGEPS"
+"VCMPGESS"
+"VCMPGE_OQPD"
+"VCMPGE_OQPS"
+"VCMPGE_OQSS"
+"VCMPGE_OSPD"
+"VCMPGE_OSPS"
+"VCMPGE_OSSD"
+"VCMPGTPD"
+"VCMPGTPS"
+"VCMPGTSS"
+"VCMPGT_OQPD"
+"VCMPGT_OQPS"
+"VCMPGT_OQSD"
+"VCMPGT_OSPD"
+"VCMPGT_OSPS"
+"VCMPGT_OSSD"
+"VCMPLEPD"
+"VCMPLEPS"
+"VCMPLESS"
+"VCMPLE_OQPD"
+"VCMPLE_OQPS"
+"VCMPLE_OQSD"
+"VCMPLE_OSPD"
+"VCMPLE_OSPS"
+"VCMPLE_OSSD"
+"VCMPLTPD"
+"VCMPLTPS"
+"VCMPLTSS"
+"VCMPLT_OQPD"
+"VCMPLT_OQPS"
+"VCMPLT_OQSS"
+"VCMPLT_OSPD"
+"VCMPLT_OSPS"
+"VCMPLT_OSSD"
+"VCMPNEQPD"
+"VCMPNEQPS"
+"VCMPNEQSS"
+"VCMPNEQ_OQPD"
+"VCMPNEQ_OQPS"
+"VCMPNEQ_OQSS"
+"VCMPNEQ_OSPD"
+"VCMPNEQ_OSPS"
+"VCMPNEQ_OSSD"
+"VCMPNEQ_UQPD"
+"VCMPNEQ_UQPS"
+"VCMPNEQ_UQSD"
+"VCMPNEQ_USPD"
+"VCMPNEQ_USPS"
+"VCMPNEQ_USSD"
+"VCMPNGEPD"
+"VCMPNGEPS"
+"VCMPNGESD"
+"VCMPNGE_UQPD"
+"VCMPNGE_UQPS"
+"VCMPNGE_UQSS"
+"VCMPNGE_USPD"
+"VCMPNGE_USPS"
+"VCMPNGE_USSS"
+"VCMPNGTPD"
+"VCMPNGTPS"
+"VCMPNGTSD"
+"VCMPNGT_UQPD"
+"VCMPNGT_UQPS"
+"VCMPNGT_UQSD"
+"VCMPNGT_USPD"
+"VCMPNGT_USPS"
+"VCMPNGT_USSS"
+"VCMPNLEPD"
+"VCMPNLEPS"
+"VCMPNLESS"
+"VCMPNLE_UQPD"
+"VCMPNLE_UQPS"
+"VCMPNLE_UQSD"
+"VCMPNLE_USPD"
+"VCMPNLE_USPS"
+"VCMPNLE_USSD"
+"VCMPNLTPD"
+"VCMPNLTPS"
+"VCMPNLTSS"
+"VCMPNLT_UQPD"
+"VCMPNLT_UQPS"
+"VCMPNLT_UQSS"
+"VCMPNLT_USPD"
+"VCMPNLT_USPS"
+"VCMPNLT_USSD"
+"VCMPORDPD"
+"VCMPORDPS"
+"VCMPORDSS"
+"VCMPORD_QPD"
+"VCMPORD_QPS"
+"VCMPORD_QSD"
+"VCMPORD_SPD"
+"VCMPORD_SPS"
+"VCMPORD_SSS"
+"VCMPPD"
+"VCMPPS"
+"VCMPSD"
+"VCMPTRUEPD"
+"VCMPTRUEPS"
+"VCMPTRUESS"
+"VCMPTRUE_UQPD"
+"VCMPTRUE_UQPS"
+"VCMPTRUE_UQSD"
+"VCMPTRUE_USPD"
+"VCMPTRUE_USPS"
+"VCMPTRUE_USSS"
+"VCMPUNORDPD"
+"VCMPUNORDPS"
+"VCMPUNORDSS"
+"VCMPUNORD_QPD"
+"VCMPUNORD_QPS"
+"VCMPUNORD_QSD"
+"VCMPUNORD_SPD"
+"VCMPUNORD_SPS"
+"VCMPUNORD_SSS"
+"VCOMISD"
+"VCOMPRESSPD"
+"VCOMPRESSPS"
+"VCVTDQ2PD"
+"VCVTDQ2PS"
+"VCVTPD2DQ"
+"VCVTPD2PS"
+"VCVTPD2QQ"
+"VCVTPD2UDQ"
+"VCVTPD2UQQ"
+"VCVTPH2PS"
+"VCVTPS2DQ"
+"VCVTPS2PD"
+"VCVTPS2PH"
+"VCVTPS2QQ"
+"VCVTPS2UDQ"
+"VCVTPS2UQQ"
+"VCVTQQ2PD"
+"VCVTQQ2PS"
+"VCVTSD2SI"
+"VCVTSD2SS"
+"VCVTSD2USI"
+"VCVTSI2SD"
+"VCVTSI2SS"
+"VCVTSS2SD"
+"VCVTSS2SI"
+"VCVTSS2USI"
+"VCVTTPD2DQ"
+"VCVTTPD2QQ"
+"VCVTTPD2UDQ"
+"VCVTTPD2UQQ"
+"VCVTTPS2DQ"
+"VCVTTPS2QQ"
+"VCVTTPS2UDQ"
+"VCVTTPS2UQQ"
+"VCVTTSD2SI"
+"VCVTTSD2USI"
+"VCVTTSS2SI"
+"VCVTTSS2USI"
+"VCVTUDQ2PD"
+"VCVTUDQ2PS"
+"VCVTUQQ2PD"
+"VCVTUQQ2PS"
+"VCVTUSI2SD"
+"VCVTUSI2SS"
+"VDBPSADBW"
+"VDIVPD"
+"VDIVPS"
+"VDIVSD"
+"VDPPD"
+"VDPPS"
+"VERR"
+"VERW"
+"VEXP2PD"
+"VEXP2PS"
+"VEXPANDPD"
+"VEXPANDPS"
+"VEXTRACTF128"
+"VEXTRACTF32X4"
+"VEXTRACTF32X8"
+"VEXTRACTF32x4"
+"VEXTRACTF32x8"
+"VEXTRACTF64X2"
+"VEXTRACTF64X4"
+"VEXTRACTF64x2"
+"VEXTRACTF64x4"
+"VEXTRACTI128"
+"VEXTRACTI32X4"
+"VEXTRACTI32X8"
+"VEXTRACTI32x4"
+"VEXTRACTI32x8"
+"VEXTRACTI64X2"
+"VEXTRACTI64X4"
+"VEXTRACTI64x2"
+"VEXTRACTI64x4"
+"VEXTRACTPS"
+"VFIXUPIMMPD"
+"VFIXUPIMMPS"
+"VFIXUPIMMSD"
+"VFIXUPIMMSS"
+"VFMADD123PD"
+"VFMADD123PS"
+"VFMADD123SD"
+"VFMADD132PD"
+"VFMADD132PS"
+"VFMADD132SD"
+"VFMADD132SS"
+"VFMADD213PD"
+"VFMADD213PS"
+"VFMADD213SD"
+"VFMADD213SS"
+"VFMADD231PD"
+"VFMADD231PS"
+"VFMADD231SD"
+"VFMADD231SS"
+"VFMADD312PD"
+"VFMADD312PS"
+"VFMADD312SD"
+"VFMADD321PD"
+"VFMADD321PS"
+"VFMADD321SD"
+"VFMADDPD"
+"VFMADDPS"
+"VFMADDSD"
+"VFMADDSS"
+"VFMADDSUB123PD"
+"VFMADDSUB123PS"
+"VFMADDSUB132PD"
+"VFMADDSUB132PS"
+"VFMADDSUB213PD"
+"VFMADDSUB213PS"
+"VFMADDSUB231PD"
+"VFMADDSUB231PS"
+"VFMADDSUB312PD"
+"VFMADDSUB312PS"
+"VFMADDSUB321PD"
+"VFMADDSUB321PS"
+"VFMADDSUBPD"
+"VFMADDSUBPS"
+"VFMSUB123PD"
+"VFMSUB123PS"
+"VFMSUB123SD"
+"VFMSUB132PD"
+"VFMSUB132PS"
+"VFMSUB132SD"
+"VFMSUB132SS"
+"VFMSUB213PD"
+"VFMSUB213PS"
+"VFMSUB213SD"
+"VFMSUB213SS"
+"VFMSUB231PD"
+"VFMSUB231PS"
+"VFMSUB231SD"
+"VFMSUB231SS"
+"VFMSUB312PD"
+"VFMSUB312PS"
+"VFMSUB312SD"
+"VFMSUB321PD"
+"VFMSUB321PS"
+"VFMSUB321SD"
+"VFMSUBADD123PD"
+"VFMSUBADD123PS"
+"VFMSUBADD132PD"
+"VFMSUBADD132PS"
+"VFMSUBADD213PD"
+"VFMSUBADD213PS"
+"VFMSUBADD231PD"
+"VFMSUBADD231PS"
+"VFMSUBADD312PD"
+"VFMSUBADD312PS"
+"VFMSUBADD321PD"
+"VFMSUBADD321PS"
+"VFMSUBADDPD"
+"VFMSUBADDPS"
+"VFMSUBPD"
+"VFMSUBPS"
+"VFMSUBSD"
+"VFMSUBSS"
+"VFNMADD123PD"
+"VFNMADD123PS"
+"VFNMADD123SD"
+"VFNMADD132PD"
+"VFNMADD132PS"
+"VFNMADD132SD"
+"VFNMADD132SS"
+"VFNMADD213PD"
+"VFNMADD213PS"
+"VFNMADD213SD"
+"VFNMADD213SS"
+"VFNMADD231PD"
+"VFNMADD231PS"
+"VFNMADD231SD"
+"VFNMADD231SS"
+"VFNMADD312PD"
+"VFNMADD312PS"
+"VFNMADD312SD"
+"VFNMADD321PD"
+"VFNMADD321PS"
+"VFNMADD321SD"
+"VFNMADDPD"
+"VFNMADDPS"
+"VFNMADDSD"
+"VFNMADDSS"
+"VFNMSUB123PD"
+"VFNMSUB123PS"
+"VFNMSUB123SD"
+"VFNMSUB132PD"
+"VFNMSUB132PS"
+"VFNMSUB132SD"
+"VFNMSUB132SS"
+"VFNMSUB213PD"
+"VFNMSUB213PS"
+"VFNMSUB213SD"
+"VFNMSUB213SS"
+"VFNMSUB231PD"
+"VFNMSUB231PS"
+"VFNMSUB231SD"
+"VFNMSUB231SS"
+"VFNMSUB312PD"
+"VFNMSUB312PS"
+"VFNMSUB312SD"
+"VFNMSUB321PD"
+"VFNMSUB321PS"
+"VFNMSUB321SD"
+"VFNMSUBPD"
+"VFNMSUBPS"
+"VFNMSUBSD"
+"VFNMSUBSS"
+"VFPCLASSPD"
+"VFPCLASSPS"
+"VFPCLASSSD"
+"VFPCLASSSS"
+"VFRCZPD"
+"VFRCZPS"
+"VFRCZSD"
+"VGATHERDPD"
+"VGATHERDPS"
+"VGATHERPF0DPD"
+"VGATHERPF0DPS"
+"VGATHERPF0QPD"
+"VGATHERPF0QPS"
+"VGATHERPF1DPD"
+"VGATHERPF1DPS"
+"VGATHERPF1QPD"
+"VGATHERPF1QPS"
+"VGATHERQPD"
+"VGATHERQPS"
+"VGETEXPPD"
+"VGETEXPPS"
+"VGETEXPSD"
+"VGETEXPSS"
+"VGETMANTPD"
+"VGETMANTPS"
+"VGETMANTSD"
+"VGETMANTSS"
+"VGF2P8AFFINEINVQB"
+"VGF2P8AFFINEQB"
+"VGF2P8MULB"
+"VHADDPD"
+"VHADDPS"
+"VHSUBPD"
+"VHSUBPS"
+"VINSERTF128"
+"VINSERTF32X4"
+"VINSERTF32x4"
+"VINSERTF32x8"
+"VINSERTF64X2"
+"VINSERTF64X4"
+"VINSERTF64x2"
+"VINSERTF64x4"
+"VINSERTI128"
+"VINSERTI32X4"
+"VINSERTI32x4"
+"VINSERTI32x8"
+"VINSERTI64X2"
+"VINSERTI64X4"
+"VINSERTI64x2"
+"VINSERTI64x4"
+"VINSERTPS"
+"VLDMXCSR"
+"VLDQQU"
+"VMASKMOV"
+"VMASKMOVPD"
+"VMASKMOVPS"
+"VMAXPD"
+"VMAXPS"
+"VMAXSD"
+"VMCALL"
+"VMCLEAR"
+"VMFUNC"
+"VMINPD"
+"VMINPS"
+"VMINSD"
+"VMLAUNCH"
+"VMLOAD"
+"VMMCALL"
+"VMOVAPD"
+"VMOVAPS"
+"VMOVD"
+"VMOVDDUP"
+"VMOVDQA"
+"VMOVDQA32"
+"VMOVDQA64"
+"VMOVDQU"
+"VMOVDQU16"
+"VMOVDQU32"
+"VMOVDQU64"
+"VMOVDQU8"
+"VMOVHLPS"
+"VMOVHPD"
+"VMOVHPS"
+"VMOVLHPS"
+"VMOVLPD"
+"VMOVLPS"
+"VMOVMSKPD"
+"VMOVMSKPS"
+"VMOVNTDQ"
+"VMOVNTDQA"
+"VMOVNTPD"
+"VMOVNTPS"
+"VMOVQ"
+"VMOVQQA"
+"VMOVQQU"
+"VMOVSD"
+"VMOVSHDUP"
+"VMOVSLDUP"
+"VMOVSS"
+"VMOVUPD"
+"VMOVUPS"
+"VMPSADBW"
+"VMPTRLD"
+"VMPTRST"
+"VMREAD"
+"VMRESUME"
+"VMRUN"
+"VMSAVE"
+"VMULPD"
+"VMULPS"
+"VMULSS"
+"VMWRITE"
+"VMX"
+"VMXOFF"
+"VMXON"
+"VORPD"
+"VORPS"
+"VP4DPWSSD"
+"VP4DPWSSDS"
+"VPABSB"
+"VPABSD"
+"VPABSQ"
+"VPABSW"
+"VPACKSSDW"
+"VPACKSSWB"
+"VPACKUSDW"
+"VPACKUSWB"
+"VPADDB"
+"VPADDD"
+"VPADDQ"
+"VPADDSB"
+"VPADDSW"
+"VPADDUSB"
+"VPADDUSW"
+"VPADDW"
+"VPALIGNR"
+"VPANDD"
+"VPANDN"
+"VPANDND"
+"VPANDNQ"
+"VPANDQ"
+"VPAVGB"
+"VPAVGW"
+"VPBLENDD"
+"VPBLENDMB"
+"VPBLENDMD"
+"VPBLENDMQ"
+"VPBLENDMW"
+"VPBLENDW"
+"VPBROADCAST"
+"VPBROADCASTB"
+"VPBROADCASTD"
+"VPBROADCASTM"
+"VPBROADCASTMB2Q"
+"VPBROADCASTMW2D"
+"VPBROADCASTQ"
+"VPBROADCASTW"
+"VPCLMULHQHQDQ"
+"VPCLMULHQLQDQ"
+"VPCLMULLQHQDQ"
+"VPCLMULLQLQDQ"
+"VPCLMULQDQ"
+"VPCMOV"
+"VPCMPB"
+"VPCMPD"
+"VPCMPEQB"
+"VPCMPEQD"
+"VPCMPEQQ"
+"VPCMPEQW"
+"VPCMPESTRM"
+"VPCMPGTB"
+"VPCMPGTD"
+"VPCMPGTQ"
+"VPCMPGTW"
+"VPCMPISTRM"
+"VPCMPQ"
+"VPCMPUB"
+"VPCMPUD"
+"VPCMPUQ"
+"VPCMPUW"
+"VPCMPW"
+"VPCOMB"
+"VPCOMPRESSB"
+"VPCOMPRESSD"
+"VPCOMPRESSQ"
+"VPCOMPRESSW"
+"VPCOMQ"
+"VPCOMUD"
+"VPCOMUW"
+"VPCONFLICTD"
+"VPCONFLICTQ"
+"VPDPBUSD"
+"VPDPBUSDS"
+"VPDPWSSD"
+"VPDPWSSDS"
+"VPERM2F128"
+"VPERM2I128"
+"VPERMB"
+"VPERMD"
+"VPERMI2B"
+"VPERMI2D"
+"VPERMI2PD"
+"VPERMI2PS"
+"VPERMI2Q"
+"VPERMI2W"
+"VPERMILPD"
+"VPERMILPS"
+"VPERMPD"
+"VPERMPS"
+"VPERMQ"
+"VPERMT2B"
+"VPERMT2D"
+"VPERMT2PD"
+"VPERMT2PS"
+"VPERMT2Q"
+"VPERMT2W"
+"VPERMW"
+"VPEXPANDB"
+"VPEXPANDD"
+"VPEXPANDQ"
+"VPEXPANDW"
+"VPEXTRB"
+"VPEXTRD"
+"VPEXTRQ"
+"VPEXTRW"
+"VPGATHERDD"
+"VPGATHERDQ"
+"VPGATHERQD"
+"VPGATHERQQ"
+"VPHADDBD"
+"VPHADDBW"
+"VPHADDD"
+"VPHADDUBD"
+"VPHADDUBW"
+"VPHADDUWD"
+"VPHADDWD"
+"VPHMINPOSUW"
+"VPHSUBBW"
+"VPHSUBD"
+"VPHSUBSW"
+"VPHSUBW"
+"VPHSUBWD"
+"VPINSRB"
+"VPINSRD"
+"VPINSRQ"
+"VPINSRW"
+"VPLZCNTD"
+"VPLZCNTQ"
+"VPMACSDQH"
+"VPMACSSDD"
+"VPMACSSDQL"
+"VPMACSSWW"
+"VPMACSWW"
+"VPMADCSWD"
+"VPMADD52HUQ"
+"VPMADD52LUQ"
+"VPMADDUBSW"
+"VPMADDWD"
+"VPMASKMOV"
+"VPMASKMOVD"
+"VPMASKMOVQ"
+"VPMAXSB"
+"VPMAXSD"
+"VPMAXSQ"
+"VPMAXSW"
+"VPMAXUB"
+"VPMAXUD"
+"VPMAXUQ"
+"VPMAXUW"
+"VPMINSB"
+"VPMINSD"
+"VPMINSQ"
+"VPMINSW"
+"VPMINUB"
+"VPMINUD"
+"VPMINUQ"
+"VPMINUW"
+"VPMOVB2M"
+"VPMOVD2M"
+"VPMOVDB"
+"VPMOVDW"
+"VPMOVM2B"
+"VPMOVM2D"
+"VPMOVM2Q"
+"VPMOVM2W"
+"VPMOVMSKB"
+"VPMOVQ2M"
+"VPMOVQB"
+"VPMOVQD"
+"VPMOVQW"
+"VPMOVSDB"
+"VPMOVSDW"
+"VPMOVSQB"
+"VPMOVSQD"
+"VPMOVSQW"
+"VPMOVSWB"
+"VPMOVSXBD"
+"VPMOVSXBQ"
+"VPMOVSXBW"
+"VPMOVSXDQ"
+"VPMOVSXWD"
+"VPMOVSXWQ"
+"VPMOVUSDB"
+"VPMOVUSDW"
+"VPMOVUSQB"
+"VPMOVUSQD"
+"VPMOVUSQW"
+"VPMOVUSWB"
+"VPMOVW2M"
+"VPMOVWB"
+"VPMOVZXBD"
+"VPMOVZXBQ"
+"VPMOVZXBW"
+"VPMOVZXDQ"
+"VPMOVZXWD"
+"VPMOVZXWQ"
+"VPMULDQ"
+"VPMULHRSW"
+"VPMULHUW"
+"VPMULHW"
+"VPMULLD"
+"VPMULLQ"
+"VPMULLW"
+"VPMULTISHIFTQB"
+"VPMULUDQ"
+"VPOPCNTB"
+"VPOPCNTD"
+"VPOPCNTQ"
+"VPOPCNTW"
+"VPOR"
+"VPORD"
+"VPORQ"
+"VPPERM"
+"VPROLD"
+"VPROLQ"
+"VPROLVD"
+"VPROLVQ"
+"VPRORD"
+"VPRORQ"
+"VPRORVD"
+"VPRORVQ"
+"VPROTB"
+"VPROTD"
+"VPROTQ"
+"VPROTW"
+"VPSADBW"
+"VPSCATTERDD"
+"VPSCATTERDQ"
+"VPSCATTERQD"
+"VPSCATTERQQ"
+"VPSHAB"
+"VPSHAD"
+"VPSHAQ"
+"VPSHAW"
+"VPSHLB"
+"VPSHLD"
+"VPSHLDD"
+"VPSHLDQ"
+"VPSHLDVD"
+"VPSHLDVQ"
+"VPSHLDVW"
+"VPSHLDW"
+"VPSHLQ"
+"VPSHLW"
+"VPSHRDD"
+"VPSHRDQ"
+"VPSHRDVD"
+"VPSHRDVQ"
+"VPSHRDVW"
+"VPSHRDW"
+"VPSHUFB"
+"VPSHUFBITQMB"
+"VPSHUFD"
+"VPSHUFHW"
+"VPSHUFLW"
+"VPSIGNB"
+"VPSIGND"
+"VPSIGNW"
+"VPSLLD"
+"VPSLLDQ"
+"VPSLLQ"
+"VPSLLVD"
+"VPSLLVQ"
+"VPSLLVW"
+"VPSLLW"
+"VPSRAD"
+"VPSRAQ"
+"VPSRAVD"
+"VPSRAVQ"
+"VPSRAVW"
+"VPSRAW"
+"VPSRLD"
+"VPSRLDQ"
+"VPSRLQ"
+"VPSRLVD"
+"VPSRLVQ"
+"VPSRLVW"
+"VPSRLW"
+"VPSUBB"
+"VPSUBD"
+"VPSUBQ"
+"VPSUBSB"
+"VPSUBSW"
+"VPSUBUSB"
+"VPSUBUSW"
+"VPSUBW"
+"VPTERNLOGD"
+"VPTERNLOGQ"
+"VPTEST"
+"VPTESTMB"
+"VPTESTMD"
+"VPTESTMQ"
+"VPTESTMW"
+"VPTESTNMB"
+"VPTESTNMD"
+"VPTESTNMQ"
+"VPTESTNMW"
+"VPUNPCKHBW"
+"VPUNPCKHDQ"
+"VPUNPCKHQDQ"
+"VPUNPCKHWD"
+"VPUNPCKLBW"
+"VPUNPCKLDQ"
+"VPUNPCKLQDQ"
+"VPUNPCKLWD"
+"VPXOR"
+"VPXORD"
+"VPXORQ"
+"VRANGEPD"
+"VRANGEPS"
+"VRANGESD"
+"VRANGESS"
+"VRCP14PD"
+"VRCP14PS"
+"VRCP14SD"
+"VRCP14SS"
+"VRCP28PD"
+"VRCP28PS"
+"VRCP28SD"
+"VRCP28SS"
+"VRCPPS"
+"VREDUCEPD"
+"VREDUCEPS"
+"VREDUCESD"
+"VREDUCESS"
+"VRNDSCALEPD"
+"VRNDSCALEPS"
+"VRNDSCALESD"
+"VRNDSCALESS"
+"VROUNDPD"
+"VROUNDPS"
+"VROUNDSS"
+"VRSQRT14PD"
+"VRSQRT14PS"
+"VRSQRT14SD"
+"VRSQRT14SS"
+"VRSQRT28PD"
+"VRSQRT28PS"
+"VRSQRT28SD"
+"VRSQRT28SS"
+"VRSQRTPS"
+"VRSQRTSS"
+"VSCALEFPD"
+"VSCALEFPS"
+"VSCALEFSD"
+"VSCALEFSS"
+"VSCATTERDPD"
+"VSCATTERDPS"
+"VSCATTERPF0DPD"
+"VSCATTERPF0DPS"
+"VSCATTERPF0QPD"
+"VSCATTERPF0QPS"
+"VSCATTERPF1DPD"
+"VSCATTERPF1DPS"
+"VSCATTERPF1QPD"
+"VSCATTERPF1QPS"
+"VSCATTERQPD"
+"VSCATTERQPS"
+"VSHUFF32X4"
+"VSHUFF32x4"
+"VSHUFF64X2"
+"VSHUFF64x2"
+"VSHUFI32X4"
+"VSHUFI32x4"
+"VSHUFI64X2"
+"VSHUFI64x2"
+"VSHUFPD"
+"VSHUFPS"
+"VSQRTPD"
+"VSQRTPS"
+"VSQRTSD"
+"VSQRTSS"
+"VSUBPD"
+"VSUBPS"
+"VSUBSD"
+"VTESTPD"
+"VTESTPS"
+"VUCOMISD"
+"VUNPCKHPD"
+"VUNPCKHPS"
+"VUNPCKLPD"
+"VUNPCKLPS"
+"VXORPD"
+"VXORPS"
+"VZEROALL"
+"VZEROUPPER"
+"WAIT"
+"WBINVD"
+"WBNOINVD"
+"WRFSBASE"
+"WRGSBASE"
+"WRMSR"
+"WRPKRU"
+"WRSHR"
+"XABORT"
+"XACQUIRE"
+"XADD"
+"XBEGIN"
+"XBTS"
+"XCHG"
+"XCRYPTCTR"
+"XCRYPTECB"
+"XCRYPTOFB"
+"XEND"
+"XGETBV"
+"XLAT"
+"XLATB"
+"XOR"
+"XORPD"
+"XORPS"
+"XRELEASE"
+"XRSTOR"
+"XRSTORS"
+"XSAVE"
+"XSAVEC"
+"XSAVEOPT"
+"XSAVES"
+"XSETBV"
+"XSHA1"
+"XTEST"
+
+
+# registers
+"RAX"
+"RBX"
+"RCX"
+"RDX"
+"RSI"
+"RBP"
+"RSP"
+"R8"
+"R9"
+"R10"
+"R11"
+"R12"
+"R13"
+"R14"
+"R15"
+"RIP"
+"EAX"
+"EBX"
+"ECX"
+"EDX"
+"ESI"
+"EBP"
+"ESP"
+"AX"
+"BX"
+"CX"
+"DX"
+"SI"
+"BP"
+"SP"
+"SI"
+"DI"
+"R8W"
+"R9W"
+"R10W"
+"R11W"
+"R12W"
+"R13W"
+"R14W"
+"R15W"
+"IP"
+"AH"
+"BH"
+"CH"
+"DH"
+"AL"
+"BL"
+"CL"
+"DL"
+"dil"
+"sil"
+"R8B"
+"R9B"
+"R10B"
+"R11B"
+"R12B"
+"R13B"
+"R14B"
+"R15B"
+"CS"
+"DS"
+"ES"
+"SS"
+"FS"
+"GS"
+"CR2"
+"CR3"
+"CR4"
+"DR0"
+"DR1"
+"DR2"
+"DR3"
+"DR6"
+"DR7"
+"TR3"
+"TR4"
+"TR5"
+"TR6"
+"TR7"
+"GDTR"
+"LDTR"
+"IDTR"
+
+# sizes
+"WORD"
+"DWORD"
+"QWORD"
+"far"
diff --git a/dictionaries/xml.dict b/dictionaries/xml.dict
new file mode 100644
index 00000000..d8375452
--- /dev/null
+++ b/dictionaries/xml.dict
@@ -0,0 +1,72 @@
+#
+# AFL dictionary for XML
+# ----------------------
+#
+# Several basic syntax elements and attributes, modeled on libxml2.
+#
+# Created by Michal Zalewski
+#
+
+attr_encoding=" encoding=\"1\""
+attr_generic=" a=\"1\""
+attr_href=" href=\"1\""
+attr_standalone=" standalone=\"no\""
+attr_version=" version=\"1\""
+attr_xml_base=" xml:base=\"1\""
+attr_xml_id=" xml:id=\"1\""
+attr_xml_lang=" xml:lang=\"1\""
+attr_xml_space=" xml:space=\"1\""
+attr_xmlns=" xmlns=\"1\""
+
+entity_builtin="&lt;"
+entity_decimal="&#1;"
+entity_external="&a;"
+entity_hex="&#x1;"
+
+string_any="ANY"
+string_brackets="[]"
+string_cdata="CDATA"
+string_col_fallback=":fallback"
+string_col_generic=":a"
+string_col_include=":include"
+string_dashes="--"
+string_empty="EMPTY"
+string_empty_dblquotes="\"\""
+string_empty_quotes="''"
+string_entities="ENTITIES"
+string_entity="ENTITY"
+string_fixed="#FIXED"
+string_id="ID"
+string_idref="IDREF"
+string_idrefs="IDREFS"
+string_implied="#IMPLIED"
+string_nmtoken="NMTOKEN"
+string_nmtokens="NMTOKENS"
+string_notation="NOTATION"
+string_parentheses="()"
+string_pcdata="#PCDATA"
+string_percent="%a"
+string_public="PUBLIC"
+string_required="#REQUIRED"
+string_schema=":schema"
+string_system="SYSTEM"
+string_ucs4="UCS-4"
+string_utf16="UTF-16"
+string_utf8="UTF-8"
+string_xmlns="xmlns:"
+
+tag_attlist="<!ATTLIST"
+tag_cdata="<![CDATA["
+tag_close="</a>"
+tag_doctype="<!DOCTYPE"
+tag_element="<!ELEMENT"
+tag_entity="<!ENTITY"
+tag_ignore="<![IGNORE["
+tag_include="<![INCLUDE["
+tag_notation="<!NOTATION"
+tag_open="<a>"
+tag_open_close="<a />"
+tag_open_exclamation="<!"
+tag_open_q="<?"
+tag_sq2_close="]]>"
+tag_xml_q="<?xml?>"
diff --git a/dictionaries/xml_UTF_16.dict b/dictionaries/xml_UTF_16.dict
new file mode 100644
index 00000000..404d327b
--- /dev/null
+++ b/dictionaries/xml_UTF_16.dict
@@ -0,0 +1,103 @@
+# xml.dict converted to UTF-16 encoding.
+"\xff\xfe \x00e\x00n\x00c\x00o\x00d\x00i\x00n\x00g\x00=\x00\\\x00"\x001\x00\\\x00"\x00"
+"\xff\xfe \x00a\x00=\x00\\\x00"\x001\x00\\\x00"\x00"
+"\xff\xfe \x00h\x00r\x00e\x00f\x00=\x00\\\x00"\x001\x00\\\x00"\x00"
+"\xff\xfe \x00s\x00t\x00a\x00n\x00d\x00a\x00l\x00o\x00n\x00e\x00=\x00\\\x00"\x00n\x00o\x00\\\x00"\x00"
+"\xff\xfe \x00v\x00e\x00r\x00s\x00i\x00o\x00n\x00=\x00\\\x00"\x001\x00\\\x00"\x00"
+"\xff\xfe \x00x\x00m\x00l\x00:\x00b\x00a\x00s\x00e\x00=\x00\\\x00"\x001\x00\\\x00"\x00"
+"\xff\xfe \x00x\x00m\x00l\x00:\x00i\x00d\x00=\x00\\\x00"\x001\x00\\\x00"\x00"
+"\xff\xfe \x00x\x00m\x00l\x00:\x00l\x00a\x00n\x00g\x00=\x00\\\x00"\x001\x00\\\x00"\x00"
+"\xff\xfe \x00x\x00m\x00l\x00:\x00s\x00p\x00a\x00c\x00e\x00=\x00\\\x00"\x001\x00\\\x00"\x00"
+"\xff\xfe \x00x\x00m\x00l\x00n\x00s\x00=\x00\\\x00"\x001\x00\\\x00"\x00"
+"\xff\xfe&\x00l\x00t\x00;\x00"
+"\xff\xfe&\x00#\x001\x00;\x00"
+"\xff\xfe&\x00a\x00;\x00"
+"\xff\xfe&\x00#\x00x\x001\x00;\x00"
+"\xff\xfeA\x00N\x00Y\x00"
+"\xff\xfeA\x00T\x00T\x00L\x00I\x00S\x00T\x00"
+"\xff\xfeC\x00D\x00A\x00T\x00A\x00"
+"\xff\xfeD\x00O\x00C\x00T\x00Y\x00P\x00E\x00"
+"\xff\xfeE\x00L\x00E\x00M\x00E\x00N\x00T\x00"
+"\xff\xfeE\x00M\x00P\x00T\x00Y\x00"
+"\xff\xfeE\x00N\x00T\x00I\x00T\x00I\x00E\x00S\x00"
+"\xff\xfeE\x00N\x00T\x00I\x00T\x00Y\x00"
+"\xff\xfeF\x00I\x00X\x00E\x00D\x00"
+"\xff\xfeI\x00D\x00"
+"\xff\xfeI\x00D\x00R\x00E\x00F\x00"
+"\xff\xfeI\x00D\x00R\x00E\x00F\x00S\x00"
+"\xff\xfeI\x00G\x00N\x00O\x00R\x00E\x00"
+"\xff\xfeI\x00M\x00P\x00L\x00I\x00E\x00D\x00"
+"\xff\xfeI\x00N\x00C\x00L\x00U\x00D\x00E\x00"
+"\xff\xfeN\x00D\x00A\x00T\x00A\x00"
+"\xff\xfeN\x00M\x00T\x00O\x00K\x00E\x00N\x00"
+"\xff\xfeN\x00M\x00T\x00O\x00K\x00E\x00N\x00S\x00"
+"\xff\xfeN\x00O\x00T\x00A\x00T\x00I\x00O\x00N\x00"
+"\xff\xfeP\x00C\x00D\x00A\x00T\x00A\x00"
+"\xff\xfeP\x00U\x00B\x00L\x00I\x00C\x00"
+"\xff\xfeR\x00E\x00Q\x00U\x00I\x00R\x00E\x00D\x00"
+"\xff\xfeS\x00Y\x00S\x00T\x00E\x00M\x00"
+"\xff\xfe<\x00"
+"\xff\xfe>\x00"
+"\xff\xfe/\x00>\x00"
+"\xff\xfe<\x00/\x00"
+"\xff\xfe<\x00?\x00"
+"\xff\xfe?\x00>\x00"
+"\xff\xfe<\x00!\x00"
+"\xff\xfe!\x00>\x00"
+"\xff\xfe[\x00]\x00"
+"\xff\xfe]\x00]\x00"
+"\xff\xfe<\x00!\x00[\x00C\x00D\x00A\x00T\x00A\x00[\x00"
+"\xff\xfe<\x00!\x00[\x00C\x00D\x00A\x00T\x00A\x00[\x00]\x00]\x00>\x00"
+"\xff\xfe\\\x00"\x00\\\x00"\x00"
+"\xff\xfe'\x00'\x00"
+"\xff\xfe=\x00\\\x00"\x00\\\x00"\x00"
+"\xff\xfe=\x00'\x00'\x00"
+"\xff\xfe<\x00!\x00A\x00T\x00T\x00L\x00I\x00S\x00T\x00"
+"\xff\xfe<\x00!\x00D\x00O\x00C\x00T\x00Y\x00P\x00E\x00"
+"\xff\xfe<\x00!\x00E\x00L\x00E\x00M\x00E\x00N\x00T\x00"
+"\xff\xfe<\x00!\x00E\x00N\x00T\x00I\x00T\x00Y\x00"
+"\xff\xfe<\x00!\x00[\x00I\x00G\x00N\x00O\x00R\x00E\x00[\x00"
+"\xff\xfe<\x00!\x00[\x00I\x00N\x00C\x00L\x00U\x00D\x00E\x00[\x00"
+"\xff\xfe<\x00!\x00N\x00O\x00T\x00A\x00T\x00I\x00O\x00N\x00"
+"\xff\xfe#\x00C\x00D\x00A\x00T\x00A\x00"
+"\xff\xfe#\x00F\x00I\x00X\x00E\x00D\x00"
+"\xff\xfe#\x00I\x00M\x00P\x00L\x00I\x00E\x00D\x00"
+"\xff\xfe#\x00P\x00C\x00D\x00A\x00T\x00A\x00"
+"\xff\xfe#\x00R\x00E\x00Q\x00U\x00I\x00R\x00E\x00D\x00"
+"\xff\xfeI\x00S\x00O\x00-\x008\x008\x005\x009\x00-\x001\x00"
+"\xff\xfeU\x00S\x00-\x00A\x00S\x00C\x00I\x00I\x00"
+"\xff\xfeU\x00T\x00F\x00-\x008\x00"
+"\xff\xfeU\x00T\x00F\x00-\x001\x006\x00"
+"\xff\xfeU\x00T\x00F\x00-\x001\x006\x00B\x00E\x00"
+"\xff\xfeU\x00T\x00F\x00-\x001\x006\x00L\x00E\x00"
+"\xff\xfex\x00m\x00l\x00n\x00s\x00"
+"\xff\xfex\x00m\x00l\x00n\x00s\x00:\x00"
+"\xff\xfex\x00m\x00l\x00n\x00s\x00:\x00x\x00h\x00t\x00m\x00l\x00=\x00\\\x00"\x00h\x00t\x00t\x00p\x00:\x00/\x00/\x00w\x00w\x00w\x00.\x00w\x003\x00.\x00o\x00r\x00g\x00/\x001\x009\x009\x009\x00/\x00x\x00h\x00t\x00m\x00l\x00\\\x00"\x00"
+"\xff\xfex\x00m\x00l\x00n\x00s\x00:\x00x\x00m\x00l\x00=\x00\\\x00"\x00h\x00t\x00t\x00p\x00:\x00/\x00/\x00w\x00w\x00w\x00.\x00w\x003\x00.\x00o\x00r\x00g\x00/\x00X\x00M\x00L\x00/\x001\x009\x009\x008\x00/\x00n\x00a\x00m\x00e\x00s\x00p\x00a\x00c\x00e\x00\\\x00"\x00"
+"\xff\xfex\x00m\x00l\x00n\x00s\x00:\x00x\x00m\x00l\x00n\x00s\x00=\x00\\\x00"\x00h\x00t\x00t\x00p\x00:\x00/\x00/\x00w\x00w\x00w\x00.\x00w\x003\x00.\x00o\x00r\x00g\x00/\x002\x000\x000\x000\x00/\x00x\x00m\x00l\x00n\x00s\x00\\\x00"\x00"
+"\xff\xfe:\x00f\x00a\x00l\x00l\x00b\x00a\x00c\x00k\x00"
+"\xff\xfe:\x00a\x00"
+"\xff\xfe:\x00i\x00n\x00c\x00l\x00u\x00d\x00e\x00"
+"\xff\xfe-\x00-\x00"
+"\xff\xfe(\x00)\x00"
+"\xff\xfe%\x00a\x00"
+"\xff\xfe:\x00s\x00c\x00h\x00e\x00m\x00a\x00"
+"\xff\xfeU\x00C\x00S\x00-\x004\x00"
+"\xff\xfe<\x00/\x00a\x00>\x00"
+"\xff\xfe<\x00a\x00>\x00"
+"\xff\xfe<\x00a\x00 \x00/\x00>\x00"
+"\xff\xfe<\x00?\x00x\x00m\x00l\x00?\x00>\x00"
+"\xff\xfeh\x00t\x00t\x00p\x00:\x00/\x00/\x00d\x00o\x00c\x00b\x00o\x00o\x00"
+"\xff\xfeh\x00t\x00t\x00p\x00:\x00/\x00/\x00w\x00w\x00w\x00.\x00w\x00"
+"\xff\xfeh\x00e\x003\x000\x00"
+"\xff\xfeh\x00e\x002\x00"
+"\xff\xfeI\x00E\x00T\x00"
+"\xff\xfeF\x00D\x00F\x00-\x001\x000\x00"
+"\xff\xfea\x00D\x00U\x00C\x00S\x00-\x004\x00O\x00P\x00v\x00e\x00b\x00:\x00"
+"\xff\xfea\x00>\x00"
+"\xff\xfeU\x00T\x00"
+"\xff\xfex\x00M\x00l\x00"
+"\xff\xfe/\x00u\x00s\x00r\x00/\x00s\x00h\x00a\x00r\x00e\x00/\x00s\x00g\x00"
+"\xff\xfeh\x00a\x000\x007\x00"
+"\xff\xfeh\x00t\x00t\x00p\x00:\x00/\x00/\x00w\x00w\x00w\x00.\x00o\x00a\x00"
+"\xff\xfec\x00l\x00e\x00"
diff --git a/dictionaries/xml_UTF_16BE.dict b/dictionaries/xml_UTF_16BE.dict
new file mode 100644
index 00000000..c1bdbcf9
--- /dev/null
+++ b/dictionaries/xml_UTF_16BE.dict
@@ -0,0 +1,103 @@
+# xml.dict converted to UTF-16BE encoding.
+"\x00 \x00e\x00n\x00c\x00o\x00d\x00i\x00n\x00g\x00=\x00\\\x00"\x001\x00\\\x00""
+"\x00 \x00a\x00=\x00\\\x00"\x001\x00\\\x00""
+"\x00 \x00h\x00r\x00e\x00f\x00=\x00\\\x00"\x001\x00\\\x00""
+"\x00 \x00s\x00t\x00a\x00n\x00d\x00a\x00l\x00o\x00n\x00e\x00=\x00\\\x00"\x00n\x00o\x00\\\x00""
+"\x00 \x00v\x00e\x00r\x00s\x00i\x00o\x00n\x00=\x00\\\x00"\x001\x00\\\x00""
+"\x00 \x00x\x00m\x00l\x00:\x00b\x00a\x00s\x00e\x00=\x00\\\x00"\x001\x00\\\x00""
+"\x00 \x00x\x00m\x00l\x00:\x00i\x00d\x00=\x00\\\x00"\x001\x00\\\x00""
+"\x00 \x00x\x00m\x00l\x00:\x00l\x00a\x00n\x00g\x00=\x00\\\x00"\x001\x00\\\x00""
+"\x00 \x00x\x00m\x00l\x00:\x00s\x00p\x00a\x00c\x00e\x00=\x00\\\x00"\x001\x00\\\x00""
+"\x00 \x00x\x00m\x00l\x00n\x00s\x00=\x00\\\x00"\x001\x00\\\x00""
+"\x00&\x00l\x00t\x00;"
+"\x00&\x00#\x001\x00;"
+"\x00&\x00a\x00;"
+"\x00&\x00#\x00x\x001\x00;"
+"\x00A\x00N\x00Y"
+"\x00A\x00T\x00T\x00L\x00I\x00S\x00T"
+"\x00C\x00D\x00A\x00T\x00A"
+"\x00D\x00O\x00C\x00T\x00Y\x00P\x00E"
+"\x00E\x00L\x00E\x00M\x00E\x00N\x00T"
+"\x00E\x00M\x00P\x00T\x00Y"
+"\x00E\x00N\x00T\x00I\x00T\x00I\x00E\x00S"
+"\x00E\x00N\x00T\x00I\x00T\x00Y"
+"\x00F\x00I\x00X\x00E\x00D"
+"\x00I\x00D"
+"\x00I\x00D\x00R\x00E\x00F"
+"\x00I\x00D\x00R\x00E\x00F\x00S"
+"\x00I\x00G\x00N\x00O\x00R\x00E"
+"\x00I\x00M\x00P\x00L\x00I\x00E\x00D"
+"\x00I\x00N\x00C\x00L\x00U\x00D\x00E"
+"\x00N\x00D\x00A\x00T\x00A"
+"\x00N\x00M\x00T\x00O\x00K\x00E\x00N"
+"\x00N\x00M\x00T\x00O\x00K\x00E\x00N\x00S"
+"\x00N\x00O\x00T\x00A\x00T\x00I\x00O\x00N"
+"\x00P\x00C\x00D\x00A\x00T\x00A"
+"\x00P\x00U\x00B\x00L\x00I\x00C"
+"\x00R\x00E\x00Q\x00U\x00I\x00R\x00E\x00D"
+"\x00S\x00Y\x00S\x00T\x00E\x00M"
+"\x00<"
+"\x00>"
+"\x00/\x00>"
+"\x00<\x00/"
+"\x00<\x00?"
+"\x00?\x00>"
+"\x00<\x00!"
+"\x00!\x00>"
+"\x00[\x00]"
+"\x00]\x00]"
+"\x00<\x00!\x00[\x00C\x00D\x00A\x00T\x00A\x00["
+"\x00<\x00!\x00[\x00C\x00D\x00A\x00T\x00A\x00[\x00]\x00]\x00>"
+"\x00\\\x00"\x00\\\x00""
+"\x00'\x00'"
+"\x00=\x00\\\x00"\x00\\\x00""
+"\x00=\x00'\x00'"
+"\x00<\x00!\x00A\x00T\x00T\x00L\x00I\x00S\x00T"
+"\x00<\x00!\x00D\x00O\x00C\x00T\x00Y\x00P\x00E"
+"\x00<\x00!\x00E\x00L\x00E\x00M\x00E\x00N\x00T"
+"\x00<\x00!\x00E\x00N\x00T\x00I\x00T\x00Y"
+"\x00<\x00!\x00[\x00I\x00G\x00N\x00O\x00R\x00E\x00["
+"\x00<\x00!\x00[\x00I\x00N\x00C\x00L\x00U\x00D\x00E\x00["
+"\x00<\x00!\x00N\x00O\x00T\x00A\x00T\x00I\x00O\x00N"
+"\x00#\x00C\x00D\x00A\x00T\x00A"
+"\x00#\x00F\x00I\x00X\x00E\x00D"
+"\x00#\x00I\x00M\x00P\x00L\x00I\x00E\x00D"
+"\x00#\x00P\x00C\x00D\x00A\x00T\x00A"
+"\x00#\x00R\x00E\x00Q\x00U\x00I\x00R\x00E\x00D"
+"\x00I\x00S\x00O\x00-\x008\x008\x005\x009\x00-\x001"
+"\x00U\x00S\x00-\x00A\x00S\x00C\x00I\x00I"
+"\x00U\x00T\x00F\x00-\x008"
+"\x00U\x00T\x00F\x00-\x001\x006"
+"\x00U\x00T\x00F\x00-\x001\x006\x00B\x00E"
+"\x00U\x00T\x00F\x00-\x001\x006\x00L\x00E"
+"\x00x\x00m\x00l\x00n\x00s"
+"\x00x\x00m\x00l\x00n\x00s\x00:"
+"\x00x\x00m\x00l\x00n\x00s\x00:\x00x\x00h\x00t\x00m\x00l\x00=\x00\\\x00"\x00h\x00t\x00t\x00p\x00:\x00/\x00/\x00w\x00w\x00w\x00.\x00w\x003\x00.\x00o\x00r\x00g\x00/\x001\x009\x009\x009\x00/\x00x\x00h\x00t\x00m\x00l\x00\\\x00""
+"\x00x\x00m\x00l\x00n\x00s\x00:\x00x\x00m\x00l\x00=\x00\\\x00"\x00h\x00t\x00t\x00p\x00:\x00/\x00/\x00w\x00w\x00w\x00.\x00w\x003\x00.\x00o\x00r\x00g\x00/\x00X\x00M\x00L\x00/\x001\x009\x009\x008\x00/\x00n\x00a\x00m\x00e\x00s\x00p\x00a\x00c\x00e\x00\\\x00""
+"\x00x\x00m\x00l\x00n\x00s\x00:\x00x\x00m\x00l\x00n\x00s\x00=\x00\\\x00"\x00h\x00t\x00t\x00p\x00:\x00/\x00/\x00w\x00w\x00w\x00.\x00w\x003\x00.\x00o\x00r\x00g\x00/\x002\x000\x000\x000\x00/\x00x\x00m\x00l\x00n\x00s\x00\\\x00""
+"\x00:\x00f\x00a\x00l\x00l\x00b\x00a\x00c\x00k"
+"\x00:\x00a"
+"\x00:\x00i\x00n\x00c\x00l\x00u\x00d\x00e"
+"\x00-\x00-"
+"\x00(\x00)"
+"\x00%\x00a"
+"\x00:\x00s\x00c\x00h\x00e\x00m\x00a"
+"\x00U\x00C\x00S\x00-\x004"
+"\x00<\x00/\x00a\x00>"
+"\x00<\x00a\x00>"
+"\x00<\x00a\x00 \x00/\x00>"
+"\x00<\x00?\x00x\x00m\x00l\x00?\x00>"
+"\x00h\x00t\x00t\x00p\x00:\x00/\x00/\x00d\x00o\x00c\x00b\x00o\x00o"
+"\x00h\x00t\x00t\x00p\x00:\x00/\x00/\x00w\x00w\x00w\x00.\x00w"
+"\x00h\x00e\x003\x000"
+"\x00h\x00e\x002"
+"\x00I\x00E\x00T"
+"\x00F\x00D\x00F\x00-\x001\x000"
+"\x00a\x00D\x00U\x00C\x00S\x00-\x004\x00O\x00P\x00v\x00e\x00b\x00:"
+"\x00a\x00>"
+"\x00U\x00T"
+"\x00x\x00M\x00l"
+"\x00/\x00u\x00s\x00r\x00/\x00s\x00h\x00a\x00r\x00e\x00/\x00s\x00g"
+"\x00h\x00a\x000\x007"
+"\x00h\x00t\x00t\x00p\x00:\x00/\x00/\x00w\x00w\x00w\x00.\x00o\x00a"
+"\x00c\x00l\x00e"
diff --git a/dictionaries/xml_UTF_16LE.dict b/dictionaries/xml_UTF_16LE.dict
new file mode 100644
index 00000000..02619db5
--- /dev/null
+++ b/dictionaries/xml_UTF_16LE.dict
@@ -0,0 +1,103 @@
+# xml.dict converted to UTF-16LE encoding.
+" \x00e\x00n\x00c\x00o\x00d\x00i\x00n\x00g\x00=\x00\\\x00"\x001\x00\\\x00"\x00"
+" \x00a\x00=\x00\\\x00"\x001\x00\\\x00"\x00"
+" \x00h\x00r\x00e\x00f\x00=\x00\\\x00"\x001\x00\\\x00"\x00"
+" \x00s\x00t\x00a\x00n\x00d\x00a\x00l\x00o\x00n\x00e\x00=\x00\\\x00"\x00n\x00o\x00\\\x00"\x00"
+" \x00v\x00e\x00r\x00s\x00i\x00o\x00n\x00=\x00\\\x00"\x001\x00\\\x00"\x00"
+" \x00x\x00m\x00l\x00:\x00b\x00a\x00s\x00e\x00=\x00\\\x00"\x001\x00\\\x00"\x00"
+" \x00x\x00m\x00l\x00:\x00i\x00d\x00=\x00\\\x00"\x001\x00\\\x00"\x00"
+" \x00x\x00m\x00l\x00:\x00l\x00a\x00n\x00g\x00=\x00\\\x00"\x001\x00\\\x00"\x00"
+" \x00x\x00m\x00l\x00:\x00s\x00p\x00a\x00c\x00e\x00=\x00\\\x00"\x001\x00\\\x00"\x00"
+" \x00x\x00m\x00l\x00n\x00s\x00=\x00\\\x00"\x001\x00\\\x00"\x00"
+"&\x00l\x00t\x00;\x00"
+"&\x00#\x001\x00;\x00"
+"&\x00a\x00;\x00"
+"&\x00#\x00x\x001\x00;\x00"
+"A\x00N\x00Y\x00"
+"A\x00T\x00T\x00L\x00I\x00S\x00T\x00"
+"C\x00D\x00A\x00T\x00A\x00"
+"D\x00O\x00C\x00T\x00Y\x00P\x00E\x00"
+"E\x00L\x00E\x00M\x00E\x00N\x00T\x00"
+"E\x00M\x00P\x00T\x00Y\x00"
+"E\x00N\x00T\x00I\x00T\x00I\x00E\x00S\x00"
+"E\x00N\x00T\x00I\x00T\x00Y\x00"
+"F\x00I\x00X\x00E\x00D\x00"
+"I\x00D\x00"
+"I\x00D\x00R\x00E\x00F\x00"
+"I\x00D\x00R\x00E\x00F\x00S\x00"
+"I\x00G\x00N\x00O\x00R\x00E\x00"
+"I\x00M\x00P\x00L\x00I\x00E\x00D\x00"
+"I\x00N\x00C\x00L\x00U\x00D\x00E\x00"
+"N\x00D\x00A\x00T\x00A\x00"
+"N\x00M\x00T\x00O\x00K\x00E\x00N\x00"
+"N\x00M\x00T\x00O\x00K\x00E\x00N\x00S\x00"
+"N\x00O\x00T\x00A\x00T\x00I\x00O\x00N\x00"
+"P\x00C\x00D\x00A\x00T\x00A\x00"
+"P\x00U\x00B\x00L\x00I\x00C\x00"
+"R\x00E\x00Q\x00U\x00I\x00R\x00E\x00D\x00"
+"S\x00Y\x00S\x00T\x00E\x00M\x00"
+"<\x00"
+">\x00"
+"/\x00>\x00"
+"<\x00/\x00"
+"<\x00?\x00"
+"?\x00>\x00"
+"<\x00!\x00"
+"!\x00>\x00"
+"[\x00]\x00"
+"]\x00]\x00"
+"<\x00!\x00[\x00C\x00D\x00A\x00T\x00A\x00[\x00"
+"<\x00!\x00[\x00C\x00D\x00A\x00T\x00A\x00[\x00]\x00]\x00>\x00"
+"\\\x00"\x00\\\x00"\x00"
+"'\x00'\x00"
+"=\x00\\\x00"\x00\\\x00"\x00"
+"=\x00'\x00'\x00"
+"<\x00!\x00A\x00T\x00T\x00L\x00I\x00S\x00T\x00"
+"<\x00!\x00D\x00O\x00C\x00T\x00Y\x00P\x00E\x00"
+"<\x00!\x00E\x00L\x00E\x00M\x00E\x00N\x00T\x00"
+"<\x00!\x00E\x00N\x00T\x00I\x00T\x00Y\x00"
+"<\x00!\x00[\x00I\x00G\x00N\x00O\x00R\x00E\x00[\x00"
+"<\x00!\x00[\x00I\x00N\x00C\x00L\x00U\x00D\x00E\x00[\x00"
+"<\x00!\x00N\x00O\x00T\x00A\x00T\x00I\x00O\x00N\x00"
+"#\x00C\x00D\x00A\x00T\x00A\x00"
+"#\x00F\x00I\x00X\x00E\x00D\x00"
+"#\x00I\x00M\x00P\x00L\x00I\x00E\x00D\x00"
+"#\x00P\x00C\x00D\x00A\x00T\x00A\x00"
+"#\x00R\x00E\x00Q\x00U\x00I\x00R\x00E\x00D\x00"
+"I\x00S\x00O\x00-\x008\x008\x005\x009\x00-\x001\x00"
+"U\x00S\x00-\x00A\x00S\x00C\x00I\x00I\x00"
+"U\x00T\x00F\x00-\x008\x00"
+"U\x00T\x00F\x00-\x001\x006\x00"
+"U\x00T\x00F\x00-\x001\x006\x00B\x00E\x00"
+"U\x00T\x00F\x00-\x001\x006\x00L\x00E\x00"
+"x\x00m\x00l\x00n\x00s\x00"
+"x\x00m\x00l\x00n\x00s\x00:\x00"
+"x\x00m\x00l\x00n\x00s\x00:\x00x\x00h\x00t\x00m\x00l\x00=\x00\\\x00"\x00h\x00t\x00t\x00p\x00:\x00/\x00/\x00w\x00w\x00w\x00.\x00w\x003\x00.\x00o\x00r\x00g\x00/\x001\x009\x009\x009\x00/\x00x\x00h\x00t\x00m\x00l\x00\\\x00"\x00"
+"x\x00m\x00l\x00n\x00s\x00:\x00x\x00m\x00l\x00=\x00\\\x00"\x00h\x00t\x00t\x00p\x00:\x00/\x00/\x00w\x00w\x00w\x00.\x00w\x003\x00.\x00o\x00r\x00g\x00/\x00X\x00M\x00L\x00/\x001\x009\x009\x008\x00/\x00n\x00a\x00m\x00e\x00s\x00p\x00a\x00c\x00e\x00\\\x00"\x00"
+"x\x00m\x00l\x00n\x00s\x00:\x00x\x00m\x00l\x00n\x00s\x00=\x00\\\x00"\x00h\x00t\x00t\x00p\x00:\x00/\x00/\x00w\x00w\x00w\x00.\x00w\x003\x00.\x00o\x00r\x00g\x00/\x002\x000\x000\x000\x00/\x00x\x00m\x00l\x00n\x00s\x00\\\x00"\x00"
+":\x00f\x00a\x00l\x00l\x00b\x00a\x00c\x00k\x00"
+":\x00a\x00"
+":\x00i\x00n\x00c\x00l\x00u\x00d\x00e\x00"
+"-\x00-\x00"
+"(\x00)\x00"
+"%\x00a\x00"
+":\x00s\x00c\x00h\x00e\x00m\x00a\x00"
+"U\x00C\x00S\x00-\x004\x00"
+"<\x00/\x00a\x00>\x00"
+"<\x00a\x00>\x00"
+"<\x00a\x00 \x00/\x00>\x00"
+"<\x00?\x00x\x00m\x00l\x00?\x00>\x00"
+"h\x00t\x00t\x00p\x00:\x00/\x00/\x00d\x00o\x00c\x00b\x00o\x00o\x00"
+"h\x00t\x00t\x00p\x00:\x00/\x00/\x00w\x00w\x00w\x00.\x00w\x00"
+"h\x00e\x003\x000\x00"
+"h\x00e\x002\x00"
+"I\x00E\x00T\x00"
+"F\x00D\x00F\x00-\x001\x000\x00"
+"a\x00D\x00U\x00C\x00S\x00-\x004\x00O\x00P\x00v\x00e\x00b\x00:\x00"
+"a\x00>\x00"
+"U\x00T\x00"
+"x\x00M\x00l\x00"
+"/\x00u\x00s\x00r\x00/\x00s\x00h\x00a\x00r\x00e\x00/\x00s\x00g\x00"
+"h\x00a\x000\x007\x00"
+"h\x00t\x00t\x00p\x00:\x00/\x00/\x00w\x00w\x00w\x00.\x00o\x00a\x00"
+"c\x00l\x00e\x00"
diff --git a/dictionaries/xpath.dict b/dictionaries/xpath.dict
new file mode 100644
index 00000000..1101585c
--- /dev/null
+++ b/dictionaries/xpath.dict
@@ -0,0 +1,66 @@
+# https://developer.mozilla.org/en-US/docs/Web/XPath
+# https://devhints.io/xpath
+
+# selectors
+"//"
+"./"
+"::"
+"[*]"
+
+
+# functions - https://developer.mozilla.org/en-US/docs/Web/XPath/Functions
+"boolean("
+"ceiling("
+"choose("
+"concat("
+"contains("
+"count("
+"current()"
+"document("
+"element-available("
+"ends-with("
+"false()"
+"floor("
+"format-number("
+"function-available("
+"generate-id("
+"id("
+"key("
+"lang("
+"last()"
+"local-name("
+"name("
+"namespace-uri("
+"normalize-space("
+"not("
+"number("
+"or"
+"position("
+"round("
+"starts-with("
+"string("
+"string-length("
+"substring("
+"substring-after("
+"substring-before("
+"sum("
+"system-property("
+"text()"
+"translate("
+"true()"
+"unparsed-entity-url("
+
+# axes - https://developer.mozilla.org/en-US/docs/Web/XPath/Axes
+"ancestor"
+"ancestor-or-self"
+"attribute"
+"child"
+"descendant"
+"descendant-or-self"
+"following"
+"following-sibling"
+"namespace"
+"parent"
+"preceding"
+"preceding-sibling"
+"self"
diff --git a/dictionaries/xslt.dict b/dictionaries/xslt.dict
new file mode 100644
index 00000000..81633b12
--- /dev/null
+++ b/dictionaries/xslt.dict
@@ -0,0 +1,118 @@
+# Tokens taken from:
+# - https://www.w3.org/TR/xslt20/
+# - https://en.wikipedia.org/wiki/XSLT_elements
+# - https://developer.mozilla.org/en-US/docs/Web/XSLT/Element
+
+
+"<?"
+"<?xslt-"
+"?>"
+"version=\"1.0\""
+"encoding=\""
+"<xsl:"
+"/>"
+"</xsl:"
+">"
+"<"
+"<!--"
+"-->"
+"@"
+
+"apply-imports"
+"apply-templates"
+"attribute"
+"attribute-set"
+"call-template"
+"character-map"
+"choose"
+"comment"
+"copy"
+"copy-of"
+"decimal-format"
+"default-collection"
+"element"
+"exclude-result-prefixes"
+"extension-element-prefixes"
+"fallback"
+"for-each"
+"function"
+"if"
+"import"
+"import-schema"
+"include"
+"key"
+"message"
+"namespace-alias"
+"number"
+"otherwise"
+"output"
+"param"
+"preserve-space"
+"processing-instruction"
+"sort"
+"strip-space"
+"stylesheet"
+"template"
+"text"
+"transform"
+"use-when"
+"value-of"
+"variable"
+"version"
+"when"
+"with-param"
+
+# attributes
+" name=\""
+" namespace=\""
+" select=\""
+" test=\""
+" type=\""
+" value=\""
+" prefix=\""
+
+# functions
+"ceiling"
+"concat"
+"contains"
+"count"
+"floor"
+"normalize_space"
+"position"
+"round"
+"string"
+"string-length"
+"substring"
+"substring-after"
+"substring-before"
+"sum"
+"translate"
+
+
+# math extension
+"http://exslt.org/math"
+"math:highest"
+"math:lowest"
+"math:max"
+"math:min"
+
+# regex extension
+"http://exslt.org/regular-expressions"
+"regexp:match"
+"regexp:replace"
+"regexp:test"
+
+# set extension
+"http://exslt.org/sets"
+"set:difference"
+"set:distinct"
+"set:has-same-node"
+"set:intersection"
+"set:leading"
+"set:trailing"
+
+# str extension
+"http://exslt.org/strings"
+"str:concat"
+"str:split"
+"str:tokenize"
diff --git a/dictionaries/yaml.dict b/dictionaries/yaml.dict
new file mode 100644
index 00000000..f535d508
--- /dev/null
+++ b/dictionaries/yaml.dict
@@ -0,0 +1,79 @@
+# sources:
+# - https://en.wikipedia.org/wiki/YAML
+# - https://yaml.org/spec/1.1/
+# - https://yaml.org/type/
+
+directive_yaml="%YAML 1.2"
+directive_tag="%TAG !yaml! tag:yaml.org,2002:"
+directive_tag2="%TAG !m! !my-"
+true="true"
+caps_true="TRUE"
+caps_false="FALSE"
+literal_true="YES"
+literal_false="NO"
+false="false"
+start="---"
+comment="#"
+list="- "
+key="k: "
+walrus="=:"
+question_key="?k: "
+number="\"0e5\""
+expand="!!"
+list="[a,b]"
+dict="{k: v, x: y}"
+value=": v"
+exponent="e+03"
+neg_inf="-.inf"
+nan=".NaN"
+end="..."
+quoted_key="'k'"
+newline="k: |"
+newline2="k: >"
+anchor="&a"
+reference="*a"
+type_binary="!!binary"
+type_bool="!!bool"
+type_float="!!float"
+type_int="!!int"
+type_map="!!map"
+type_merge="!!merge"
+type_null="!!null"
+type_omap="!!omap"
+type_pairs="!!pairs"
+type_seq="!!seq"
+type_set="!!set"
+type_str="!!str"
+type_timestamp="!!timestamp"
+type_value="!!value"
+type_yaml="!!yaml"
+type_python="!!python"
+merge = "<<"
+number_separation="_"
+decimal_number="+30_123"
+octal_number="0123"
+hex_number="0x_12_23"
+bin_number="0b1001_1001"
+sexa_number="123:34:75"
+complex_mapping="? "
+litteral_style=" |"
+folded_style=" >"
+timestamp="2001-12-14t21:59:43.10-05:00"
+escaped_unicode="\\u2029"
+"["
+"]"
+"{"
+"}"
+"-"
+","
+"&"
+"<<"
+":"
+"|"
+"!!"
+">"
+"\""
+"'"
+integer="123"
+float="12.5"
+mantissa="1.3e+9"
diff --git a/dictionaries/yara.dict b/dictionaries/yara.dict
new file mode 100644
index 00000000..844d3e58
--- /dev/null
+++ b/dictionaries/yara.dict
@@ -0,0 +1,196 @@
+# https://yara.readthedocs.io/en/latest/
+
+# Keywords
+"all"
+"and"
+"any"
+"ascii"
+"at"
+"condition"
+"contains"
+"entrypoint"
+"false"
+"filesize"
+"for"
+"fullword"
+"global"
+"import"
+"in"
+"include"
+"int16"
+"int16be"
+"int32"
+"int32be"
+"int8"
+"int8be"
+"matches"
+"meta"
+"nocase"
+"not"
+"of"
+"or"
+"private"
+"rule"
+"strings"
+"them"
+"true"
+"uint16"
+"uint16be"
+"uint32"
+"uint32be"
+"uint8"
+"uint8be"
+"wide"
+"xor"
+
+# pe module
+"\"pe\""
+"pe.machine"
+"pe.checksum"
+"pe.calculate_checksum"
+"pe.subsystem"
+"pe.timestamp"
+"pe.pointer_to_symbol_table"
+"pe.number_of_sumbols"
+"pe.size_of_optional_header"
+"pe.pothdr_magic"
+"pe.size_of_code"
+"pe.size_of_initialized_data"
+"pe.size_of_unnitialized_data"
+"pe.entrypoint"
+"pe.base_of_code"
+"pe.base_of_data"
+"pe.image_base"
+"pe.section_alignment"
+"pe.file_alignment"
+"pe.win32_version_value"
+"pe.size_of_image"
+"pe.size_of_headers"
+"pe.characteristics"
+"pe.linker_version"
+"pe.os_version"
+"pe.image_version"
+"pe.subsystem_version"
+"pe.dll_characteristics"
+"pe.size_of_stack_reserve"
+"pe.size_of_stack_commit"
+"pe.size_of_heap_reserve"
+"pe.size_of_heap_commit"
+"pe.loader_flags"
+"pe.number_of_rva_and_sizes"
+"pe.data_directories"
+"pe.number_of_sections"
+"pe.sections"
+"pe.overlay"
+"pe.number_of_resources"
+"pe.resource_timestamp"
+"pe.resource_version"
+"pe.resources"
+"pe.version_info"
+"pe.number_of_signatures"
+"pe.signatures"
+"pe.rich_signature"
+"pe.exports"
+"pe.number_of_exports"
+"pe.number_of_imports"
+"pe.imports"
+"pe.locale"
+"pe.language"
+"pe.imphash"
+"pe.section_index"
+"pe.is_dll()"
+"pe.is_32bit()"
+"pe.is_64bit()"
+"pe.rva_to_offset"
+
+# elf module
+"\"elf\""
+"elf.type"
+"elf.machine"
+"elf.entry_point"
+"elf.number_of_sections"
+"elf.sections"
+"elf.number_of_segments"
+"elf.segments"
+"elf.dynamic_section_entires"
+"elf.dynamic"
+"elf.symtab_entries"
+"elf.symtab"
+
+# cuckoo module
+"\"cuckoo\""
+"cuckoo.network"
+"cuckoo.registry"
+"cuckoo.filesystem"
+"cuckoo.sync"
+
+# magic module
+"\"magic\""
+"magic.type()"
+"magic.mime_type()"
+
+
+# hash module
+"\"hash\""
+"hash.md5"
+"hash.sha1"
+"hash.sha256"
+"hash.checksum32"
+"hash.crc32"
+
+# math module
+"\"math\""
+"math.entropuy"
+"math.monte_carlo_pi"
+"math.serial_correlation"
+"math.mean"
+"math.deviation"
+"math.in_range"
+"math.max"
+"max.min"
+
+# dotnet module
+"\"dotnet\""
+"dotnet.version"
+"dotnet.module_name"
+"dotnet.number_of_streams"
+"dotnet.streams"
+"dotnet.number_of_guid"
+"dotnet.guids"
+"dotnet.number_of_resources"
+"dotnet.resources"
+"dotnet.assembly"
+"dotnet.number_of_modulerefs"
+"dotnet.modulerefs"
+"dotnet.typelib"
+"dotnet.assembly_refs"
+"dotnet.number_of_user_strings"
+"dotnet.user_strings"
+"dotnet.number_of_field_offsets"
+"dotnet.field_offsets"
+
+# time module
+"\"time\""
+"time.now()"
+
+
+# misc
+"/*"
+"*/"
+"//"
+"$a="
+"{a?}"
+"[0-9]"
+"{(0A|??)}"
+"<<"
+">>"
+"#a"
+"$a"
+".."
+"@a"
+
+# regex
+"*?"
+"+?"
+"??"
+"{1,2}?"
diff --git a/dictionaries/zip.dict b/dictionaries/zip.dict
new file mode 100644
index 00000000..31713f54
--- /dev/null
+++ b/dictionaries/zip.dict
@@ -0,0 +1,3 @@
+header1="\x50\x4B\x03\x04"
+header2="\x50\x4B\x05\x06"
+header2="\x50\x4B\x07\x08"
diff --git a/docs/COPYING b/docs/COPYING
new file mode 100644
index 00000000..d6456956
--- /dev/null
+++ b/docs/COPYING
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/docs/Changelog.md b/docs/Changelog.md
new file mode 100644
index 00000000..b18bf30f
--- /dev/null
+++ b/docs/Changelog.md
@@ -0,0 +1,3111 @@
+# Changelog
+
+ This is the list of all noteworthy changes made in every public
+ release of the tool. See README.md for the general instruction manual.
+
+## Staying informed
+
+Want to stay in the loop on major new features? Join our mailing list by
+sending a mail to <afl-users+subscribe@googlegroups.com>.
+
+### Version ++4.01a (dev)
+ - fix */build_...sh scripts to work outside of git
+ - new custom_mutator: libafl with token fuzzing :)
+ - afl-fuzz:
+ - when you just want to compile once and set CMPLOG, then just
+ set -c 0 to tell afl-fuzz that the fuzzing binary is also for
+ CMPLOG.
+ - new commandline options -g/G to set min/max length of generated
+ fuzz inputs
+ - reintroduced AFL_PERSISTENT and AFL_DEFER_FORKSRV to allow
+ persistent mode and manual forkserver support if these are not
+ in the target binary (e.g. are in a shared library)
+ - add AFL_EARLY_FORKSERVER to install the forkserver as earliest as
+ possible in the target (for afl-gcc-fast/afl-clang-fast/
+ afl-clang-lto)
+ - "saved timeouts" was wrong information, timeouts are still thrown
+ away by default even if they have new coverage (hangs are always
+ kept), unless AFL_KEEP_TIMEOUTS are set
+ - AFL never implemented auto token inserts (but user token inserts,
+ user token overwrite and auto token overwrite), added now!
+ - Mopt fix to always select the correct algorithm
+ - fix effector map calculation (deterministic mode)
+ - fix custom mutator post_process functionality
+ - document and auto-activate pizza mode on condition
+ - afl-cc:
+ - due a bug in lld of llvm 15 LTO instrumentation wont work atm :-(
+ - converted all passed to use the new llvm pass manager for llvm 11+
+ - AFL++ PCGUARD mode is not available for 10.0.1 anymore (11+ only)
+ - trying to stay on top on all these #$&§!! changes in llvm 15 ...
+ - frida_mode:
+ - update to new frida release, handles now c++ throw/catch
+ - unicorn_mode:
+ - update unicorn engine, fix C example
+
+
+### Version ++4.00c (release)
+ - complete documentation restructuring, made possible by Google Season
+ of Docs :) thank you Jana!
+ - we renamed several UI and fuzzer_stat entries to be more precise,
+ e.g. "unique crashes" -> "saved crashes", "total paths" ->
+ "corpus count", "current path" -> "current item".
+ This might need changing custom scripting!
+ - Nyx mode (full system emulation with snapshot capability) has been
+ added - thanks to @schumilo and @eqv!
+ - unicorn_mode:
+ - Moved to unicorn2! by Ziqiao Kong (@lazymio)
+ - Faster, more accurate emulation (newer QEMU base), risc-v support
+ - removed indirections in rust callbacks
+ - new binary-only fuzzing mode: coresight_mode for aarch64 CPUs :)
+ thanks to RICSecLab submitting!
+ - if instrumented libaries are dlopen()'ed after the forkserver you
+ will now see a crash. Before you would have colliding coverage.
+ We changed this to force fixing a broken setup rather then allowing
+ ineffective fuzzing.
+ See docs/best_practices.md how to fix such setups.
+ - afl-fuzz:
+ - cmplog binaries will need to be recompiled for this version
+ (it is better!)
+ - fix a regression introduced in 3.10 that resulted in less
+ coverage being detected. thanks to Collin May for reporting!
+ - ensure all spawned targets are killed on exit
+ - added AFL_IGNORE_PROBLEMS, plus checks to identify and abort on
+ incorrect LTO usage setups and enhanced the READMEs for better
+ information on how to deal with instrumenting libraries
+ - fix -n dumb mode (nobody should use this mode though)
+ - fix stability issue with LTO and cmplog
+ - better banner
+ - more effective cmplog mode
+ - more often update the UI when in input2stage mode
+ - qemu_mode/unicorn_mode: fixed OOB write when using libcompcov,
+ thanks to kotee4ko for reporting!
+ - frida_mode:
+ - better performance, bug fixes
+ - David Carlier added Android support :)
+ - afl-showmap, afl-tmin and afl-analyze:
+ - honor persistent mode for more speed. thanks to dloffre-snl
+ for reporting!
+ - fix bug where targets are not killed on timeouts
+ - moved hidden afl-showmap -A option to -H to be used for
+ coresight_mode
+ - Prevent accidentally killing non-afl/fuzz services when aborting
+ afl-showmap and other tools.
+ - afl-cc:
+ - detect overflow reads on initial input buffer for asan
+ - new cmplog mode (incompatible with older afl++ versions)
+ - support llvm IR select instrumentation for default PCGUARD and LTO
+ - fix for shared linking on MacOS
+ - better selective instrumentation AFL_LLVM_{ALLOW|DENY}LIST
+ on filename matching (requires llvm 11 or newer)
+ - fixed a potential crash in targets for LAF string handling
+ - fixed a bad assert in LAF split switches
+ - added AFL_USE_TSAN thread sanitizer support
+ - llvm and LTO mode modified to work with new llvm 14-dev (again.)
+ - fix for AFL_REAL_LD
+ - more -z defs filtering
+ - make -v without options work
+ - added the very good grammar mutator "GramaTron" to the
+ custom_mutators
+ - added optimin, a faster and better corpus minimizer by
+ Adrian Herrera. Thank you!
+ - added afl-persistent-config script to set perform permanent system
+ configuration settings for fuzzing, for Linux and Macos.
+ thanks to jhertz!
+ - added xml, curl & exotic string functions to llvm dictionary feature
+ - fix AFL_PRELOAD issues on MacOS
+ - removed utils/afl_frida because frida_mode/ is now so much better
+ - added uninstall target to makefile (todo: update new readme!)
+
+### Version ++3.14c (release)
+ - afl-fuzz:
+ - fix -F when a '/' was part of the parameter
+ - fixed a crash for cmplog for very slow inputs
+ - fix for AFLfast schedule counting
+ - removed implied -D determinstic from -M main
+ - if the target becomes unavailable check out out/default/error.txt
+ for an indicator why
+ - AFL_CAL_FAST was a dead env, now does the same as AFL_FAST_CAL
+ - reverse read the queue on resumes (more effective)
+ - fix custom mutator trimming
+ - afl-cc:
+ - Update to COMPCOV/laf-intel that speeds up the instrumentation
+ process a lot - thanks to Michael Rodler/f0rki for the PR!
+ - Fix for failures for some sized string instrumentations
+ - Fix to instrument global namespace functions in c++
+ - Fix for llvm 13
+ - support partial linking
+ - do honor AFL_LLVM_{ALLOW/DENY}LIST for LTO autodictionary andDICT2FILE
+ - We do support llvm versions from 3.8 to 5.0 again
+ - frida_mode:
+ - several fixes for cmplog
+ - remove need for AFL_FRIDA_PERSISTENT_RETADDR_OFFSET
+ - less coverage collision
+ - feature parity of aarch64 with intel now (persistent, cmplog,
+ in-memory testcases, asan)
+ - afl-cmin and afl-showmap -i do now descend into subdirectories
+ (like afl-fuzz does) - note that afl-cmin.bash does not!
+ - afl_analyze:
+ - fix timeout handling
+ - add forkserver support for better performance
+ - ensure afl-compiler-rt is built for gcc_module
+ - always build aflpp_driver for libfuzzer harnesses
+ - added `AFL_NO_FORKSRV` env variable support to
+ afl-cmin, afl-tmin, and afl-showmap, by @jhertz
+ - removed outdated documents, improved existing documentation
+
+### Version ++3.13c (release)
+ - Note: plot_data switched to relative time from unix time in 3.10
+ - frida_mode - new mode that uses frida to fuzz binary-only targets,
+ it currently supports persistent mode and cmplog.
+ thanks to @WorksButNotTested!
+ - create a fuzzing dictionary with the help of CodeQL thanks to
+ @microsvuln! see utils/autodict_ql
+ - afl-fuzz:
+ - added patch by @realmadsci to support @@ as part of command line
+ options, e.g. `afl-fuzz ... -- ./target --infile=@@`
+ - add recording of previous fuzz attempts for persistent mode
+ to allow replay of non-reproducable crashes, see
+ AFL_PERSISTENT_RECORD in config.h and docs/envs.h
+ - fixed a bug when trimming for stdin targets
+ - cmplog -l: default cmplog level is now 2, better efficiency.
+ level 3 now performs redqueen on everything. use with care.
+ - better fuzzing strategy yield display for enabled options
+ - ensure one fuzzer sync per cycle
+ - fix afl_custom_queue_new_entry original file name when syncing
+ from fuzzers
+ - fixed a crash when more than one custom mutator was used together
+ with afl_custom_post_process
+ - on a crashing seed potentially the wrong input was disabled
+ - added AFL_EXIT_ON_SEED_ISSUES env that will exit if a seed in
+ -i dir crashes the target or results in a timeout. By default
+ AFL++ ignores these and uses them for splicing instead.
+ - added AFL_EXIT_ON_TIME env that will make afl-fuzz exit fuzzing
+ after no new paths have been found for n seconds
+ - when AFL_FAST_CAL is set a variable path will now be calibrated
+ 8 times instead of originally 40. Long calibration is now 20.
+ - added AFL_TRY_AFFINITY to try to bind to CPUs but don't error if
+ it fails
+ - afl-cc:
+ - We do not support llvm versions prior 6.0 anymore
+ - added thread safe counters to all modes (`AFL_LLVM_THREADSAFE_INST`),
+ note that this disables NeverZero counters.
+ - Fix for -pie compiled binaries with default afl-clang-fast PCGUARD
+ - Leak Sanitizer (AFL_USE_LSAN) added by Joshua Rogers, thanks!
+ - Removed InsTrim instrumentation as it is not as good as PCGUARD
+ - Removed automatic linking with -lc++ for LTO mode
+ - Fixed a crash in llvm dict2file when a strncmp length was -1
+ - added --afl-noopt support
+ - utils/aflpp_driver:
+ - aflpp_qemu_driver_hook fixed to work with qemu_mode
+ - aflpp_driver now compiled with -fPIC
+ - unicornafl:
+ - fix MIPS delay slot caching, thanks @JackGrence
+ - fixed aarch64 exit address
+ - execution no longer stops at address 0x0
+ - updated afl-system-config to support Arch Linux weirdness and increase
+ MacOS shared memory
+ - updated the grammar custom mutator to the newest version
+ - add -d (add dead fuzzer stats) to afl-whatsup
+ - added AFL_PRINT_FILENAMES to afl-showmap/cmin to print the
+ current filename
+ - afl-showmap/cmin will now process queue items in alphabetical order
+
+### Version ++3.12c (release)
+ - afl-fuzz:
+ - added AFL_TARGET_ENV variable to pass extra env vars to the target
+ (for things like LD_LIBRARY_PATH)
+ - fix map detection, AFL_MAP_SIZE not needed anymore for most cases
+ - fix counting favorites (just a display thing)
+ - afl-cc:
+ - fix cmplog rtn (rare crash and not being able to gather ptr data)
+ - fix our own PCGUARD implementation to compile with llvm 10.0.1
+ - link runtime not to shared libs
+ - ensure shared libraries are properly built and instrumented
+ - AFL_LLVM_INSTRUMENT_ALLOW/DENY were not implemented for LTO, added
+ - show correct LLVM PCGUARD NATIVE mode when auto switching to it
+ and keep fsanitize-coverage-*list=...
+ Short mnemnonic NATIVE is now also accepted.
+ - qemu_mode (thanks @realmadsci):
+ - move AFL_PRELOAD and AFL_USE_QASAN logic inside afl-qemu-trace
+ - add AFL_QEMU_CUSTOM_BIN
+ - unicorn_mode
+ - accidently removed the subfolder from github, re-added
+ - added DEFAULT_PERMISSION to config.h for all files created, default
+ to 0600
+
+### Version ++3.11c (release)
+ - afl-fuzz:
+ - better auto detection of map size
+ - fix sanitizer settings (bug since 3.10c)
+ - fix an off-by-one overwrite in cmplog
+ - add non-unicode variants from unicode-looking dictionary entries
+ - Rust custom mutator API improvements
+ - Imported crash stats painted yellow on resume (only new ones are red)
+ - afl-cc:
+ - added AFL_NOOPT that will just pass everything to the normal
+ gcc/clang compiler without any changes - to pass weird configure
+ scripts
+ - fixed a crash that can occur with ASAN + CMPLOG together plus
+ better support for unicode (thanks to @stbergmann for reporting!)
+ - fixed a crash in LAF transform for empty strings
+ - handle erroneous setups in which multiple afl-compiler-rt are
+ compiled into the target. This now also supports dlopen()
+ instrumented libs loaded before the forkserver and even after the
+ forkserver is started (then with collisions though)
+ - the compiler rt was added also in object building (-c) which
+ should have been fixed years ago but somewhere got lost :(
+ - Renamed CTX to CALLER, added correct/real CTX implementation to
+ CLASSIC
+ - qemu_mode:
+ - added AFL_QEMU_EXCLUDE_RANGES env by @realmadsci, thanks!
+ - if no new/updated checkout is wanted, build with:
+ NO_CHECKOUT=1 ./build_qemu_support.sh
+ - we no longer perform a "git drop"
+ - afl-cmin: support filenames with spaces
+
+### Version ++3.10c (release)
+ - Mac OS ARM64 support
+ - Android support fixed and updated by Joey Jiaojg - thanks!
+ - New selective instrumentation option with __AFL_COVERAGE_* commands
+ to be placed in the source code.
+ Check out instrumentation/README.instrument_list.md
+ - afl-fuzz
+ - Making AFL_MAP_SIZE (mostly) obsolete - afl-fuzz now learns on
+ start the target map size
+ - upgraded cmplog/redqueen: solving for floating point, solving
+ transformations (e.g. toupper, tolower, to/from hex, xor,
+ arithmetics, etc.). This is costly hence new command line option
+ `-l` that sets the intensity (values 1 to 3). Recommended is 2.
+ - added `AFL_CMPLOG_ONLY_NEW` to not use cmplog on initial seeds
+ from `-i` or resumes (these have most likely already been done)
+ - fix crash for very, very fast targets+systems (thanks to mhlakhani
+ for reporting)
+ - on restarts (`-i`)/autoresume (AFL_AUTORESUME) the stats are now
+ reloaded and used, thanks to Vimal Joseph for this patch!
+ - changed the meaning of '+' of the '-t' option, it now means to
+ auto-calculate the timeout with the value given being the max
+ timeout. The original meaning of skipping timeouts instead of
+ abort is now inherent to the -t option.
+ - if deterministic mode is active (`-D`, or `-M` without `-d`) then
+ we sync after every queue entry as this can take very long time
+ otherwise
+ - added minimum SYNC_TIME to include/config.h (30 minutes default)
+ - better detection if a target needs a large shared map
+ - fix for `-Z`
+ - fixed a few crashes
+ - switched to an even faster RNG
+ - added hghwng's patch for faster trace map analysis
+ - printing suggestions for mistyped `AFL_` env variables
+ - added Rust bindings for custom mutators (thanks @julihoh)
+ - afl-cc
+ - allow instrumenting LLVMFuzzerTestOneInput
+ - fixed endless loop for allow/blocklist lines starting with a
+ comment (thanks to Zherya for reporting)
+ - cmplog/redqueen now also tracks floating point, _ExtInt() + 128bit
+ - cmplog/redqueen can now process basic libc++ and libstdc++
+ std::string comparisons (no position or length type variants)
+ - added support for __afl_coverage_interesting() for LTO and our
+ own PCGUARD (llvm 10.0.1+), read more about this function and
+ selective coverage in instrumentation/README.instrument_list.md
+ - added AFL_LLVM_INSTRUMENT option NATIVE for native clang pc-guard
+ support (less performant than our own), GCC for old afl-gcc and
+ CLANG for old afl-clang
+ - fixed a potential crash in the LAF feature
+ - workaround for llvm bitcast lto bug
+ - workaround for llvm 13
+ - qemuafl
+ - QASan (address sanitizer for Qemu) ported to qemuafl!
+ See qemu_mode/libqasan/README.md
+ - solved some persistent mode bugs (thanks Dil4rd)
+ - solved an issue when dumping the memory maps (thanks wizche)
+ - Android support for QASan
+ - unicornafl
+ - Substantial speed gains in python bindings for certain use cases
+ - Improved rust bindings
+ - Added a new example harness to compare python, c and rust bindings
+ - afl-cmin and afl-showmap now support the -f option
+ - afl_plot now also generates a graph on the discovered edges
+ - changed default: no memory limit for afl-cmin and afl-cmin.bash
+ - warn on any _AFL and __AFL env vars.
+ - set AFL_IGNORE_UNKNOWN_ENVS to not warn on unknown AFL_... env vars
+ - added dummy Makefile to instrumentation/
+ - Updated utils/afl_frida to be 5% faster, 7% on x86_x64
+ - Added `AFL_KILL_SIGNAL` env variable (thanks @v-p-b)
+ - @Edznux added a nice documentation on how to use rpc.statsd with
+ AFL++ in docs/rpc_statsd.md, thanks!
+
+### Version ++3.00c (release)
+ - llvm_mode/ and gcc_plugin/ moved to instrumentation/
+ - examples/ renamed to utils/
+ - moved libdislocator, libtokencap and qdbi_mode to utils/
+ - all compilers combined to afl-cc which emulates the previous ones
+ - afl-llvm/gcc-rt.o merged into afl-compiler-rt.o
+ - afl-fuzz
+ - not specifying -M or -S will now auto-set "-S default"
+ - deterministic fuzzing is now disabled by default and can be enabled with
+ -D. It is still enabled by default for -M.
+ - a new seed selection was implemented that uses weighted randoms based on
+ a schedule performance score, which is much better that the previous
+ walk the whole queue approach. Select the old mode with -Z (auto enabled
+ with -M)
+ - Marcel Boehme submitted a patch that improves all AFFast schedules :)
+ - the default schedule is now FAST
+ - memory limits are now disabled by default, set them with -m if required
+ - rpc.statsd support, for stats and charts, by Edznux, thanks a lot!
+ - reading testcases from -i now descends into subdirectories
+ - allow the -x command line option up to 4 times
+ - loaded extras now have a duplication protection
+ - If test cases are too large we do a partial read on the maximum
+ supported size
+ - longer seeds with the same trace information will now be ignored
+ for fuzzing but still be used for splicing
+ - crashing seeds are now not prohibiting a run anymore but are
+ skipped - they are used for splicing, though
+ - update MOpt for expanded havoc modes
+ - setting the env var AFL_NO_AUTODICT will not load an LTO autodictionary
+ - added NO_SPLICING compile option and makefile define
+ - added INTROSPECTION make target that writes all mutations to
+ out/NAME/introspection.txt
+ - print special compile time options used in help output
+ - when using -c cmplog, one of the childs was not killed, fixed
+ - somewhere we broke -n dumb fuzzing, fixed
+ - added afl_custom_describe to the custom mutator API to allow for easy
+ mutation reproduction on crashing inputs
+ - new env. var. AFL_NO_COLOR (or AFL_NO_COLOUR) to suppress colored
+ console output (when configured with USE_COLOR and not ALWAYS_COLORED)
+ - instrumentation
+ - We received an enhanced gcc_plugin module from AdaCore, thank you
+ very much!!
+ - not overriding -Ox or -fno-unroll-loops anymore
+ - we now have our own trace-pc-guard implementation. It is the same as
+ -fsanitize-coverage=trace-pc-guard from llvm 12, but: it is a) inline
+ and b) works from llvm 10.0.1 + onwards :)
+ - new llvm pass: dict2file via AFL_LLVM_DICT2FILE, create afl-fuzz
+ -x dictionary of string comparisons found during compilation
+ - LTO autodict now also collects interesting cmp comparisons,
+ std::string compare + find + ==, bcmp
+ - fix crash in dict2file for integers > 64 bit
+ - custom mutators
+ - added a new custom mutator: symcc -> https://github.com/eurecom-s3/symcc/
+ - added a new custom mutator: libfuzzer that integrates libfuzzer mutations
+ - Our AFL++ Grammar-Mutator is now better integrated into custom_mutators/
+ - added INTROSPECTION support for custom modules
+ - python fuzz function was not optional, fixed
+ - some python mutator speed improvements
+ - afl-cmin/afl-cmin.bash now search first in PATH and last in AFL_PATH
+ - unicornafl synced with upstream version 1.02 (fixes, better rust bindings)
+ - renamed AFL_DEBUG_CHILD_OUTPUT to AFL_DEBUG_CHILD
+ - added AFL_CRASH_EXITCODE env variable to treat a child exitcode as crash
+
+
+### Version ++2.68c (release)
+ - added the GSoC excellent AFL++ grammar mutator by Shengtuo to our
+ custom_mutators/ (see custom_mutators/README.md) - or get it here:
+ https://github.com/AFLplusplus/Grammar-Mutator
+ - a few QOL changes for Apple and its outdated gmake
+ - afl-fuzz:
+ - fix for auto dictionary entries found during fuzzing to not throw out
+ a -x dictionary
+ - added total execs done to plot file
+ - AFL_MAX_DET_EXTRAS env variable added to control the amount of
+ deterministic dict entries without recompiling.
+ - AFL_FORKSRV_INIT_TMOUT env variable added to control the time to wait
+ for the forkserver to come up without the need to increase the overall
+ timeout.
+ - bugfix for cmplog that results in a heap overflow based on target data
+ (thanks to the magma team for reporting!)
+ - write fuzzing setup into out/fuzzer_setup (environment variables and
+ command line)
+ - custom mutators:
+ - added afl_custom_fuzz_count/fuzz_count function to allow specifying
+ the number of fuzz attempts for custom_fuzz
+ - llvm_mode:
+ - ported SanCov to LTO, and made it the default for LTO. better
+ instrumentation locations
+ - Further llvm 12 support (fast moving target like AFL++ :-) )
+ - deprecated LLVM SKIPSINGLEBLOCK env environment
+
+
+### Version ++2.67c (release)
+ - 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
+ - added -b option to bind to a specific CPU
+ - 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 and made deterministic with -s
+ - Compiletime autodictionary fixes
+ - llvm_mode:
+ - now supports llvm 12
+ - support for AFL_LLVM_ALLOWLIST/AFL_LLVM_DENYLIST (previous
+ AFL_LLVM_WHITELIST and AFL_LLVM_INSTRUMENT_FILE are deprecated and
+ are matched to AFL_LLVM_ALLOWLIST). The format is compatible to llvm
+ sancov, and also supports function matching :)
+ - 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: 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 fixed default now
+ - LTO: instrim instrumentation disabled, only classic support used
+ as it is always better
+ - LTO: env var AFL_LLVM_DOCUMENT_IDS=file will document which edge ID
+ was given to which function during compilation
+ - LTO: single block functions were not implemented by default, fixed
+ - LTO: AFL_LLVM_SKIP_NEVERZERO behaviour was inversed, fixed
+ - setting AFL_LLVM_LAF_SPLIT_FLOATS now activates
+ AFL_LLVM_LAF_SPLIT_COMPARES
+ - support for -E and -shared compilation runs
+ - added honggfuzz mangle as a custom mutator in custom_mutators/honggfuzz
+ - added afl-frida gum solution to examples/afl_frida (mostly imported
+ from https://github.com/meme/hotwax/)
+ - small fixes to afl-plot, afl-whatsup and man page creation
+ - new README, added FAQ
+
+
+### Version ++2.66c (release)
+ - renamed the main branch on Github to "stable"
+ - renamed master/slave to main/secondary
+ - renamed blacklist/whitelist to ignorelist/instrumentlist ->
+ AFL_LLVM_INSTRUMENT_FILE and AFL_GCC_INSTRUMENT_FILE
+ - warn on deprecated environment variables
+ - afl-fuzz:
+ - -S secondary nodes now only sync from the main node to increase
+ performance, the -M main node still syncs from everyone. Added checks
+ that ensure exactly one main node is present and warn otherwise
+ - Add -D after -S to force a secondary to perform deterministic fuzzing
+ - If no main node is present at a sync one secondary node automatically
+ becomes a temporary main node until a real main nodes shows up
+ - Fixed a mayor performance issue we inherited from AFLfast
+ - switched murmur2 hashing and random() for xxh3 and xoshiro256**,
+ resulting in an up to 5.5% speed increase
+ - Resizing the window does not crash afl-fuzz anymore
+ - Ensure that the targets are killed on exit
+ - fix/update to MOpt (thanks to arnow117)
+ - added MOpt dictionary support from repo
+ - added experimental SEEK power schedule. It is EXPLORE with ignoring
+ the runtime and less focus on the length of the test case
+ - llvm_mode:
+ - the default instrumentation is now PCGUARD if the llvm version is >= 7,
+ as it is faster and provides better coverage. The original afl
+ instrumentation can be set via AFL_LLVM_INSTRUMENT=AFL. This is
+ automatically done when the instrument_file list feature is used.
+ - PCGUARD mode is now even better because we made it collision free - plus
+ it has a fixed map size, so it is also faster! :)
+ - some targets want a ld variant for LD that is not gcc/clang but ld,
+ added afl-ld-lto to solve this
+ - lowered minimum required llvm version to 3.4 (except LLVMInsTrim, which
+ needs 3.8.0)
+ - instrument_file list feature now supports wildcards (thanks to sirmc)
+ - small change to cmplog to make it work with current llvm 11-dev
+ - added AFL_LLVM_LAF_ALL, sets all laf-intel settings
+ - LTO instrument_files functionality rewritten, now main, _init etc functions
+ need not to be listed anymore
+ - fixed crash in compare-transform-pass when strcasecmp/strncasecmp was
+ tried to be instrumented with LTO
+ - fixed crash in cmplog with LTO
+ - enable snapshot lkm also for persistent mode
+ - Unicornafl
+ - Added powerPC support from unicorn/next
+ - rust bindings!
+ - CMPLOG/Redqueen now also works for MMAP sharedmem
+ - ensure shmem is released on errors
+ - we moved radamsa to be a custom mutator in ./custom_mutators/. It is not
+ compiled by default anymore.
+ - allow running in /tmp (only unsafe with umask 0)
+ - persistent mode shared memory testcase handover (instead of via
+ files/stdin) - 10-100% performance increase
+ - General support for 64 bit PowerPC, RiscV, Sparc etc.
+ - fix afl-cmin.bash
+ - slightly better performance compilation options for AFL++ and targets
+ - fixed afl-gcc/afl-as that could break on fast systems reusing pids in
+ the same second
+ - added lots of dictionaries from oss-fuzz, go-fuzz and Jakub Wilk
+ - added former post_library examples to examples/custom_mutators/
+ - Dockerfile upgraded to Ubuntu 20.04 Focal and installing llvm 11 and
+ gcc 10 so afl-clang-lto can be build
+
+
+### Version ++2.65c (release):
+ - afl-fuzz:
+ - AFL_MAP_SIZE was not working correctly
+ - better python detection
+ - an old, old bug in AFL that would show negative stability in rare
+ circumstances is now hopefully fixed
+ - AFL_POST_LIBRARY was deprecated, use AFL_CUSTOM_MUTATOR_LIBRARY
+ instead (see docs/custom_mutators.md)
+ - llvm_mode:
+ - afl-clang-fast/lto now do not skip single block functions. This
+ behaviour can be reactivated with AFL_LLVM_SKIPSINGLEBLOCK
+ - if LLVM 11 is installed the posix shm_open+mmap is used and a fixed
+ address for the shared memory map is used as this increases the
+ fuzzing speed
+ - InsTrim now has an LTO version! :-) That is the best and fastest mode!
+ - fixes to LTO mode if instrumented edges > MAP_SIZE
+ - CTX and NGRAM can now be used together
+ - CTX and NGRAM are now also supported in CFG/INSTRIM mode
+ - AFL_LLVM_LAF_TRANSFORM_COMPARES could crash, fixed
+ - added AFL_LLVM_SKIP_NEVERZERO to skip the never zero coverage counter
+ implementation. For targets with few or no loops or heavily called
+ functions. Gives a small performance boost.
+ - qemu_mode:
+ - add information on PIE/PIC load addresses for 32 bit
+ - better dependency checks
+ - gcc_plugin:
+ - better dependency checks
+ - unicorn_mode:
+ - validate_crash_callback can now count non-crashing inputs as crash as well
+ - better submodule handling
+ - afl-showmap: fix for -Q mode
+ - added examples/afl_network_proxy which allows to fuzz a target over the
+ network (not fuzzing tcp/ip services but running afl-fuzz on one system
+ and the target being on an embedded device)
+ - added examples/afl_untracer which does a binary-only fuzzing with the
+ modifications done in memory (intel32/64 and aarch64 support)
+ - added examples/afl_proxy which can be easily used to fuzz and instrument
+ non-standard things
+ - all:
+ - forkserver communication now also used for error reporting
+ - fix 32 bit build options
+ - make clean now leaves qemu-3.1.1.tar.xz and the unicornafl directory
+ intact if in a git/svn checkout - unless "deepclean" is used
+
+
+### Version ++2.64c (release):
+ - llvm_mode LTO mode:
+ - now requires llvm11 - but compiles all targets! :)
+ - autodictionary feature added, enable with `AFL_LLVM_LTO_AUTODICTIONARY`
+ - variable map size usage
+ - afl-fuzz:
+ - variable map size support added (only LTO mode can use this)
+ - snapshot feature usage now visible in UI
+ - Now setting `-L -1` will enable MOpt in parallel to normal mutation.
+ Additionally, this allows to run dictionaries, radamsa and cmplog.
+ - fix for cmplog/redqueen mode if stdin was used
+ - fix for writing a better plot_data file
+ - qemu_mode: fix for persistent mode (which would not terminate or get stuck)
+ - compare-transform/AFL_LLVM_LAF_TRANSFORM_COMPARES now transforms also
+ static global and local variable comparisons (cannot find all though)
+ - extended forkserver: map_size and more information is communicated to
+ afl-fuzz (and afl-fuzz acts accordingly)
+ - new environment variable: AFL_MAP_SIZE to specify the size of the shared map
+ - if AFL_CC/AFL_CXX is set but empty AFL compilers did fail, fixed
+ (this bug is in vanilla AFL too)
+ - added NO_PYTHON flag to disable python support when building afl-fuzz
+ - more refactoring
+
+
+### Version ++2.63c (release):
+
+ ! the repository was moved from vanhauser-thc to AFLplusplus. It is now
+ an own organisation :)
+ ! development and acceptance of PRs now happen only in the dev branch
+ and only occasionally when everything is fine we PR to master
+ - all:
+ - big code changes to make afl-fuzz thread-safe so afl-fuzz can spawn
+ multiple fuzzing threads in the future or even become a library
+ - AFL basic tools now report on the environment variables picked up
+ - more tools get environment variable usage info in the help output
+ - force all output to stdout (some OK/SAY/WARN messages were sent to
+ stdout, some to stderr)
+ - uninstrumented mode uses an internal forkserver ("fauxserver")
+ - now builds with `-D_FORTIFY_SOURCE=2`
+ - drastically reduced number of (de)allocations during fuzzing
+ - afl-fuzz:
+ - python mutator modules and custom mutator modules now use the same
+ interface and hence the API changed
+ - AFL_AUTORESUME will resume execution without the need to specify `-i -`
+ - added experimental power schedules (-p):
+ - mmopt: ignores runtime of queue entries, gives higher weighting to
+ the last 5 queue entries
+ - rare: puts focus on queue entries that hits rare branches, also ignores
+ runtime
+ - llvm_mode:
+ - added SNAPSHOT feature (using https://github.com/AFLplusplus/AFL-Snapshot-LKM)
+ - added Control Flow Integrity sanitizer (AFL_USE_CFISAN)
+ - added AFL_LLVM_INSTRUMENT option to control the instrumentation type
+ easier: DEFAULT, CFG (INSTRIM), LTO, CTX, NGRAM-x (x=2-16)
+ - made USE_TRACE_PC compile obsolete
+ - LTO collision free instrumented added in llvm_mode with afl-clang-lto -
+ this mode is amazing but requires you to build llvm 11 yourself
+ - Added llvm_mode NGRAM prev_loc coverage by Adrean Herrera
+ (https://github.com/adrianherrera/afl-ngram-pass/), activate by setting
+ AFL_LLVM_INSTRUMENT=NGRAM-<value> or AFL_LLVM_NGRAM_SIZE=<value>
+ - Added llvm_mode context sensitive branch coverage, activated by setting
+ AFL_LLVM_INSTRUMENT=CTX or AFL_LLVM_CTX=1
+ - llvm_mode InsTrim mode:
+ - removed workaround for bug where paths were not instrumented and
+ imported fix by author
+ - made skipping 1 block functions an option and is disabled by default,
+ set AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK=1 to re-enable this
+ - qemu_mode:
+ - qemu_mode now uses solely the internal capstone version to fix builds
+ on modern Linux distributions
+ - QEMU now logs routine arguments for CmpLog when the target is x86
+ - afl-tmin:
+ - now supports hang mode `-H` to minimize hangs
+ - fixed potential afl-tmin missbehavior for targets with multiple hangs
+ - Pressing Control-c in afl-cmin did not terminate it for some OS
+ - the custom API was rewritten and is now the same for Python and shared
+ libraries.
+
+
+### Version ++2.62c (release):
+
+ - Important fix for memory allocation functions that result in afl-fuzz
+ not identifying crashes - UPDATE!
+ - Small fix for -E/-V to release the CPU
+ - CmpLog does not need sancov anymore
+
+
+### Version ++2.61c (release):
+
+ - use -march=native if available
+ - most tools now check for mistyped environment variables
+ - gcc 10 is now supported
+ - the memory safety checks are now disabled for a little more speed during
+ fuzzing (only affects creating queue entries), can be toggled in config.h
+ - afl-fuzz:
+ - MOpt out of bounds writing crash fixed
+ - now prints the real python version support compiled in
+ - set stronger performance compile options and little tweaks
+ - Android: prefer bigcores when selecting a CPU
+ - CmpLog forkserver
+ - Redqueen input-2-state mutator (cmp instructions only ATM)
+ - all Python 2+3 versions supported now
+ - changed execs_per_sec in fuzzer_stats from "current" execs per second
+ (which is pointless) to total execs per second
+ - bugfix for dictionary insert stage count (fix via Google repo PR)
+ - added warning if -M is used together with custom mutators with _ONLY option
+ - AFL_TMPDIR checks are now later and better explained if they fail
+ - llvm_mode
+ - InsTrim: three bug fixes:
+ 1. (minor) no pointless instrumentation of 1 block functions
+ 2. (medium) path bug that leads a few blocks not instrumented that
+ should be
+ 3. (major) incorrect prev_loc was written, fixed!
+ - afl-clang-fast:
+ - show in the help output for which llvm version it was compiled for
+ - now does not need to be recompiled between trace-pc and pass
+ instrumentation. compile normally and set AFL_LLVM_USE_TRACE_PC :)
+ - LLVM 11 is supported
+ - CmpLog instrumentation using SanCov (see llvm_mode/README.cmplog.md)
+ - afl-gcc, afl-clang-fast, afl-gcc-fast:
+ - experimental support for undefined behaviour sanitizer UBSAN
+ (set AFL_USE_UBSAN=1)
+ - the instrumentation summary output now also lists activated sanitizers
+ - afl-as: added isatty(2) check back in
+ - added AFL_DEBUG (for upcoming merge)
+ - qemu_mode:
+ - persistent mode is now also available for arm and aarch64
+ - CmpLog instrumentation for QEMU (-c afl-fuzz command line option)
+ for x86, x86_64, arm and aarch64
+ - AFL_PERSISTENT_HOOK callback module for persistent QEMU
+ (see examples/qemu_persistent_hook)
+ - added qemu_mode/README.persistent.md documentation
+ - AFL_ENTRYPOINT now has instruction granularity
+ - afl-cmin is now a sh script (invoking awk) instead of bash for portability
+ the original script is still present as afl-cmin.bash
+ - afl-showmap: -i dir option now allows processing multiple inputs using the
+ forkserver. This is for enhanced speed in afl-cmin.
+ - added blacklist and instrument_filesing function check in all modules of llvm_mode
+ - added fix from Debian project to compile libdislocator and libtokencap
+ - libdislocator: AFL_ALIGNED_ALLOC to force size alignment to max_align_t
+
+
+### Version ++2.60c (release):
+
+ - fixed a critical bug in afl-tmin that was introduced during ++2.53d
+ - added test cases for afl-cmin and afl-tmin to test/test.sh
+ - added ./examples/argv_fuzzing ld_preload library by Kjell Braden
+ - added preeny's desock_dup ld_preload library as
+ ./examples/socket_fuzzing for network fuzzing
+ - added AFL_AS_FORCE_INSTRUMENT environment variable for afl-as - this is
+ for the retrorewrite project
+ - we now set QEMU_SET_ENV from AFL_PRELOAD when qemu_mode is used
+
+
+### Version ++2.59c (release):
+
+ - qbdi_mode: fuzz android native libraries via QBDI framework
+ - unicorn_mode: switched to the new unicornafl, thanks domenukk
+ (see https://github.com/vanhauser-thc/unicorn)
+ - afl-fuzz:
+ - added radamsa as (an optional) mutator stage (-R[R])
+ - added -u command line option to not unlink the fuzz input file
+ - Python3 support (autodetect)
+ - AFL_DISABLE_TRIM env var to disable the trim stage
+ - CPU affinity support for DragonFly
+ - llvm_mode:
+ - float splitting is now configured via AFL_LLVM_LAF_SPLIT_FLOATS
+ - support for llvm 10 included now (thanks to devnexen)
+ - libtokencap:
+ - support for *BSD/OSX/Dragonfly added
+ - hook common *cmp functions from widely used libraries
+ - compcov:
+ - hook common *cmp functions from widely used libraries
+ - floating point splitting support for QEMU on x86 targets
+ - qemu_mode: AFL_QEMU_DISABLE_CACHE env to disable QEMU TranslationBlocks caching
+ - afl-analyze: added AFL_SKIP_BIN_CHECK support
+ - better random numbers for gcc_plugin and llvm_mode (thanks to devnexen)
+ - Dockerfile by courtesy of devnexen
+ - added regex.dictionary
+ - qemu and unicorn download scripts now try to download until the full
+ download succeeded. f*ckin travis fails downloading 40% of the time!
+ - more support for Android (please test!)
+ - added the few Android stuff we didnt have already from Google AFL repository
+ - removed unnecessary warnings
+
+
+### Version ++2.58c (release):
+
+ - reverted patch to not unlink and recreate the input file, it resulted in
+ performance loss of ~10%
+ - added test/test-performance.sh script
+ - (re)added gcc_plugin, fast inline instrumentation is not yet finished,
+ however it includes the instrument_filesing and persistance feature! by hexcoder-
+ - gcc_plugin tests added to testing framework
+
+
+### Version ++2.54d-2.57c (release):
+
+ - we jump to 2.57 instead of 2.55 to catch up with Google's versioning
+ - persistent mode for QEMU (see qemu_mode/README.md)
+ - custom mutator library is now an additional mutator, to exclusivly use it
+ add AFL_CUSTOM_MUTATOR_ONLY (that will trigger the previous behaviour)
+ - new library qemu_mode/unsigaction which filters sigaction events
+ - afl-fuzz: new command line option -I to execute a command on a new crash
+ - no more unlinking the input file, this way the input file can also be a
+ FIFO or disk partition
+ - setting LLVM_CONFIG for llvm_mode will now again switch to the selected
+ llvm version. If your setup is correct.
+ - fuzzing strategy yields for custom mutator were missing from the UI, added them :)
+ - added "make tests" which will perform checks to see that all functionality
+ is working as expected. this is currently the starting point, its not complete :)
+ - added mutation documentation feature ("make document"), creates afl-fuzz-document
+ and saves all mutations of the first run on the first file into out/queue/mutations
+ - libtokencap and libdislocator now compile to the afl_root directory and are
+ installed to the .../lib/afl directory when present during make install
+ - more BSD support, e.g. free CPU binding code for FreeBSD (thanks to devnexen)
+ - reducing duplicate code in afl-fuzz
+ - added "make help"
+ - removed compile warnings from python internal stuff
+ - added man page for afl-clang-fast[++]
+ - updated documentation
+ - Wine mode to run Win32 binaries with the QEMU instrumentation (-W)
+ - CompareCoverage for ARM target in QEMU/Unicorn
+ - laf-intel in llvm_mode now also handles floating point comparisons
+
+
+### Version ++2.54c (release):
+
+ - big code refactoring:
+ * all includes are now in include/
+ * all AFL sources are now in src/ - see src/README.md
+ * afl-fuzz was split up in various individual files for including
+ functionality in other programs (e.g. forkserver, memory map, etc.)
+ for better readability.
+ * new code indention everywhere
+ - auto-generating man pages for all (main) tools
+ - added AFL_FORCE_UI to show the UI even if the terminal is not detected
+ - llvm 9 is now supported (still needs testing)
+ - Android is now supported (thank to JoeyJiao!) - still need to modify the Makefile though
+ - fix building qemu on some Ubuntus (thanks to floyd!)
+ - custom mutator by a loaded library is now supported (thanks to kyakdan!)
+ - added PR that includes peak_rss_mb and slowest_exec_ms in the fuzzer_stats report
+ - more support for *BSD (thanks to devnexen!)
+ - fix building on *BSD (thanks to tobias.kortkamp for the patch)
+ - fix for a few features to support different map sized than 2^16
+ - afl-showmap: new option -r now shows the real values in the buckets (stock
+ AFL never did), plus shows tuple content summary information now
+ - small docu updates
+ - NeverZero counters for QEMU
+ - NeverZero counters for Unicorn
+ - CompareCoverage Unicorn
+ - immediates-only instrumentation for CompareCoverage
+
+
+### Version ++2.53c (release):
+
+ - README is now README.md
+ - imported the few minor changes from the 2.53b release
+ - unicorn_mode got added - thanks to domenukk for the patch!
+ - fix llvm_mode AFL_TRACE_PC with modern llvm
+ - fix a crash in qemu_mode which also exists in stock afl
+ - added libcompcov, a laf-intel implementation for qemu! :)
+ see qemu_mode/libcompcov/README.libcompcov.md
+ - afl-fuzz now displays the selected core in the status screen (blue {#})
+ - updated afl-fuzz and afl-system-config for new scaling governor location
+ in modern kernels
+ - using the old ineffective afl-gcc will now show a deprecation warning
+ - all queue, hang and crash files now have their discovery time in their name
+ - if llvm_mode was compiled, afl-clang/afl-clang++ will point to these
+ instead of afl-gcc
+ - added instrim, a much faster llvm_mode instrumentation at the cost of
+ path discovery. See llvm_mode/README.instrim.md (https://github.com/csienslab/instrim)
+ - added MOpt (github.com/puppet-meteor/MOpt-AFL) mode, see docs/README.MOpt.md
+ - added code to make it more portable to other platforms than Intel Linux
+ - added never zero counters for afl-gcc and optionally (because of an
+ optimization issue in llvm < 9) for llvm_mode (AFL_LLVM_NEVER_ZERO=1)
+ - added a new doc about binary only fuzzing: docs/binaryonly_fuzzing.txt
+ - more cpu power for afl-system-config
+ - added forkserver patch to afl-tmin, makes it much faster (originally from
+ github.com/nccgroup/TriforceAFL)
+ - added instrument_files support for llvm_mode via AFL_LLVM_WHITELIST to allow
+ only to instrument what is actually interesting. Gives more speed and less
+ map pollution (originally by choller@mozilla)
+ - added Python Module mutator support, python2.7-dev is autodetected.
+ see docs/python_mutators.txt (originally by choller@mozilla)
+ - added AFL_CAL_FAST for slow applications and AFL_DEBUG_CHILD_OUTPUT for
+ debugging
+ - added -V time and -E execs option to better comparison runs, runs afl-fuzz
+ for a specific time/executions.
+ - added a -s seed switch to allow AFL run with a fixed initial
+ seed that is not updated. This is good for performance and path discovery
+ tests as the random numbers are deterministic then
+ - llvm_mode LAF_... env variables can now be specified as AFL_LLVM_LAF_...
+ that is longer but in line with other llvm specific env vars
+
+
+### Version ++2.52c (2019-06-05):
+
+ - Applied community patches. See docs/PATCHES for the full list.
+ LLVM and Qemu modes are now faster.
+ Important changes:
+ afl-fuzz: -e EXTENSION commandline option
+ llvm_mode: LAF-intel performance (needs activation, see llvm/README.laf-intel.md)
+ a few new environment variables for afl-fuzz, llvm and qemu, see docs/env_variables.md
+ - Added the power schedules of AFLfast by Marcel Boehme, but set the default
+ to the AFL schedule, not to the FAST schedule. So nothing changes unless
+ you use the new -p option :-) - see docs/power_schedules.md
+ - added afl-system-config script to set all system performance options for fuzzing
+ - llvm_mode works with llvm 3.9 up to including 8 !
+ - qemu_mode got upgraded from 2.1 to 3.1 - incorporated from
+ https://github.com/andreafioraldi/afl and with community patches added
+
+
+### Version 2.52b (2017-11-04):
+
+ - Upgraded QEMU patches from 2.3.0 to 2.10.0. Required troubleshooting
+ several weird issues. All the legwork done by Andrew Griffiths.
+
+ - Added setsid to afl-showmap. See the notes for 2.51b.
+
+ - Added target mode (deferred, persistent, qemu, etc) to fuzzer_stats.
+ Requested by Jakub Wilk.
+
+ - afl-tmin should now save a partially minimized file when Ctrl-C
+ is pressed. Suggested by Jakub Wilk.
+
+ - Added an option for afl-analyze to dump offsets in hex. Suggested by
+ Jakub Wilk.
+
+ - Added support for parameters in triage_crashes.sh. Patch by Adam of
+ DC949.
+
+### Version 2.51b (2017-08-30):
+
+ - Made afl-tmin call setsid to prevent glibc traceback junk from showing
+ up on the terminal in some distros. Suggested by Jakub Wilk.
+
+### Version 2.50b (2017-08-19):
+
+ - Fixed an interesting timing corner case spotted by Jakub Wilk.
+
+ - Addressed a libtokencap / pthreads incompatibility issue. Likewise, spotted
+ by Jakub Wilk.
+
+ - Added a mention of afl-kit and Pythia.
+
+ - Added AFL_FAST_CAL.
+
+ - In-place resume now preserves .synced. Suggested by Jakub Wilk.
+
+### Version 2.49b (2017-07-18):
+
+ - Added AFL_TMIN_EXACT to allow path constraint for crash minimization.
+
+ - Added dates for releases (retroactively for all of 2017).
+
+### Version 2.48b (2017-07-17):
+
+ - Added AFL_ALLOW_TMP to permit some scripts to run in /tmp.
+
+ - Fixed cwd handling in afl-analyze (similar to the quirk in afl-tmin).
+
+ - Made it possible to point -o and -f to the same file in afl-tmin.
+
+### Version 2.47b (2017-07-14):
+
+ - Fixed cwd handling in afl-tmin. Spotted by Jakub Wilk.
+
+### Version 2.46b (2017-07-10):
+
+ - libdislocator now supports AFL_LD_NO_CALLOC_OVER for folks who do not
+ want to abort on calloc() overflows.
+
+ - Made a minor fix to libtokencap. Reported by Daniel Stender.
+
+ - Added a small JSON dictionary, inspired on a dictionary done by Jakub Wilk.
+
+### Version 2.45b (2017-07-04):
+
+ - Added strstr, strcasestr support to libtokencap. Contributed by
+ Daniel Hodson.
+
+ - Fixed a resumption offset glitch spotted by Jakub Wilk.
+
+ - There are definitely no bugs in afl-showmap -c now.
+
+### Version 2.44b (2017-06-28):
+
+ - Added a visual indicator of ASAN / MSAN mode when compiling. Requested
+ by Jakub Wilk.
+
+ - Added support for afl-showmap coredumps (-c). Suggested by Jakub Wilk.
+
+ - Added LD_BIND_NOW=1 for afl-showmap by default. Although not really useful,
+ it reportedly helps reproduce some crashes. Suggested by Jakub Wilk.
+
+ - Added a note about allocator_may_return_null=1 not always working with
+ ASAN. Spotted by Jakub Wilk.
+
+### Version 2.43b (2017-06-16):
+
+ - Added AFL_NO_ARITH to aid in the fuzzing of text-based formats.
+ Requested by Jakub Wilk.
+
+### Version 2.42b (2017-06-02):
+
+ - Renamed the R() macro to avoid a problem with llvm_mode in the latest
+ versions of LLVM. Fix suggested by Christian Holler.
+
+### Version 2.41b (2017-04-12):
+
+ - Addressed a major user complaint related to timeout detection. Timing out
+ inputs are now binned as "hangs" only if they exceed a far more generous
+ time limit than the one used to reject slow paths.
+
+### Version 2.40b (2017-04-02):
+
+ - Fixed a minor oversight in the insertion strategy for dictionary words.
+ Spotted by Andrzej Jackowski.
+
+ - Made a small improvement to the havoc block insertion strategy.
+
+ - Adjusted color rules for "is it done yet?" indicators.
+
+### Version 2.39b (2017-02-02):
+
+ - Improved error reporting in afl-cmin. Suggested by floyd.
+
+ - Made a minor tweak to trace-pc-guard support. Suggested by kcc.
+
+ - Added a mention of afl-monitor.
+
+### Version 2.38b (2017-01-22):
+
+ - Added -mllvm -sanitizer-coverage-block-threshold=0 to trace-pc-guard
+ mode, as suggested by Kostya Serebryany.
+
+### Version 2.37b (2017-01-22):
+
+ - Fixed a typo. Spotted by Jakub Wilk.
+
+ - Fixed support for make install when using trace-pc. Spotted by
+ Kurt Roeckx.
+
+ - Switched trace-pc to trace-pc-guard, which should be considerably
+ faster and is less quirky. Kudos to Konstantin Serebryany (and sorry
+ for dragging my feet).
+
+ Note that for some reason, this mode doesn't perform as well as
+ "vanilla" afl-clang-fast / afl-clang.
+
+### Version 2.36b (2017-01-14):
+
+ - Fixed a cosmetic bad free() bug when aborting -S sessions. Spotted
+ by Johannes S.
+
+ - Made a small change to afl-whatsup to sort fuzzers by name.
+
+ - Fixed a minor issue with malloc(0) in libdislocator. Spotted by
+ Rene Freingruber.
+
+ - Changed the clobber pattern in libdislocator to a slightly more
+ reliable one. Suggested by Rene Freingruber.
+
+ - Added a note about THP performance. Suggested by Sergey Davidoff.
+
+ - Added a somewhat unofficial support for running afl-tmin with a
+ baseline "mask" that causes it to minimize only for edges that
+ are unique to the input file, but not to the "boring" baseline.
+ Suggested by Sami Liedes.
+
+ - "Fixed" a getPassName() problem with newer versions of clang.
+ Reported by Craig Young and several other folks.
+
+ Yep, I know I have a backlog on several other feature requests.
+ Stay tuned!
+
+### Version 2.35b:
+
+ - Fixed a minor cmdline reporting glitch, spotted by Leo Barnes.
+
+ - Fixed a silly bug in libdislocator. Spotted by Johannes Schultz.
+
+### Version 2.34b:
+
+ - Added a note about afl-tmin to technical_details.txt.
+
+ - Added support for AFL_NO_UI, as suggested by Leo Barnes.
+
+### Version 2.33b:
+
+ - Added code to strip -Wl,-z,defs and -Wl,--no-undefined for afl-clang-fast,
+ since they interfere with -shared. Spotted and diagnosed by Toby Hutton.
+
+ - Added some fuzzing tips for Android.
+
+### Version 2.32b:
+
+ - Added a check for AFL_HARDEN combined with AFL_USE_*SAN. Suggested by
+ Hanno Boeck.
+
+ - Made several other cosmetic adjustments to cycle timing in the wake of the
+ big tweak made in 2.31b.
+
+### Version 2.31b:
+
+ - Changed havoc cycle counts for a marked performance boost, especially
+ with -S / -d. See the discussion of FidgetyAFL in:
+
+ https://groups.google.com/forum/#!topic/afl-users/fOPeb62FZUg
+
+ While this does not implement the approach proposed by the authors of
+ the CCS paper, the solution is a result of digging into that research;
+ more improvements may follow as I do more experiments and get more
+ definitive data.
+
+### Version 2.30b:
+
+ - Made minor improvements to persistent mode to avoid the remote
+ possibility of "no instrumentation detected" issues with very low
+ instrumentation densities.
+
+ - Fixed a minor glitch with a leftover process in persistent mode.
+ Reported by Jakub Wilk and Daniel Stender.
+
+ - Made persistent mode bitmaps a bit more consistent and adjusted the way
+ this is shown in the UI, especially in persistent mode.
+
+### Version 2.29b:
+
+ - Made a minor #include fix to llvm_mode. Suggested by Jonathan Metzman.
+
+ - Made cosmetic updates to the docs.
+
+### Version 2.28b:
+
+ - Added "life pro tips" to docs/.
+
+ - Moved testcases/_extras/ to dictionaries/ for visibility.
+
+ - Made minor improvements to install scripts.
+
+ - Added an important safety tip.
+
+### Version 2.27b:
+
+ - Added libtokencap, a simple feature to intercept strcmp / memcmp and
+ generate dictionary entries that can help extend coverage.
+
+ - Moved libdislocator to its own dir, added README.md.
+
+ - The demo in examples/instrumented_cmp is no more.
+
+### Version 2.26b:
+
+ - Made a fix for libdislocator.so to compile on MacOS X.
+
+ - Added support for DYLD_INSERT_LIBRARIES.
+
+ - Renamed AFL_LD_PRELOAD to AFL_PRELOAD.
+
+### Version 2.25b:
+
+ - Made some cosmetic updates to libdislocator.so, renamed one env
+ variable.
+
+### Version 2.24b:
+
+ - Added libdislocator.so, an experimental, abusive allocator. Try
+ it out with AFL_LD_PRELOAD=/path/to/libdislocator.so when running
+ afl-fuzz.
+
+### Version 2.23b:
+
+ - Improved the stability metric for persistent mode binaries. Problem
+ spotted by Kurt Roeckx.
+
+ - Made a related improvement that may bring the metric to 100% for those
+ targets.
+
+### Version 2.22b:
+
+ - Mentioned the potential conflicts between MSAN / ASAN and FORTIFY_SOURCE.
+ There is no automated check for this, since some distros may implicitly
+ set FORTIFY_SOURCE outside of the compiler's argv[].
+
+ - Populated the support for AFL_LD_PRELOAD to all companion tools.
+
+ - Made a change to the handling of ./afl-clang-fast -v. Spotted by
+ Jan Kneschke.
+
+### Version 2.21b:
+
+ - Added some crash reporting notes for Solaris in docs/INSTALL, as
+ investigated by Martin Carpenter.
+
+ - Fixed a minor UI mix-up with havoc strategy stats.
+
+### Version 2.20b:
+
+ - Revamped the handling of variable paths, replacing path count with a
+ "stability" score to give users a much better signal. Based on the
+ feedback from Vegard Nossum.
+
+ - Made a stability improvement to the syncing behavior with resuming
+ fuzzers. Based on the feedback from Vegard.
+
+ - Changed the UI to include current input bitmap density along with
+ total density. Ditto.
+
+ - Added experimental support for parallelizing -M.
+
+### Version 2.19b:
+
+ - Made a fix to make sure that auto CPU binding happens at non-overlapping
+ times.
+
+### Version 2.18b:
+
+ - Made several performance improvements to has_new_bits() and
+ classify_counts(). This should offer a robust performance bump with
+ fast targets.
+
+### Version 2.17b:
+
+ - Killed the error-prone and manual -Z option. On Linux, AFL will now
+ automatically bind to the first free core (or complain if there are no
+ free cores left).
+
+ - Made some doc updates along these lines.
+
+### Version 2.16b:
+
+ - Improved support for older versions of clang (hopefully without
+ breaking anything).
+
+ - Moved version data from Makefile to config.h. Suggested by
+ Jonathan Metzman.
+
+### Version 2.15b:
+
+ - Added a README section on looking for non-crashing bugs.
+
+ - Added license data to several boring files. Contributed by
+ Jonathan Metzman.
+
+### Version 2.14b:
+
+ - Added FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION as a macro defined when
+ compiling with afl-gcc and friends. Suggested by Kostya Serebryany.
+
+ - Refreshed some of the non-x86 docs.
+
+### Version 2.13b:
+
+ - Fixed a spurious build test error with trace-pc and llvm_mode/Makefile.
+ Spotted by Markus Teufelberger.
+
+ - Fixed a cosmetic issue with afl-whatsup. Spotted by Brandon Perry.
+
+### Version 2.12b:
+
+ - Fixed a minor issue in afl-tmin that can make alphabet minimization less
+ efficient during passes > 1. Spotted by Daniel Binderman.
+
+### Version 2.11b:
+
+ - Fixed a minor typo in instrumented_cmp, spotted by Hanno Eissfeldt.
+
+ - Added a missing size check for deterministic insertion steps.
+
+ - Made an improvement to afl-gotcpu when -Z not used.
+
+ - Fixed a typo in post_library_png.so.c in examples/. Spotted by Kostya
+ Serebryany.
+
+### Version 2.10b:
+
+ - Fixed a minor core counting glitch, reported by Tyler Nighswander.
+
+### Version 2.09b:
+
+ - Made several documentation updates.
+
+ - Added some visual indicators to promote and simplify the use of -Z.
+
+### Version 2.08b:
+
+ - Added explicit support for -m32 and -m64 for llvm_mode. Inspired by
+ a request from Christian Holler.
+
+ - Added a new benchmarking option, as requested by Kostya Serebryany.
+
+### Version 2.07b:
+
+ - Added CPU affinity option (-Z) on Linux. With some caution, this can
+ offer a significant (10%+) performance bump and reduce jitter.
+ Proposed by Austin Seipp.
+
+ - Updated afl-gotcpu to use CPU affinity where supported.
+
+ - Fixed confusing CPU_TARGET error messages with QEMU build. Spotted by
+ Daniel Komaromy and others.
+
+### Version 2.06b:
+
+ - Worked around LLVM persistent mode hiccups with -shared code.
+ Contributed by Christian Holler.
+
+ - Added __AFL_COMPILER as a convenient way to detect that something is
+ built under afl-gcc / afl-clang / afl-clang-fast and enable custom
+ optimizations in your code. Suggested by Pedro Corte-Real.
+
+ - Upstreamed several minor changes developed by Franjo Ivancic to
+ allow AFL to be built as a library. This is fairly use-specific and
+ may have relatively little appeal to general audiences.
+
+### Version 2.05b:
+
+ - Put __sanitizer_cov_module_init & co behind #ifdef to avoid problems
+ with ASAN. Spotted by Christian Holler.
+
+### Version 2.04b:
+
+ - Removed indirect-calls coverage from -fsanitize-coverage (since it's
+ redundant). Spotted by Kostya Serebryany.
+
+### Version 2.03b:
+
+ - Added experimental -fsanitize-coverage=trace-pc support that goes with
+ some recent additions to LLVM, as implemented by Kostya Serebryany.
+ Right now, this is cumbersome to use with common build systems, so
+ the mode remains undocumented.
+
+ - Made several substantial improvements to better support non-standard
+ map sizes in LLVM mode.
+
+ - Switched LLVM mode to thread-local execution tracing, which may offer
+ better results in some multithreaded apps.
+
+ - Fixed a minor typo, reported by Heiko Eissfeldt.
+
+ - Force-disabled symbolization for ASAN, as suggested by Christian Holler.
+
+ - AFL_NOX86 renamed to AFL_NO_X86 for consistency.
+
+ - Added AFL_LD_PRELOAD to allow LD_PRELOAD to be set for targets without
+ affecting AFL itself. Suggested by Daniel Godas-Lopez.
+
+### Version 2.02b:
+
+ - Fixed a "lcamtuf can't count to 16" bug in the havoc stage. Reported
+ by Guillaume Endignoux.
+
+### Version 2.01b:
+
+ - Made an improvement to cycle counter color coding, based on feedback
+ from Shai Sarfaty.
+
+ - Added a mention of aflize to sister_projects.txt.
+
+ - Fixed an installation issue with afl-as, as spotted by ilovezfs.
+
+### Version 2.00b:
+
+ - Cleaned up color handling after a minor snafu in 1.99b (affecting some
+ terminals).
+
+ - Made minor updates to the documentation.
+
+### Version 1.99b:
+
+ - Substantially revamped the output and the internal logic of afl-analyze.
+
+ - Cleaned up some of the color handling code and added support for
+ background colors.
+
+ - Removed some stray files (oops).
+
+ - Updated docs to better explain afl-analyze.
+
+### Version 1.98b:
+
+ - Improved to "boring string" detection in afl-analyze.
+
+ - Added technical_details.txt for afl-analyze.
+
+### Version 1.97b:
+
+ - Added afl-analyze, a nifty tool to analyze the structure of a file
+ based on the feedback from AFL instrumentation. This is kinda experimental,
+ so field reports welcome.
+
+ - Added a mention of afl-cygwin.
+
+ - Fixed a couple of typos, as reported by Jakub Wilk and others.
+
+### Version 1.96b:
+
+ - Added -fpic to CFLAGS for the clang plugin, as suggested by Hanno Boeck.
+
+ - Made another clang change (IRBuilder) suggested by Jeff Trull.
+
+ - Fixed several typos, spotted by Jakub Wilk.
+
+ - Added support for AFL_SHUFFLE_QUEUE, based on discussions with
+ Christian Holler.
+
+### Version 1.95b:
+
+ - Fixed a harmless bug when handling -B. Spotted by Jacek Wielemborek.
+
+ - Made the exit message a bit more accurate when AFL_EXIT_WHEN_DONE is set.
+
+ - Added some error-checking for old-style forkserver syntax. Suggested by
+ Ben Nagy.
+
+ - Switched from exit() to _exit() in injected code to avoid snafus with
+ destructors in C++ code. Spotted by sunblate.
+
+ - Made a change to avoid spuriously setting __AFL_SHM_ID when
+ AFL_DUMB_FORKSRV is set in conjunction with -n. Spotted by Jakub Wilk.
+
+### Version 1.94b:
+
+ - Changed allocator alignment to improve support for non-x86 systems (now
+ that llvm_mode makes this more feasible).
+
+ - Fixed a minor typo in afl-cmin. Spotted by Jonathan Neuschafer.
+
+ - Fixed an obscure bug that would affect people trying to use afl-gcc
+ with $TMP set but $TMPDIR absent. Spotted by Jeremy Barnes.
+
+### Version 1.93b:
+
+ - Hopefully fixed a problem with MacOS X and persistent mode, spotted by
+ Leo Barnes.
+
+### Version 1.92b:
+
+ - Made yet another C++ fix (namespaces). Reported by Daniel Lockyer.
+
+### Version 1.91b:
+
+ - Made another fix to make 1.90b actually work properly with C++ (d'oh).
+ Problem spotted by Daniel Lockyer.
+
+### Version 1.90b:
+
+ - Fixed a minor typo spotted by Kai Zhao; and made several other minor updates
+ to docs.
+
+ - Updated the project URL for python-afl. Requested by Jakub Wilk.
+
+ - Fixed a potential problem with deferred mode signatures getting optimized
+ out by the linker (with --gc-sections).
+
+### Version 1.89b:
+
+ - Revamped the support for persistent and deferred forkserver modes.
+ Both now feature simpler syntax and do not require companion env
+ variables. Suggested by Jakub Wilk.
+
+ - Added a bit more info about afl-showmap. Suggested by Jacek Wielemborek.
+
+### Version 1.88b:
+
+ - Made AFL_EXIT_WHEN_DONE work in non-tty mode. Issue spotted by
+ Jacek Wielemborek.
+
+### Version 1.87b:
+
+ - Added QuickStartGuide.txt, a one-page quick start doc.
+
+ - Fixed several typos spotted by Dominique Pelle.
+
+ - Revamped several parts of README.
+
+### Version 1.86b:
+
+ - Added support for AFL_SKIP_CRASHES, which is a very hackish solution to
+ the problem of resuming sessions with intermittently crashing inputs.
+
+ - Removed the hard-fail terminal size check, replaced with a dynamic
+ warning shown in place of the UI. Based on feedback from Christian Holler.
+
+ - Fixed a minor typo in show_stats. Spotted by Dingbao Xie.
+
+### Version 1.85b:
+
+ - Fixed a garbled sentence in notes on parallel fuzzing. Thanks to Jakub Wilk.
+
+ - Fixed a minor glitch in afl-cmin. Spotted by Jonathan Foote.
+
+### Version 1.84b:
+
+ - Made SIMPLE_FILES behave as expected when naming backup directories for
+ crashes and hangs.
+
+ - Added the total number of favored paths to fuzzer_stats. Requested by
+ Ben Nagy.
+
+ - Made afl-tmin, afl-fuzz, and afl-cmin reject negative values passed to
+ -t and -m, since they generally won't work as expected.
+
+ - Made a fix for no lahf / sahf support on older versions of FreeBSD.
+ Patch contributed by Alex Moneger.
+
+### Version 1.83b:
+
+ - Fixed a problem with xargs -d on non-Linux systems in afl-cmin. Spotted by
+ teor2345 and Ben Nagy.
+
+ - Fixed an implicit declaration in LLVM mode on MacOS X. Reported by
+ Kai Zhao.
+
+### Version 1.82b:
+
+ - Fixed a harmless but annoying race condition in persistent mode - signal
+ delivery is a bit more finicky than I thought.
+
+ - Updated the documentation to explain persistent mode a bit better.
+
+ - Tweaked AFL_PERSISTENT to force AFL_NO_VAR_CHECK.
+
+### Version 1.81b:
+
+ - Added persistent mode for in-process fuzzing. See llvm_mode/README.llvm.
+ Inspired by Kostya Serebryany and Christian Holler.
+
+ - Changed the in-place resume code to preserve crashes/README.txt. Suggested
+ by Ben Nagy.
+
+ - Included a potential fix for LLVM mode issues on MacOS X, based on the
+ investigation done by teor2345.
+
+### Version 1.80b:
+
+ - Made afl-cmin tolerant of whitespaces in filenames. Suggested by
+ Jonathan Neuschafer and Ketil Froyn.
+
+ - Added support for AFL_EXIT_WHEN_DONE, as suggested by Michael Rash.
+
+### Version 1.79b:
+
+ - Added support for dictionary levels, see testcases/README.testcases.
+
+ - Reworked the SQL dictionary to use levels.
+
+ - Added a note about Preeny.
+
+### Version 1.78b:
+
+ - Added a dictionary for PDF, contributed by Ben Nagy.
+
+ - Added several references to afl-cov, a new tool by Michael Rash.
+
+ - Fixed a problem with crash reporter detection on MacOS X, as reported by
+ Louis Dassy.
+
+### Version 1.77b:
+
+ - Extended the -x option to support single-file dictionaries.
+
+ - Replaced factory-packaged dictionaries with file-based variants.
+
+ - Removed newlines from HTML keywords in testcases/_extras/html/.
+
+### Version 1.76b:
+
+ - Very significantly reduced the number of duplicate execs during
+ deterministic checks, chiefly in int16 and int32 stages. Confirmed
+ identical path yields. This should improve early-stage efficiency by
+ around 5-10%.
+
+ - Reduced the likelihood of duplicate non-deterministic execs by
+ bumping up lowest stacking factor from 1 to 2. Quickly confirmed
+ that this doesn't seem to have significant impact on coverage with
+ libpng.
+
+ - Added a note about integrating afl-fuzz with third-party tools.
+
+### Version 1.75b:
+
+ - Improved argv_fuzzing to allow it to emit empty args. Spotted by Jakub
+ Wilk.
+
+ - afl-clang-fast now defines __AFL_HAVE_MANUAL_INIT. Suggested by Jakub Wilk.
+
+ - Fixed a libtool-related bug with afl-clang-fast that would make some
+ ./configure invocations generate incorrect output. Spotted by Jakub Wilk.
+
+ - Removed flock() on Solaris. This means no locking on this platform,
+ but so be it. Problem reported by Martin Carpenter.
+
+ - Fixed a typo. Reported by Jakub Wilk.
+
+### Version 1.74b:
+
+ - Added an example argv[] fuzzing wrapper in examples/argv_fuzzing.
+ Reworked the bash example to be faster, too.
+
+ - Clarified llvm_mode prerequisites for FreeBSD.
+
+ - Improved afl-tmin to use /tmp if cwd is not writeable.
+
+ - Removed redundant includes for sys/fcntl.h, which caused warnings with
+ some nitpicky versions of libc.
+
+ - Added a corpus of basic HTML tags that parsers are likely to pay attention
+ to (no attributes).
+
+ - Added EP_EnabledOnOptLevel0 to llvm_mode, so that the instrumentation is
+ inserted even when AFL_DONT_OPTIMIZE=1 is set.
+
+ - Switched qemu_mode to use the newly-released QEMU 2.3.0, which contains
+ a couple of minor bugfixes.
+
+### Version 1.73b:
+
+ - Fixed a pretty stupid bug in effector maps that could sometimes cause
+ AFL to fuzz slightly more than necessary; and in very rare circumstances,
+ could lead to SEGV if eff_map is aligned with page boundary and followed
+ by an unmapped page. Spotted by Jonathan Gray.
+
+### Version 1.72b:
+
+ - Fixed a glitch in non-x86 install, spotted by Tobias Ospelt.
+
+ - Added a minor safeguard to llvm_mode Makefile following a report from
+ Kai Zhao.
+
+### Version 1.71b:
+
+ - Fixed a bug with installed copies of AFL trying to use QEMU mode. Spotted
+ by G.M. Lime.
+
+ - Added last find / crash / hang times to fuzzer_stats, suggested by
+ Richard Hipp.
+
+ - Fixed a typo, thanks to Jakub Wilk.
+
+### Version 1.70b:
+
+ - Modified resumption code to reuse the original timeout value when resuming
+ a session if -t is not given. This prevents timeout creep in continuous
+ fuzzing.
+
+ - Added improved error messages for failed handshake when AFL_DEFER_FORKSRV
+ is set.
+
+ - Made a slight improvement to llvm_mode/Makefile based on feedback from
+ Jakub Wilk.
+
+ - Refreshed several bits of documentation.
+
+ - Added a more prominent note about the MacOS X trade-offs to Makefile.
+
+### Version 1.69b:
+
+ - Added support for deferred initialization in LLVM mode. Suggested by
+ Richard Godbee.
+
+### Version 1.68b:
+
+ - Fixed a minor PRNG glitch that would make the first seconds of a fuzzing
+ job deterministic. Thanks to Andreas Stieger.
+
+ - Made tmp[] static in the LLVM runtime to keep Valgrind happy (this had
+ no impact on anything else). Spotted by Richard Godbee.
+
+ - Clarified the footnote in README.
+
+### Version 1.67b:
+
+ - Made one more correction to llvm_mode Makefile, spotted by Jakub Wilk.
+
+### Version 1.66b:
+
+ - Added CC / CXX support to llvm_mode Makefile. Requested by Charlie Eriksen.
+
+ - Fixed 'make clean' with gmake. Suggested by Oliver Schneider.
+
+ - Fixed 'make -j n clean all'. Suggested by Oliver Schneider.
+
+ - Removed build date and time from banners to give people deterministic
+ builds. Requested by Jakub Wilk.
+
+### Version 1.65b:
+
+ - Fixed a snafu with some leftover code in afl-clang-fast.
+
+ - Corrected even moar typos.
+
+### Version 1.64b:
+
+ - Further simplified afl-clang-fast runtime by reverting .init_array to
+ __attribute__((constructor(0)). This should improve compatibility with
+ non-ELF platforms.
+
+ - Fixed a problem with afl-clang-fast and -shared libraries. Simplified
+ the code by getting rid of .preinit_array and replacing it with a .comm
+ object. Problem reported by Charlie Eriksen.
+
+ - Removed unnecessary instrumentation density adjustment for the LLVM mode.
+ Reported by Jonathan Neuschafer.
+
+### Version 1.63b:
+
+ - Updated cgroups_asan/ with a new version from Sam, made a couple changes
+ to streamline it and keep parallel AFL instances in separate groups.
+
+ - Fixed typos, thanks to Jakub Wilk.
+
+### Version 1.62b:
+
+ - Improved the handling of -x in afl-clang-fast,
+
+ - Improved the handling of low AFL_INST_RATIO settings for QEMU and
+ LLVM modes.
+
+ - Fixed the llvm-config bug for good (thanks to Tobias Ospelt).
+
+### Version 1.61b:
+
+ - Fixed an obscure bug compiling OpenSSL with afl-clang-fast. Patch by
+ Laszlo Szekeres.
+
+ - Fixed a 'make install' bug on non-x86 systems, thanks to Tobias Ospelt.
+
+ - Fixed a problem with half-broken llvm-config on Odroid, thanks to
+ Tobias Ospelt. (There is another odd bug there that hasn't been fully
+ fixed - TBD).
+
+### Version 1.60b:
+
+ - Allowed examples/llvm_instrumentation/ to graduate to llvm_mode/.
+
+ - Removed examples/arm_support/, since it's completely broken and likely
+ unnecessary with LLVM support in place.
+
+ - Added ASAN cgroups script to examples/asan_cgroups/, updated existing
+ docs. Courtesy Sam Hakim and David A. Wheeler.
+
+ - Refactored afl-tmin to reduce the number of execs in common use cases.
+ Ideas from Jonathan Neuschafer and Turo Lamminen.
+
+ - Added a note about CLAs at the bottom of README.
+
+ - Renamed testcases_readme.txt to README.testcases for some semblance of
+ consistency.
+
+ - Made assorted updates to docs.
+
+ - Added MEM_BARRIER() to afl-showmap and afl-tmin, just to be safe.
+
+### Version 1.59b:
+
+ - Imported Laszlo Szekeres' experimental LLVM instrumentation into
+ examples/llvm_instrumentation. I'll work on including it in the
+ "mainstream" version soon.
+
+ - Fixed another typo, thanks to Jakub Wilk.
+
+### Version 1.58b:
+
+ - Added a workaround for abort() behavior in -lpthread programs in QEMU mode.
+ Spotted by Aidan Thornton.
+
+ - Made several documentation updates, including links to the static
+ instrumentation tool (sister_projects.txt).
+
+### Version 1.57b:
+
+ - Fixed a problem with exception handling on some versions of MacOS X.
+ Spotted by Samir Aguiar and Anders Wang Kristensen.
+
+ - Tweaked afl-gcc to use BIN_PATH instead of a fixed string in help
+ messages.
+
+### Version 1.56b:
+
+ - Renamed related_work.txt to historical_notes.txt.
+
+ - Made minor edits to the ASAN doc.
+
+ - Added docs/sister_projects.txt with a list of inspired or closely
+ related utilities.
+
+### Version 1.55b:
+
+ - Fixed a glitch with afl-showmap opening /dev/null with O_RDONLY when
+ running in quiet mode. Spotted by Tyler Nighswander.
+
+### Version 1.54b:
+
+ - Added another postprocessor example for PNG.
+
+ - Made a cosmetic fix to realloc() handling in examples/post_library/,
+ suggested by Jakub Wilk.
+
+ - Improved -ldl handling. Suggested by Jakub Wilk.
+
+### Version 1.53b:
+
+ - Fixed an -l ordering issue that is apparently still a problem on Ubuntu.
+ Spotted by William Robinet.
+
+### Version 1.52b:
+
+ - Added support for file format postprocessors. Requested by Ben Nagy. This
+ feature is intentionally buried, since it's fairly easy to misuse and
+ useful only in some scenarios. See examples/post_library/.
+
+### Version 1.51b:
+
+ - Made it possible to properly override LD_BIND_NOW after one very unusual
+ report of trouble.
+
+ - Cleaned up typos, thanks to Jakub Wilk.
+
+ - Fixed a bug in AFL_DUMB_FORKSRV.
+
+### Version 1.50b:
+
+ - Fixed a flock() bug that would prevent dir reuse errors from kicking
+ in every now and then.
+
+ - Renamed references to ppvm (the project is now called recidivm).
+
+ - Made improvements to file descriptor handling to avoid leaving some fds
+ unnecessarily open in the child process.
+
+ - Fixed a typo or two.
+
+### Version 1.49b:
+
+ - Added code to save original command line in fuzzer_stats and
+ crashes/README.txt. Also saves fuzzer version in fuzzer_stats.
+ Requested by Ben Nagy.
+
+### Version 1.48b:
+
+ - Fixed a bug with QEMU fork server crashes when translation is attempted
+ after a jump to an invalid pointer in the child process (i.e., after
+ bumping into a particularly nasty security bug in the tested binary).
+ Reported by Tyler Nighswander.
+
+### Version 1.47b:
+
+ - Fixed a bug with afl-cmin in -Q mode complaining about binary being not
+ instrumented. Thanks to Jonathan Neuschafer for the bug report.
+
+ - Fixed another bug with argv handling for afl-fuzz in -Q mode. Reported
+ by Jonathan Neuschafer.
+
+ - Improved the use of colors when showing crash counts in -C mode.
+
+### Version 1.46b:
+
+ - Improved instrumentation performance on 32-bit systems by getting rid of
+ xor-swap (oddly enough, xor-swap is still faster on 64-bit) and tweaking
+ alignment.
+
+ - Made path depth numbers more accurate with imported test cases.
+
+### Version 1.45b:
+
+ - Added support for SIMPLE_FILES in config.h for folks who don't like
+ descriptive file names. Generates very simple names without colons,
+ commas, plus signs, dashes, etc.
+
+ - Replaced zero-sized files with symlinks in the variable behavior state
+ dir to simplify examining the relevant test cases.
+
+ - Changed the period of limited-range block ops from 5 to 10 minutes based
+ on a couple of experiments. The basic goal of this delay timer behavior
+ is to better support jobs that are seeded with completely invalid files,
+ in which case, the first few queue cycles may be completed very quickly
+ without discovering new paths. Should have no effect on well-seeded jobs.
+
+ - Made several minor updates to docs.
+
+### Version 1.44b:
+
+ - Corrected two bungled attempts to get the -C mode work properly
+ with afl-cmin (accounting for the short-lived releases tagged 1.42 and
+ 1.43b) - sorry.
+
+ - Removed AFL_ALLOW_CRASHES in favor of the -C mode in said tool.
+
+ - Said goodbye to Hello Kitty, as requested by Padraig Brady.
+
+### Version 1.41b:
+
+ - Added AFL_ALLOW_CRASHES=1 to afl-cmin. Allows crashing inputs in the
+ output corpus. Changed the default behavior to disallow it.
+
+ - Made the afl-cmin output dir default to 0700, not 0755, to be consistent
+ with afl-fuzz; documented the rationale for 0755 in afl-plot.
+
+ - Lowered the output dir reuse time limit to 25 minutes as a dice-roll
+ compromise after a discussion on afl-users@.
+
+ - Made afl-showmap accept -o /dev/null without borking out.
+
+ - Added support for crash / hang info in exit codes of afl-showmap.
+
+ - Tweaked block operation scaling to also factor in ballpark run time
+ in cases where queue passes take very little time.
+
+ - Fixed typos and made improvements to several docs.
+
+### Version 1.40b:
+
+ - Switched to smaller block op sizes during the first passes over the
+ queue. Helps keep test cases small.
+
+ - Added memory barrier for run_target(), just in case compilers get
+ smarter than they are today.
+
+ - Updated a bunch of docs.
+
+### Version 1.39b:
+
+ - Added the ability to skip inputs by sending SIGUSR1 to the fuzzer.
+
+ - Reworked several portions of the documentation.
+
+ - Changed the code to reset splicing perf scores between runs to keep
+ them closer to intended length.
+
+ - Reduced the minimum value of -t to 5 for afl-fuzz (~200 exec/sec)
+ and to 10 for auxiliary tools (due to the absence of a fork server).
+
+ - Switched to more aggressive default timeouts (rounded up to 25 ms
+ versus 50 ms - ~40 execs/sec) and made several other cosmetic changes
+ to the timeout code.
+
+### Version 1.38b:
+
+ - Fixed a bug in the QEMU build script, spotted by William Robinet.
+
+ - Improved the reporting of skipped bitflips to keep the UI counters a bit
+ more accurate.
+
+ - Cleaned up related_work.txt and added some non-goals.
+
+ - Fixed typos, thanks to Jakub Wilk.
+
+### Version 1.37b:
+
+ - Added effector maps, which detect regions that do not seem to respond
+ to bitflips and subsequently exclude them from more expensive steps
+ (arithmetics, known ints, etc). This should offer significant performance
+ improvements with quite a few types of text-based formats, reducing the
+ number of deterministic execs by a factor of 2 or so.
+
+ - Cleaned up mem limit handling in afl-cmin.
+
+ - Switched from uname -i to uname -m to work around Gentoo-specific
+ issues with coreutils when building QEMU. Reported by William Robinet.
+
+ - Switched from PID checking to flock() to detect running sessions.
+ Problem, against all odds, bumped into by Jakub Wilk.
+
+ - Added SKIP_COUNTS and changed the behavior of COVERAGE_ONLY in config.h.
+ Useful only for internal benchmarking.
+
+ - Made improvements to UI refresh rates and exec/sec stats to make them
+ more stable.
+
+ - Made assorted improvements to the documentation and to the QEMU build
+ script.
+
+ - Switched from perror() to strerror() in error macros, thanks to Jakub
+ Wilk for the nag.
+
+ - Moved afl-cmin back to bash, wasn't thinking straight. It has to stay
+ on bash because other shells may have restrictive limits on array sizes.
+
+### Version 1.36b:
+
+ - Switched afl-cmin over to /bin/sh. Thanks to Jonathan Gray.
+
+ - Fixed an off-by-one bug in queue limit check when resuming sessions
+ (could cause NULL ptr deref if you are *really* unlucky).
+
+ - Fixed the QEMU script to tolerate i686 if returned by uname -i. Based on
+ a problem report from Sebastien Duquette.
+
+ - Added multiple references to Jakub's ppvm tool.
+
+ - Made several minor improvements to the Makefile.
+
+ - Believe it or not, fixed some typos. Thanks to Jakub Wilk.
+
+### Version 1.35b:
+
+ - Cleaned up regular expressions in some of the scripts to avoid errors
+ on *BSD systems. Spotted by Jonathan Gray.
+
+### Version 1.34b:
+
+ - Performed a substantial documentation and program output cleanup to
+ better explain the QEMU feature.
+
+### Version 1.33b:
+
+ - Added support for AFL_INST_RATIO and AFL_INST_LIBS in the QEMU mode.
+
+ - Fixed a stack allocation crash in QEMU mode (bug in QEMU, fixed with
+ an extra patch applied to the downloaded release).
+
+ - Added code to test the QEMU instrumentation once the afl-qemu-trace
+ binary is built.
+
+ - Modified afl-tmin and afl-showmap to search $PATH for binaries and to
+ better handle QEMU support.
+
+ - Added a check for instrumented binaries when passing -Q to afl-fuzz.
+
+### Version 1.32b:
+
+ - Fixed 'make install' following the QEMU changes. Spotted by Hanno Boeck.
+
+ - Fixed EXTRA_PAR handling in afl-cmin.
+
+### Version 1.31b:
+
+ - Hallelujah! Thanks to Andrew Griffiths, we now support very fast, black-box
+ instrumentation of binary-only code. See qemu_mode/README.qemu.
+
+ To use this feature, you need to follow the instructions in that
+ directory and then run afl-fuzz with -Q.
+
+### Version 1.30b:
+
+ - Added -s (summary) option to afl-whatsup. Suggested by Jodie Cunningham.
+
+ - Added a sanity check in afl-tmin to detect minimization to zero len or
+ excess hangs.
+
+ - Fixed alphabet size counter in afl-tmin.
+
+ - Slightly improved the handling of -B in afl-fuzz.
+
+ - Fixed process crash messages with -m none.
+
+### Version 1.29b:
+
+ - Improved the naming of test cases when orig: is already present in the file
+ name.
+
+ - Made substantial improvements to technical_details.txt.
+
+### Version 1.28b:
+
+ - Made a minor tweak to the instrumentation to preserve the directionality
+ of tuples (i.e., A -> B != B -> A) and to maintain the identity of tight
+ loops (A -> A). You need to recompile targeted binaries to leverage this.
+
+ - Cleaned up some of the afl-whatsup stats.
+
+ - Added several sanity checks to afl-cmin.
+
+### Version 1.27b:
+
+ - Made afl-tmin recursive. Thanks to Hanno Boeck for the tip.
+
+ - Added docs/technical_details.txt.
+
+ - Changed afl-showmap search strategy in afl-cmap to just look into the
+ same place that afl-cmin is executed from. Thanks to Jakub Wilk.
+
+ - Removed current_todo.txt and cleaned up the remaining docs.
+
+### Version 1.26b:
+
+ - Added total execs/sec stat for afl-whatsup.
+
+ - afl-cmin now auto-selects between cp or ln. Based on feedback from
+ Even Huus.
+
+ - Fixed a typo. Thanks to Jakub Wilk.
+
+ - Made afl-gotcpu a bit more accurate by using getrusage instead of
+ times. Thanks to Jakub Wilk.
+
+ - Fixed a memory limit issue during the build process on NetBSD-current.
+ Reported by Thomas Klausner.
+
+### Version 1.25b:
+
+ - Introduced afl-whatsup, a simple tool for querying the status of
+ local synced instances of afl-fuzz.
+
+ - Added -x compiler to clang options on Darwin. Suggested by Filipe
+ Cabecinhas.
+
+ - Improved exit codes for afl-gotcpu.
+
+ - Improved the checks for -m and -t values in afl-cmin. Bug report
+ from Evan Huus.
+
+### Version 1.24b:
+
+ - Introduced afl-getcpu, an experimental tool to empirically measure
+ CPU preemption rates. Thanks to Jakub Wilk for the idea.
+
+### Version 1.23b:
+
+ - Reverted one change to afl-cmin that actually made it slower.
+
+### Version 1.22b:
+
+ - Reworked afl-showmap.c to support normal options, including -o, -q,
+ -e. Also added support for timeouts and memory limits.
+
+ - Made changes to afl-cmin and other scripts to accommodate the new
+ semantics.
+
+ - Officially retired AFL_EDGES_ONLY.
+
+ - Fixed another typo in afl-tmin, courtesy of Jakub Wilk.
+
+### Version 1.21b:
+
+ - Graduated minimize_corpus.sh to afl-cmin. It is now a first-class
+ utility bundled with the fuzzer.
+
+ - Made significant improvements to afl-cmin to make it faster, more
+ robust, and more versatile.
+
+ - Refactored some of afl-tmin code to make it a bit more readable.
+
+ - Made assorted changes to the doc to document afl-cmin and other stuff.
+
+### Version 1.20b:
+
+ - Added AFL_DUMB_FORKSRV, as requested by Jakub Wilk. This works only
+ in -n mode and allows afl-fuzz to run with "dummy" fork servers that
+ don't output any instrumentation, but follow the same protocol.
+
+ - Renamed AFL_SKIP_CHECKS to AFL_SKIP_BIN_CHECK to make it at least
+ somewhat descriptive.
+
+ - Switched to using clang as the default assembler on MacOS X to work
+ around Xcode issues with newer builds of clang. Testing and patch by
+ Nico Weber.
+
+ - Fixed a typo (via Jakub Wilk).
+
+### Version 1.19b:
+
+ - Improved exec failure detection in afl-fuzz and afl-showmap.
+
+ - Improved Ctrl-C handling in afl-showmap.
+
+ - Added afl-tmin, a handy instrumentation-enabled minimizer.
+
+### Version 1.18b:
+
+ - Fixed a serious but short-lived bug in the resumption behavior introduced
+ in version 1.16b.
+
+ - Added -t nn+ mode for soft-skipping timing-out paths.
+
+### Version 1.17b:
+
+ - Fixed a compiler warning introduced in 1.16b for newer versions of GCC.
+ Thanks to Jakub Wilk and Ilfak Guilfanov.
+
+ - Improved the consistency of saving fuzzer_stats, bitmap info, and
+ auto-dictionaries when aborting fuzzing sessions.
+
+ - Made several noticeable performance improvements to deterministic arith
+ and known int steps.
+
+### Version 1.16b:
+
+ - Added a bit of code to make resumption pick up from the last known
+ offset in the queue, rather than always rewinding to the start. Suggested
+ by Jakub Wilk.
+
+ - Switched to tighter timeout control for slow programs (3x rather than
+ 5x average exec speed at init).
+
+### Version 1.15b:
+
+ - Added support for AFL_NO_VAR_CHECK to speed up resumption and inhibit
+ variable path warnings for some programs.
+
+ - Made the trimmer run even for variable paths, since there is no special
+ harm in doing so and it can be very beneficial if the trimming still
+ pans out.
+
+ - Made the UI a bit more descriptive by adding "n/a" instead of "0" in a
+ couple of corner cases.
+
+### Version 1.14b:
+
+ - Added a (partial) dictionary for JavaScript.
+
+ - Added AFL_NO_CPU_RED, as suggested by Jakub Wilk.
+
+ - Tweaked the havoc scaling logic added in 1.12b.
+
+### Version 1.13b:
+
+ - Improved the performance of minimize_corpus.sh by switching to a
+ sort-based approach.
+
+ - Made several minor revisions to the docs.
+
+### Version 1.12b:
+
+ - Made an improvement to dictionary generation to avoid runs of identical
+ bytes.
+
+ - Added havoc cycle scaling to help with slow binaries in -d mode. Based on
+ a thread with Sami Liedes.
+
+ - Added AFL_SYNC_FIRST for afl-fuzz. This is useful for those who obsess
+ over stats, no special purpose otherwise.
+
+ - Switched to more robust box drawing codes, suggested by Jakub Wilk.
+
+ - Created faster 64-bit variants of several critical-path bitmap functions
+ (sorry, no difference on 32 bits).
+
+ - Fixed moar typos, as reported by Jakub Wilk.
+
+### Version 1.11b:
+
+ - Added a bit more info about dictionary strategies to the status screen.
+
+### Version 1.10b:
+
+ - Revised the dictionary behavior to use insertion and overwrite in
+ deterministic steps, rather than just the latter. This improves coverage
+ with SQL and the like.
+
+ - Added a mention of "*" in status_screen.txt, as suggested by Jakub Wilk.
+
+### Version 1.09b:
+
+ - Corrected a cosmetic problem with 'extras' stage count not always being
+ accurate in the stage yields view.
+
+ - Fixed a typo reported by Jakub Wilk and made some minor documentation
+ improvements.
+
+### Version 1.08b:
+
+ - Fixed a div-by-zero bug in the newly-added code when using a dictionary.
+
+### Version 1.07b:
+
+ - Added code that automatically finds and extracts syntax tokens from the
+ input corpus.
+
+ - Fixed a problem with ld dead-code removal option on MacOS X, reported
+ by Filipe Cabecinhas.
+
+ - Corrected minor typos spotted by Jakub Wilk.
+
+ - Added a couple of more exotic archive format samples.
+
+### Version 1.06b:
+
+ - Switched to slightly more accurate (if still not very helpful) reporting
+ of short read and short write errors. These theoretically shouldn't happen
+ unless you kill the forkserver or run out of disk space. Suggested by
+ Jakub Wilk.
+
+ - Revamped some of the allocator and debug code, adding comments and
+ cleaning up other mess.
+
+ - Tweaked the odds of fuzzing non-favored test cases to make sure that
+ baseline coverage of all inputs is reached sooner.
+
+### Version 1.05b:
+
+ - Added a dictionary for WebP.
+
+ - Made some additional performance improvements to minimize_corpus.sh,
+ getting deeper into the bash woods.
+
+### Version 1.04b:
+
+ - Made substantial performance improvements to minimize_corpus.sh with
+ large datasets, albeit at the expense of having to switch back to bash
+ (other shells may have limits on array sizes, etc).
+
+ - Tweaked afl-showmap to support the format used by the new script.
+
+### Version 1.03b:
+
+ - Added code to skip README.txt in the input directory to make the crash
+ exploration mode work better. Suggested by Jakub Wilk.
+
+ - Added a dictionary for SQLite.
+
+### Version 1.02b:
+
+ - Reverted the ./ search path in minimize_corpus.sh because people did
+ not like it.
+
+ - Added very explicit warnings not to run various shell scripts that
+ read or write to /tmp/ (since this is generally a pretty bad idea on
+ multi-user systems).
+
+ - Added a check for /tmp binaries and -f locations in afl-fuzz.
+
+### Version 1.01b:
+
+ - Added dictionaries for XML and GIF.
+
+### Version 1.00b:
+
+ - Slightly improved the performance of minimize_corpus.sh, especially on
+ Linux.
+
+ - Made a couple of improvements to calibration timeouts for resumed scans.
+
+### Version 0.99b:
+
+ - Fixed minimize_corpus.sh to work with dash, as suggested by Jakub Wilk.
+
+ - Modified minimize_corpus.sh to try locate afl-showmap in $PATH and ./.
+ The first part requested by Jakub Wilk.
+
+ - Added support for afl-as --version, as required by one funky build
+ script. Reported by William Robinet.
+
+### Version 0.98b:
+
+ - Added a dictionary for TIFF.
+
+ - Fixed another cosmetic snafu with stage exec counts for -x.
+
+ - Switched afl-plot to /bin/sh, since it seems bashism-free. Also tried
+ to remove any obvious bashisms from other examples/ scripts,
+ most notably including minimize_corpus.sh and triage_crashes.sh.
+ Requested by Jonathan Gray.
+
+### Version 0.97b:
+
+ - Fixed cosmetic issues around the naming of -x strategy files.
+
+ - Added a dictionary for JPEG.
+
+ - Fixed a very rare glitch when running instrumenting 64-bit code that makes
+ heavy use of xmm registers that are also touched by glibc.
+
+### Version 0.96b:
+
+ - Added support for extra dictionaries, provided testcases/_extras/png/
+ as a demo.
+
+ - Fixed a minor bug in number formatting routines used by the UI.
+
+ - Added several additional PNG test cases that are relatively unlikely
+ to be hit by chance.
+
+ - Fixed afl-plot syntax for gnuplot 5.x. Reported by David Necas.
+
+### Version 0.95b:
+
+ - Cleaned up the OSX ReportCrash code. Thanks to Tobias Ospelt for help.
+
+ - Added some extra tips for AFL_NO_FORKSERVER on OSX.
+
+ - Refreshed the INSTALL file.
+
+### Version 0.94b:
+
+ - Added in-place resume (-i-) to address a common user complaint.
+
+ - Added an awful workaround for ReportCrash on MacOS X. Problem
+ spotted by Joseph Gentle.
+
+### Version 0.93b:
+
+ - Fixed the link() workaround, as reported by Jakub Wilk.
+
+### Version 0.92b:
+
+ - Added support for reading test cases from another filesystem.
+ Requested by Jakub Wilk.
+
+ - Added pointers to the mailing list.
+
+ - Added a sample PDF document.
+
+### Version 0.91b:
+
+ - Refactored minimize_corpus.sh to make it a bit more user-friendly and to
+ select for smallest files, not largest bitmaps. Offers a modest corpus
+ size improvement in most cases.
+
+ - Slightly improved the performance of splicing code.
+
+### Version 0.90b:
+
+ - Moved to an algorithm where paths are marked as preferred primarily based
+ on size and speed, rather than bitmap coverage. This should offer
+ noticeable performance gains in many use cases.
+
+ - Refactored path calibration code; calibration now takes place as soon as a
+ test case is discovered, to facilitate better prioritization decisions later
+ on.
+
+ - Changed the way of marking variable paths to avoid .state metadata
+ inconsistencies.
+
+ - Made sure that calibration routines always create a new test case to avoid
+ hypothetical problems with utilities that modify the input file.
+
+ - Added bitmap saturation to fuzzer stats and plot data.
+
+ - Added a testcase for JPEG XR.
+
+ - Added a tty check for the colors warning in Makefile, to keep distro build
+ logs tidy. Suggested by Jakub Wilk.
+
+### Version 0.89b:
+
+ - Renamed afl-plot.sh to afl-plot, as requested by Padraig Brady.
+
+ - Improved the compatibility of afl-plot with older versions of gnuplot.
+
+ - Added banner information to fuzzer_stats, populated it to afl-plot.
+
+### Version 0.88b:
+
+ - Added support for plotting, with design and implementation based on a
+ prototype design proposed by Michael Rash. Huge thanks!
+
+ - Added afl-plot.sh, which allows you to, well, generate a nice plot using
+ this data.
+
+ - Refactored the code slightly to make more frequent updates to fuzzer_stats
+ and to provide more detail about synchronization.
+
+ - Added an fflush(stdout) call for non-tty operation, as requested by
+ Joonas Kuorilehto.
+
+ - Added some detail to fuzzer_stats for parity with plot_file.
+
+### Version 0.87b:
+
+ - Added support for MSAN, via AFL_USE_MSAN, same gotchas as for ASAN.
+
+### Version 0.86b:
+
+ - Added AFL_NO_FORKSRV, allowing the forkserver to be bypassed. Suggested
+ by Ryan Govostes.
+
+ - Simplified afl-showmap.c to make use of the no-forkserver mode.
+
+ - Made minor improvements to crash_triage.sh, as suggested by Jakub Wilk.
+
+### Version 0.85b:
+
+ - Fixed the CPU counting code - no sysctlbyname() on OpenBSD, d'oh. Bug
+ reported by Daniel Dickman.
+
+ - Made a slight correction to error messages - the advice on testing
+ with ulimit was a tiny bit off by a factor of 1024.
+
+### Version 0.84b:
+
+ - Added support for the CPU widget on some non-Linux platforms (I hope).
+ Based on feedback from Ryan Govostes.
+
+ - Cleaned up the changelog (very meta).
+
+### Version 0.83b:
+
+ - Added examples/clang_asm_normalize/ and related notes in
+ env_variables.txt and afl-as.c. Thanks to Ryan Govostes for the idea.
+
+ - Added advice on hardware utilization in README.
+
+### Version 0.82b:
+
+ - Made additional fixes for Xcode support, juggling -Q and -q flags. Thanks to
+ Ryan Govostes.
+
+ - Added a check for __asm__ blocks and switches to .intel_syntax in assembly.
+ Based on feedback from Ryan Govostes.
+
+### Version 0.81b:
+
+ - A workaround for Xcode 6 as -Q flag glitch. Spotted by Ryan Govostes.
+
+ - Improved Solaris build instructions, as suggested by Martin Carpenter.
+
+ - Fix for a slightly busted path scoring conditional. Minor practical impact.
+
+### Version 0.80b:
+
+ - Added a check for $PATH-induced loops. Problem noticed by Kartik Agaram.
+
+ - Added AFL_KEEP_ASSEMBLY for easier troubleshooting.
+
+ - Added an override for AFL_USE_ASAN if set at AFL compile time. Requested by
+ Hanno Boeck.
+
+### Version 0.79b:
+
+ - Made minor adjustments to path skipping logic.
+
+ - Made several documentation updates to reflect the path selection changes
+ made in 0.78b.
+
+### Version 0.78b:
+
+ - Added a CPU governor check. Bug report from Joe Zbiciak.
+
+ - Favored paths are now selected strictly based on new edges, not hit
+ counts. This speeds up the first pass by a factor of 3-6x without
+ significantly impacting ultimate coverage (tested with libgif, libpng,
+ libjpeg).
+
+ It also allows some performance & memory usage improvements by making
+ some of the in-memory bitmaps much smaller.
+
+ - Made multiple significant performance improvements to bitmap checking
+ functions, plus switched to a faster hash.
+
+ - Owing largely to these optimizations, bumped the size of the bitmap to
+ 64k and added a warning to detect older binaries that rely on smaller
+ bitmaps.
+
+### Version 0.77b:
+
+ - Added AFL_SKIP_CHECKS to bypass binary checks when really warranted.
+ Feature requested by Jakub Wilk.
+
+ - Fixed a couple of typos.
+
+ - Added a warning for runs that are aborted early on.
+
+### Version 0.76b:
+
+ - Incorporated another signal handling fix for Solaris. Suggestion
+ submitted by Martin Carpenter.
+
+### Version 0.75b:
+
+ - Implemented a slightly more "elegant" kludge for the %llu glitch (see
+ types.h).
+
+ - Relaxed CPU load warnings to stay in sync with reality.
+
+### Version 0.74b:
+
+ - Switched to more responsive exec speed averages and better UI speed
+ scaling.
+
+ - Fixed a bug with interrupted reads on Solaris. Issue spotted by Martin
+ Carpenter.
+
+### Version 0.73b:
+
+ - Fixed a stray memcpy() instead of memmove() on overlapping buffers.
+ Mostly harmless but still dumb. Mistake spotted thanks to David Higgs.
+
+### Version 0.72b:
+
+ - Bumped map size up to 32k. You may want to recompile instrumented
+ binaries (but nothing horrible will happen if you don't).
+
+ - Made huge performance improvements for bit-counting functions.
+
+ - Default optimizations now include -funroll-loops. This should have
+ interesting effects on the instrumentation. Frankly, I'm just going to
+ ship it and see what happens next. I have a good feeling about this.
+
+ - Made a fix for stack alignment crash on MacOS X 10.10; looks like the
+ rhetorical question in the comments in afl-as.h has been answered.
+ Tracked down by Mudge Zatko.
+
+### Version 0.71b:
+
+ - Added a fix for the nonsensical MacOS ELF check. Spotted by Mudge Zatko.
+
+ - Made some improvements to ASAN checks.
+
+### Version 0.70b:
+
+ - Added explicit detection of ASANified binaries.
+
+ - Fixed compilation issues on Solaris. Reported by Martin Carpenter.
+
+### Version 0.69b:
+
+ - Improved the detection of non-instrumented binaries.
+
+ - Made the crash counter in -C mode accurate.
+
+ - Fixed an obscure install bug that made afl-as non-functional with the tool
+ installed to /usr/bin instead of /usr/local/bin. Found by Florian Kiersch.
+
+ - Fixed for a cosmetic SIGFPE when Ctrl-C is pressed while the fork server
+ is spinning up.
+
+### Version 0.68b:
+
+ - Added crash exploration mode! Woot!
+
+### Version 0.67b:
+
+ - Fixed several more typos, the project is now cartified 100% typo-free.
+ Thanks to Thomas Jarosch and Jakub Wilk.
+
+ - Made a change to write fuzzer_stats early on.
+
+ - Fixed a glitch when (not!) running on MacOS X as root. Spotted by Tobias
+ Ospelt.
+
+ - Made it possible to override -O3 in Makefile. Suggested by Jakub Wilk.
+
+### Version 0.66b:
+
+ - Fixed a very obscure issue with build systems that use gcc as an assembler
+ for hand-written .s files; this would confuse afl-as. Affected nss, reported
+ by Hanno Boeck.
+
+ - Fixed a bug when cleaning up synchronized fuzzer output dirs. Issue reported
+ by Thomas Jarosch.
+
+### Version 0.65b:
+
+ - Cleaned up shell printf escape codes in Makefile. Reported by Jakub Wilk.
+
+ - Added more color to fuzzer_stats, provided short documentation of the file
+ format, and made several other stats-related improvements.
+
+### Version 0.64b:
+
+ - Enabled GCC support on MacOS X.
+
+### Version 0.63b:
+
+ - Provided a new, simplified way to pass data in files (@@). See README.
+
+ - Made additional fixes for 64-bit MacOS X, working around a crashing bug in
+ their linker (umpf) and several other things. It's alive!
+
+ - Added a minor workaround for a bug in 64-bit FreeBSD (clang -m32 -g doesn't
+ work on that platform, but clang -m32 does, so we no longer insert -g).
+
+ - Added a build-time warning for inverse video terminals and better
+ instructions in status_screen.txt.
+
+### Version 0.62b:
+
+ - Made minor improvements to the allocator, as suggested by Tobias Ospelt.
+
+ - Added example instrumented memcmp() in examples/instrumented_cmp.
+
+ - Added a speculative fix for MacOS X (clang detection, again).
+
+ - Fixed typos in parallel_fuzzing.txt. Problems spotted by Thomas Jarosch.
+
+### Version 0.61b:
+
+ - Fixed a minor issue with clang detection on systems with a clang cc
+ wrapper, so that afl-gcc doesn't confuse it with GCC.
+
+ - Made cosmetic improvements to docs and to the CPU load indicator.
+
+ - Fixed a glitch with crash removal (README.txt left behind, d'oh).
+
+### Version 0.60b:
+
+ - Fixed problems with jump tables generated by exotic versions of GCC. This
+ solves an outstanding problem on OpenBSD when using afl-gcc + PIE (not
+ present with afl-clang).
+
+ - Fixed permissions on one of the sample archives.
+
+ - Added a lahf / sahf workaround for OpenBSD (their assembler doesn't know
+ about these opcodes).
+
+ - Added docs/INSTALL.
+
+### Version 0.59b:
+
+ - Modified 'make install' to also install test cases.
+
+ - Provided better pointers to installed README in afl-fuzz.
+
+ - More work on RLIMIT_AS for OpenBSD.
+
+### Version 0.58b:
+
+ - Added a core count check on Linux.
+
+ - Refined the code for the lack-of-RLIMIT_AS case on OpenBSD.
+
+ - Added a rudimentary CPU utilization meter to help with optimal loading.
+
+### Version 0.57b:
+
+ - Made fixes to support FreeBSD and OpenBSD: use_64bit is now inferred if not
+ explicitly specified when calling afl-as, and RLIMIT_AS is behind an #ifdef.
+ Thanks to Fabian Keil and Jonathan Gray for helping troubleshoot this.
+
+ - Modified 'make install' to also install docs (in /usr/local/share/doc/afl).
+
+ - Fixed a typo in status_screen.txt.
+
+ - Made a couple of Makefile improvements as proposed by Jakub Wilk.
+
+### Version 0.56b:
+
+ - Added probabilistic instrumentation density reduction in ASAN mode. This
+ compensates for ASAN-specific branches in a crude but workable way.
+
+ - Updated notes_for_asan.txt.
+
+### Version 0.55b:
+
+ - Implemented smarter out_dir behavior, automatically deleting directories
+ that don't contain anything of special value. Requested by several folks,
+ including Hanno Boeck.
+
+ - Added more detail in fuzzer_stats (start time, run time, fuzzer PID).
+
+ - Implemented support for configurable install prefixes in Makefile
+ ($PREFIX), as requested by Luca Barbato.
+
+ - Made it possible to resume by doing -i <out_dir>, without having to specify
+ -i <out_dir>/queue/.
+
+### Version 0.54b:
+
+ - Added a fix for -Wformat warning messages (oops, I thought this had been in
+ place for a while).
+
+### Version 0.53b:
+
+ - Redesigned the crash & hang duplicate detection code to better deal with
+ fault conditions that can be reached in a multitude of ways.
+
+ The old approach could be compared to hashing stack traces to de-dupe
+ crashes, a method prone to crash count inflation. The alternative I
+ wanted to avoid would be equivalent to just looking at crash %eip,
+ which can have false negatives in common functions such as memcpy().
+
+ The middle ground currently used in afl-fuzz can be compared to looking
+ at every line item in the stack trace and tagging crashes as unique if
+ we see any function name that we haven't seen before (or if something that
+ we have *always* seen there suddenly disappears). We do the comparison
+ without paying any attention to ordering or hit counts. This can still
+ cause some crash inflation early on, but the problem will quickly taper
+ off. So, you may get 20 dupes instead of 5,000.
+
+ - Added a fix for harmless but absurd trim ratios shown if the first exec in
+ the trimmer timed out. Spotted by @EspenGx.
+
+### Version 0.52b:
+
+ - Added a quick summary of the contents in examples/.
+
+ - Made a fix to the process of writing fuzzer_stats.
+
+ - Slightly reorganized the .state/ directory, now recording redundant paths,
+ too. Note that this breaks the ability to properly resume older sessions
+ - sorry about that.
+
+ (To fix this, simply move <out_dir>/.state/* from an older run
+ to <out_dir>/.state/deterministic_done/*.)
+
+### Version 0.51b:
+
+ - Changed the search order for afl-as to avoid the problem with older copies
+ installed system-wide; this also means that I can remove the Makefile check
+ for that.
+
+ - Made it possible to set instrumentation ratio of 0%.
+
+ - Introduced some typos, fixed others.
+
+ - Fixed the test_prev target in Makefile, as reported by Ozzy Johnson.
+
+### Version 0.50b:
+
+ - Improved the 'make install' logic, as suggested by Padraig Brady.
+
+ - Revamped various bits of the documentation, especially around perf_tips.txt;
+ based on the feedback from Alexander Cherepanov.
+
+ - Added AFL_INST_RATIO to afl-as. The only case where this comes handy is
+ ffmpeg, at least as far as I can tell. (Trivia: the current version of
+ ffmpeg ./configure also ignores CC and --cc, probably unintentionally).
+
+ - Added documentation for all environmental variables (env_variables.txt).
+
+ - Implemented a visual warning for excessive or insufficient bitmap density.
+
+ - Changed afl-gcc to add -O3 by default; use AFL_DONT_OPTIMIZE if you don't
+ like that. Big speed gain for ffmpeg, so seems like a good idea.
+
+ - Made a regression fix to afl-as to ignore .LBB labels in gcc mode.
+
+### Version 0.49b:
+
+ - Fixed more typos, as found by Jakub Wilk.
+
+ - Added support for clang!
+
+ - Changed AFL_HARDEN to *not* include ASAN by default. Use AFL_USE_ASAN if
+ needed. The reasons for this are in notes_for_asan.txt.
+
+ - Switched from configure auto-detection to isatty() to keep afl-as and
+ afl-gcc quiet.
+
+ - Improved installation process to properly create symlinks, rather than
+ copies of binaries.
+
+### Version 0.48b:
+
+ - Improved afl-fuzz to force-set ASAN_OPTIONS=abort_on_error=1. Otherwise,
+ ASAN crashes wouldn't be caught at all. Reported by Hanno Boeck.
+
+ - Improved Makefile mkdir logic, as suggested by Hanno Boeck.
+
+ - Improved the 64-bit instrumentation to properly save r8-r11 registers in
+ the x86 setup code. The old behavior could cause rare problems running
+ *without* instrumentation when the first function called in a particular
+ .o file has 5+ parameters. No impact on code running under afl-fuzz or
+ afl-showmap. Issue spotted by Padraig Brady.
+
+### Version 0.47b:
+
+ - Fixed another Makefile bug for parallel builds of afl. Problem identified
+ by Richard W. M. Jones.
+
+ - Added support for suffixes for -m.
+
+ - Updated the documentation and added notes_for_asan.txt. Based on feedback
+ from Hanno Boeck, Ben Laurie, and others.
+
+ - Moved the project to https://lcamtuf.coredump.cx/afl/.
+
+### Version 0.46b:
+
+ - Cleaned up Makefile dependencies for parallel builds. Requested by
+ Richard W. M. Jones.
+
+ - Added support for DESTDIR in Makefile. Once again suggested by
+ Richard W. M. Jones :-)
+
+ - Removed all the USE_64BIT stuff; we now just auto-detect compilation mode.
+ As requested by many callers to the show.
+
+ - Fixed rare problems with programs that use snippets of assembly and
+ switch between .code32 and .code64. Addresses a glitch spotted by
+ Hanno Boeck with compiling ToT gdb.
+
+### Version 0.45b:
+
+ - Implemented a test case trimmer. Results in 20-30% size reduction for many
+ types of work loads, with very pronounced improvements in path discovery
+ speeds.
+
+ - Added better warnings for various problems with input directories.
+
+ - Added a Makefile warning for older copies, based on counterintuitive
+ behavior observed by Hovik Manucharyan.
+
+ - Added fuzzer_stats file for status monitoring. Suggested by @dronesec.
+
+ - Fixed moar typos, thanks to Alexander Cherepanov.
+
+ - Implemented better warnings for ASAN memory requirements, based on calls
+ from several angry listeners.
+
+ - Switched to saner behavior with non-tty stdout (less output generated,
+ no ANSI art).
+
+### Version 0.44b:
+
+ - Added support for AFL_CC and AFL_CXX, based on a patch from Ben Laurie.
+
+ - Replaced afl-fuzz -S -D with -M for simplicity.
+
+ - Added a check for .section .text; lack of this prevented main() from
+ getting instrumented for some users. Reported by Tom Ritter.
+
+ - Reorganized the testcases/ directory.
+
+ - Added an extra check to confirm that the build is operational.
+
+ - Made more consistent use of color reset codes, as suggested by Oliver
+ Kunz.
+
+### Version 0.43b:
+
+ - Fixed a bug with 64-bit gcc -shared relocs.
+
+ - Removed echo -e from Makefile for compatibility with dash. Suggested
+ by Jakub Wilk.
+
+ - Added status_screen.txt.
+
+ - Added examples/canvas_harness.
+
+ - Made a minor change to the Makefile GCC check. Suggested by Hanno Boeck.
+
+### Version 0.42b:
+
+ - Fixed a bug with red zone handling for 64-bit (oops!). Problem reported by
+ Felix Groebert.
+
+ - Implemented horribly experimental ARM support in examples/arm_support.
+
+ - Made several improvements to error messages.
+
+ - Added AFL_QUIET to silence afl-gcc and afl-as when using wonky build
+ systems. Reported by Hanno Boeck.
+
+ - Improved check for 64-bit compilation, plus several sanity checks
+ in Makefile.
+
+### Version 0.41b:
+
+ - Fixed a fork served bug for processes that call execve().
+
+ - Made minor compatibility fixes to Makefile, afl-gcc; suggested by Jakub
+ Wilk.
+
+ - Fixed triage_crashes.sh to work with the new layout of output directories.
+ Suggested by Jakub Wilk.
+
+ - Made multiple performance-related improvements to the injected
+ instrumentation.
+
+ - Added visual indication of the number of imported paths.
+
+ - Fixed afl-showmap to make it work well with new instrumentation.
+
+ - Added much better error messages for crashes when importing test cases
+ or otherwise calibrating the binary.
+
+### Version 0.40b:
+
+ - Added support for parallelized fuzzing. Inspired by earlier patch
+ from Sebastian Roschke.
+
+ - Added an example in examples/distributed_fuzzing/.
+
+### Version 0.39b:
+
+ - Redesigned status screen, now 90% more spiffy.
+
+ - Added more verbose and user-friendly messages for some common problems.
+
+ - Modified the resumption code to reconstruct path depth.
+
+ - Changed the code to inhibit core dumps and improve the ability to detect
+ SEGVs.
+
+ - Added a check for redirection of core dumps to programs.
+
+ - Made a minor improvement to the handling of variable paths.
+
+ - Made additional performance tweaks to afl-fuzz, chiefly around mem limits.
+
+ - Added performance_tips.txt.
+
+### Version 0.38b:
+
+ - Fixed an fd leak and +cov tracking bug resulting from changes in 0.37b.
+
+ - Implemented auto-scaling for screen update speed.
+
+ - Added a visual indication when running in non-instrumented mode.
+
+### Version 0.37b:
+
+ - Added fuzz state tracking for more seamless resumption of aborted
+ fuzzing sessions.
+
+ - Removed the -D option, as it's no longer necessary.
+
+ - Refactored calibration code and improved startup reporting.
+
+ - Implemented dynamically scaled timeouts, so that you don't need to
+ play with -t except in some very rare cases.
+
+ - Added visual notification for slow binaries.
+
+ - Improved instrumentation to explicitly cover the other leg of every
+ branch.
+
+### Version 0.36b:
+
+ - Implemented fork server support to avoid the overhead of execve(). A
+ nearly-verbatim design from Jann Horn; still pending part 2 that would
+ also skip initial setup steps (thinking about reliable heuristics now).
+
+ - Added a check for shell scripts used as fuzz targets.
+
+ - Added a check for fuzz jobs that don't seem to be finding anything.
+
+ - Fixed the way IGNORE_FINDS works (was a bit broken after adding splicing
+ and path skip heuristics).
+
+### Version 0.35b:
+
+ - Properly integrated 64-bit instrumentation into afl-as.
+
+### Version 0.34b:
+
+ - Added a new exec count classifier (the working theory is that it gets
+ meaningful coverage with fewer test cases spewed out).
+
+### Version 0.33b:
+
+ - Switched to new, somewhat experimental instrumentation that tries to
+ target only arcs, rather than every line. May be fragile, but is a lot
+ faster (2x+).
+
+ - Made several other cosmetic fixes and typo corrections, thanks to
+ Jakub Wilk.
+
+### Version 0.32b:
+
+ - Another take at fixing the C++ exception thing. Reported by Jakub Wilk.
+
+### Version 0.31b:
+
+ - Made another fix to afl-as to address a potential problem with newer
+ versions of GCC (introduced in 0.28b). Thanks to Jann Horn.
+
+### Version 0.30b:
+
+ - Added more detail about the underlying operations in file names.
+
+### Version 0.29b:
+
+ - Made some general improvements to chunk operations.
+
+### Version 0.28b:
+
+ - Fixed C++ exception handling in newer versions of GCC. Problem diagnosed
+ by Eberhard Mattes.
+
+ - Fixed the handling of the overflow flag. Once again, thanks to
+ Eberhard Mattes.
+
+### Version 0.27b:
+
+ - Added prioritization of new paths over the already-fuzzed ones.
+
+ - Included spliced test case ID in the output file name.
+
+ - Fixed a rare, cosmetic null ptr deref after Ctrl-C.
+
+ - Refactored the code to make copies of test cases in the output directory.
+
+ - Switched to better output file names, keeping track of stage and splicing
+ sources.
+
+### Version 0.26b:
+
+ - Revamped storage of testcases, -u option removed,
+
+ - Added a built-in effort minimizer to get rid of potentially redundant
+ inputs,
+
+ - Provided a testcase count minimization script in examples/,
+
+ - Made miscellaneous improvements to directory and file handling.
+
+ - Fixed a bug in timeout detection.
+
+### Version 0.25b:
+
+ - Improved count-based instrumentation.
+
+ - Improved the hang deduplication logic.
+
+ - Added -cov prefixes for test cases.
+
+ - Switched from readdir() to scandir() + alphasort() to preserve ordering of
+ test cases.
+
+ - Added a splicing strategy.
+
+ - Made various minor UI improvements and several other bugfixes.
+
+### Version 0.24b:
+
+ - Added program name to the status screen, plus the -T parameter to go with
+ it.
+
+### Version 0.23b:
+
+ - Improved the detection of variable behaviors.
+
+ - Added path depth tracking,
+
+ - Improved the UI a bit,
+
+ - Switched to simplified (XOR-based) tuple instrumentation.
+
+### Version 0.22b:
+
+ - Refactored the handling of long bitflips and some swaps.
+
+ - Fixed the handling of gcc -pipe, thanks to anonymous reporter.
+
+### Version 0.21b (2013-11-12):
+
+ - Initial public release.
+
+ - Added support for use of multiple custom mutators which can be specified using
+ the environment variable AFL_CUSTOM_MUTATOR_LIBRARY.
diff --git a/docs/FAQ.md b/docs/FAQ.md
new file mode 100644
index 00000000..1822e46b
--- /dev/null
+++ b/docs/FAQ.md
@@ -0,0 +1,257 @@
+# Frequently asked questions (FAQ)
+
+If you find an interesting or important question missing, submit it via
+[https://github.com/AFLplusplus/AFLplusplus/discussions](https://github.com/AFLplusplus/AFLplusplus/discussions).
+
+## General
+
+<details>
+ <summary id="what-is-the-difference-between-afl-and-aflplusplus">What is the difference between AFL and AFL++?</summary><p>
+
+ AFL++ is a superior fork to Google's AFL - more speed, more and better
+ mutations, more and better instrumentation, custom module support, etc.
+
+ 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 maintenance of AFL,
+ however, it is only accepting PRs from the community and is not developing
+ enhancements anymore.
+
+ In the second quarter of 2019, 1 1/2 years later, when no further development
+ of AFL had happened and it became clear there would none be coming, AFL++ was
+ born, where initially community patches were collected and applied for bug
+ fixes 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 features, 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).
+</p></details>
+
+<details>
+ <summary id="is-afl-a-whitebox-graybox-or-blackbox-fuzzer">Is AFL++ a whitebox, graybox, or blackbox fuzzer?</summary><p>
+
+ The definition of the terms whitebox, graybox, and blackbox fuzzing varies
+ from one source to another. For example, "graybox fuzzing" could mean
+ binary-only or source code fuzzing, or something completely different.
+ Therefore, we try to avoid them.
+
+ [The Fuzzing Book](https://www.fuzzingbook.org/html/GreyboxFuzzer.html#AFL:-An-Effective-Greybox-Fuzzer)
+ describes the original AFL to be a graybox fuzzer. In that sense, AFL++ is
+ also a graybox fuzzer.
+</p></details>
+
+<details>
+ <summary id="where-can-i-find-tutorials">Where can I find tutorials?</summary><p>
+
+ We compiled a list of tutorials and exercises, see
+ [tutorials.md](tutorials.md).
+</p></details>
+
+<details>
+ <summary id="what-is-an-edge">What is an "edge"?</summary><p>
+
+ A program contains `functions`, `functions` contain the compiled machine code.
+ The compiled machine code in a `function` can be in a single or many `basic
+ blocks`. A `basic block` is the **largest possible number of subsequent machine
+ code instructions** that has **exactly one entry point** (which can be be entered by
+ multiple other basic blocks) and runs linearly **without branching or jumping to
+ other addresses** (except at the end).
+
+ ```
+ function() {
+ A:
+ some
+ code
+ B:
+ if (x) goto C; else goto D;
+ C:
+ some code
+ goto E
+ D:
+ some code
+ goto B
+ E:
+ return
+ }
+ ```
+
+ Every code block between two jump locations is a `basic block`.
+
+ An `edge` is then the unique relationship between two directly connected
+ `basic blocks` (from the code example above):
+
+ ```
+ Block A
+ |
+ v
+ Block B <------+
+ / \ |
+ v v |
+ Block C Block D --+
+ \
+ v
+ Block E
+ ```
+
+ Every line between two blocks is an `edge`. Note that a few basic block loop
+ to itself, this too would be an edge.
+</p></details>
+
+## Targets
+
+<details>
+ <summary id="how-can-i-fuzz-a-binary-only-target">How can I fuzz a binary-only target?</summary><p>
+
+ AFL++ is a great fuzzer if you have the source code available.
+
+ However, if there is only the binary program and no source code available,
+ then the standard non-instrumented mode is not effective.
+
+ To learn how these binaries can be fuzzed, read
+ [fuzzing_binary-only_targets.md](fuzzing_binary-only_targets.md).
+</p></details>
+
+<details>
+ <summary id="how-can-i-fuzz-a-network-service">How can I fuzz a network service?</summary><p>
+
+ The short answer is - you cannot, at least not "out of the box".
+
+ For more information on fuzzing network services, see
+ [best_practices.md#fuzzing-a-network-service](best_practices.md#fuzzing-a-network-service).
+</p></details>
+
+<details>
+ <summary id="how-can-i-fuzz-a-gui-program">How can I fuzz a GUI program?</summary><p>
+
+ Not all GUI programs are suitable for fuzzing. If the GUI program can read the
+ fuzz data from a file without needing any user interaction, then it would be
+ suitable for fuzzing.
+
+ For more information on fuzzing GUI programs, see
+ [best_practices.md#fuzzing-a-gui-program](best_practices.md#fuzzing-a-gui-program).
+</p></details>
+
+## Performance
+
+<details>
+ <summary id="what-makes-a-good-performance">What makes a good performance?</summary><p>
+
+ Good performance generally means "making the fuzzing results better". This can
+ be influenced by various factors, for example, speed (finding lots of paths
+ quickly) or thoroughness (working with decreased speed, but finding better
+ mutations).
+</p></details>
+
+<details>
+ <summary id="how-can-i-improve-the-fuzzing-speed">How can I improve the fuzzing speed?</summary><p>
+
+ There are a few things you can do to improve the fuzzing speed, see
+ [best_practices.md#improving-speed](best_practices.md#improving-speed).
+</p></details>
+
+<details>
+ <summary id="why-is-my-stability-below-100percent">Why is my stability below 100%?</summary><p>
+
+ 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 other external data,
+ reaction to timing, etc., then in some of the re-executions with the same data
+ the edge coverage result will be different across runs. Those edges that
+ change are then flagged "unstable".
+
+ The more "unstable" edges there are, the harder it is for AFL++ to identify
+ valid new paths.
+
+ A value above 90% is usually fine and a value above 80% is also still ok, and
+ even a value above 20% can still result in successful finds of bugs. However,
+ it is recommended that for values below 90% or 80% you should take
+ countermeasures to improve stability.
+
+ For more information on stability and how to improve the stability value, see
+ [best_practices.md#improving-stability](best_practices.md#improving-stability).
+</p></details>
+
+<details>
+ <summary id="what-are-power-schedules">What are power schedules?</summary><p>
+
+ Not every item in our queue/corpus is the same, some are more interesting,
+ others provide little value.
+ A power schedule measures how "interesting" a value is, and depending on
+ the calculated value spends more or less time mutating it.
+
+ AFL++ comes with several power schedules, initially ported from
+ [AFLFast](https://github.com/mboehme/aflfast), however, modified to be more
+ effective and several more modes added.
+
+ The most effective modes are `-p fast` (default) and `-p explore`.
+
+ If you fuzz with several parallel afl-fuzz instances, then it is beneficial
+ to assign a different schedule to each instance, however the majority should
+ be `fast` and `explore`.
+
+ It does not make sense to explain the details of the calculation and
+ reasoning behind all of the schedules. If you are interested, read the source
+ code and the AFLFast paper.
+</p></details>
+
+## Troubleshooting
+
+<details>
+ <summary id="fatal-forkserver-is-already-up-but-an-instrumented-dlopen-library-loaded-afterwards">FATAL: forkserver is already up but an instrumented dlopen library loaded afterwards</summary><p>
+
+ It can happen that you see this error on startup when fuzzing a target:
+
+ ```
+ [-] FATAL: forkserver is already up, but an instrumented dlopen() library
+ loaded afterwards. You must AFL_PRELOAD such libraries to be able
+ to fuzz them or LD_PRELOAD to run outside of afl-fuzz.
+ To ignore this set AFL_IGNORE_PROBLEMS=1.
+ ```
+
+ As the error describes, a dlopen() call is happening in the target that is
+ loading an instrumented library after the forkserver is already in place. This
+ is a problem for afl-fuzz because when the forkserver is started, we must know
+ the map size already and it can't be changed later.
+
+ The best solution is to simply set `AFL_PRELOAD=foo.so` to the libraries that
+ are dlopen'ed (e.g., use `strace` to see which), or to set a manual forkserver
+ after the final dlopen().
+
+ If this is not a viable option, you can set `AFL_IGNORE_PROBLEMS=1` but then
+ the existing map will be used also for the newly loaded libraries, which
+ allows it to work, however, the efficiency of the fuzzing will be partially
+ degraded.
+</p></details>
+
+<details>
+ <summary id="i-got-a-weird-compile-error-from-clang">I got a weird compile error from clang.</summary><p>
+
+ If you see this kind of error when trying to instrument a target with
+ afl-cc/afl-clang-fast/afl-clang-lto:
+
+ ```
+ /prg/tmp/llvm-project/build/bin/clang-13: symbol lookup error: /usr/local/bin/../lib/afl//cmplog-instructions-pass.so: undefined symbol: _ZNK4llvm8TypeSizecvmEv
+ clang-13: error: unable to execute command: No such file or directory
+ clang-13: error: clang frontend command failed due to signal (use -v to see invocation)
+ clang version 13.0.0 (https://github.com/llvm/llvm-project 1d7cf550721c51030144f3cd295c5789d51c4aad)
+ Target: x86_64-unknown-linux-gnu
+ Thread model: posix
+ InstalledDir: /prg/tmp/llvm-project/build/bin
+ clang-13: note: diagnostic msg:
+ ********************
+ ```
+
+ Then this means that your OS updated the clang installation from an upgrade
+ package and because of that the AFL++ llvm plugins do not match anymore.
+
+ Solution: `git pull ; make clean install` of AFL++.
+</p></details>
diff --git a/docs/INSTALL.md b/docs/INSTALL.md
new file mode 100644
index 00000000..01343b7f
--- /dev/null
+++ b/docs/INSTALL.md
@@ -0,0 +1,182 @@
+# Building and installing AFL++
+
+## Linux on x86
+
+An easy way to install AFL++ with everything compiled is available via docker:
+You can use the [Dockerfile](../Dockerfile) (which has gcc-10 and clang-12 -
+hence afl-clang-lto is available) or just pull directly from the Docker Hub
+(for x86_64 and arm64):
+
+```shell
+docker pull aflplusplus/aflplusplus
+docker run -ti -v /location/of/your/target:/src aflplusplus/aflplusplus
+```
+
+This image is automatically generated when a push to the stable repo happens.
+You will find your target source code in `/src` in the container.
+
+If you want to build AFL++ yourself, you have many options. The easiest choice
+is to build and install everything:
+
+```shell
+sudo apt-get update
+sudo apt-get install -y build-essential python3-dev automake cmake git flex bison libglib2.0-dev libpixman-1-dev python3-setuptools
+# try to install llvm 12 and install the distro default if that fails
+sudo apt-get install -y lld-12 llvm-12 llvm-12-dev clang-12 || sudo apt-get install -y lld llvm llvm-dev clang
+sudo apt-get install -y gcc-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-plugin-dev libstdc++-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-dev
+sudo apt-get install -y ninja-build # for QEMU mode
+git clone https://github.com/AFLplusplus/AFLplusplus
+cd AFLplusplus
+make distrib
+sudo make install
+```
+
+It is recommended to install the newest available gcc, clang and llvm-dev
+possible in your distribution!
+
+Note that `make distrib` also builds FRIDA mode, QEMU mode, unicorn_mode, and
+more. If you just want plain AFL++, then do `make all`. If you want some
+assisting tooling compiled but are not interested in binary-only targets, then
+instead choose:
+
+```shell
+make source-only
+```
+
+These build targets exist:
+
+* all: the main afl++ binaries and llvm/gcc instrumentation
+* binary-only: everything for binary-only fuzzing: frida_mode, nyx_mode,
+ qemu_mode, frida_mode, unicorn_mode, coresight_mode, libdislocator,
+ libtokencap
+* source-only: everything for source code fuzzing: nyx_mode, libdislocator,
+ libtokencap
+* distrib: everything (for both binary-only and source code fuzzing)
+* man: creates simple man pages from the help option of the programs
+* install: installs everything you have compiled with the build options above
+* clean: cleans everything compiled, not downloads (unless not on a checkout)
+* deepclean: cleans everything including downloads
+* code-format: format the code, do this before you commit and send a PR please!
+* tests: runs test cases to ensure that all features are still working as they
+ should
+* unit: perform unit tests (based on cmocka)
+* help: shows these build options
+
+[Unless you are on Mac OS X](https://developer.apple.com/library/archive/qa/qa1118/_index.html),
+you can also build statically linked versions of the AFL++ binaries by passing
+the `STATIC=1` argument to make:
+
+```shell
+make STATIC=1
+```
+
+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)
+* INTROSPECTION - compile afl-fuzz with mutation introspection
+* NO_PYTHON - disable python support
+* NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for
+ normal fuzzing
+* NO_NYX - disable building nyx mode dependencies
+* AFL_NO_X86 - if compiling on non-intel/amd platforms
+* LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config
+ (e.g., Debian)
+
+e.g.: `make ASAN_BUILD=1`
+
+## MacOS X on x86 and arm64 (M1)
+
+MacOS has some gotchas due to the idiosyncrasies of the platform.
+
+To build AFL, install llvm (and perhaps gcc) from brew and follow the general
+instructions for Linux. If possible, avoid Xcode at all cost.
+
+```shell
+brew install wget git make cmake llvm gdb coreutils
+```
+
+Be sure to setup `PATH` to point to the correct clang binaries and use the
+freshly installed clang, clang++, llvm-config, gmake and coreutils, e.g.:
+
+```shell
+# Depending on your MacOS system + brew version it is either
+export PATH="/opt/homebrew/opt/llvm/bin:$PATH"
+# or
+export PATH="/usr/local/opt/llvm/bin:$PATH"
+# you can check with "brew info llvm"
+
+export PATH="/usr/local/opt/coreutils/libexec/gnubin:/usr/local/bin:$PATH"
+export CC=clang
+export CXX=clang++
+gmake
+cd frida_mode
+gmake
+cd ..
+sudo gmake install
+```
+
+`afl-gcc` will fail unless you have GCC installed, but that is using outdated
+instrumentation anyway. `afl-clang` might fail too depending on your PATH setup.
+But you don't want neither, you want `afl-clang-fast` anyway :) Note that
+`afl-clang-lto`, `afl-gcc-fast` and `qemu_mode` are not working on MacOS.
+
+The crash reporting daemon that comes by default with MacOS X will cause
+problems with fuzzing. You need to turn it off:
+
+```
+launchctl unload -w /System/Library/LaunchAgents/com.apple.ReportCrash.plist
+sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.ReportCrash.Root.plist
+```
+
+The `fork()` semantics on OS X are a bit unusual compared to other unix systems
+and definitely don't look POSIX-compliant. This means two things:
+
+ - Fuzzing will be probably slower than on Linux. In fact, some folks report
+ considerable performance gains by running the jobs inside a Linux VM on
+ MacOS X.
+ - Some non-portable, platform-specific code may be incompatible with the AFL++
+ forkserver. If you run into any problems, set `AFL_NO_FORKSRV=1` in the
+ environment before starting afl-fuzz.
+
+User emulation mode of QEMU does not appear to be supported on MacOS X, so
+black-box instrumentation mode (`-Q`) will not work. However, Frida mode (`-O`)
+works on both x86 and arm64 MacOS boxes.
+
+MacOS X supports SYSV shared memory used by AFL's instrumentation, but the
+default settings aren't usable with AFL++. The default settings on 10.14 seem to
+be:
+
+```bash
+$ ipcs -M
+IPC status from <running system> as of XXX
+shminfo:
+ shmmax: 4194304 (max shared memory segment size)
+ shmmin: 1 (min shared memory segment size)
+ shmmni: 32 (max number of shared memory identifiers)
+ shmseg: 8 (max shared memory segments per process)
+ shmall: 1024 (max amount of shared memory in pages)
+```
+
+To temporarily change your settings to something minimally usable with AFL++,
+run these commands as root:
+
+```bash
+sysctl kern.sysv.shmmax=8388608
+sysctl kern.sysv.shmall=4096
+```
+
+If you're running more than one instance of AFL, you likely want to make
+`shmall` bigger and increase `shmseg` as well:
+
+```bash
+sysctl kern.sysv.shmmax=8388608
+sysctl kern.sysv.shmseg=48
+sysctl kern.sysv.shmall=98304
+```
+
+See
+[http://www.spy-hill.com/help/apple/SharedMemory.html](http://www.spy-hill.com/help/apple/SharedMemory.html)
+for documentation for these settings and how to make them permanent.
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 00000000..2bd07bb6
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,65 @@
+# AFL++ documentation
+
+This is the overview of the AFL++ docs content.
+
+For general information on AFL++, see the
+[README.md of the repository](../README.md).
+
+Also take a look at our [FAQ.md](FAQ.md) and
+[best_practices.md](best_practices.md).
+
+## Fuzzing targets with the source code available
+
+You can find a quickstart for fuzzing targets with the source code available in
+the [README.md of the repository](../README.md#quick-start-fuzzing-with-afl).
+
+For in-depth information on the steps of the fuzzing process, see
+[fuzzing_in_depth.md](fuzzing_in_depth.md) or click on the following
+image and select a step.
+
+![Fuzzing process overview](https://raw.githubusercontent.com/AFLplusplus/AFLplusplus/dev/docs/resources/0_fuzzing_process_overview.drawio.svg "Fuzzing process overview")
+
+For further information on instrumentation, see the
+[READMEs in the instrumentation/ folder](../instrumentation/).
+
+### Instrumenting the target
+
+For more information, click on the following image and select a step.
+
+![Instrumenting the target](https://raw.githubusercontent.com/AFLplusplus/AFLplusplus/dev/docs/resources/1_instrument_target.drawio.svg "Instrumenting the target")
+
+### Preparing the fuzzing campaign
+
+For more information, click on the following image and select a step.
+
+![Preparing the fuzzing campaign](https://raw.githubusercontent.com/AFLplusplus/AFLplusplus/dev/docs/resources/2_prepare_campaign.drawio.svg "Preparing the fuzzing campaign")
+
+### Fuzzing the target
+
+For more information, click on the following image and select a step.
+
+![Fuzzing the target](https://raw.githubusercontent.com/AFLplusplus/AFLplusplus/dev/docs/resources/3_fuzz_target.drawio.svg "Fuzzing the target")
+
+### Managing the fuzzing campaign
+
+For more information, click on the following image and select a step.
+
+![Managing the fuzzing campaign](https://raw.githubusercontent.com/AFLplusplus/AFLplusplus/dev/docs/resources/4_manage_campaign.drawio.svg "Managing the fuzzing campaign")
+
+## Fuzzing other targets
+
+To learn about fuzzing other targets, see:
+
+* Binary-only: [fuzzing_binary-only_targets.md](fuzzing_binary-only_targets.md)
+* GUI programs:
+ [best_practices.md#fuzzing-a-gui-program](best_practices.md#fuzzing-a-gui-program)
+* Libraries: [frida_mode/README.md](../frida_mode/README.md)
+* Network services:
+ [best_practices.md#fuzzing-a-network-service](best_practices.md#fuzzing-a-network-service)
+* Non-linux: [unicorn_mode/README.md](../unicorn_mode/README.md)
+
+## Additional information
+
+* Tools that help fuzzing with AFL++:
+ [third_party_tools.md](third_party_tools.md)
+* Tutorials: [tutorials.md](tutorials.md) \ No newline at end of file
diff --git a/docs/afl-fuzz_approach.md b/docs/afl-fuzz_approach.md
new file mode 100644
index 00000000..6af39769
--- /dev/null
+++ b/docs/afl-fuzz_approach.md
@@ -0,0 +1,543 @@
+# The afl-fuzz approach
+
+AFL++ is a brute-force fuzzer coupled with an exceedingly simple but rock-solid
+instrumentation-guided genetic algorithm. It uses a modified form of edge
+coverage to effortlessly pick up subtle, local-scale changes to program control
+flow.
+
+Simplifying a bit, the overall algorithm can be summed up as:
+
+1) Load user-supplied initial test cases into the queue.
+
+2) Take the next input file from the queue.
+
+3) Attempt to trim the test case to the smallest size that doesn't alter the
+ measured behavior of the program.
+
+4) Repeatedly mutate the file using a balanced and well-researched variety of
+ traditional fuzzing strategies.
+
+5) If any of the generated mutations resulted in a new state transition recorded
+ by the instrumentation, add mutated output as a new entry in the queue.
+
+6) Go to 2.
+
+The discovered test cases are also periodically culled to eliminate ones that
+have been obsoleted by newer, higher-coverage finds; and undergo several other
+instrumentation-driven effort minimization steps.
+
+As a side result of the fuzzing process, the tool creates a small,
+self-contained corpus of interesting test cases. These are extremely useful for
+seeding other, labor- or resource-intensive testing regimes - for example, for
+stress-testing browsers, office applications, graphics suites, or closed-source
+tools.
+
+The fuzzer is thoroughly tested to deliver out-of-the-box performance far
+superior to blind fuzzing or coverage-only tools.
+
+## Understanding the status screen
+
+This section provides an overview of the status screen - plus tips for
+troubleshooting any warnings and red text shown in the UI.
+
+For the general instruction manual, see [README.md](README.md).
+
+### A note about colors
+
+The status screen and error messages use colors to keep things readable and
+attract your attention to the most important details. For example, red almost
+always means "consult this doc" :-)
+
+Unfortunately, the UI will only render correctly if your terminal is using
+traditional un*x palette (white text on black background) or something close to
+that.
+
+If you are using inverse video, you may want to change your settings, say:
+
+- For GNOME Terminal, go to `Edit > Profile` preferences, select the "colors"
+ tab, and from the list of built-in schemes, choose "white on black".
+- For the MacOS X Terminal app, open a new window using the "Pro" scheme via the
+ `Shell > New Window` menu (or make "Pro" your default).
+
+Alternatively, if you really like your current colors, you can edit config.h to
+comment out USE_COLORS, then do `make clean all`.
+
+We are not aware of any other simple way to make this work without causing other
+side effects - sorry about that.
+
+With that out of the way, let's talk about what's actually on the screen...
+
+### The status bar
+
+```
+american fuzzy lop ++3.01a (default) [fast] {0}
+```
+
+The top line shows you which mode afl-fuzz is running in (normal: "american
+fuzzy lop", crash exploration mode: "peruvian rabbit mode") and the version of
+AFL++. Next to the version is the banner, which, if not set with -T by hand,
+will either show the binary name being fuzzed, or the -M/-S main/secondary name
+for parallel fuzzing. Second to last is the power schedule mode being run
+(default: fast). Finally, the last item is the CPU id.
+
+### Process timing
+
+```
+ +----------------------------------------------------+
+ | run time : 0 days, 8 hrs, 32 min, 43 sec |
+ | last new find : 0 days, 0 hrs, 6 min, 40 sec |
+ | last uniq crash : none seen yet |
+ | last uniq hang : 0 days, 1 hrs, 24 min, 32 sec |
+ +----------------------------------------------------+
+```
+
+This section is fairly self-explanatory: it tells you how long the fuzzer has
+been running and how much time has elapsed since its most recent finds. This is
+broken down into "paths" (a shorthand for test cases that trigger new execution
+patterns), crashes, and hangs.
+
+When it comes to timing: there is no hard rule, but most fuzzing jobs should be
+expected to run for days or weeks; in fact, for a moderately complex project,
+the first pass will probably take a day or so. Every now and then, some jobs
+will be allowed to run for months.
+
+There's one important thing to watch out for: if the tool is not finding new
+paths within several minutes of starting, you're probably not invoking the
+target binary correctly and it never gets to parse the input files that are
+thrown at it; other possible explanations are that the default memory limit
+(`-m`) is too restrictive and the program exits after failing to allocate a
+buffer very early on; or that the input files are patently invalid and always
+fail a basic header check.
+
+If there are no new paths showing up for a while, you will eventually see a big
+red warning in this section, too :-)
+
+### Overall results
+
+```
+ +-----------------------+
+ | cycles done : 0 |
+ | total paths : 2095 |
+ | uniq crashes : 0 |
+ | uniq hangs : 19 |
+ +-----------------------+
+```
+
+The first field in this section gives you the count of queue passes done so far
+- that is, the number of times the fuzzer went over all the interesting test
+ cases discovered so far, fuzzed them, and looped back to the very beginning.
+ Every fuzzing session should be allowed to complete at least one cycle; and
+ ideally, should run much longer than that.
+
+As noted earlier, the first pass can take a day or longer, so sit back and
+relax.
+
+To help make the call on when to hit `Ctrl-C`, the cycle counter is color-coded.
+It is shown in magenta during the first pass, progresses to yellow if new finds
+are still being made in subsequent rounds, then blue when that ends - and
+finally, turns green after the fuzzer hasn't been seeing any action for a longer
+while.
+
+The remaining fields in this part of the screen should be pretty obvious:
+there's the number of test cases ("paths") discovered so far, and the number of
+unique faults. The test cases, crashes, and hangs can be explored in real-time
+by browsing the output directory, see
+[#interpreting-output](#interpreting-output).
+
+### Cycle progress
+
+```
+ +-------------------------------------+
+ | now processing : 1296 (61.86%) |
+ | paths timed out : 0 (0.00%) |
+ +-------------------------------------+
+```
+
+This box tells you how far along the fuzzer is with the current queue cycle: it
+shows the ID of the test case it is currently working on, plus the number of
+inputs it decided to ditch because they were persistently timing out.
+
+The "*" suffix sometimes shown in the first line means that the currently
+processed path is not "favored" (a property discussed later on).
+
+### Map coverage
+
+```
+ +--------------------------------------+
+ | map density : 10.15% / 29.07% |
+ | count coverage : 4.03 bits/tuple |
+ +--------------------------------------+
+```
+
+The section provides some trivia about the coverage observed by the
+instrumentation embedded in the target binary.
+
+The first line in the box tells you how many branch tuples already were hit, in
+proportion to how much the bitmap can hold. The number on the left describes the
+current input; the one on the right is the value for the entire input corpus.
+
+Be wary of extremes:
+
+- Absolute numbers below 200 or so suggest one of three things: that the program
+ is extremely simple; that it is not instrumented properly (e.g., due to being
+ linked against a non-instrumented copy of the target library); or that it is
+ bailing out prematurely on your input test cases. The fuzzer will try to mark
+ this in pink, just to make you aware.
+- Percentages over 70% may very rarely happen with very complex programs that
+ make heavy use of template-generated code. Because high bitmap density makes
+ it harder for the fuzzer to reliably discern new program states, we recommend
+ recompiling the binary with `AFL_INST_RATIO=10` or so and trying again (see
+ [env_variables.md](env_variables.md)). The fuzzer will flag high percentages
+ in red. Chances are, you will never see that unless you're fuzzing extremely
+ hairy software (say, v8, perl, ffmpeg).
+
+The other line deals with the variability in tuple hit counts seen in the
+binary. In essence, if every taken branch is always taken a fixed number of
+times for all the inputs that were tried, this will read `1.00`. As we manage to
+trigger other hit counts for every branch, the needle will start to move toward
+`8.00` (every bit in the 8-bit map hit), but will probably never reach that
+extreme.
+
+Together, the values can be useful for comparing the coverage of several
+different fuzzing jobs that rely on the same instrumented binary.
+
+### Stage progress
+
+```
+ +-------------------------------------+
+ | now trying : interest 32/8 |
+ | stage execs : 3996/34.4k (11.62%) |
+ | total execs : 27.4M |
+ | exec speed : 891.7/sec |
+ +-------------------------------------+
+```
+
+This part gives you an in-depth peek at what the fuzzer is actually doing right
+now. It tells you about the current stage, which can be any of:
+
+- calibration - a pre-fuzzing stage where the execution path is examined to
+ detect anomalies, establish baseline execution speed, and so on. Executed very
+ briefly whenever a new find is being made.
+- trim L/S - another pre-fuzzing stage where the test case is trimmed to the
+ shortest form that still produces the same execution path. The length (L) and
+ stepover (S) are chosen in general relationship to file size.
+- bitflip L/S - deterministic bit flips. There are L bits toggled at any given
+ time, walking the input file with S-bit increments. The current L/S variants
+ are: `1/1`, `2/1`, `4/1`, `8/8`, `16/8`, `32/8`.
+- arith L/8 - deterministic arithmetics. The fuzzer tries to subtract or add
+ small integers to 8-, 16-, and 32-bit values. The stepover is always 8 bits.
+- interest L/8 - deterministic value overwrite. The fuzzer has a list of known
+ "interesting" 8-, 16-, and 32-bit values to try. The stepover is 8 bits.
+- extras - deterministic injection of dictionary terms. This can be shown as
+ "user" or "auto", depending on whether the fuzzer is using a user-supplied
+ dictionary (`-x`) or an auto-created one. You will also see "over" or
+ "insert", depending on whether the dictionary words overwrite existing data or
+ are inserted by offsetting the remaining data to accommodate their length.
+- havoc - a sort-of-fixed-length cycle with stacked random tweaks. The
+ operations attempted during this stage include bit flips, overwrites with
+ random and "interesting" integers, block deletion, block duplication, plus
+ assorted dictionary-related operations (if a dictionary is supplied in the
+ first place).
+- splice - a last-resort strategy that kicks in after the first full queue cycle
+ with no new paths. It is equivalent to 'havoc', except that it first splices
+ together two random inputs from the queue at some arbitrarily selected
+ midpoint.
+- sync - a stage used only when `-M` or `-S` is set (see
+ [fuzzing_in_depth.md:3c) Using multiple cores](fuzzing_in_depth.md#c-using-multiple-cores)).
+ No real fuzzing is involved, but the tool scans the output from other fuzzers
+ and imports test cases as necessary. The first time this is done, it may take
+ several minutes or so.
+
+The remaining fields should be fairly self-evident: there's the exec count
+progress indicator for the current stage, a global exec counter, and a benchmark
+for the current program execution speed. This may fluctuate from one test case
+to another, but the benchmark should be ideally over 500 execs/sec most of the
+time - and if it stays below 100, the job will probably take very long.
+
+The fuzzer will explicitly warn you about slow targets, too. If this happens,
+see the [best_practices.md#improving-speed](best_practices.md#improving-speed)
+for ideas on how to speed things up.
+
+### Findings in depth
+
+```
+ +--------------------------------------+
+ | favored paths : 879 (41.96%) |
+ | new edges on : 423 (20.19%) |
+ | total crashes : 0 (0 unique) |
+ | total tmouts : 24 (19 unique) |
+ +--------------------------------------+
+```
+
+This gives you several metrics that are of interest mostly to complete nerds.
+The section includes the number of paths that the fuzzer likes the most based on
+a minimization algorithm baked into the code (these will get considerably more
+air time), and the number of test cases that actually resulted in better edge
+coverage (versus just pushing the branch hit counters up). There are also
+additional, more detailed counters for crashes and timeouts.
+
+Note that the timeout counter is somewhat different from the hang counter; this
+one includes all test cases that exceeded the timeout, even if they did not
+exceed it by a margin sufficient to be classified as hangs.
+
+### Fuzzing strategy yields
+
+```
+ +-----------------------------------------------------+
+ | bit flips : 57/289k, 18/289k, 18/288k |
+ | byte flips : 0/36.2k, 4/35.7k, 7/34.6k |
+ | arithmetics : 53/2.54M, 0/537k, 0/55.2k |
+ | known ints : 8/322k, 12/1.32M, 10/1.70M |
+ | dictionary : 9/52k, 1/53k, 1/24k |
+ |havoc/splice : 1903/20.0M, 0/0 |
+ |py/custom/rq : unused, 53/2.54M, unused |
+ | trim/eff : 20.31%/9201, 17.05% |
+ +-----------------------------------------------------+
+```
+
+This is just another nerd-targeted section keeping track of how many paths were
+netted, in proportion to the number of execs attempted, for each of the fuzzing
+strategies discussed earlier on. This serves to convincingly validate
+assumptions about the usefulness of the various approaches taken by afl-fuzz.
+
+The trim strategy stats in this section are a bit different than the rest. The
+first number in this line shows the ratio of bytes removed from the input files;
+the second one corresponds to the number of execs needed to achieve this goal.
+Finally, the third number shows the proportion of bytes that, although not
+possible to remove, were deemed to have no effect and were excluded from some of
+the more expensive deterministic fuzzing steps.
+
+Note that when deterministic mutation mode is off (which is the default because
+it is not very efficient) the first five lines display "disabled (default,
+enable with -D)".
+
+Only what is activated will have counter shown.
+
+### Path geometry
+
+```
+ +---------------------+
+ | levels : 5 |
+ | pending : 1570 |
+ | pend fav : 583 |
+ | own finds : 0 |
+ | imported : 0 |
+ | stability : 100.00% |
+ +---------------------+
+```
+
+The first field in this section tracks the path depth reached through the guided
+fuzzing process. In essence: the initial test cases supplied by the user are
+considered "level 1". The test cases that can be derived from that through
+traditional fuzzing are considered "level 2"; the ones derived by using these as
+inputs to subsequent fuzzing rounds are "level 3"; and so forth. The maximum
+depth is therefore a rough proxy for how much value you're getting out of the
+instrumentation-guided approach taken by afl-fuzz.
+
+The next field shows you the number of inputs that have not gone through any
+fuzzing yet. The same stat is also given for "favored" entries that the fuzzer
+really wants to get to in this queue cycle (the non-favored entries may have to
+wait a couple of cycles to get their chance).
+
+Next is the number of new paths found during this fuzzing section and imported
+from other fuzzer instances when doing parallelized fuzzing; and the extent to
+which identical inputs appear to sometimes produce variable behavior in the
+tested binary.
+
+That last bit is actually fairly interesting: it measures the consistency of
+observed traces. If a program always behaves the same for the same input data,
+it will earn a score of 100%. When the value is lower but still shown in purple,
+the fuzzing process is unlikely to be negatively affected. If it goes into red,
+you may be in trouble, since AFL++ will have difficulty discerning between
+meaningful and "phantom" effects of tweaking the input file.
+
+Now, most targets will just get a 100% score, but when you see lower figures,
+there are several things to look at:
+
+- The use of uninitialized memory in conjunction with some intrinsic sources of
+ entropy in the tested binary. Harmless to AFL, but could be indicative of a
+ security bug.
+- Attempts to manipulate persistent resources, such as left over temporary files
+ or shared memory objects. This is usually harmless, but you may want to
+ double-check to make sure the program isn't bailing out prematurely. Running
+ out of disk space, SHM handles, or other global resources can trigger this,
+ too.
+- Hitting some functionality that is actually designed to behave randomly.
+ Generally harmless. For example, when fuzzing sqlite, an input like `select
+ random();` will trigger a variable execution path.
+- Multiple threads executing at once in semi-random order. This is harmless when
+ the 'stability' metric stays over 90% or so, but can become an issue if not.
+ Here's what to try:
+ * Use afl-clang-fast from [instrumentation](../instrumentation/) - it uses a
+ thread-local tracking model that is less prone to concurrency issues,
+ * See if the target can be compiled or run without threads. Common
+ `./configure` options include `--without-threads`, `--disable-pthreads`, or
+ `--disable-openmp`.
+ * Replace pthreads with GNU Pth (https://www.gnu.org/software/pth/), which
+ allows you to use a deterministic scheduler.
+- In persistent mode, minor drops in the "stability" metric can be normal,
+ because not all the code behaves identically when re-entered; but major dips
+ may signify that the code within `__AFL_LOOP()` is not behaving correctly on
+ subsequent iterations (e.g., due to incomplete clean-up or reinitialization of
+ the state) and that most of the fuzzing effort goes to waste.
+
+The paths where variable behavior is detected are marked with a matching entry
+in the `<out_dir>/queue/.state/variable_behavior/` directory, so you can look
+them up easily.
+
+### CPU load
+
+```
+ [cpu: 25%]
+```
+
+This tiny widget shows the apparent CPU utilization on the local system. It is
+calculated by taking the number of processes in the "runnable" state, and then
+comparing it to the number of logical cores on the system.
+
+If the value is shown in green, you are using fewer CPU cores than available on
+your system and can probably parallelize to improve performance; for tips on how
+to do that, see
+[fuzzing_in_depth.md:3c) Using multiple cores](fuzzing_in_depth.md#c-using-multiple-cores).
+
+If the value is shown in red, your CPU is *possibly* oversubscribed, and running
+additional fuzzers may not give you any benefits.
+
+Of course, this benchmark is very simplistic; it tells you how many processes
+are ready to run, but not how resource-hungry they may be. It also doesn't
+distinguish between physical cores, logical cores, and virtualized CPUs; the
+performance characteristics of each of these will differ quite a bit.
+
+If you want a more accurate measurement, you can run the `afl-gotcpu` utility
+from the command line.
+
+## Interpreting output
+
+See [#understanding-the-status-screen](#understanding-the-status-screen) for
+information on how to interpret the displayed stats and monitor the health of
+the process. Be sure to consult this file especially if any UI elements are
+highlighted in red.
+
+The fuzzing process will continue until you press Ctrl-C. At a minimum, you want
+to allow the fuzzer to complete one queue cycle, which may take anywhere from a
+couple of hours to a week or so.
+
+There are three subdirectories created within the output directory and updated
+in real-time:
+
+- queue/ - test cases for every distinctive execution path, plus all the
+ starting files given by the user. This is the synthesized corpus.
+
+ Before using this corpus for any other purposes, you can shrink
+ it to a smaller size using the afl-cmin tool. The tool will find
+ a smaller subset of files offering equivalent edge coverage.
+
+- crashes/ - unique test cases that cause the tested program to receive a fatal
+ signal (e.g., SIGSEGV, SIGILL, SIGABRT). The entries are grouped by
+ the received signal.
+
+- hangs/ - unique test cases that cause the tested program to time out. The
+ default time limit before something is classified as a hang is the
+ larger of 1 second and the value of the -t parameter. The value can
+ be fine-tuned by setting AFL_HANG_TMOUT, but this is rarely
+ necessary.
+
+Crashes and hangs are considered "unique" if the associated execution paths
+involve any state transitions not seen in previously-recorded faults. If a
+single bug can be reached in multiple ways, there will be some count inflation
+early in the process, but this should quickly taper off.
+
+The file names for crashes and hangs are correlated with the parent,
+non-faulting queue entries. This should help with debugging.
+
+## Visualizing
+
+If you have gnuplot installed, you can also generate some pretty graphs for any
+active fuzzing task using afl-plot. For an example of how this looks like, see
+[https://lcamtuf.coredump.cx/afl/plot/](https://lcamtuf.coredump.cx/afl/plot/).
+
+You can also manually build and install afl-plot-ui, which is a helper utility
+for showing the graphs generated by afl-plot in a graphical window using GTK.
+You can build and install it as follows:
+
+```shell
+sudo apt install libgtk-3-0 libgtk-3-dev pkg-config
+cd utils/plot_ui
+make
+cd ../../
+sudo make install
+```
+
+To learn more about remote monitoring and metrics visualization with StatsD, see
+[rpc_statsd.md](rpc_statsd.md).
+
+### Addendum: status and plot files
+
+For unattended operation, some of the key status screen information can be also
+found in a machine-readable format in the fuzzer_stats file in the output
+directory. This includes:
+
+- `start_time` - unix time indicating the start time of afl-fuzz
+- `last_update` - unix time corresponding to the last update of this file
+- `run_time` - run time in seconds to the last update of this file
+- `fuzzer_pid` - PID of the fuzzer process
+- `cycles_done` - queue cycles completed so far
+- `cycles_wo_finds` - number of cycles without any new paths found
+- `execs_done` - number of execve() calls attempted
+- `execs_per_sec` - overall number of execs per second
+- `corpus_count` - total number of entries in the queue
+- `corpus_favored` - number of queue entries that are favored
+- `corpus_found` - number of entries discovered through local fuzzing
+- `corpus_imported` - number of entries imported from other instances
+- `max_depth` - number of levels in the generated data set
+- `cur_item` - currently processed entry number
+- `pending_favs` - number of favored entries still waiting to be fuzzed
+- `pending_total` - number of all entries waiting to be fuzzed
+- `corpus_variable` - number of test cases showing variable behavior
+- `stability` - percentage of bitmap bytes that behave consistently
+- `bitmap_cvg` - percentage of edge coverage found in the map so far
+- `saved_crashes` - number of unique crashes recorded
+- `saved_hangs` - number of unique hangs encountered
+- `last_find` - seconds since the last find was found
+- `last_crash` - seconds since the last crash was found
+- `last_hang` - seconds since the last hang was found
+- `execs_since_crash` - execs since the last crash was found
+- `exec_timeout` - the -t command line value
+- `slowest_exec_ms` - real time of the slowest execution in ms
+- `peak_rss_mb` - max rss usage reached during fuzzing in MB
+- `edges_found` - how many edges have been found
+- `var_byte_count` - how many edges are non-deterministic
+- `afl_banner` - banner text (e.g., the target name)
+- `afl_version` - the version of AFL++ used
+- `target_mode` - default, persistent, qemu, unicorn, non-instrumented
+- `command_line` - full command line used for the fuzzing session
+
+Most of these map directly to the UI elements discussed earlier on.
+
+On top of that, you can also find an entry called `plot_data`, containing a
+plottable history for most of these fields. If you have gnuplot installed, you
+can turn this into a nice progress report with the included `afl-plot` tool.
+
+### Addendum: automatically sending metrics with StatsD
+
+In a CI environment or when running multiple fuzzers, it can be tedious to log
+into each of them or deploy scripts to read the fuzzer statistics. Using
+`AFL_STATSD` (and the other related environment variables `AFL_STATSD_HOST`,
+`AFL_STATSD_PORT`, `AFL_STATSD_TAGS_FLAVOR`) you can automatically send metrics
+to your favorite StatsD server. Depending on your StatsD server, you will be
+able to monitor, trigger alerts, or perform actions based on these metrics
+(e.g.: alert on slow exec/s for a new build, threshold of crashes, time since
+last crash > X, etc.).
+
+The selected metrics are a subset of all the metrics found in the status and in
+the plot file. The list is the following: `cycle_done`, `cycles_wo_finds`,
+`execs_done`,`execs_per_sec`, `corpus_count`, `corpus_favored`, `corpus_found`,
+`corpus_imported`, `max_depth`, `cur_item`, `pending_favs`, `pending_total`,
+`corpus_variable`, `saved_crashes`, `saved_hangs`, `total_crashes`,
+`slowest_exec_ms`, `edges_found`, `var_byte_count`, `havoc_expansion`. Their
+definitions can be found in the addendum above.
+
+When using multiple fuzzer instances with StatsD, it is *strongly* recommended
+to setup the flavor (`AFL_STATSD_TAGS_FLAVOR`) to match your StatsD server. This
+will allow you to see individual fuzzer performance, detect bad ones, see the
+progress of each strategy... \ No newline at end of file
diff --git a/docs/best_practices.md b/docs/best_practices.md
new file mode 100644
index 00000000..133c645e
--- /dev/null
+++ b/docs/best_practices.md
@@ -0,0 +1,192 @@
+# Best practices
+
+## Contents
+
+### Targets
+
+* [Fuzzing a target with source code available](#fuzzing-a-target-with-source-code-available)
+* [Fuzzing a target with dlopen() instrumented libraries](#fuzzing-a-target-with-dlopen-instrumented-libraries)
+* [Fuzzing a binary-only target](#fuzzing-a-binary-only-target)
+* [Fuzzing a GUI program](#fuzzing-a-gui-program)
+* [Fuzzing a network service](#fuzzing-a-network-service)
+
+### Improvements
+
+* [Improving speed](#improving-speed)
+* [Improving stability](#improving-stability)
+
+## Targets
+
+### Fuzzing a target with source code available
+
+To learn how to fuzz a target if source code is available, see
+[fuzzing_in_depth.md](fuzzing_in_depth.md).
+
+### Fuzzing a target with dlopen instrumented libraries
+
+If a source code based fuzzing target loads instrumented libraries with
+dlopen() after the forkserver has been activated and non-colliding coverage
+instrumentation is used (PCGUARD (which is the default), or LTO), then this
+an issue, because this would enlarge the coverage map, but afl-fuzz doesn't
+know about it.
+
+The solution is to use `AFL_PRELOAD` for all dlopen()'ed libraries to
+ensure that all coverage targets are present on startup in the target,
+even if accessed only later with dlopen().
+
+For PCGUARD instrumentation `abort()` is called if this is detected, for LTO
+there will either be no coverage for the instrumented dlopen()'ed libraries or
+you will see lots of crashes in the UI.
+
+Note that this is not an issue if you use the inferiour `afl-gcc-fast`,
+`afl-gcc` or`AFL_LLVM_INSTRUMENT=CLASSIC/NGRAM/CTX afl-clang-fast`
+instrumentation.
+
+### Fuzzing a binary-only target
+
+For a comprehensive guide, see
+[fuzzing_binary-only_targets.md](fuzzing_binary-only_targets.md).
+
+### Fuzzing 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 it would be suitable for fuzzing.
+
+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.
+
+### Fuzzing a network service
+
+Fuzzing a network service does not work "out of the box".
+
+Using a network channel is inadequate for several reasons:
+- it has a slow-down of x10-20 on the fuzzing speed
+- it does not scale to fuzzing multiple instances easily,
+- instead of one initial data packet often a back-and-forth interplay of packets
+ is needed for stateful protocols (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
+[instrumentation/README.persistent_mode.md](../instrumentation/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 the real network would be.
+See [utils/socket_fuzzing/](../utils/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.
+
+## Improvements
+
+### Improving speed
+
+1. Use [llvm_mode](../instrumentation/README.llvm.md): afl-clang-lto (llvm >=
+ 11) or afl-clang-fast (llvm >= 9 recommended).
+2. Use [persistent mode](../instrumentation/README.persistent_mode.md) (x2-x20
+ speed increase).
+3. Instrument just what you are interested in, see
+ [instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md).
+4. If you do not use shmem persistent mode, use `AFL_TMPDIR` to put the input
+ file directory on a tempfs location, see
+ [env_variables.md](env_variables.md).
+5. Improve Linux kernel performance: modify `/etc/default/grub`, set
+ `GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=off l1tf=off mds=off
+ mitigations=off no_stf_barrier noibpb noibrs nopcid nopti
+ nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=off pti=off
+ spec_store_bypass_disable=off spectre_v2=off stf_barrier=off"`; then
+ `update-grub` and `reboot` (warning: makes the system less secure).
+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
+ ([fuzzing_in_depth.md:3c) Using multiple cores](fuzzing_in_depth.md#c-using-multiple-cores))!
+
+### Improving stability
+
+For fuzzing, a 100% stable target that covers all edges is the best case. 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
+ignored functions you have a full loss on that edges.
+
+There are functions that are unstable, but also provide value to coverage, e.g.,
+init functions that use fuzz data as input. If, however, a function that has
+nothing to do with the input data is the source of instability, e.g., checking
+jitter, or is a hash map function etc., then it should not be instrumented.
+
+To be able to exclude these functions (based on AFL++'s measured stability), the
+following process will allow to identify functions with variable edges.
+
+Four steps are required to do this and it also requires quite some knowledge of
+coding and/or disassembly and is effectively possible only with `afl-clang-fast`
+`PCGUARD` and `afl-clang-lto` `LTO` instrumentation.
+
+ 1. Instrument to be able to find the responsible function(s):
+
+ a) For LTO instrumented binaries, this can be documented during compile
+ 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
+ `instrumentation/afl-llvm-rt.o.c` to write a backtrace to a file if the
+ ID in `__afl_area_ptr[*guard]` is one of the unstable edge IDs. (Example
+ code is already there). Then recompile and reinstall `llvm_mode` and
+ rebuild your target. Run the recompiled target with `afl-fuzz` for a
+ while and then check the file that you wrote with the backtrace
+ information. Alternatively, you can use `gdb` to hook
+ `__sanitizer_cov_trace_pc_guard_init` 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 other instrumentation types, this is not possible. So just recompile
+ with the two mentioned above. This is just for identifying the functions
+ that have unstable edges.
+
+ 2. Identify which edge ID numbers are unstable.
+
+ Run the target with `export AFL_DEBUG=1` for a few minutes then terminate.
+ The out/fuzzer_stats file will then show the edge IDs that were identified
+ as unstable in the `var_bytes` entry. You can match these numbers directly
+ to the data you created in the first step. Now you know which functions are
+ responsible for the instability
+
+ 3. Create a text file with the filenames/functions
+
+ Identify which source code files contain the functions that you need to
+ remove from instrumentation, or just specify the functions you want to skip
+ for instrumentation. Note that optimization might inline functions!
+
+ Follow this document on how to do this:
+ [instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md).
+
+ If `PCGUARD` is used, then you need to follow this guide (needs llvm 12+!):
+ [https://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation](https://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation)
+
+ Only exclude 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. 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/docs/custom_mutators.md b/docs/custom_mutators.md
new file mode 100644
index 00000000..7b4e0516
--- /dev/null
+++ b/docs/custom_mutators.md
@@ -0,0 +1,311 @@
+# Custom Mutators in AFL++
+
+This file describes how you can implement custom mutations to be used in AFL.
+For now, we support C/C++ library and Python module, collectively named as the
+custom mutator.
+
+There is also experimental support for Rust in `custom_mutators/rust`. For
+documentation, refer to that directory. Run `cargo doc -p custom_mutator --open`
+in that directory to view the documentation in your web browser.
+
+Implemented by
+- C/C++ library (`*.so`): Khaled Yakdan from Code Intelligence
+ (<yakdan@code-intelligence.de>)
+- Python module: Christian Holler from Mozilla (<choller@mozilla.com>)
+
+## 1) Introduction
+
+Custom mutators can be passed to `afl-fuzz` to perform custom mutations on test
+cases beyond those available in AFL. For example, to enable structure-aware
+fuzzing by using libraries that perform mutations according to a given grammar.
+
+The custom mutator is passed to `afl-fuzz` via the `AFL_CUSTOM_MUTATOR_LIBRARY`
+or `AFL_PYTHON_MODULE` environment variable, and must export a fuzz function.
+Now AFL++ also supports multiple custom mutators which can be specified in the
+same `AFL_CUSTOM_MUTATOR_LIBRARY` environment variable like this.
+
+```bash
+export AFL_CUSTOM_MUTATOR_LIBRARY="full/path/to/mutator_first.so;full/path/to/mutator_second.so"
+```
+
+For details, see [APIs](#2-apis) and [Usage](#3-usage).
+
+The custom mutation stage is set to be the first non-deterministic stage (right
+before the havoc stage).
+
+Note: If `AFL_CUSTOM_MUTATOR_ONLY` is set, all mutations will solely be
+performed with the custom mutator.
+
+## 2) APIs
+
+C/C++:
+
+```c
+void *afl_custom_init(afl_state_t *afl, unsigned int seed);
+unsigned int afl_custom_fuzz_count(void *data, const unsigned char *buf, size_t buf_size);
+size_t afl_custom_fuzz(void *data, unsigned char *buf, size_t buf_size, unsigned char **out_buf, unsigned char *add_buf, size_t add_buf_size, size_t max_size);
+const char *afl_custom_describe(void *data, size_t max_description_len);
+size_t afl_custom_post_process(void *data, unsigned char *buf, size_t buf_size, unsigned char **out_buf);
+int afl_custom_init_trim(void *data, unsigned char *buf, size_t buf_size);
+size_t afl_custom_trim(void *data, unsigned char **out_buf);
+int afl_custom_post_trim(void *data, unsigned char success);
+size_t afl_custom_havoc_mutation(void *data, unsigned char *buf, size_t buf_size, unsigned char **out_buf, size_t max_size);
+unsigned char afl_custom_havoc_mutation_probability(void *data);
+unsigned char afl_custom_queue_get(void *data, const unsigned char *filename);
+u8 afl_custom_queue_new_entry(void *data, const unsigned char *filename_new_queue, const unsigned int *filename_orig_queue);
+const char* afl_custom_introspection(my_mutator_t *data);
+void afl_custom_deinit(void *data);
+```
+
+Python:
+
+```python
+def init(seed):
+ pass
+
+def fuzz_count(buf, add_buf, max_size):
+ return cnt
+
+def fuzz(buf, add_buf, max_size):
+ return mutated_out
+
+def describe(max_description_length):
+ return "description_of_current_mutation"
+
+def post_process(buf):
+ return out_buf
+
+def init_trim(buf):
+ return cnt
+
+def trim():
+ return out_buf
+
+def post_trim(success):
+ return next_index
+
+def havoc_mutation(buf, max_size):
+ return mutated_out
+
+def havoc_mutation_probability():
+ return probability # int in [0, 100]
+
+def queue_get(filename):
+ return True
+
+def queue_new_entry(filename_new_queue, filename_orig_queue):
+ return False
+
+def introspection():
+ return string
+
+def deinit(): # optional for Python
+ pass
+```
+
+### Custom Mutation
+
+- `init`:
+
+ This method is called when AFL++ starts up and is used to seed RNG and set
+ up buffers and state.
+
+- `queue_get` (optional):
+
+ This method determines whether the custom fuzzer should fuzz the current
+ queue entry or not
+
+- `fuzz_count` (optional):
+
+ When a queue entry is selected to be fuzzed, afl-fuzz selects the number of
+ fuzzing attempts with this input based on a few factors. If, however, the
+ custom mutator wants to set this number instead on how often it is called
+ for a specific queue entry, use this function. This function is most useful
+ if `AFL_CUSTOM_MUTATOR_ONLY` is **not** used.
+
+- `fuzz` (optional):
+
+ This method performs custom mutations on a given input. It also accepts an
+ additional test case. Note that this function is optional - but it makes
+ sense to use it. You would only skip this if `post_process` is used to fix
+ checksums etc. so if you are using it, e.g., as a post processing library.
+ Note that a length > 0 *must* be returned!
+
+- `describe` (optional):
+
+ When this function is called, it shall describe the current test case,
+ generated by the last mutation. This will be called, for example, to name
+ the written test case file after a crash occurred. Using it can help to
+ reproduce crashing mutations.
+
+- `havoc_mutation` and `havoc_mutation_probability` (optional):
+
+ `havoc_mutation` performs a single custom mutation on a given input. This
+ mutation is stacked with other mutations in havoc. The other method,
+ `havoc_mutation_probability`, returns the probability that `havoc_mutation`
+ is called in havoc. By default, it is 6%.
+
+- `post_process` (optional):
+
+ For some cases, the format of the mutated data returned from the custom
+ mutator is not suitable to directly execute the target with this input. For
+ example, when using libprotobuf-mutator, the data returned is in a protobuf
+ format which corresponds to a given grammar. In order to execute the target,
+ the protobuf data must be converted to the plain-text format expected by the
+ target. In such scenarios, the user can define the `post_process` function.
+ This function is then transforming the data into the format expected by the
+ API before executing the target.
+
+ This can return any python object that implements the buffer protocol and
+ supports PyBUF_SIMPLE. These include bytes, bytearray, etc.
+
+- `queue_new_entry` (optional):
+
+ This methods is called after adding a new test case to the queue. If the
+ contents of the file was changed, return True, False otherwise.
+
+- `introspection` (optional):
+
+ This method is called after a new queue entry, crash or timeout is
+ discovered if compiled with INTROSPECTION. The custom mutator can then
+ return a string (const char *) that reports the exact mutations used.
+
+- `deinit`:
+
+ The last method to be called, deinitializing the state.
+
+Note that there are also three functions for trimming as described in the next
+section.
+
+### Trimming Support
+
+The generic trimming routines implemented in AFL++ can easily destroy the
+structure of complex formats, possibly leading to a point where you have a lot
+of test cases in the queue that your Python module cannot process anymore but
+your target application still accepts. This is especially the case when your
+target can process a part of the input (causing coverage) and then errors out on
+the remaining input.
+
+In such cases, it makes sense to implement a custom trimming routine. The API
+consists of multiple methods because after each trimming step, we have to go
+back into the C code to check if the coverage bitmap is still the same for the
+trimmed input. Here's a quick API description:
+
+- `init_trim` (optional):
+
+ This method is called at the start of each trimming operation and receives
+ the initial buffer. It should return the amount of iteration steps possible
+ on this input (e.g., if your input has n elements and you want to remove
+ them one by one, return n, if you do a binary search, return log(n), and so
+ on).
+
+ If your trimming algorithm doesn't allow to determine the amount of
+ (remaining) steps easily (esp. while running), then you can alternatively
+ return 1 here and always return 0 in `post_trim` until you are finished and
+ no steps remain. In that case, returning 1 in `post_trim` will end the
+ trimming routine. The whole current index/max iterations stuff is only used
+ to show progress.
+
+- `trim` (optional)
+
+ This method is called for each trimming operation. It doesn't have any
+ arguments because there is already the initial buffer from `init_trim` and
+ we can memorize the current state in the data variables. This can also save
+ reparsing steps for each iteration. It should return the trimmed input
+ buffer.
+
+- `post_trim` (optional)
+
+ This method is called after each trim operation to inform you if your
+ trimming step was successful or not (in terms of coverage). If you receive a
+ failure here, you should reset your input to the last known good state. In
+ any case, this method must return the next trim iteration index (from 0 to
+ the maximum amount of steps you returned in `init_trim`).
+
+Omitting any of three trimming methods will cause the trimming to be disabled
+and trigger a fallback to the built-in default trimming routine.
+
+### Environment Variables
+
+Optionally, the following environment variables are supported:
+
+- `AFL_CUSTOM_MUTATOR_ONLY`
+
+ Disable all other mutation stages. This can prevent broken test cases (those
+ that your Python module can't work with anymore) to fill up your queue. Best
+ combined with a custom trimming routine (see below) because trimming can
+ cause the same test breakage like havoc and splice.
+
+- `AFL_PYTHON_ONLY`
+
+ Deprecated and removed, use `AFL_CUSTOM_MUTATOR_ONLY` instead.
+
+- `AFL_DEBUG`
+
+ When combined with `AFL_NO_UI`, this causes the C trimming code to emit
+ additional messages about the performance and actions of your custom
+ trimmer. Use this to see if it works :)
+
+## 3) Usage
+
+### Prerequisite
+
+For Python mutators, the python 3 or 2 development package is required. On
+Debian/Ubuntu/Kali it can be installed like this:
+
+```bash
+sudo apt install python3-dev
+# or
+sudo apt install python-dev
+```
+
+Then, AFL++ can be compiled with Python support. The AFL++ Makefile detects
+Python 2 and 3 through `python-config` if it is in the PATH and compiles
+`afl-fuzz` with the feature if available.
+
+Note: for some distributions, you might also need the package `python[23]-apt`.
+In case your setup is different, set the necessary variables like this:
+`PYTHON_INCLUDE=/path/to/python/include LDFLAGS=-L/path/to/python/lib make`.
+
+### Custom Mutator Preparation
+
+For C/C++ mutators, the source code must be compiled as a shared object:
+
+```bash
+gcc -shared -Wall -O3 example.c -o example.so
+```
+
+Note that if you specify multiple custom mutators, the corresponding functions
+will be called in the order in which they are specified. E.g., the first
+`post_process` function of `example_first.so` will be called and then that of
+`example_second.so`.
+
+### Run
+
+C/C++
+
+```bash
+export AFL_CUSTOM_MUTATOR_LIBRARY="/full/path/to/example_first.so;/full/path/to/example_second.so"
+afl-fuzz /path/to/program
+```
+
+Python
+
+```bash
+export PYTHONPATH=`dirname /full/path/to/example.py`
+export AFL_PYTHON_MODULE=example
+afl-fuzz /path/to/program
+```
+
+## 4) Example
+
+See [example.c](../custom_mutators/examples/example.c) and
+[example.py](../custom_mutators/examples/example.py).
+
+## 5) Other Resources
+
+- AFL libprotobuf mutator
+ - [bruce30262/libprotobuf-mutator_fuzzing_learning](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator)
+ - [thebabush/afl-libprotobuf-mutator](https://github.com/thebabush/afl-libprotobuf-mutator)
+- [XML Fuzzing@NullCon 2017](https://www.agarri.fr/docs/XML_Fuzzing-NullCon2017-PUBLIC.pdf)
+ - [A bug detected by AFL + XML-aware mutators](https://bugs.chromium.org/p/chromium/issues/detail?id=930663) \ No newline at end of file
diff --git a/docs/env_variables.md b/docs/env_variables.md
new file mode 100644
index 00000000..fe9c6e07
--- /dev/null
+++ b/docs/env_variables.md
@@ -0,0 +1,812 @@
+# Environment variables
+
+ This document discusses the environment variables used by AFL++ to expose
+ various exotic functions that may be (rarely) useful for power users or for
+ some types of custom fuzzing setups. For general information about AFL++, see
+ [README.md](../README.md).
+
+ Note: Most tools will warn on any unknown AFL++ environment variables; for
+ example, because of typos. If you want to disable this check, then set the
+ `AFL_IGNORE_UNKNOWN_ENVS` environment variable.
+
+## 1) Settings for all compilers
+
+Starting with AFL++ 3.0, there is only one compiler: afl-cc.
+
+To select the different instrumentation modes, use one of the following options:
+
+ - Pass the --afl-MODE command-line option to the compiler. Only this option
+ accepts further AFL-specific command-line options.
+ - Use a symlink to afl-cc: afl-clang, afl-clang++, afl-clang-fast,
+ afl-clang-fast++, afl-clang-lto, afl-clang-lto++, afl-g++, afl-g++-fast,
+ afl-gcc, afl-gcc-fast. This option does not accept AFL-specific command-line
+ options. Instead, use environment variables.
+ - Use the `AFL_CC_COMPILER` environment variable with `MODE`. To select
+ `MODE`, use one of the following values:
+
+ - `GCC` (afl-gcc/afl-g++)
+ - `GCC_PLUGIN` (afl-g*-fast)
+ - `LLVM` (afl-clang-fast*)
+ - `LTO` (afl-clang-lto*).
+
+The compile-time tools do not accept AFL-specific command-line options. The
+--afl-MODE command line option is the only exception. The other options make
+fairly broad use of environment variables instead:
+
+ - Some build/configure scripts break with AFL++ compilers. To be able to pass
+ them, do:
+
+ ```
+ export CC=afl-cc
+ export CXX=afl-c++
+ export AFL_NOOPT=1
+ ./configure --disable-shared --disabler-werror
+ unset AFL_NOOPT
+ make
+ ```
+
+ - Setting `AFL_AS`, `AFL_CC`, and `AFL_CXX` lets you use alternate downstream
+ compilation tools, rather than the default 'as', 'clang', or 'gcc' binaries
+ in your `$PATH`.
+
+ - If you are a weird person that wants to compile and instrument asm text
+ files, then use the `AFL_AS_FORCE_INSTRUMENT` variable:
+ `AFL_AS_FORCE_INSTRUMENT=1 afl-gcc foo.s -o foo`
+
+ - Most AFL tools do not print any output if stdout/stderr are redirected. If
+ you want to get the output into a file, then set the `AFL_DEBUG` environment
+ variable. This is sadly necessary for various build processes which fail
+ otherwise.
+
+ - By default, the wrapper appends `-O3` to optimize builds. Very rarely, this
+ will cause problems in programs built with -Werror, because `-O3` enables
+ more thorough code analysis and can spew out additional warnings. To disable
+ optimizations, set `AFL_DONT_OPTIMIZE`. However, if `-O...` and/or
+ `-fno-unroll-loops` are set, these are not overridden.
+
+ - Setting `AFL_HARDEN` automatically adds code hardening options when invoking
+ the downstream compiler. This currently includes `-D_FORTIFY_SOURCE=2` and
+ `-fstack-protector-all`. The setting is useful for catching non-crashing
+ memory bugs at the expense of a very slight (sub-5%) performance loss.
+
+ - Setting `AFL_INST_RATIO` to a percentage between 0 and 100 controls the
+ probability of instrumenting every branch. This is (very rarely) useful when
+ dealing with exceptionally complex programs that saturate the output bitmap.
+ Examples include ffmpeg, perl, and v8.
+
+ (If this ever happens, afl-fuzz will warn you ahead of the time by
+ displaying the "bitmap density" field in fiery red.)
+
+ Setting `AFL_INST_RATIO` to 0 is a valid choice. This will instrument only
+ the transitions between function entry points, but not individual branches.
+
+ Note that this is an outdated variable. A few instances (e.g., afl-gcc)
+ still support these, but state-of-the-art (e.g., LLVM LTO and LLVM PCGUARD)
+ do not need this.
+
+ - `AFL_NO_BUILTIN` causes the compiler to generate code suitable for use with
+ libtokencap.so (but perhaps running a bit slower than without the flag).
+
+ - `AFL_PATH` can be used to point afl-gcc to an alternate location of afl-as.
+ One possible use of this is utils/clang_asm_normalize/, which lets you
+ instrument hand-written assembly when compiling clang code by plugging a
+ normalizer into the chain. (There is no equivalent feature for GCC.)
+
+ - Setting `AFL_QUIET` will prevent afl-as and afl-cc banners from being
+ displayed during compilation, in case you find them distracting.
+
+ - Setting `AFL_USE_...` automatically enables supported sanitizers - provided
+ that your compiler supports it. Available are:
+ - `AFL_USE_ASAN=1` - activates the address sanitizer (memory corruption
+ detection)
+ - `AFL_USE_CFISAN=1` - activates the Control Flow Integrity sanitizer (e.g.
+ type confusion vulnerabilities)
+ - `AFL_USE_LSAN` - activates the leak sanitizer. To perform a leak check
+ within your program at a certain point (such as at the end of an
+ `__AFL_LOOP()`), you can run the macro `__AFL_LEAK_CHECK();` which will
+ cause an abort if any memory is leaked (you can combine this with the
+ `__AFL_LSAN_OFF();` and `__AFL_LSAN_ON();` macros to avoid checking for
+ memory leaks from memory allocated between these two calls.
+ - `AFL_USE_MSAN=1` - activates the memory sanitizer (uninitialized memory)
+ - `AFL_USE_TSAN=1` - activates the thread sanitizer to find thread race
+ conditions
+ - `AFL_USE_UBSAN=1` - activates the undefined behavior sanitizer
+
+ - `TMPDIR` is used by afl-as for temporary files; if this variable is not set,
+ the tool defaults to /tmp.
+
+## 2) Settings for LLVM and LTO: afl-clang-fast / afl-clang-fast++ / afl-clang-lto / afl-clang-lto++
+
+The native instrumentation helpers (instrumentation and gcc_plugin) accept a
+subset of the settings discussed in section 1, with the exception of:
+
+ - `AFL_AS`, since this toolchain does not directly invoke GNU `as`.
+
+ - `AFL_INST_RATIO`, as we use collision free instrumentation by default. Not
+ all passes support this option though as it is an outdated feature.
+
+ - LLVM modes support `AFL_LLVM_DICT2FILE=/absolute/path/file.txt` which will
+ write all constant string comparisons to this file to be used later with
+ afl-fuzz' `-x` option.
+
+ - `TMPDIR` and `AFL_KEEP_ASSEMBLY`, since no temporary assembly files are
+ created.
+
+Then there are a few specific features that are only available in
+instrumentation mode:
+
+### Select the instrumentation mode
+
+`AFL_LLVM_INSTRUMENT` - this configures the instrumentation mode.
+
+Available options:
+
+ - CLANG - outdated clang instrumentation
+ - CLASSIC - classic AFL (map[cur_loc ^ prev_loc >> 1]++) (default)
+
+ You can also specify CTX and/or NGRAM, separate the options with a comma ","
+ then, e.g.: `AFL_LLVM_INSTRUMENT=CLASSIC,CTX,NGRAM-4`
+
+ Note: It is actually not a good idea to use both CTX and NGRAM. :)
+ - CTX - context sensitive instrumentation
+ - GCC - outdated gcc instrumentation
+ - LTO - LTO instrumentation
+ - NATIVE - clang's original pcguard based instrumentation
+ - NGRAM-x - deeper previous location coverage (from NGRAM-2 up to NGRAM-16)
+ - PCGUARD - our own pcgard based instrumentation (default)
+
+#### CMPLOG
+
+Setting `AFL_LLVM_CMPLOG=1` during compilation will tell afl-clang-fast to
+produce a CmpLog binary.
+
+For more information, see
+[instrumentation/README.cmplog.md](../instrumentation/README.cmplog.md).
+
+#### CTX
+
+Setting `AFL_LLVM_CTX` or `AFL_LLVM_INSTRUMENT=CTX` activates context sensitive
+branch coverage - meaning that each edge is additionally combined with its
+caller. It is highly recommended to increase the `MAP_SIZE_POW2` definition in
+config.h to at least 18 and maybe up to 20 for this as otherwise too many map
+collisions occur.
+
+For more information, see
+[instrumentation/README.llvm.md#6) AFL++ Context Sensitive Branch Coverage](../instrumentation/README.llvm.md#6-afl-context-sensitive-branch-coverage).
+
+#### INSTRUMENT LIST (selectively instrument files and functions)
+
+This feature allows selective instrumentation of the source.
+
+Setting `AFL_LLVM_ALLOWLIST` or `AFL_LLVM_DENYLIST` with a file name and/or
+function will only instrument (or skip) those files that match the names listed
+in the specified file.
+
+For more information, see
+[instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md).
+
+#### LAF-INTEL
+
+This great feature will split compares into series of single byte comparisons to
+allow afl-fuzz to find otherwise rather impossible paths. It is not restricted
+to Intel CPUs. ;-)
+
+ - Setting `AFL_LLVM_LAF_TRANSFORM_COMPARES` will split string compare
+ functions.
+
+ - Setting `AFL_LLVM_LAF_SPLIT_COMPARES` will split all floating point and 64,
+ 32 and 16 bit integer CMP instructions.
+
+ - Setting `AFL_LLVM_LAF_SPLIT_FLOATS` will split floating points, needs
+ `AFL_LLVM_LAF_SPLIT_COMPARES` to be set.
+
+ - Setting `AFL_LLVM_LAF_SPLIT_SWITCHES` will split all `switch` constructs.
+
+ - Setting `AFL_LLVM_LAF_ALL` sets all of the above.
+
+For more information, see
+[instrumentation/README.laf-intel.md](../instrumentation/README.laf-intel.md).
+
+#### LTO
+
+This is a different way of instrumentation: first it compiles all code in LTO
+(link time optimization) and then performs an edge inserting instrumentation
+which is 100% collision free (collisions are a big issue in AFL and AFL-like
+instrumentations). This is performed by using afl-clang-lto/afl-clang-lto++
+instead of afl-clang-fast, but is only built if LLVM 11 or newer is used.
+
+`AFL_LLVM_INSTRUMENT=CFG` will use Control Flow Graph instrumentation. (Not
+recommended for afl-clang-fast, default for afl-clang-lto as there it is a
+different and better kind of instrumentation.)
+
+None of the following options are necessary to be used and are rather for manual
+use (which only ever the author of this LTO implementation will use). These are
+used if several separated instrumentations are performed which are then later
+combined.
+
+ - `AFL_LLVM_DOCUMENT_IDS=file` will document to a file which edge ID was given
+ to which function. This helps to identify functions with variable bytes or
+ which functions were touched by an input.
+ - `AFL_LLVM_LTO_DONTWRITEID` prevents that the highest location ID written
+ into the instrumentation is set in a global variable.
+ - `AFL_LLVM_LTO_STARTID` sets the starting location ID for the
+ instrumentation. This defaults to 1.
+ - `AFL_LLVM_MAP_ADDR` sets the fixed map address to a different address than
+ the default `0x10000`. A value of 0 or empty sets the map address to be
+ dynamic (the original AFL way, which is slower).
+ - `AFL_LLVM_MAP_DYNAMIC` sets the shared memory address to be dynamic.
+
+ For more information, see
+ [instrumentation/README.lto.md](../instrumentation/README.lto.md).
+
+#### NGRAM
+
+Setting `AFL_LLVM_INSTRUMENT=NGRAM-{value}` or `AFL_LLVM_NGRAM_SIZE` activates
+ngram prev_loc coverage. Good values are 2, 4, or 8 (any value between 2 and 16
+is valid). It is highly recommended to increase the `MAP_SIZE_POW2` definition
+in config.h to at least 18 and maybe up to 20 for this as otherwise too many map
+collisions occur.
+
+For more information, see
+[instrumentation/README.llvm.md#7) AFL++ N-Gram Branch Coverage](../instrumentation/README.llvm.md#7-afl-n-gram-branch-coverage).
+
+#### NOT_ZERO
+
+ - Setting `AFL_LLVM_NOT_ZERO=1` during compilation will use counters that skip
+ zero on overflow. This is the default for llvm >= 9, however, for llvm
+ versions below that this will increase an unnecessary slowdown due a
+ performance issue that is only fixed in llvm 9+. This feature increases path
+ discovery by a little bit.
+
+ - Setting `AFL_LLVM_SKIP_NEVERZERO=1` will not implement the skip zero test.
+ If the target performs only a few loops, then this will give a small
+ performance boost.
+
+#### Thread safe instrumentation counters (in all modes)
+
+Setting `AFL_LLVM_THREADSAFE_INST` will inject code that implements thread safe
+counters. The overhead is a little bit higher compared to the older non-thread
+safe case. Note that this disables neverzero (see NOT_ZERO).
+
+## 3) Settings for GCC / GCC_PLUGIN modes
+
+There are a few specific features that are only available in GCC and GCC_PLUGIN
+mode.
+
+ - GCC mode only: Setting `AFL_KEEP_ASSEMBLY` prevents afl-as from deleting
+ instrumented assembly files. Useful for troubleshooting problems or
+ understanding how the tool works.
+
+ To get them in a predictable place, try something like:
+
+ ```
+ mkdir assembly_here
+ TMPDIR=$PWD/assembly_here AFL_KEEP_ASSEMBLY=1 make clean all
+ ```
+
+ - GCC_PLUGIN mode only: Setting `AFL_GCC_INSTRUMENT_FILE` or
+ `AFL_GCC_ALLOWLIST` with a filename will only instrument those files that
+ match the names listed in this file (one filename per line).
+
+ Setting `AFL_GCC_DENYLIST` or `AFL_GCC_BLOCKLIST` with a file name and/or
+ function will only skip those files that match the names listed in the
+ specified file. See
+ [instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md)
+ for more information.
+
+ Setting `AFL_GCC_OUT_OF_LINE=1` will instruct afl-gcc-fast to instrument the
+ code with calls to an injected subroutine instead of the much more efficient
+ inline instrumentation.
+
+ Setting `AFL_GCC_SKIP_NEVERZERO=1` will not implement the skip zero test. If
+ the target performs only a few loops, then this will give a small
+ performance boost.
+
+## 4) Settings for afl-fuzz
+
+The main fuzzer binary accepts several options that disable a couple of sanity
+checks or alter some of the more exotic semantics of the tool:
+
+ - Setting `AFL_AUTORESUME` will resume a fuzz run (same as providing `-i -`)
+ for an existing out folder, even if a different `-i` was provided. Without
+ this setting, afl-fuzz will refuse execution for a long-fuzzed out dir.
+
+ - Benchmarking only: `AFL_BENCH_JUST_ONE` causes the fuzzer to exit after
+ processing the first queue entry; and `AFL_BENCH_UNTIL_CRASH` causes it to
+ exit soon after the first crash is found.
+
+ - `AFL_CMPLOG_ONLY_NEW` will only perform the expensive cmplog feature for
+ newly found test cases and not for test cases that are loaded on startup
+ (`-i in`). This is an important feature to set when resuming a fuzzing
+ session.
+
+ - Setting `AFL_CRASH_EXITCODE` sets the exit code AFL++ treats as crash. For
+ example, if `AFL_CRASH_EXITCODE='-1'` is set, each input resulting in a `-1`
+ return code (i.e. `exit(-1)` got called), will be treated as if a crash had
+ occurred. This may be beneficial if you look for higher-level faulty
+ conditions in which your target still exits gracefully.
+
+ - Setting `AFL_CUSTOM_MUTATOR_LIBRARY` to a shared library with
+ afl_custom_fuzz() creates additional mutations through this library. If
+ afl-fuzz is compiled with Python (which is autodetected during building
+ afl-fuzz), setting `AFL_PYTHON_MODULE` to a Python module can also provide
+ additional mutations. If `AFL_CUSTOM_MUTATOR_ONLY` is also set, all
+ mutations will solely be performed with the custom mutator. This feature
+ allows to configure custom mutators which can be very helpful, e.g., fuzzing
+ XML or other highly flexible structured input. For details, see
+ [custom_mutators.md](custom_mutators.md).
+
+ - Setting `AFL_CYCLE_SCHEDULES` will switch to a different schedule every time
+ a cycle is finished.
+
+ - Setting `AFL_DEBUG_CHILD` will not suppress the child output. This lets you
+ see all output of the child, making setup issues obvious. For example, in an
+ unicornafl harness, you might see python stacktraces. You may also see other
+ logs that way, indicating why the forkserver won't start. Not pretty but
+ good for debugging purposes. Note that `AFL_DEBUG_CHILD_OUTPUT` is
+ deprecated.
+
+ - Setting `AFL_DISABLE_TRIM` tells afl-fuzz not to trim test cases. This is
+ usually a bad idea!
+
+ - Setting `AFL_KEEP_TIMEOUTS` will keep longer running inputs if they reach
+ new coverage
+
+ - `AFL_EXIT_ON_SEED_ISSUES` will restore the vanilla afl-fuzz behavior which
+ does not allow crashes or timeout seeds in the initial -i corpus.
+
+ - `AFL_EXIT_ON_TIME` causes afl-fuzz to terminate if no new paths were found
+ within a specified period of time (in seconds). May be convenient for some
+ types of automated jobs.
+
+ - `AFL_EXIT_WHEN_DONE` causes afl-fuzz to terminate when all existing paths
+ have been fuzzed and there were no new finds for a while. This would be
+ normally indicated by the cycle counter in the UI turning green. May be
+ convenient for some types of automated jobs.
+
+ - Setting `AFL_EXPAND_HAVOC_NOW` will start in the extended havoc mode that
+ includes costly mutations. afl-fuzz automatically enables this mode when
+ deemed useful otherwise.
+
+ - `AFL_FAST_CAL` keeps the calibration stage about 2.5x faster (albeit less
+ precise), which can help when starting a session against a slow target.
+ `AFL_CAL_FAST` works too.
+
+ - Setting `AFL_FORCE_UI` will force painting the UI on the screen even if no
+ valid terminal was detected (for virtual consoles).
+
+ - Setting `AFL_FORKSRV_INIT_TMOUT` allows you to specify a different timeout
+ to wait for the forkserver to spin up. The default is the `-t` value times
+ `FORK_WAIT_MULT` from `config.h` (usually 10), so for a `-t 100`, the
+ default would wait for `1000` milliseconds. Setting a different time here is
+ useful if the target has a very slow startup time, for example, when doing
+ full-system fuzzing or emulation, but you don't want the actual runs to wait
+ too long for timeouts.
+
+ - Setting `AFL_HANG_TMOUT` allows you to specify a different timeout for
+ deciding if a particular test case is a "hang". The default is 1 second or
+ the value of the `-t` parameter, whichever is larger. Dialing the value down
+ can be useful if you are very concerned about slow inputs, or if you don't
+ want AFL++ to spend too much time classifying that stuff and just rapidly
+ put all timeouts in that bin.
+
+ - If you are Jakub, you may need `AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES`.
+ Others need not apply, unless they also want to disable the
+ `/proc/sys/kernel/core_pattern` check.
+
+ - If afl-fuzz encounters an incorrect fuzzing setup during a fuzzing session
+ (not at startup), it will terminate. If you do not want this, then you can
+ set `AFL_IGNORE_PROBLEMS`.
+
+ - When running in the `-M` or `-S` mode, setting `AFL_IMPORT_FIRST` causes the
+ fuzzer to import test cases from other instances before doing anything else.
+ This makes the "own finds" counter in the UI more accurate. Beyond counter
+ aesthetics, not much else should change.
+
+ - Setting `AFL_INPUT_LEN_MIN` and `AFL_INPUT_LEN_MAX` are an alternative to
+ the afl-fuzz -g/-G command line option to control the minimum/maximum
+ of fuzzing input generated.
+
+ - `AFL_KILL_SIGNAL`: Set the signal ID to be delivered to child processes on
+ timeout. Unless you implement your own targets or instrumentation, you
+ likely don't have to set it. By default, on timeout and on exit, `SIGKILL`
+ (`AFL_KILL_SIGNAL=9`) will be delivered to the child.
+
+ - `AFL_MAP_SIZE` sets the size of the shared map that afl-analyze, afl-fuzz,
+ afl-showmap, and afl-tmin create to gather instrumentation data from the
+ target. This must be equal or larger than the size the target was compiled
+ with.
+
+ - Setting `AFL_MAX_DET_EXTRAS` will change the threshold at what number of
+ elements in the `-x` dictionary and LTO autodict (combined) the
+ probabilistic mode will kick off. In probabilistic mode, not all dictionary
+ entries will be used all of the time for fuzzing mutations to not slow down
+ fuzzing. The default count is `200` elements. So for the 200 + 1st element,
+ there is a 1 in 201 chance, that one of the dictionary entries will not be
+ used directly.
+
+ - Setting `AFL_NO_AFFINITY` disables attempts to bind to a specific CPU core
+ on Linux systems. This slows things down, but lets you run more instances of
+ afl-fuzz than would be prudent (if you really want to).
+
+ - `AFL_NO_ARITH` causes AFL++ to skip most of the deterministic arithmetics.
+ This can be useful to speed up the fuzzing of text-based file formats.
+
+ - Setting `AFL_NO_AUTODICT` will not load an LTO generated auto dictionary
+ that is compiled into the target.
+
+ - Setting `AFL_NO_COLOR` or `AFL_NO_COLOUR` will omit control sequences for
+ coloring console output when configured with USE_COLOR and not
+ ALWAYS_COLORED.
+
+ - The CPU widget shown at the bottom of the screen is fairly simplistic and
+ may complain of high load prematurely, especially on systems with low core
+ counts. To avoid the alarming red color for very high CPU usages, you can
+ set `AFL_NO_CPU_RED`.
+
+ - Setting `AFL_NO_FORKSRV` disables the forkserver optimization, reverting to
+ fork + execve() call for every tested input. This is useful mostly when
+ working with unruly libraries that create threads or do other crazy things
+ when initializing (before the instrumentation has a chance to run).
+
+ Note that this setting inhibits some of the user-friendly diagnostics
+ normally done when starting up the forkserver and causes a pretty
+ significant performance drop.
+
+ - `AFL_NO_SNAPSHOT` will advice afl-fuzz not to use the snapshot feature if
+ the snapshot lkm is loaded.
+
+ - Setting `AFL_NO_UI` inhibits the UI altogether and just periodically prints
+ some basic stats. This behavior is also automatically triggered when the
+ output from afl-fuzz is redirected to a file or to a pipe.
+
+ - In QEMU mode (-Q) and Frida mode (-O), `AFL_PATH` will be searched for
+ afl-qemu-trace and afl-frida-trace.so.
+
+ - If you are using persistent mode (you should, see
+ [instrumentation/README.persistent_mode.md](../instrumentation/README.persistent_mode.md)),
+ some targets keep inherent state due which a detected crash test case does
+ not crash the target again when the test case is given. To be able to still
+ re-trigger these crashes, you can use the `AFL_PERSISTENT_RECORD` variable
+ with a value of how many previous fuzz cases to keep prio a crash. If set to
+ e.g., 10, then the 9 previous inputs are written to out/default/crashes as
+ RECORD:000000,cnt:000000 to RECORD:000000,cnt:000008 and
+ RECORD:000000,cnt:000009 being the crash case. NOTE: This option needs to be
+ enabled in config.h first!
+
+ - Note that `AFL_POST_LIBRARY` is deprecated, use `AFL_CUSTOM_MUTATOR_LIBRARY`
+ instead.
+
+ - Setting `AFL_PRELOAD` causes AFL++ to set `LD_PRELOAD` for the target binary
+ without disrupting the afl-fuzz process itself. This is useful, among other
+ things, for bootstrapping libdislocator.so.
+
+ - In QEMU mode (-Q), setting `AFL_QEMU_CUSTOM_BIN` will cause afl-fuzz to skip
+ prepending `afl-qemu-trace` to your command line. Use this if you wish to
+ use a custom afl-qemu-trace or if you need to modify the afl-qemu-trace
+ arguments.
+
+ - `AFL_SHUFFLE_QUEUE` randomly reorders the input queue on startup. Requested
+ by some users for unorthodox parallelized fuzzing setups, but not advisable
+ otherwise.
+
+ - When developing custom instrumentation on top of afl-fuzz, you can use
+ `AFL_SKIP_BIN_CHECK` to inhibit the checks for non-instrumented binaries and
+ shell scripts; and `AFL_DUMB_FORKSRV` in conjunction with the `-n` setting
+ to instruct afl-fuzz to still follow the fork server protocol without
+ expecting any instrumentation data in return. Note that this also turns off
+ auto map size detection.
+
+ - Setting `AFL_SKIP_CPUFREQ` skips the check for CPU scaling policy. This is
+ useful if you can't change the defaults (e.g., no root access to the system)
+ and are OK with some performance loss.
+
+ - Setting `AFL_STATSD` enables StatsD metrics collection. By default, AFL++
+ will send these metrics over UDP to 127.0.0.1:8125. The host and port are
+ configurable with `AFL_STATSD_HOST` and `AFL_STATSD_PORT` respectively. To
+ enable tags (banner and afl_version), you should provide
+ `AFL_STATSD_TAGS_FLAVOR` that matches your StatsD server (see
+ `AFL_STATSD_TAGS_FLAVOR`).
+
+ - Setting `AFL_STATSD_TAGS_FLAVOR` to one of `dogstatsd`, `influxdb`,
+ `librato`, or `signalfx` allows you to add tags to your fuzzing instances.
+ This is especially useful when running multiple instances (`-M/-S` for
+ example). Applied tags are `banner` and `afl_version`. `banner` corresponds
+ to the name of the fuzzer provided through `-M/-S`. `afl_version`
+ corresponds to the currently running AFL++ version (e.g., `++3.0c`). Default
+ (empty/non present) will add no tags to the metrics. For more information,
+ see [rpc_statsd.md](rpc_statsd.md).
+
+ - Setting `AFL_TARGET_ENV` causes AFL++ to set extra environment variables for
+ the target binary. Example: `AFL_TARGET_ENV="VAR1=1 VAR2='a b c'" afl-fuzz
+ ... `. This exists mostly for things like `LD_LIBRARY_PATH` but it would
+ theoretically allow fuzzing of AFL++ itself (with 'target' AFL++ using some
+ AFL_ vars that would disrupt work of 'fuzzer' AFL++). Note that when using
+ QEMU mode, the `AFL_TARGET_ENV` environment variables will apply to QEMU, as
+ well as the target binary. Therefore, in this case, you might want to use
+ QEMU's `QEMU_SET_ENV` environment variable (see QEMU's documentation because
+ the format is different from `AFL_TARGET_ENV`) to apply the environment
+ variables to the target and not QEMU.
+
+ - `AFL_TESTCACHE_SIZE` allows you to override the size of `#define
+ TESTCASE_CACHE` in config.h. Recommended values are 50-250MB - or more if
+ your fuzzing finds a huge amount of paths for large inputs.
+
+ - `AFL_TMPDIR` is used to write the `.cur_input` file to if it exists, and in
+ the normal output directory otherwise. You would use this to point to a
+ ramdisk/tmpfs. This increases the speed by a small value but also reduces
+ the stress on SSDs.
+
+ - Setting `AFL_TRY_AFFINITY` tries to attempt binding to a specific CPU core
+ on Linux systems, but will not terminate if that fails.
+
+ - The following environment variables are only needed if you implemented
+ your own forkserver or persistent mode, or if __AFL_LOOP or __AFL_INIT
+ are in a shared library and not the main binary:
+ - `AFL_DEFER_FORKSRV` enforces a deferred forkserver even if none was
+ detected in the target binary
+ - `AFL_PERSISTENT` enforces persistent mode even if none was detected
+ in the target binary
+
+ - If you need an early forkserver in your target because of early
+ constructors in your target you can set `AFL_EARLY_FORKSERVER`.
+ Note that this is not a compile time option but a runtime option :-)
+
+ - set `AFL_PIZZA_MODE` to 1 to enable the April 1st stats menu, set to 0
+ to disable although it is 1st of April.
+
+## 5) Settings for afl-qemu-trace
+
+The QEMU wrapper used to instrument binary-only code supports several settings:
+
+ - Setting `AFL_COMPCOV_LEVEL` enables the CompareCoverage tracing of all cmp
+ and sub in x86 and x86_64 and memory comparison functions (e.g., strcmp,
+ memcmp, ...) when libcompcov is preloaded using `AFL_PRELOAD`. More info at
+ [qemu_mode/libcompcov/README.md](../qemu_mode/libcompcov/README.md).
+
+ There are two levels at the moment, `AFL_COMPCOV_LEVEL=1` that instruments
+ only comparisons with immediate values / read-only memory and
+ `AFL_COMPCOV_LEVEL=2` that instruments all the comparisons. Level 2 is more
+ accurate but may need a larger shared memory.
+
+ - `AFL_DEBUG` will print the found entry point for the binary to stderr. Use
+ this if you are unsure if the entry point might be wrong - but use it
+ directly, e.g., `afl-qemu-trace ./program`.
+
+ - `AFL_ENTRYPOINT` allows you to specify a specific entry point into the
+ binary (this can be very good for the performance!). The entry point is
+ specified as hex address, e.g., `0x4004110`. Note that the address must be
+ the address of a basic block.
+
+ - Setting `AFL_INST_LIBS` causes the translator to also instrument the code
+ inside any dynamically linked libraries (notably including glibc).
+
+ - It is possible to set `AFL_INST_RATIO` to skip the instrumentation on some
+ of the basic blocks, which can be useful when dealing with very complex
+ binaries.
+
+ - Setting `AFL_QEMU_COMPCOV` enables the CompareCoverage tracing of all cmp
+ and sub in x86 and x86_64. This is an alias of `AFL_COMPCOV_LEVEL=1` when
+ `AFL_COMPCOV_LEVEL` is not specified.
+
+ - With `AFL_QEMU_FORCE_DFL`, you force QEMU to ignore the registered signal
+ handlers of the target.
+
+ - When the target is i386/x86_64, you can specify the address of the function
+ that has to be the body of the persistent loop using
+ `AFL_QEMU_PERSISTENT_ADDR=start addr`.
+
+ - With `AFL_QEMU_PERSISTENT_GPR=1`, QEMU will save the original value of
+ general purpose registers and restore them in each persistent cycle.
+
+ - Another modality to execute the persistent loop is to specify also the
+ `AFL_QEMU_PERSISTENT_RET=end addr` environment variable. With this variable
+ assigned, instead of patching the return address, the specified instruction
+ is transformed to a jump towards `start addr`.
+
+ - With `AFL_QEMU_PERSISTENT_RETADDR_OFFSET`, you can specify the offset from
+ the stack pointer in which QEMU can find the return address when `start
+ addr` is hit.
+
+ - With `AFL_USE_QASAN`, you can enable QEMU AddressSanitizer for dynamically
+ linked binaries.
+
+ - The underlying QEMU binary will recognize any standard "user space
+ emulation" variables (e.g., `QEMU_STACK_SIZE`), but there should be no
+ reason to touch them.
+
+## 7) Settings for afl-frida-trace
+
+The FRIDA wrapper used to instrument binary-only code supports many of the same
+options as `afl-qemu-trace`, but also has a number of additional advanced
+options. These are listed in brief below (see
+[frida_mode/README.md](../frida_mode/README.md) for more details). These
+settings are provided for compatibility with QEMU mode, the preferred way to
+configure FRIDA mode is through its [scripting](../frida_mode/Scripting.md)
+support.
+
+* `AFL_FRIDA_DEBUG_MAPS` - See `AFL_QEMU_DEBUG_MAPS`
+* `AFL_FRIDA_DRIVER_NO_HOOK` - See `AFL_QEMU_DRIVER_NO_HOOK`. When using the
+ QEMU driver to provide a `main` loop for a user provided
+ `LLVMFuzzerTestOneInput`, this option configures the driver to read input from
+ `stdin` rather than using in-memory test cases.
+* `AFL_FRIDA_EXCLUDE_RANGES` - See `AFL_QEMU_EXCLUDE_RANGES`
+* `AFL_FRIDA_INST_COVERAGE_FILE` - File to write DynamoRio format coverage
+ information (e.g., to be loaded within IDA lighthouse).
+* `AFL_FRIDA_INST_DEBUG_FILE` - File to write raw assembly of original blocks
+ and their instrumented counterparts during block compilation.
+* `AFL_FRIDA_INST_JIT` - Enable the instrumentation of Just-In-Time compiled
+ code. Code is considered to be JIT if the executable segment is not backed by
+ a file.
+* `AFL_FRIDA_INST_NO_OPTIMIZE` - Don't use optimized inline assembly coverage
+ instrumentation (the default where available). Required to use
+ `AFL_FRIDA_INST_TRACE`.
+* `AFL_FRIDA_INST_NO_BACKPATCH` - Disable backpatching. At the end of executing
+ each block, control will return to FRIDA to identify the next block to
+ execute.
+* `AFL_FRIDA_INST_NO_PREFETCH` - Disable prefetching. By default, the child will
+ report instrumented blocks back to the parent so that it can also instrument
+ them and they be inherited by the next child on fork, implies
+ `AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH`.
+* `AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH` - Disable prefetching of stalker
+ backpatching information. By default, the child will report applied
+ backpatches to the parent so that they can be applied and then be inherited by
+ the next child on fork.
+* `AFL_FRIDA_INST_RANGES` - See `AFL_QEMU_INST_RANGES`
+* `AFL_FRIDA_INST_SEED` - Sets the initial seed for the hash function used to
+ generate block (and hence edge) IDs. Setting this to a constant value may be
+ useful for debugging purposes, e.g., investigating unstable edges.
+* `AFL_FRIDA_INST_TRACE` - Log to stdout the address of executed blocks, implies
+ `AFL_FRIDA_INST_NO_OPTIMIZE`.
+* `AFL_FRIDA_INST_TRACE_UNIQUE` - As per `AFL_FRIDA_INST_TRACE`, but each edge
+ is logged only once, requires `AFL_FRIDA_INST_NO_OPTIMIZE`.
+* `AFL_FRIDA_INST_UNSTABLE_COVERAGE_FILE` - File to write DynamoRio format
+ coverage information for unstable edges (e.g., to be loaded within IDA
+ lighthouse).
+* `AFL_FRIDA_JS_SCRIPT` - Set the script to be loaded by the FRIDA scripting
+ engine. See [frida_mode/Scripting.md](../frida_mode/Scripting.md) for details.
+* `AFL_FRIDA_OUTPUT_STDOUT` - Redirect the standard output of the target
+ application to the named file (supersedes the setting of `AFL_DEBUG_CHILD`)
+* `AFL_FRIDA_OUTPUT_STDERR` - Redirect the standard error of the target
+ application to the named file (supersedes the setting of `AFL_DEBUG_CHILD`)
+* `AFL_FRIDA_PERSISTENT_ADDR` - See `AFL_QEMU_PERSISTENT_ADDR`
+* `AFL_FRIDA_PERSISTENT_CNT` - See `AFL_QEMU_PERSISTENT_CNT`
+* `AFL_FRIDA_PERSISTENT_DEBUG` - Insert a Breakpoint into the instrumented code
+ at `AFL_FRIDA_PERSISTENT_HOOK` and `AFL_FRIDA_PERSISTENT_RET` to allow the
+ user to detect issues in the persistent loop using a debugger.
+* `AFL_FRIDA_PERSISTENT_HOOK` - See `AFL_QEMU_PERSISTENT_HOOK`
+* `AFL_FRIDA_PERSISTENT_RET` - See `AFL_QEMU_PERSISTENT_RET`
+* `AFL_FRIDA_SECCOMP_FILE` - Write a log of any syscalls made by the target to
+ the specified file.
+* `AFL_FRIDA_STALKER_ADJACENT_BLOCKS` - Configure the number of adjacent blocks
+ to fetch when generating instrumented code. By fetching blocks in the same
+ order they appear in the original program, rather than the order of execution
+ should help reduce locallity and adjacency. This includes allowing us to
+ vector between adjancent blocks using a NOP slide rather than an immediate
+ branch.
+* `AFL_FRIDA_STALKER_IC_ENTRIES` - Configure the number of inline cache entries
+ stored along-side branch instructions which provide a cache to avoid having to
+ call back into FRIDA to find the next block. Default is 32.
+* `AFL_FRIDA_STATS_FILE` - Write statistics information about the code being
+ instrumented to the given file name. The statistics are written only for the
+ child process when new block is instrumented (when the
+ `AFL_FRIDA_STATS_INTERVAL` has expired). Note that just because a new path is
+ found does not mean a new block needs to be compiled. It could be that the
+ existing blocks instrumented have been executed in a different order.
+* `AFL_FRIDA_STATS_INTERVAL` - The maximum frequency to output statistics
+ information. Stats will be written whenever they are updated if the given
+ interval has elapsed since last time they were written.
+* `AFL_FRIDA_TRACEABLE` - Set the child process to be traceable by any process
+ to aid debugging and overcome the restrictions imposed by YAMA. Supported on
+ Linux only. Permits a non-root user to use `gcore` or similar to collect a
+ core dump of the instrumented target. Note that in order to capture the core
+ dump you must set a sufficient timeout (using `-t`) to avoid `afl-fuzz`
+ killing the process whilst it is being dumped.
+
+## 8) Settings for afl-cmin
+
+The corpus minimization script offers very little customization:
+
+ - `AFL_ALLOW_TMP` permits this and some other scripts to run in /tmp. This is
+ a modest security risk on multi-user systems with rogue users, but should be
+ safe on dedicated fuzzing boxes.
+
+ - `AFL_KEEP_TRACES` makes the tool keep traces and other metadata used for
+ minimization and normally deleted at exit. The files can be found in the
+ `<out_dir>/.traces/` directory.
+
+ - Setting `AFL_PATH` offers a way to specify the location of afl-showmap and
+ afl-qemu-trace (the latter only in `-Q` mode).
+
+ - `AFL_PRINT_FILENAMES` prints each filename to stdout, as it gets processed.
+ This can help when embedding `afl-cmin` or `afl-showmap` in other scripts.
+
+## 9) Settings for afl-tmin
+
+Virtually nothing to play with. Well, in QEMU mode (`-Q`), `AFL_PATH` will be
+searched for afl-qemu-trace. In addition to this, `TMPDIR` may be used if a
+temporary file can't be created in the current working directory.
+
+You can specify `AFL_TMIN_EXACT` if you want afl-tmin to require execution paths
+to match when minimizing crashes. This will make minimization less useful, but
+may prevent the tool from "jumping" from one crashing condition to another in
+very buggy software. You probably want to combine it with the `-e` flag.
+
+## 10) Settings for afl-analyze
+
+You can set `AFL_ANALYZE_HEX` to get file offsets printed as hexadecimal instead
+of decimal.
+
+## 11) Settings for libdislocator
+
+The library honors these environment variables:
+
+ - `AFL_ALIGNED_ALLOC=1` will force the alignment of the allocation size to
+ `max_align_t` to be compliant with the C standard.
+
+ - `AFL_LD_HARD_FAIL` alters the behavior by calling `abort()` on excessive
+ allocations, thus causing what AFL++ would perceive as a crash. Useful for
+ programs that are supposed to maintain a specific memory footprint.
+
+ - `AFL_LD_LIMIT_MB` caps the size of the maximum heap usage permitted by the
+ library, in megabytes. The default value is 1 GB. Once this is exceeded,
+ allocations will return NULL.
+
+ - `AFL_LD_NO_CALLOC_OVER` inhibits `abort()` on `calloc()` overflows. Most of
+ the common allocators check for that internally and return NULL, so it's a
+ security risk only in more exotic setups.
+
+ - `AFL_LD_VERBOSE` causes the library to output some diagnostic messages that
+ may be useful for pinpointing the cause of any observed issues.
+
+## 11) Settings for libtokencap
+
+This library accepts `AFL_TOKEN_FILE` to indicate the location to which the
+discovered tokens should be written.
+
+## 12) Third-party variables set by afl-fuzz & other tools
+
+Several variables are not directly interpreted by afl-fuzz, but are set to
+optimal values if not already present in the environment:
+
+ - By default, `ASAN_OPTIONS` are set to (among others):
+
+ ```
+ abort_on_error=1
+ detect_leaks=0
+ malloc_context_size=0
+ symbolize=0
+ allocator_may_return_null=1
+ ```
+
+ If you want to set your own options, be sure to include `abort_on_error=1` -
+ otherwise, the fuzzer will not be able to detect crashes in the tested app.
+ Similarly, include `symbolize=0`, since without it, AFL++ may have
+ difficulty telling crashes and hangs apart.
+
+ - Similarly, the default `LSAN_OPTIONS` are set to:
+
+ ```
+ exit_code=23
+ fast_unwind_on_malloc=0
+ symbolize=0
+ print_suppressions=0
+ ```
+
+ Be sure to include the first ones for LSAN and MSAN when customizing
+ anything, since some MSAN and LSAN versions don't call `abort()` on error,
+ and we need a way to detect faults.
+
+ - In the same vein, by default, `MSAN_OPTIONS` are set to:
+
+ ```
+ exit_code=86 (required for legacy reasons)
+ abort_on_error=1
+ symbolize=0
+ msan_track_origins=0
+ allocator_may_return_null=1
+ ```
+
+ - By default, `LD_BIND_NOW` is set to speed up fuzzing by forcing the linker
+ to do all the work before the fork server kicks in. You can override this by
+ setting `LD_BIND_LAZY` beforehand, but it is almost certainly pointless.
diff --git a/docs/features.md b/docs/features.md
new file mode 100644
index 00000000..dd3d2bcb
--- /dev/null
+++ b/docs/features.md
@@ -0,0 +1,118 @@
+# Important features of AFL++
+
+AFL++ supports llvm from 3.8 up to version 12, very fast binary fuzzing with
+QEMU 5.1 with laf-intel and Redqueen, FRIDA mode, unicorn mode, gcc plugin, full
+*BSD, Mac OS, Solaris and Android support and much, much, much more.
+
+## Features and instrumentation
+
+| Feature/Instrumentation | afl-gcc | llvm | gcc_plugin | FRIDA mode(9) | QEMU mode(10) | unicorn_mode(10) | nyx_mode(12) | coresight_mode(11) |
+| ------------------------------|:--------:|:---------:|:----------:|:--------------:|:----------------:|:----------------:|:------------:|:------------------:|
+| Threadsafe counters [A] | | x(3) | | | | | x | |
+| NeverZero [B] | x86[_64] | x(1) | x | x | x | x | | |
+| Persistent Mode [C] | | x | x | x86[_64]/arm64 | x86[_64]/arm[64] | x | | |
+| LAF-Intel / CompCov [D] | | x | | | x86[_64]/arm[64] | x86[_64]/arm[64] | x86[_64] | |
+| CmpLog [E] | | x | | x86[_64]/arm64 | x86[_64]/arm[64] | | | |
+| Selective Instrumentation [F] | | x | x | x | x | | | |
+| Non-Colliding Coverage [G] | | x(4) | | | (x)(5) | | | |
+| Ngram prev_loc Coverage [H] | | x(6) | | | | | | |
+| Context Coverage [I] | | x(6) | | | | | | |
+| Auto Dictionary [J] | | x(7) | | | | | | |
+| Snapshot Support [K] | | (x)(8) | (x)(8) | | (x)(5) | | x | |
+| Shared Memory Test cases [L] | | x | x | x86[_64]/arm64 | x | x | x | |
+
+## More information about features
+
+A. Default is not thread-safe coverage counter updates for better performance,
+ see [instrumentation/README.llvm.md](../instrumentation/README.llvm.md)
+
+B. On wrapping coverage counters (255 + 1), skip the 0 value and jump to 1
+ instead. This has shown to give better coverage data and is the default; see
+ [instrumentation/README.llvm.md](../instrumentation/README.llvm.md).
+
+C. Instead of forking, reiterate the fuzz target function in a loop (like
+ `LLVMFuzzerTestOneInput`. Great speed increase but only works with target
+ functions that do not keep state, leak memory, or exit; see
+ [instrumentation/README.persistent_mode.md](../instrumentation/README.persistent_mode.md)
+
+D. Split any non-8-bit comparison to 8-bit comparison; see
+ [instrumentation/README.laf-intel.md](../instrumentation/README.laf-intel.md)
+
+E. CmpLog is our enhanced
+ [Redqueen](https://www.ndss-symposium.org/ndss-paper/redqueen-fuzzing-with-input-to-state-correspondence/)
+ implementation, see
+ [instrumentation/README.cmplog.md](../instrumentation/README.cmplog.md)
+
+F. Similar and compatible to clang 13+ sancov sanitize-coverage-allow/deny but
+ for all llvm versions and all our compile modes, only instrument what should
+ be instrumented, for more speed, directed fuzzing and less instability; see
+ [instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md)
+
+G. Vanilla AFL uses coverage where edges could collide to the same coverage
+ bytes the larger the target is. Our default instrumentation in LTO and
+ afl-clang-fast (PCGUARD) uses non-colliding coverage that also makes it
+ faster. Vanilla AFL style is available with `AFL_LLVM_INSTRUMENT=AFL`; see
+ [instrumentation/README.llvm.md](../instrumentation/README.llvm.md).
+
+H.+I. Alternative coverage based on previous edges (NGRAM) or depending on the
+ caller (CTX), based on
+ [https://www.usenix.org/system/files/raid2019-wang-jinghan.pdf](https://www.usenix.org/system/files/raid2019-wang-jinghan.pdf);
+ see [instrumentation/README.llvm.md](../instrumentation/README.llvm.md).
+
+J. An LTO feature that creates a fuzzing dictionary based on comparisons found
+ during compilation/instrumentation. Automatic feature :) See
+ [instrumentation/README.lto.md](../instrumentation/README.lto.md)
+
+K. The snapshot feature requires a kernel module that was a lot of work to get
+ right and maintained so it is no longer supported. We have
+ [nyx_mode](../nyx_mode/README.md) instead.
+
+L. Faster fuzzing and less kernel syscall overhead by in-memory fuzz testcase
+ delivery, see
+ [instrumentation/README.persistent_mode.md](../instrumentation/README.persistent_mode.md)
+
+## More information about instrumentation
+
+1. Default for LLVM >= 9.0, environment variable for older version due an
+ efficiency bug in previous llvm versions
+2. GCC creates non-performant code, hence it is disabled in gcc_plugin
+3. With `AFL_LLVM_THREADSAFE_INST`, disables NeverZero
+4. With pcguard mode and LTO mode for LLVM 11 and newer
+5. Upcoming, development in the branch
+6. Not compatible with LTO instrumentation and needs at least LLVM v4.1
+7. Automatic in LTO mode with LLVM 11 and newer, an extra pass for all LLVM
+ versions that write to a file to use with afl-fuzz' `-x`
+8. The snapshot LKM is currently unmaintained due to too many kernel changes
+ coming too fast :-(
+9. FRIDA mode is supported on Linux and MacOS for Intel and ARM
+10. QEMU/Unicorn is only supported on Linux
+11. Coresight mode is only available on AARCH64 Linux with a CPU with Coresight
+ extension
+12. Nyx mode is only supported on Linux and currently restricted to x86_x64
+
+## Integrated features and patches
+
+Among others, the following features and patches have been integrated:
+
+* NeverZero patch for afl-gcc, instrumentation, QEMU mode and unicorn_mode which
+ prevents a wrapping map value to zero, increases coverage
+* Persistent mode, deferred forkserver and in-memory fuzzing for QEMU mode
+* Unicorn mode which allows fuzzing of binaries from completely different
+ platforms (integration provided by domenukk)
+* The new CmpLog instrumentation for LLVM and QEMU inspired by
+ [Redqueen](https://github.com/RUB-SysSec/redqueen)
+* Win32 PE binary-only fuzzing with QEMU and Wine
+* AFLfast's power schedules by Marcel Böhme:
+ [https://github.com/mboehme/aflfast](https://github.com/mboehme/aflfast)
+* The MOpt mutator:
+ [https://github.com/puppet-meteor/MOpt-AFL](https://github.com/puppet-meteor/MOpt-AFL)
+* LLVM mode Ngram coverage by Adrian Herrera
+ [https://github.com/adrianherrera/afl-ngram-pass](https://github.com/adrianherrera/afl-ngram-pass)
+* LAF-Intel/CompCov support for instrumentation, QEMU mode and unicorn_mode
+ (with enhanced capabilities)
+* Radamsa and honggfuzz mutators (as custom mutators).
+* QBDI mode to fuzz android native libraries via Quarkslab's
+ [QBDI](https://github.com/QBDI/QBDI) framework
+* Frida and ptrace mode to fuzz binary-only libraries, etc.
+
+So all in all this is the best-of AFL that is out there :-) \ No newline at end of file
diff --git a/docs/fuzzing_binary-only_targets.md b/docs/fuzzing_binary-only_targets.md
new file mode 100644
index 00000000..c97af1b9
--- /dev/null
+++ b/docs/fuzzing_binary-only_targets.md
@@ -0,0 +1,310 @@
+# Fuzzing binary-only targets
+
+AFL++, libfuzzer, and other fuzzers are great if you have the source code of the
+target. This allows for very fast and coverage guided fuzzing.
+
+However, if there is only the binary program and no source code available, then
+standard `afl-fuzz -n` (non-instrumented mode) is not effective.
+
+For fast, on-the-fly instrumentation of black-box binaries, AFL++ still offers
+various support. The following is a description of how these binaries can be
+fuzzed with AFL++.
+
+## TL;DR:
+
+FRIDA mode and QEMU mode in persistent mode are the fastest - if persistent mode
+is possible and the stability is high enough.
+
+Otherwise, try Zafl, RetroWrite, Dyninst, and if these fail, too, then try
+standard FRIDA/QEMU mode with `AFL_ENTRYPOINT` to where you need it.
+
+If your target is non-linux, then use unicorn_mode.
+
+## Fuzzing binary-only targets with AFL++
+
+### QEMU mode
+
+QEMU mode is the "native" solution to the program. It is available in the
+./qemu_mode/ directory and, once compiled, it can be accessed by the afl-fuzz -Q
+command line option. It is the easiest to use alternative and even works for
+cross-platform binaries.
+
+For linux programs and its libraries, this is accomplished with a version of
+QEMU running in the lesser-known "user space emulation" mode. QEMU is a project
+separate from AFL++, but you can conveniently build the feature by doing:
+
+```shell
+cd qemu_mode
+./build_qemu_support.sh
+```
+
+The following setup to use QEMU mode is recommended:
+
+* run 1 afl-fuzz -Q instance with CMPLOG (`-c 0` + `AFL_COMPCOV_LEVEL=2`)
+* run 1 afl-fuzz -Q instance with QASAN (`AFL_USE_QASAN=1`)
+* run 1 afl-fuzz -Q instance with LAF (`AFL_PRELOAD=libcmpcov.so` +
+ `AFL_COMPCOV_LEVEL=2`), alternatively you can use FRIDA mode, just switch `-Q`
+ with `-O` and remove the LAF instance
+
+Then run as many instances as you have cores left with either -Q mode or - even
+better - use a binary rewriter like Dyninst, RetroWrite, ZAFL, etc.
+The binary rewriters all have their own advantages and caveats.
+ZAFL is the best but cannot be used in a business/commercial context.
+
+If a binary rewriter works for your target then you can use afl-fuzz normally
+and it will have twice the speed compared to QEMU mode (but slower than QEMU
+persistent mode).
+
+The speed decrease of QEMU mode is at about 50%. However, various options exist
+to increase the speed:
+- using AFL_ENTRYPOINT to move the forkserver entry to a later basic block in
+ the binary (+5-10% speed)
+- using persistent mode
+ [qemu_mode/README.persistent.md](../qemu_mode/README.persistent.md) this will
+ result in a 150-300% overall speed increase - so 3-8x the original QEMU mode
+ speed!
+- using AFL_CODE_START/AFL_CODE_END to only instrument specific parts
+
+For additional instructions and caveats, see
+[qemu_mode/README.md](../qemu_mode/README.md). If possible, you should use the
+persistent mode, see
+[qemu_mode/README.persistent.md](../qemu_mode/README.persistent.md). The mode is
+approximately 2-5x slower than compile-time instrumentation, and is less
+conducive to parallelization.
+
+Note that there is also honggfuzz:
+[https://github.com/google/honggfuzz](https://github.com/google/honggfuzz) which
+now has a QEMU mode, but its performance is just 1.5% ...
+
+If you like to code a customized fuzzer without much work, we highly recommend
+to check out our sister project libafl which supports QEMU, too:
+[https://github.com/AFLplusplus/LibAFL](https://github.com/AFLplusplus/LibAFL)
+
+### WINE+QEMU
+
+Wine mode can run Win32 PE binaries with the QEMU instrumentation. It needs
+Wine, python3, and the pefile python package installed.
+
+It is included in AFL++.
+
+For more information, see
+[qemu_mode/README.wine.md](../qemu_mode/README.wine.md).
+
+### FRIDA mode
+
+In FRIDA mode, you can fuzz binary-only targets as easily as with QEMU mode.
+FRIDA mode is most of the times slightly faster than QEMU mode. It is also
+newer, lacks COMPCOV, and has the advantage that it works on MacOS (both intel
+and M1).
+
+To build FRIDA mode:
+
+```shell
+cd frida_mode
+gmake
+```
+
+For additional instructions and caveats, see
+[frida_mode/README.md](../frida_mode/README.md).
+
+If possible, you should use the persistent mode, see
+[instrumentation/README.persistent_mode.md](../instrumentation/README.persistent_mode.md).
+The mode is approximately 2-5x slower than compile-time instrumentation, and is
+less conducive to parallelization. But for binary-only fuzzing, it gives a huge
+speed improvement if it is possible to use.
+
+If you want to fuzz a binary-only library, then you can fuzz it with frida-gum
+via frida_mode/. You will have to write a harness to call the target function in
+the library, use afl-frida.c as a template.
+
+You can also perform remote fuzzing with frida, e.g., if you want to fuzz on
+iPhone or Android devices, for this you can use
+[https://github.com/ttdennis/fpicker/](https://github.com/ttdennis/fpicker/) as
+an intermediate that uses AFL++ for fuzzing.
+
+If you like to code a customized fuzzer without much work, we highly recommend
+to check out our sister project libafl which supports Frida, too:
+[https://github.com/AFLplusplus/LibAFL](https://github.com/AFLplusplus/LibAFL).
+Working examples already exist :-)
+
+### Nyx mode
+
+Nyx is a full system emulation fuzzing environment with snapshot support that is
+built upon KVM and QEMU. It is only available on Linux and currently restricted
+to x86_x64.
+
+For binary-only fuzzing a special 5.10 kernel is required.
+
+See [nyx_mode/README.md](../nyx_mode/README.md).
+
+### Unicorn
+
+Unicorn is a fork of QEMU. The instrumentation is, therefore, very similar. In
+contrast to QEMU, Unicorn does not offer a full system or even userland
+emulation. Runtime environment and/or loaders have to be written from scratch,
+if needed. On top, block chaining has been removed. This means the speed boost
+introduced in the patched QEMU Mode of AFL++ cannot be ported over to Unicorn.
+
+For non-Linux binaries, you can use AFL++'s unicorn_mode which can emulate
+anything you want - for the price of speed and user written scripts.
+
+To build unicorn_mode:
+
+```shell
+cd unicorn_mode
+./build_unicorn_support.sh
+```
+
+For further information, check out
+[unicorn_mode/README.md](../unicorn_mode/README.md).
+
+### Shared libraries
+
+If the goal is to fuzz a dynamic library, then there are two options available.
+For both, you need to write a small harness that loads and calls the library.
+Then you fuzz this with either FRIDA mode or QEMU mode and either use
+`AFL_INST_LIBS=1` or `AFL_QEMU/FRIDA_INST_RANGES`.
+
+Another, less precise and slower option is to fuzz it with utils/afl_untracer/
+and use afl-untracer.c as a template. It is slower than FRIDA mode.
+
+For more information, see
+[utils/afl_untracer/README.md](../utils/afl_untracer/README.md).
+
+### Coresight
+
+Coresight is ARM's answer to Intel's PT. With AFL++ v3.15, there is a coresight
+tracer implementation available in `coresight_mode/` which is faster than QEMU,
+however, cannot run in parallel. Currently, only one process can be traced, it
+is WIP.
+
+Fore more information, see
+[coresight_mode/README.md](../coresight_mode/README.md).
+
+## Binary rewriters
+
+An alternative solution are binary rewriters. They are faster than the solutions
+native to AFL++ but don't always work.
+
+### ZAFL
+
+ZAFL is a static rewriting platform supporting x86-64 C/C++,
+stripped/unstripped, and PIE/non-PIE binaries. Beyond conventional
+instrumentation, ZAFL's API enables transformation passes (e.g., laf-Intel,
+context sensitivity, InsTrim, etc.).
+
+Its baseline instrumentation speed typically averages 90-95% of
+afl-clang-fast's.
+
+[https://git.zephyr-software.com/opensrc/zafl](https://git.zephyr-software.com/opensrc/zafl)
+
+### RetroWrite
+
+RetroWrite is a static binary rewriter that can be combined with AFL++. If you
+have an x86_64 binary that still has its symbols (i.e., not stripped binary), is
+compiled with position independent code (PIC/PIE), and does not contain C++
+exceptions, then the RetroWrite solution might be for you. It decompiles to ASM
+files which can then be instrumented with afl-gcc.
+
+Binaries that are statically instrumented for fuzzing using RetroWrite are close
+in performance to compiler-instrumented binaries and outperform the QEMU-based
+instrumentation.
+
+[https://github.com/HexHive/retrowrite](https://github.com/HexHive/retrowrite)
+
+### Dyninst
+
+Dyninst is a binary instrumentation framework similar to Pintool and DynamoRIO.
+However, whereas Pintool and DynamoRIO work at runtime, Dyninst instruments the
+target at load time and then let it run - or save the binary with the changes.
+This is great for some things, e.g., fuzzing, and not so effective for others,
+e.g., malware analysis.
+
+So, what you can do with Dyninst is taking every basic block and putting AFL++'s
+instrumentation code in there - and then save the binary. Afterwards, just fuzz
+the newly saved target binary with afl-fuzz. Sounds great? It is. The issue
+though - it is a non-trivial problem to insert instructions, which change
+addresses in the process space, so that everything is still working afterwards.
+Hence, more often than not binaries crash when they are run.
+
+The speed decrease is about 15-35%, depending on the optimization options used
+with afl-dyninst.
+
+[https://github.com/vanhauser-thc/afl-dyninst](https://github.com/vanhauser-thc/afl-dyninst)
+
+### Mcsema
+
+Theoretically, you can also decompile to llvm IR with mcsema, and then use
+llvm_mode to instrument the binary. Good luck with that.
+
+[https://github.com/lifting-bits/mcsema](https://github.com/lifting-bits/mcsema)
+
+## Binary tracers
+
+### Pintool & DynamoRIO
+
+Pintool and DynamoRIO are dynamic instrumentation engines. They can be used for
+getting basic block information at runtime. Pintool is only available for Intel
+x32/x64 on Linux, Mac OS, and Windows, whereas DynamoRIO is additionally
+available for ARM and AARCH64. DynamoRIO is also 10x faster than Pintool.
+
+The big issue with DynamoRIO (and therefore Pintool, too) is speed. DynamoRIO
+has a speed decrease of 98-99%, Pintool has a speed decrease of 99.5%.
+
+Hence, DynamoRIO is the option to go for if everything else fails and Pintool
+only if DynamoRIO fails, too.
+
+DynamoRIO solutions:
+* [https://github.com/vanhauser-thc/afl-dynamorio](https://github.com/vanhauser-thc/afl-dynamorio)
+* [https://github.com/mxmssh/drAFL](https://github.com/mxmssh/drAFL)
+* [https://github.com/googleprojectzero/winafl/](https://github.com/googleprojectzero/winafl/)
+ <= very good but windows only
+
+Pintool solutions:
+* [https://github.com/vanhauser-thc/afl-pin](https://github.com/vanhauser-thc/afl-pin)
+* [https://github.com/mothran/aflpin](https://github.com/mothran/aflpin)
+* [https://github.com/spinpx/afl_pin_mode](https://github.com/spinpx/afl_pin_mode)
+ <= only old Pintool version supported
+
+### Intel PT
+
+If you have a newer Intel CPU, you can make use of Intel's processor trace. The
+big issue with Intel's PT is the small buffer size and the complex encoding of
+the debug information collected through PT. This makes the decoding very CPU
+intensive and hence slow. As a result, the overall speed decrease is about
+70-90% (depending on the implementation and other factors).
+
+There are two AFL intel-pt implementations:
+
+1. [https://github.com/junxzm1990/afl-pt](https://github.com/junxzm1990/afl-pt)
+ => This needs Ubuntu 14.04.05 without any updates and the 4.4 kernel.
+
+2. [https://github.com/hunter-ht-2018/ptfuzzer](https://github.com/hunter-ht-2018/ptfuzzer)
+ => This needs a 4.14 or 4.15 kernel. The "nopti" kernel boot option must be
+ used. This one is faster than the other.
+
+Note that there is also honggfuzz:
+[https://github.com/google/honggfuzz](https://github.com/google/honggfuzz). But
+its IPT performance is just 6%!
+
+## Non-AFL++ solutions
+
+There are many binary-only fuzzing frameworks. Some are great for CTFs but don't
+work with large binaries, others are very slow but have good path discovery,
+some are very hard to set-up...
+
+* Jackalope:
+ [https://github.com/googleprojectzero/Jackalope](https://github.com/googleprojectzero/Jackalope)
+* Manticore:
+ [https://github.com/trailofbits/manticore](https://github.com/trailofbits/manticore)
+* QSYM:
+ [https://github.com/sslab-gatech/qsym](https://github.com/sslab-gatech/qsym)
+* S2E: [https://github.com/S2E](https://github.com/S2E)
+* TinyInst:
+ [https://github.com/googleprojectzero/TinyInst](https://github.com/googleprojectzero/TinyInst)
+ (Mac/Windows only)
+* ... please send me any missing that are good
+
+## Closing words
+
+That's it! News, corrections, updates? Send an email to vh@thc.org.
diff --git a/docs/fuzzing_in_depth.md b/docs/fuzzing_in_depth.md
new file mode 100644
index 00000000..2c27dfe1
--- /dev/null
+++ b/docs/fuzzing_in_depth.md
@@ -0,0 +1,949 @@
+# Fuzzing with AFL++
+
+The following describes how to fuzz with a target if source code is available.
+If you have a binary-only target, go to
+[fuzzing_binary-only_targets.md](fuzzing_binary-only_targets.md).
+
+Fuzzing source code is a three-step process:
+
+1. Compile the target with a special compiler that prepares the target to be
+ fuzzed efficiently. This step is called "instrumenting a target".
+2. Prepare the fuzzing by selecting and optimizing the input corpus for the
+ target.
+3. Perform the fuzzing of the target by randomly mutating input and assessing if
+ that input was processed on a new path in the target binary.
+
+## 0. Common sense risks
+
+Please keep in mind that, similarly to many other computationally-intensive
+tasks, fuzzing may put a strain on your hardware and on the OS. In particular:
+
+- Your CPU will run hot and will need adequate cooling. In most cases, if
+ cooling is insufficient or stops working properly, CPU speeds will be
+ automatically throttled. That said, especially when fuzzing on less suitable
+ hardware (laptops, smartphones, etc.), it's not entirely impossible for
+ something to blow up.
+
+- Targeted programs may end up erratically grabbing gigabytes of memory or
+ filling up disk space with junk files. AFL++ tries to enforce basic memory
+ limits, but can't prevent each and every possible mishap. The bottom line is
+ that you shouldn't be fuzzing on systems where the prospect of data loss is
+ not an acceptable risk.
+
+- Fuzzing involves billions of reads and writes to the filesystem. On modern
+ systems, this will be usually heavily cached, resulting in fairly modest
+ "physical" I/O - but there are many factors that may alter this equation. It
+ is your responsibility to monitor for potential trouble; with very heavy I/O,
+ the lifespan of many HDDs and SSDs may be reduced.
+
+ A good way to monitor disk I/O on Linux is the `iostat` command:
+
+ ```shell
+ $ iostat -d 3 -x -k [...optional disk ID...]
+ ```
+
+ Using the `AFL_TMPDIR` environment variable and a RAM-disk, you can have the
+ heavy writing done in RAM to prevent the aforementioned wear and tear. For
+ example, the following line will run a Docker container with all this preset:
+
+ ```shell
+ # docker run -ti --mount type=tmpfs,destination=/ramdisk -e AFL_TMPDIR=/ramdisk aflplusplus/aflplusplus
+ ```
+
+## 1. Instrumenting the target
+
+### a) Selecting the best AFL++ compiler for instrumenting the target
+
+AFL++ comes with a central compiler `afl-cc` that incorporates various different
+kinds of compiler targets and instrumentation options. The following
+evaluation flow will help you to select the best possible.
+
+It is highly recommended to have the newest llvm version possible installed,
+anything below 9 is not recommended.
+
+```
++--------------------------------+
+| clang/clang++ 11+ is available | --> use LTO mode (afl-clang-lto/afl-clang-lto++)
++--------------------------------+ see [instrumentation/README.lto.md](instrumentation/README.lto.md)
+ |
+ | if not, or if the target fails with LTO afl-clang-lto/++
+ |
+ v
++---------------------------------+
+| clang/clang++ 3.8+ is available | --> use LLVM mode (afl-clang-fast/afl-clang-fast++)
++---------------------------------+ see [instrumentation/README.llvm.md](instrumentation/README.llvm.md)
+ |
+ | if not, or if the target fails with LLVM afl-clang-fast/++
+ |
+ v
+ +--------------------------------+
+ | gcc 5+ is available | -> use GCC_PLUGIN mode (afl-gcc-fast/afl-g++-fast)
+ +--------------------------------+ see [instrumentation/README.gcc_plugin.md](instrumentation/README.gcc_plugin.md) and
+ [instrumentation/README.instrument_list.md](instrumentation/README.instrument_list.md)
+ |
+ | if not, or if you do not have a gcc with plugin support
+ |
+ v
+ use GCC mode (afl-gcc/afl-g++) (or afl-clang/afl-clang++ for clang)
+```
+
+Clickable README links for the chosen compiler:
+
+* [LTO mode - afl-clang-lto](../instrumentation/README.lto.md)
+* [LLVM mode - afl-clang-fast](../instrumentation/README.llvm.md)
+* [GCC_PLUGIN mode - afl-gcc-fast](../instrumentation/README.gcc_plugin.md)
+* GCC/CLANG modes (afl-gcc/afl-clang) have no README as they have no own
+ features
+
+You can select the mode for the afl-cc compiler by one of the following methods:
+
+* Using a symlink to afl-cc: afl-gcc, afl-g++, afl-clang, afl-clang++,
+ afl-clang-fast, afl-clang-fast++, afl-clang-lto, afl-clang-lto++,
+ afl-gcc-fast, afl-g++-fast (recommended!).
+* Using the environment variable `AFL_CC_COMPILER` with `MODE`.
+* Passing --afl-`MODE` command line options to the compiler via
+ `CFLAGS`/`CXXFLAGS`/`CPPFLAGS`.
+
+`MODE` can be one of the following:
+
+* LTO (afl-clang-lto*)
+* LLVM (afl-clang-fast*)
+* GCC_PLUGIN (afl-g*-fast) or GCC (afl-gcc/afl-g++)
+* CLANG(afl-clang/afl-clang++)
+
+Because no AFL++ specific command-line options are accepted (beside the
+--afl-MODE command), the compile-time tools make fairly broad use of environment
+variables, which can be listed with `afl-cc -hh` or looked up in
+[env_variables.md](env_variables.md).
+
+### b) Selecting instrumentation options
+
+If you instrument with LTO mode (afl-clang-fast/afl-clang-lto), the following
+options are available:
+
+* Splitting integer, string, float, and switch comparisons so AFL++ can easier
+ solve these. This is an important option if you do not have a very good and
+ large input corpus. This technique is called laf-intel or COMPCOV. To use
+ this, set the following environment variable before compiling the target:
+ `export AFL_LLVM_LAF_ALL=1`. You can read more about this in
+ [instrumentation/README.laf-intel.md](../instrumentation/README.laf-intel.md).
+* A different technique (and usually a better one than laf-intel) is to
+ instrument the target so that any compare values in the target are sent to
+ AFL++ which then tries to put these values into the fuzzing data at different
+ locations. This technique is very fast and good - if the target does not
+ transform input data before comparison. Therefore, this technique is called
+ `input to state` or `redqueen`. If you want to use this technique, then you
+ have to compile the target twice, once specifically with/for this mode by
+ setting `AFL_LLVM_CMPLOG=1`, and pass this binary to afl-fuzz via the `-c`
+ parameter. Note that you can compile also just a cmplog binary and use that
+ for both, however, there will be a performance penalty. You can read more
+ about this in
+ [instrumentation/README.cmplog.md](../instrumentation/README.cmplog.md).
+
+If you use LTO, LLVM, or GCC_PLUGIN mode
+(afl-clang-fast/afl-clang-lto/afl-gcc-fast), you have the option to selectively
+instrument _parts_ of the target that you are interested in. For afl-clang-fast,
+you have to use an llvm version newer than 10.0.0 or a mode other than
+DEFAULT/PCGUARD.
+
+This step can be done either by explicitly including parts to be instrumented or
+by explicitly excluding parts from instrumentation.
+
+* To instrument _only specified parts_, create a file (e.g., `allowlist.txt`)
+ with all the filenames and/or functions of the source code that should be
+ instrumented and then:
+
+ 1. Just put one filename or function (prefixing with `fun: `) per line (no
+ directory information necessary for filenames) in the file `allowlist.txt`.
+
+ Example:
+
+ ```
+ foo.cpp # will match foo/foo.cpp, bar/foo.cpp, barfoo.cpp etc.
+ fun: foo_func # will match the function foo_func
+ ```
+
+ 2. Set `export AFL_LLVM_ALLOWLIST=allowlist.txt` to enable selective positive
+ instrumentation.
+
+* Similarly to _exclude_ specified parts from instrumentation, create a file
+ (e.g., `denylist.txt`) with all the filenames of the source code that should
+ be skipped during instrumentation and then:
+
+ 1. Same as above. Just put one filename or function per line in the file
+ `denylist.txt`.
+
+ 2. Set `export AFL_LLVM_DENYLIST=denylist.txt` to enable selective negative
+ instrumentation.
+
+**NOTE:** During optimization functions might be
+inlined and then would not match the list! See
+[instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md).
+
+There are many more options and modes available, however, these are most of the
+time less effective. See:
+
+* [instrumentation/README.llvm.md#6) AFL++ Context Sensitive Branch Coverage](../instrumentation/README.llvm.md#6-afl-context-sensitive-branch-coverage)
+* [instrumentation/README.llvm.md#7) AFL++ N-Gram Branch Coverage](../instrumentation/README.llvm.md#7-afl-n-gram-branch-coverage)
+
+AFL++ performs "never zero" counting in its bitmap. You can read more about this
+here:
+* [instrumentation/README.llvm.md#8-neverzero-counters](../instrumentation/README.llvm.md#8-neverzero-counters)
+
+### c) Selecting sanitizers
+
+It is possible to use sanitizers when instrumenting targets for fuzzing, which
+allows you to find bugs that would not necessarily result in a crash.
+
+Note that sanitizers have a huge impact on CPU (= less executions per second)
+and RAM usage. Also, you should only run one afl-fuzz instance per sanitizer
+type. This is enough because e.g. a use-after-free bug will be picked up by ASAN
+(address sanitizer) anyway after syncing test cases from other fuzzing
+instances, so running more than one address sanitized target would be a waste.
+
+The following sanitizers have built-in support in AFL++:
+
+* ASAN = Address SANitizer, finds memory corruption vulnerabilities like
+ use-after-free, NULL pointer dereference, buffer overruns, etc. Enabled with
+ `export AFL_USE_ASAN=1` before compiling.
+* MSAN = Memory SANitizer, finds read accesses to uninitialized memory, e.g., a
+ local variable that is defined and read before it is even set. Enabled with
+ `export AFL_USE_MSAN=1` before compiling.
+* UBSAN = Undefined Behavior SANitizer, finds instances where - by the C and C++
+ standards - undefined behavior happens, e.g., adding two signed integers where
+ the result is larger than what a signed integer can hold. Enabled with `export
+ AFL_USE_UBSAN=1` before compiling.
+* CFISAN = Control Flow Integrity SANitizer, finds instances where the control
+ flow is found to be illegal. Originally this was rather to prevent return
+ oriented programming (ROP) exploit chains from functioning. In fuzzing, this
+ is mostly reduced to detecting type confusion vulnerabilities - which is,
+ however, one of the most important and dangerous C++ memory corruption
+ classes! Enabled with `export AFL_USE_CFISAN=1` before compiling.
+* TSAN = Thread SANitizer, finds thread race conditions. Enabled with `export
+ AFL_USE_TSAN=1` before compiling.
+* LSAN = Leak SANitizer, finds memory leaks in a program. This is not really a
+ security issue, but for developers this can be very valuable. Note that unlike
+ the other sanitizers above this needs `__AFL_LEAK_CHECK();` added to all areas
+ of the target source code where you find a leak check necessary! Enabled with
+ `export AFL_USE_LSAN=1` before compiling. To ignore the memory-leaking check
+ for certain allocations, `__AFL_LSAN_OFF();` can be used before memory is
+ allocated, and `__AFL_LSAN_ON();` afterwards. Memory allocated between these
+ two macros will not be checked for memory leaks.
+
+It is possible to further modify the behavior of the sanitizers at run-time by
+setting `ASAN_OPTIONS=...`, `LSAN_OPTIONS` etc. - the available parameters can
+be looked up in the sanitizer documentation of llvm/clang. afl-fuzz, however,
+requires some specific parameters important for fuzzing to be set. If you want
+to set your own, it might bail and report what it is missing.
+
+Note that some sanitizers cannot be used together, e.g., ASAN and MSAN, and
+others often cannot work together because of target weirdness, e.g., ASAN and
+CFISAN. You might need to experiment which sanitizers you can combine in a
+target (which means more instances can be run without a sanitized target, which
+is more effective).
+
+### d) Modifying the target
+
+If the target has features that make fuzzing more difficult, e.g., checksums,
+HMAC, etc., then modify the source code so that checks for these values are
+removed. This can even be done safely for source code used in operational
+products by eliminating these checks within these AFL++ specific blocks:
+
+```
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ // say that the checksum or HMAC was fine - or whatever is required
+ // to eliminate the need for the fuzzer to guess the right checksum
+ return 0;
+#endif
+```
+
+All AFL++ compilers will set this preprocessor definition automatically.
+
+### e) Instrumenting the target
+
+In this step, the target source code is compiled so that it can be fuzzed.
+
+Basically, you have to tell the target build system that the selected AFL++
+compiler is used. Also - if possible - you should always configure the build
+system in such way that the target is compiled statically and not dynamically.
+How to do this is described below.
+
+The #1 rule when instrumenting a target is: avoid instrumenting shared libraries
+at all cost. You would need to set `LD_LIBRARY_PATH` to point to these, you
+could accidentally type "make install" and install them system wide - so don't.
+Really don't. **Always compile libraries you want to have instrumented as static
+and link these to the target program!**
+
+Then build the target. (Usually with `make`.)
+
+**NOTES**
+
+1. Sometimes configure and build systems are fickle and do not like stderr
+ output (and think this means a test failure) - which is something AFL++ likes
+ to do to show statistics. It is recommended to disable AFL++ instrumentation
+ reporting via `export AFL_QUIET=1`.
+
+2. Sometimes configure and build systems error on warnings - these should be
+ disabled (e.g., `--disable-werror` for some configure scripts).
+
+3. In case the configure/build system complains about AFL++'s compiler and
+ aborts, then set `export AFL_NOOPT=1` which will then just behave like the
+ real compiler and run the configure step separately. For building the target
+ afterwards this option has to be unset again!
+
+#### configure
+
+For `configure` build systems, this is usually done by:
+
+```
+CC=afl-clang-fast CXX=afl-clang-fast++ ./configure --disable-shared
+```
+
+Note that if you are using the (better) afl-clang-lto compiler, you also have to
+set `AR` to llvm-ar[-VERSION] and `RANLIB` to llvm-ranlib[-VERSION] - as is
+described in [instrumentation/README.lto.md](../instrumentation/README.lto.md).
+
+#### CMake
+
+For CMake build systems, this is usually done by:
+
+```
+mkdir build; cd build; cmake -DCMAKE_C_COMPILER=afl-cc -DCMAKE_CXX_COMPILER=afl-c++ ..
+```
+
+Note that if you are using the (better) afl-clang-lto compiler you also have to
+set AR to llvm-ar[-VERSION] and RANLIB to llvm-ranlib[-VERSION] - as is
+described in [instrumentation/README.lto.md](../instrumentation/README.lto.md).
+
+#### Meson Build System
+
+For the Meson Build System, you have to set the AFL++ compiler with the very
+first command!
+
+```
+CC=afl-cc CXX=afl-c++ meson
+```
+
+#### Other build systems or if configure/cmake didn't work
+
+Sometimes `cmake` and `configure` do not pick up the AFL++ compiler or the
+`RANLIB`/`AR` that is needed - because this was just not foreseen by the
+developer of the target. Or they have non-standard options. Figure out if there
+is a non-standard way to set this, otherwise set up the build normally and edit
+the generated build environment afterwards manually to point it to the right
+compiler (and/or `RANLIB` and `AR`).
+
+In complex, weird, alien build systems you can try this neat project:
+[https://github.com/fuzzah/exeptor](https://github.com/fuzzah/exeptor)
+
+#### Linker scripts
+
+If the project uses linker scripts to hide the symbols exported by the
+binary, then you may see errors such as:
+
+```
+undefined symbol: __afl_area_ptr
+```
+
+The solution is to modify the linker script to add:
+
+```
+{
+ global:
+ __afl_*;
+}
+```
+
+### f) Better instrumentation
+
+If you just fuzz a target program as-is, you are wasting a great opportunity for
+much more fuzzing speed.
+
+This variant requires the usage of afl-clang-lto, afl-clang-fast or
+afl-gcc-fast.
+
+It is the so-called `persistent mode`, which is much, much faster but requires
+that you code a source file that is specifically calling the target functions
+that you want to fuzz, plus a few specific AFL++ functions around it. See
+[instrumentation/README.persistent_mode.md](../instrumentation/README.persistent_mode.md)
+for details.
+
+Basically, if you do not fuzz a target in persistent mode, then you are just
+doing it for a hobby and not professionally :-).
+
+### g) libfuzzer fuzzer harnesses with LLVMFuzzerTestOneInput()
+
+libfuzzer `LLVMFuzzerTestOneInput()` harnesses are the defacto standard for
+fuzzing, and they can be used with AFL++ (and honggfuzz) as well!
+
+Compiling them is as simple as:
+
+```
+afl-clang-fast++ -fsanitize=fuzzer -o harness harness.cpp targetlib.a
+```
+
+You can even use advanced libfuzzer features like `FuzzedDataProvider`,
+`LLVMFuzzerInitialize()` etc. and they will work!
+
+The generated binary is fuzzed with afl-fuzz like any other fuzz target.
+
+Bonus: the target is already optimized for fuzzing due to persistent mode and
+shared-memory test cases and hence gives you the fastest speed possible.
+
+For more information, see
+[utils/aflpp_driver/README.md](../utils/aflpp_driver/README.md).
+
+## 2. Preparing the fuzzing campaign
+
+As you fuzz the target with mutated input, having as diverse inputs for the
+target as possible improves the efficiency a lot.
+
+### a) Collecting inputs
+
+To operate correctly, the fuzzer requires one or more starting files that
+contain a good example of the input data normally expected by the targeted
+application.
+
+Try to gather valid inputs for the target from wherever you can. E.g., if it is
+the PNG picture format, try to find as many PNG files as possible, e.g., from
+reported bugs, test suites, random downloads from the internet, unit test case
+data - from all kind of PNG software.
+
+If the input format is not known, you can also modify a target program to write
+normal data it receives and processes to a file and use these.
+
+You can find many good examples of starting files in the
+[testcases/](../testcases) subdirectory that comes with this tool.
+
+### b) Making the input corpus unique
+
+Use the AFL++ tool `afl-cmin` to remove inputs from the corpus that do not
+produce a new path/coverage in the target:
+
+1. Put all files from [step a](#a-collecting-inputs) into one directory, e.g.,
+ `INPUTS`.
+2. Run afl-cmin:
+ * If the target program is to be called by fuzzing as `bin/target INPUTFILE`,
+ replace the INPUTFILE argument that the target program would read from with
+ `@@`:
+
+ ```
+ afl-cmin -i INPUTS -o INPUTS_UNIQUE -- bin/target -someopt @@
+ ```
+
+ * If the target reads from stdin (standard input) instead, just omit the `@@`
+ as this is the default:
+
+ ```
+ afl-cmin -i INPUTS -o INPUTS_UNIQUE -- bin/target -someopt
+ ```
+
+This step is highly recommended, because afterwards the testcase corpus is not
+bloated with duplicates anymore, which would slow down the fuzzing progress!
+
+### c) Minimizing all corpus files
+
+The shorter the input files that still traverse the same path within the target,
+the better the fuzzing will be. This minimization is done with `afl-tmin`,
+however, it is a long process as this has to be done for every file:
+
+```
+mkdir input
+cd INPUTS_UNIQUE
+for i in *; do
+ afl-tmin -i "$i" -o "../input/$i" -- bin/target -someopt @@
+done
+```
+
+This step can also be parallelized, e.g., with `parallel`.
+
+Note that this step is rather optional though.
+
+### Done!
+
+The INPUTS_UNIQUE/ directory from [step b](#b-making-the-input-corpus-unique) -
+or even better the directory input/ if you minimized the corpus in
+[step c](#c-minimizing-all-corpus-files) - is the resulting input corpus
+directory to be used in fuzzing! :-)
+
+## 3. Fuzzing the target
+
+In this final step, fuzz the target. There are not that many important options
+to run the target - unless you want to use many CPU cores/threads for the
+fuzzing, which will make the fuzzing much more useful.
+
+If you just use one instance for fuzzing, then you are fuzzing just for fun and
+not seriously :-)
+
+### a) Running afl-fuzz
+
+Before you do even a test run of afl-fuzz, execute `sudo afl-system-config` (on
+the host if you execute afl-fuzz in a Docker container). This reconfigures the
+system for optimal speed - which afl-fuzz checks and bails otherwise. Set
+`export AFL_SKIP_CPUFREQ=1` for afl-fuzz to skip this check if you cannot run
+afl-system-config with root privileges on the host for whatever reason.
+
+Note:
+
+* There is also `sudo afl-persistent-config` which sets additional permanent
+ boot options for a much better fuzzing performance.
+* Both scripts improve your fuzzing performance but also decrease your system
+ protection against attacks! So set strong firewall rules and only expose SSH
+ as a network service if you use these (which is highly recommended).
+
+If you have an input corpus from [step 2](#2-preparing-the-fuzzing-campaign),
+then specify this directory with the `-i` option. Otherwise, create a new
+directory and create a file with any content as test data in there.
+
+If you do not want anything special, the defaults are already usually best,
+hence all you need is to specify the seed input directory with the result of
+step [2a) Collecting inputs](#a-collecting-inputs):
+
+```
+afl-fuzz -i input -o output -- bin/target -someopt @@
+```
+
+Note that the directory specified with `-o` will be created if it does not
+exist.
+
+It can be valuable to run afl-fuzz in a `screen` or `tmux` shell so you can log
+off, or afl-fuzz is not aborted if you are running it in a remote ssh session
+where the connection fails in between. Only do that though once you have
+verified that your fuzzing setup works! Run it like `screen -dmS afl-main --
+afl-fuzz -M main-$HOSTNAME -i ...` and it will start away in a screen session.
+To enter this session, type `screen -r afl-main`. You see - it makes sense to
+name the screen session same as the afl-fuzz `-M`/`-S` naming :-) For more
+information on screen or tmux, check their documentation.
+
+If you need to stop and re-start the fuzzing, use the same command line options
+(or even change them by selecting a different power schedule or another mutation
+mode!) and switch the input directory with a dash (`-`):
+
+```
+afl-fuzz -i - -o output -- bin/target -someopt @@
+```
+
+Adding a dictionary is helpful. You have to following options:
+
+* See the directory
+[dictionaries/](../dictionaries/), if something is already included for your
+data format, and tell afl-fuzz to load that dictionary by adding `-x
+dictionaries/FORMAT.dict`.
+* With `afl-clang-lto`, you have an autodictionary generation for which you need
+ to do nothing except to use afl-clang-lto as the compiler.
+* With `afl-clang-fast`, you can set
+ `AFL_LLVM_DICT2FILE=/full/path/to/new/file.dic` to automatically generate a
+ dictionary during target compilation.
+* You also have the option to generate a dictionary yourself during an
+ independent run of the target, see
+ [utils/libtokencap/README.md](../utils/libtokencap/README.md).
+* Finally, you can also write a dictionary file manually, of course.
+
+afl-fuzz has a variety of options that help to workaround target quirks like
+very specific locations for the input file (`-f`), performing deterministic
+fuzzing (`-D`) and many more. Check out `afl-fuzz -h`.
+
+We highly recommend that you set a memory limit for running the target with `-m`
+which defines the maximum memory in MB. This prevents a potential out-of-memory
+problem for your system plus helps you detect missing `malloc()` failure
+handling in the target. Play around with various `-m` values until you find one
+that safely works for all your input seeds (if you have good ones and then
+double or quadruple that).
+
+By default, afl-fuzz never stops fuzzing. To terminate AFL++, press Control-C or
+send a signal SIGINT. You can limit the number of executions or approximate
+runtime in seconds with options also.
+
+When you start afl-fuzz, you will see a user interface that shows what the
+status is:
+
+![resources/screenshot.png](resources/screenshot.png)
+
+All labels are explained in
+[afl-fuzz_approach.md#understanding-the-status-screen](afl-fuzz_approach.md#understanding-the-status-screen).
+
+### b) Keeping memory use and timeouts in check
+
+Memory limits are not enforced by afl-fuzz by default and the system may run out
+of memory. You can decrease the memory with the `-m` option, the value is in MB.
+If this is too small for the target, you can usually see this by afl-fuzz
+bailing with the message that it could not connect to the forkserver.
+
+Consider setting low values for `-m` and `-t`.
+
+For programs that are nominally very fast, but get sluggish for some inputs, you
+can also try setting `-t` values that are more punishing than what `afl-fuzz`
+dares to use on its own. On fast and idle machines, going down to `-t 5` may be
+a viable plan.
+
+The `-m` parameter is worth looking at, too. Some programs can end up spending a
+fair amount of time allocating and initializing megabytes of memory when
+presented with pathological inputs. Low `-m` values can make them give up sooner
+and not waste CPU time.
+
+### c) Using multiple cores
+
+If you want to seriously fuzz, then use as many cores/threads as possible to
+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 32 and 64 cores per machine.
+
+If you have the RAM, it is highly recommended run the instances with a caching
+of the test cases. Depending on the average test case size (and those found
+during fuzzing) and their number, a value between 50-500MB is recommended. You
+can set the cache size (in MB) by setting the environment variable
+`AFL_TESTCACHE_SIZE`.
+
+There should be one main fuzzer (`-M main-$HOSTNAME` option) and as many
+secondary fuzzers (e.g., `-S variant1`) as you have cores that you use. Every
+`-M`/`-S` entry needs a unique name (that can be whatever), however, the same
+`-o` output directory location has to be used for all instances.
+
+For every secondary fuzzer there should be a variation, e.g.:
+* one should fuzz the target that was compiled differently: with sanitizers
+ activated (`export AFL_USE_ASAN=1 ; export AFL_USE_UBSAN=1 ; export
+ AFL_USE_CFISAN=1`)
+* one or two should fuzz the target with CMPLOG/redqueen (see above), at least
+ one cmplog instance should follow transformations (`-l AT`)
+* one to three fuzzers should fuzz a target compiled with laf-intel/COMPCOV (see
+ above). Important note: If you run more than one laf-intel/COMPCOV fuzzer and
+ you want them to share their intermediate results, the main fuzzer (`-M`) must
+ be one of them! (Although this is not really recommended.)
+
+All other secondaries should be used like this:
+* a quarter to a third with the MOpt mutator enabled: `-L 0`
+* run with a different power schedule, recommended are: `fast` (default),
+ `explore`, `coe`, `lin`, `quad`, `exploit`, and `rare` which you can set with
+ the `-p` option, e.g., `-p explore`. See the
+ [FAQ](FAQ.md#what-are-power-schedules) for details.
+* a few instances should use the old queue cycling with `-Z`
+
+Also, it is recommended to set `export AFL_IMPORT_FIRST=1` to load test cases
+from other fuzzers in the campaign first.
+
+If you have a large corpus, a corpus from a previous run or are fuzzing in a CI,
+then also set `export AFL_CMPLOG_ONLY_NEW=1` and `export AFL_FAST_CAL=1`.
+
+You can also use different fuzzers. If you are using AFL spinoffs or AFL
+conforming fuzzers, then just use the same -o directory and give it a unique
+`-S` name. Examples are:
+* [Fuzzolic](https://github.com/season-lab/fuzzolic)
+* [symcc](https://github.com/eurecom-s3/symcc/)
+* [Eclipser](https://github.com/SoftSec-KAIST/Eclipser/)
+* [AFLsmart](https://github.com/aflsmart/aflsmart)
+* [FairFuzz](https://github.com/carolemieux/afl-rb)
+* [Neuzz](https://github.com/Dongdongshe/neuzz)
+* [Angora](https://github.com/AngoraFuzzer/Angora)
+
+A long list can be found at
+[https://github.com/Microsvuln/Awesome-AFL](https://github.com/Microsvuln/Awesome-AFL).
+
+However, you can also sync AFL++ with honggfuzz, libfuzzer with `-entropic=1`,
+etc. Just show the main fuzzer (`-M`) with the `-F` option where the queue/work
+directory of a different fuzzer is, e.g., `-F /src/target/honggfuzz`. Using
+honggfuzz (with `-n 1` or `-n 2`) and libfuzzer in parallel is highly
+recommended!
+
+### d) Using multiple machines for fuzzing
+
+Maybe you have more than one machine you want to fuzz the same target on. Start
+the `afl-fuzz` (and perhaps libfuzzer, honggfuzz, ...) orchestra as you like,
+just ensure that your have one and only one `-M` instance per server, and that
+its name is unique, hence the recommendation for `-M main-$HOSTNAME`.
+
+Now there are three strategies on how you can sync between the servers:
+* never: sounds weird, but this makes every server an island and has the chance
+ that each follow different paths into the target. You can make this even more
+ interesting by even giving different seeds to each server.
+* regularly (~4h): this ensures that all fuzzing campaigns on the servers "see"
+ the same thing. It is like fuzzing on a huge server.
+* in intervals of 1/10th of the overall expected runtime of the fuzzing you
+ sync. This tries a bit to combine both. Have some individuality of the paths
+ each campaign on a server explores, on the other hand if one gets stuck where
+ another found progress this is handed over making it unstuck.
+
+The syncing process itself is very simple. As the `-M main-$HOSTNAME` instance
+syncs to all `-S` secondaries as well as to other fuzzers, you have to copy only
+this directory to the other machines.
+
+Lets say all servers have the `-o out` directory in /target/foo/out, and you
+created a file `servers.txt` which contains the hostnames of all participating
+servers, plus you have an ssh key deployed to all of them, then run:
+
+```bash
+for FROM in `cat servers.txt`; do
+ for TO in `cat servers.txt`; do
+ rsync -rlpogtz --rsh=ssh $FROM:/target/foo/out/main-$FROM $TO:target/foo/out/
+ done
+done
+```
+
+You can run this manually, per cron job - as you need it. There is a more
+complex and configurable script in
+[utils/distributed_fuzzing](../utils/distributed_fuzzing).
+
+### e) The status of the fuzz campaign
+
+AFL++ comes with the `afl-whatsup` script to show the status of the fuzzing
+campaign.
+
+Just supply the directory that afl-fuzz is given with the `-o` option and you
+will see a detailed status of every fuzzer in that campaign plus a summary.
+
+To have only the summary, use the `-s` switch, e.g., `afl-whatsup -s out/`.
+
+If you have multiple servers, then use the command after a sync or you have to
+execute this script per server.
+
+Another tool to inspect the current state and history of a specific instance is
+afl-plot, which generates an index.html file and graphs that show how the
+fuzzing instance is performing. The syntax is `afl-plot instance_dir web_dir`,
+e.g., `afl-plot out/default /srv/www/htdocs/plot`.
+
+### f) Stopping fuzzing, restarting fuzzing, adding new seeds
+
+To stop an afl-fuzz run, press Control-C.
+
+To restart an afl-fuzz run, just reuse the same command line but replace the `-i
+directory` with `-i -` or set `AFL_AUTORESUME=1`.
+
+If you want to add new seeds to a fuzzing campaign, you can run a temporary
+fuzzing instance, e.g., when your main fuzzer is using `-o out` and the new
+seeds are in `newseeds/` directory:
+
+```
+AFL_BENCH_JUST_ONE=1 AFL_FAST_CAL=1 afl-fuzz -i newseeds -o out -S newseeds -- ./target
+```
+
+### g) Checking the coverage of the fuzzing
+
+The `corpus count` value is a bad indicator for checking how good the coverage
+is.
+
+A better indicator - if you use default llvm instrumentation with at least
+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.
+
+An "easy" helper script for this is
+[https://github.com/vanhauser-thc/afl-cov](https://github.com/vanhauser-thc/afl-cov),
+just follow the README of that separate project.
+
+If you see that an important area or a feature has not been covered so far, then
+try to find an input that is able to reach that and start a new secondary in
+that fuzzing campaign with that seed as input, let it run for a few minutes,
+then terminate it. The main node will pick it up and make it available to the
+other secondary nodes over time. Set `export AFL_NO_AFFINITY=1` or `export
+AFL_TRY_AFFINITY=1` if you have no free core.
+
+Note that in nearly all cases you can never reach full coverage. A lot of
+functionality is usually dependent on exclusive options that would need
+individual fuzzing campaigns each with one of these options set. 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.
+
+### h) How long to fuzz a target?
+
+This is a difficult question. Basically, if no new path is found for a long time
+(e.g., for a day or a week), then you can expect that your fuzzing won't be
+fruitful anymore. However, often this just means that you should switch out
+secondaries for others, e.g., custom mutator modules, sync to very different
+fuzzers, etc.
+
+Keep the queue/ directory (for future fuzzings of the same or similar targets)
+and use them to seed other good fuzzers like libfuzzer with the -entropic switch
+or honggfuzz.
+
+### i) Improve the speed!
+
+* Use [persistent mode](../instrumentation/README.persistent_mode.md) (x2-x20
+ speed increase).
+* If you do not use shmem persistent mode, use `AFL_TMPDIR` to point the input
+ file on a tempfs location, see [env_variables.md](env_variables.md).
+* Linux: Improve kernel performance: modify `/etc/default/grub`, set
+ `GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=off l1tf=off mds=off
+ mitigations=off no_stf_barrier noibpb noibrs nopcid nopti
+ nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=off pti=off
+ spec_store_bypass_disable=off spectre_v2=off stf_barrier=off"`; then
+ `update-grub` and `reboot` (warning: makes the system more insecure) - you can
+ also just run `sudo afl-persistent-config`.
+* Linux: Running on an `ext2` filesystem with `noatime` mount option will be a
+ bit faster than on any other journaling filesystem.
+* Use your cores! See [3c) Using multiple cores](#c-using-multiple-cores).
+* Run `sudo afl-system-config` before starting the first afl-fuzz instance after
+ a reboot.
+
+### j) Going beyond crashes
+
+Fuzzing is a wonderful and underutilized technique for discovering non-crashing
+design and implementation errors, too. Quite a few interesting bugs have been
+found by modifying the target programs to call `abort()` when say:
+
+- Two bignum libraries produce different outputs when given the same
+ fuzzer-generated input.
+
+- An image library produces different outputs when asked to decode the same
+ input image several times in a row.
+
+- A serialization/deserialization library fails to produce stable outputs when
+ iteratively serializing and deserializing fuzzer-supplied data.
+
+- A compression library produces an output inconsistent with the input file when
+ asked to compress and then decompress a particular blob.
+
+Implementing these or similar sanity checks usually takes very little time; if
+you are the maintainer of a particular package, you can make this code
+conditional with `#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION` (a flag also
+shared with libfuzzer and honggfuzz) or `#ifdef __AFL_COMPILER` (this one is
+just for AFL++).
+
+### k) Known limitations & areas for improvement
+
+Here are some of the most important caveats for AFL++:
+
+- AFL++ detects faults by checking for the first spawned process dying due to a
+ signal (SIGSEGV, SIGABRT, etc.). Programs that install custom handlers for
+ these signals may need to have the relevant code commented out. In the same
+ vein, faults in child processes spawned by the fuzzed target may evade
+ detection unless you manually add some code to catch that.
+
+- As with any other brute-force tool, the fuzzer offers limited coverage if
+ encryption, checksums, cryptographic signatures, or compression are used to
+ wholly wrap the actual data format to be tested.
+
+ To work around this, you can comment out the relevant checks (see
+ utils/libpng_no_checksum/ for inspiration); if this is not possible, you can
+ also write a postprocessor, one of the hooks of custom mutators. See
+ [custom_mutators.md](custom_mutators.md) on how to use
+ `AFL_CUSTOM_MUTATOR_LIBRARY`.
+
+- There are some unfortunate trade-offs with ASAN and 64-bit binaries. This
+ isn't due to any specific fault of afl-fuzz.
+
+- There is no direct support for fuzzing network services, background daemons,
+ or interactive apps that require UI interaction to work. You may need to make
+ simple code changes to make them behave in a more traditional way. Preeny or libdesock may
+ offer a relatively simple option, too - see:
+ [https://github.com/zardus/preeny](https://github.com/zardus/preeny) or [https://github.com/fkie-cad/libdesock](https://github.com/fkie-cad/libdesock)
+
+ Some useful tips for modifying network-based services can be also found at:
+ [https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop](https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop)
+
+- Occasionally, sentient machines rise against their creators. If this happens
+ to you, please consult
+ [https://lcamtuf.coredump.cx/prep/](https://lcamtuf.coredump.cx/prep/).
+
+Beyond this, see [INSTALL.md](INSTALL.md) for platform-specific tips.
+
+## 4. Triaging crashes
+
+The coverage-based grouping of crashes usually produces a small data set that
+can be quickly triaged manually or with a very simple GDB or Valgrind script.
+Every crash is also traceable to its parent non-crashing test case in the queue,
+making it easier to diagnose faults.
+
+Having said that, it's important to acknowledge that some fuzzing crashes can be
+difficult to quickly evaluate for exploitability without a lot of debugging and
+code analysis work. To assist with this task, afl-fuzz supports a very unique
+"crash exploration" mode enabled with the `-C` flag.
+
+In this mode, the fuzzer takes one or more crashing test cases as the input and
+uses its feedback-driven fuzzing strategies to very quickly enumerate all code
+paths that can be reached in the program while keeping it in the crashing state.
+
+Mutations that do not result in a crash are rejected; so are any changes that do
+not affect the execution path.
+
+The output is a small corpus of files that can be very rapidly examined to see
+what degree of control the attacker has over the faulting address, or whether it
+is possible to get past an initial out-of-bounds read - and see what lies
+beneath.
+
+Oh, one more thing: for test case minimization, give afl-tmin a try. The tool
+can be operated in a very simple way:
+
+```shell
+./afl-tmin -i test_case -o minimized_result -- /path/to/program [...]
+```
+
+The tool works with crashing and non-crashing test cases alike. In the crash
+mode, it will happily accept instrumented and non-instrumented binaries. In the
+non-crashing mode, the minimizer relies on standard AFL++ instrumentation to
+make the file simpler without altering the execution path.
+
+The minimizer accepts the `-m`, `-t`, `-f`, and `@@` syntax in a manner
+compatible with afl-fuzz.
+
+Another tool in AFL++ is the afl-analyze tool. It takes an input file, attempts
+to sequentially flip bytes and observes the behavior of the tested program. It
+then color-codes the input based on which sections appear to be critical and
+which are not; while not bulletproof, it can often offer quick insights into
+complex file formats.
+
+## 5. CI fuzzing
+
+Some notes on continuous integration (CI) fuzzing - this fuzzing is different to
+normal fuzzing campaigns as these are much shorter runnings.
+
+1. Always:
+ * LTO has a much longer compile time which is diametrical to short fuzzing -
+ hence use afl-clang-fast instead.
+ * If you compile with CMPLOG, then you can save compilation time and reuse
+ that compiled target with the `-c` option and as the main fuzz target.
+ This will impact the speed by ~15% though.
+ * `AFL_FAST_CAL` - enables fast calibration, this halves the time the
+ saturated corpus needs to be loaded.
+ * `AFL_CMPLOG_ONLY_NEW` - only perform cmplog on new finds, not the initial
+ corpus as this very likely has been done for them already.
+ * Keep the generated corpus, use afl-cmin and reuse it every time!
+
+2. Additionally randomize the AFL++ compilation options, e.g.:
+ * 30% for `AFL_LLVM_CMPLOG`
+ * 5% for `AFL_LLVM_LAF_ALL`
+
+3. Also randomize the afl-fuzz runtime options, e.g.:
+ * 65% for `AFL_DISABLE_TRIM`
+ * 50% for `AFL_KEEP_TIMEOUTS`
+ * 50% use a dictionary generated by `AFL_LLVM_DICT2FILE`
+ * 40% use MOpt (`-L 0`)
+ * 40% for `AFL_EXPAND_HAVOC_NOW`
+ * 20% for old queue processing (`-Z`)
+ * for CMPLOG targets, 70% for `-l 2`, 10% for `-l 3`, 20% for `-l 2AT`
+
+4. Do *not* run any `-M` modes, just running `-S` modes is better for CI
+ fuzzing. `-M` enables old queue handling etc. which is good for a fuzzing
+ campaign but not good for short CI runs.
+
+How this can look like can, e.g., be seen at AFL++'s setup in Google's
+[oss-fuzz](https://github.com/google/oss-fuzz/blob/master/infra/base-images/base-builder/compile_afl)
+and
+[clusterfuzz](https://github.com/google/clusterfuzz/blob/master/src/clusterfuzz/_internal/bot/fuzzers/afl/launcher.py).
+
+## The End
+
+Check out the [FAQ](FAQ.md). Maybe it answers your question (that you might not
+even have known you had ;-) ).
+
+This is basically all you need to know to professionally run fuzzing campaigns.
+If you want to know more, the tons of texts in [docs/](./) will have you
+covered.
+
+Note that there are also a lot of tools out there that help fuzzing with AFL++
+(some might be deprecated or unsupported), see
+[third_party_tools.md](third_party_tools.md).
diff --git a/docs/ideas.md b/docs/ideas.md
new file mode 100644
index 00000000..e2360ab2
--- /dev/null
+++ b/docs/ideas.md
@@ -0,0 +1,57 @@
+# Ideas for AFL++
+
+In the following, we describe a variety of ideas that could be implemented for
+future AFL++ versions.
+
+## Analysis software
+
+Currently analysis is done by using afl-plot, which is rather outdated. A GTK or
+browser tool to create run-time analysis based on fuzzer_stats, queue/id*
+information and plot_data that allows for zooming in and out, changing min/max
+display values etc. and doing that for a single run, different runs and
+campaigns vs. campaigns. Interesting values are execs, and execs/s, edges
+discovered (total, when each edge was discovered and which other fuzzer share
+finding that edge), test cases executed. It should be clickable which value is X
+and Y axis, zoom factor, log scaling on-off, etc.
+
+Mentor: vanhauser-thc
+
+## WASM Instrumentation
+
+Currently, AFL++ can be used for source code fuzzing and traditional binaries.
+With the rise of WASM as a compile target, however, a novel way of instrumentation
+needs to be implemented for binaries compiled to Webassembly. This can either be
+done by inserting instrumentation directly into the WASM AST, or by patching
+feedback into a WASM VM of choice, similar to the current Unicorn
+instrumentation.
+
+Mentor: any
+
+## Support other programming languages
+
+Other programming languages also use llvm hence they could be (easily?) supported
+for fuzzing, e.g., mono, swift, go, kotlin native, fortran, ...
+
+GCC also supports: Objective-C, Fortran, Ada, Go, and D (according to
+[Gcc homepage](https://gcc.gnu.org/))
+
+LLVM is also used by: Rust, LLGo (Go), kaleidoscope (Haskell), flang (Fortran),
+emscripten (JavaScript, WASM), ilwasm (CIL (C#)) (according to
+[LLVM frontends](https://gist.github.com/axic/62d66fb9d8bccca6cc48fa9841db9241))
+
+Mentor: vanhauser-thc
+
+## Machine Learning
+
+Something with machine learning, better than
+[NEUZZ](https://github.com/dongdongshe/neuzz) :-) Either improve a single
+mutator through learning of many different bugs (a bug class) or gather deep
+insights about a single target beforehand (CFG, DFG, VFG, ...?) and improve
+performance for a single target.
+
+Mentor: domenukk
+
+## Your idea!
+
+Finally, we are open to proposals! Create an issue at
+https://github.com/AFLplusplus/AFLplusplus/issues and let's discuss :-)
diff --git a/docs/important_changes.md b/docs/important_changes.md
new file mode 100644
index 00000000..e847f360
--- /dev/null
+++ b/docs/important_changes.md
@@ -0,0 +1,60 @@
+# Important changes in AFL++
+
+This document lists important changes in AFL++, for example, major behavior
+changes.
+
+## From version 3.00 onwards
+
+With AFL++ 4.00, we introduced the following changes from previous behaviors:
+ * the complete documentation was overhauled and restructured thanks to @llzmb!
+ * a new CMPLOG target format requires recompiling CMPLOG targets for use with
+ AFL++ 4.0 onwards
+ * better naming for several fields in the UI
+
+With AFL++ 3.15, we introduced the following changes from previous behaviors:
+ * afl-cmin and afl-showmap `-Ci` now descend into subdirectories like afl-fuzz
+ `-i` does (but note that afl-cmin.bash does not)
+
+With AFL++ 3.14, we introduced the following changes from previous behaviors:
+ * afl-fuzz: deterministic fuzzing is not a default for `-M main` anymore
+ * afl-cmin/afl-showmap -i now descends into subdirectories (afl-cmin.bash,
+ however, does not)
+
+With AFL++ 3.10, we introduced the following changes from previous behaviors:
+ * The '+' feature of the `-t` option now means to auto-calculate the timeout
+ with the value given being the maximum timeout. The original meaning of
+ "skipping timeouts instead of abort" is now inherent to the `-t` option.
+
+With AFL++ 3.00, we introduced changes that break some previous AFL and AFL++
+behaviors and defaults:
+ * There are no llvm_mode and gcc_plugin subdirectories anymore and there is
+ only one compiler: afl-cc. All previous compilers now symlink to this one.
+ All instrumentation source code is now in the `instrumentation/` folder.
+ * The gcc_plugin was replaced with a new version submitted by AdaCore that
+ supports more features. Thank you!
+ * QEMU mode got upgraded to QEMU 5.1, but to be able to build this a current
+ ninja build tool version and python3 setuptools are required. QEMU mode also
+ got new options like snapshotting, instrumenting specific shared libraries,
+ etc. Additionally QEMU 5.1 supports more CPU targets so this is really worth
+ it.
+ * When instrumenting targets, afl-cc will not supersede optimizations anymore
+ if any were given. This allows to fuzz targets build regularly like those
+ for debug or release versions.
+ * afl-fuzz:
+ * if neither `-M` or `-S` is specified, `-S default` is assumed, so more
+ fuzzers can easily be added later
+ * `-i` input directory option now descends into subdirectories. It also does
+ not fail on crashes and too large files, instead it skips them and uses
+ them for splicing mutations
+ * `-m` none is now the default, set memory limits (in MB) with, e.g., `-m
+ 250`
+ * deterministic fuzzing is now disabled by default (unless using `-M`) and
+ can be enabled with `-D`
+ * a caching of test cases can now be performed and can be modified by
+ editing config.h for `TESTCASE_CACHE` or by specifying the environment
+ variable `AFL_TESTCACHE_SIZE` (in MB). Good values are between 50-500
+ (default: 50).
+ * `-M` mains do not perform trimming
+ * `examples/` got renamed to `utils/`
+ * `libtokencap/`, `libdislocator/`, and `qdbi_mode/` were moved to `utils/`
+ * afl-cmin/afl-cmin.bash now search first in `PATH` and last in `AFL_PATH`
diff --git a/docs/resources/0_fuzzing_process_overview.drawio.svg b/docs/resources/0_fuzzing_process_overview.drawio.svg
new file mode 100644
index 00000000..fa596e21
--- /dev/null
+++ b/docs/resources/0_fuzzing_process_overview.drawio.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Do not edit this file with editors other than diagrams.net -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1052px" height="395px" viewBox="-0.5 -0.5 1052 395" content="&lt;mxfile host=&quot;Electron&quot; modified=&quot;2022-01-14T14:13:08.726Z&quot; agent=&quot;5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/16.1.2 Chrome/96.0.4664.55 Electron/16.0.5 Safari/537.36&quot; etag=&quot;qRJESCqlpAo3aneT4Tvx&quot; version=&quot;16.1.2&quot; type=&quot;device&quot;&gt;&lt;diagram id=&quot;OVZjTGZe8BRyvyoDS4zM&quot; name=&quot;0 - overview&quot;&gt;7V1bd5s4EP41eSSHqw2PaVI37Wl226a7afalRwbZqAFEQOT261cCiZuxTWKwSYLPyYkRYoRnPn2aGSRxpJ36D58iELoX2IHekSo7D0fa2ZFKP1OF/mMlj1mJOTWygmWEnKxIKQou0RPkhTIvTZAD40pFgrFHUFgttHEQQJtUykAU4ftqtQX2qq2GYAlXCi5t4K2WXiGHuLxUmVjFiXOIli5v2lSn2Yk5sG+WEU4C3t6Rqi3ST3baB0IW/6GxCxx8XyrSPh5ppxHGJPvmP5xCj+lWqI1o2vJRn31CykQ6d755ZyfauZQJmz3nkvwXRjAgLxYdml/+vby6u1a/6z/Azd3nqx8//+KXyHfAS6DQQvpbyaPQb6ohyITIR9qHexcReBkCm529p4iiZS7xPXqk0K8xifANPMUejmhJgANa7QNvA0YEPtRstuUXKbmaKXwh9iGJHul1XIqkKDL/ARy7Ghd8XwKCbPBCtwQCzdI5Ajn6lrn0QoX0C9dis0ajxdeH+2lo3F9HX9xI8/HTx++S+iyVKttVukCeV1MoiGzeDzVWAQeEHyp6ru52um0wy3p1q5ZZ0bYur2g7LysrO6eK7pVtbFc2DJwTRjOF+krKrYIbPiDyi59h369L388eSpXOHvnBbrqHToXaVjVf0qzRoFhRFkEPEHRXJcQmZfMWvmFEb68wrDE9tkof05xU7Dyxjg2lfL7aQIyTyIZcZpmA6s3U8bNFLgHREpIVuSlQch29HDvK9M12VGOi1jrqsegpB+yr+thXO+irmqpUOqvVS1etI+jAXbUFdF5pVzXVKtcOoqsqTcPqxCPMwQtBUFH85DZhDnCqMSlOVXZCKyh6+JDqTZyn35bs/7cIMjWygAD4IUDLQIimt5pJzypusHALR7TBwqlNubi1vmoBA521AuYx9hICT/Li3ZlkP+jQegPH23VwFdmqD5wtlS1i5l20rV+fLs7/mLfwfHqu/HdmzqyrO0mbrGj7B7xNUES1SwNtEN/spvxqJ6AhsJx+uNZnwEce08U59O4gQTZgxvFYp9XObKp+SK/6wDRMT3kn/ISPHMeDzZa1qVSAAnbdfruSVjOtZq52JGXSU0dqNu2qA/p3SBAOgNeJaR0Qu3ndd2NnVTEPZ2fpNzFmlmIZXvj5zzmQb1XpQlJWu/CKYZl3KcYmHBEXLxkMPhalNe+3qPMV45Db+A8k5JErGSQE12h2nZ3XQ4PaJnr8JXxpdsC8bPnYEIeFo50e7cnT3tWFNo0qFSi6fmzocvFRX+g114frbYK7c5sbgSdwNgJvIMAzzDo+jNyf2zlEaxLWN8DahPQjwPYHME3djokXp+uosL2iSwzI+wWTyCtxLLTKLBVoKgB0XcHPejQ9E7i7ATCz/SaflOMnM+2mrm91DendfOmmoS5LKwDm50VwcVTOVriEsMeTJ6xVdbZExE3mxzb26cHJ7GvoJTH7Wzmae3jO0hQEzCna1JmDbVa8SJ6eULD8jYLfDgyJe+zT4ExbSrYL7Rt6QiIulGxMvViwhBJepMf8onKGZIe0yilriiVVeCulpApokVEZw4l14cSkToJaUwpGMfcaUQzDsesXBD0TnZiqUCK6jcwyFKJTGkx/YKKDKZ/RuiSJy+wmlTK8XXDcBQ4QoVhjMlhbI8f1w3GmcTw9NMUJ/2JIONclEiGwZAO6HTGkxB0B+ycTmz4SycV2DOz+qZrfmDxwbKty4yOU3sDdSOIibh6H67bDtTDZ1uFaZOAGMlw3TlA6MI3ZUhIzDvMTNknTY5FJ1BmV/RMzHhOi04Ak6oPQ3udIbQhvNI9G1L0O1Ru73JAw7tQx7gPbpRaLpQWOOg69VyAv2hpR3w/q2RjeGvW9Mbs2PNQDKUqCgOEeLLwU5R1B/EfCJv2I38eu2klc6e5EB8lkij7yutzfAXcVcwjjw5iceq63q7X1do1BebtiSvVo6baWFpNVtlpaGdbzFnHfQxr95tTJy5+2oCBMCItswiSWkgDdJrCrLCS4YU5e2kAW34TsXuW8kdHn62Agm1r1qRIDGMmUASYlbclHAfLRU+r2eZ7APDVmZ0H9RdYCLMOdyR/B3g/YqSkGAPYBhvWAotvzoE0Y2FMG7grip5lcQeyvLgU/YDQPIQYRK1pGz7S1Zzpp65mag/JM396jlecZtvc5hta0uuZendQ67ZoJhi+YFtho4Mlo4P0aWBNub/cGbnz0f5Akwj6nfb5rME3bLUnuii3ew1S5gZtct3obIBr5wxr54w2DaVKT0fPWA+pB3I19L0LoJo5oVKC8GkY0Lys/VBSx6a6HlfuIoUh9sAz3HMYkfc5L2wmRB6N0agMKKDskPrWdqMc1302a5BLyLIlodMyT7LDbQG0Fn8kf++0jS9JMdm/e9e6Z7BoWFTQrelBkN8AlBfMS2RWUBtjuCBJON0noKvGbM1ohdnym0Qe7Kbp6aHozR3rbid7UlvR2sFkpm+56SPRml+gtBgEi1GZR54yWSx45rSdOo1Y4MKeJ+a0jp72Q0xqm2jXW0wfFaQOcfAz7jj1Ps5CzMFZuXRaOOu1mo2zhtSoJvl9i08SWm9uITbV6QnjT1jIH39DBQ3N2CmZLSOg/F0QBjGMYS/e0Scnz7vzsDIExoUblswQ7wf9VRKHLVB04RQKG6SK7h+7hPw7yWV8QS0gPN8i/i51wehzkG1aPbhpWBzLID3DtqCP52EGLx14G+ItUdGl8H6OWfqIWMWPnYISmrPqvn3PnsQSAtcaWtxv7bewA/fItiXuz3at5Itp3sl9vOaoow4odN6zd2Xl391m6qnOVwMeN3WvrNF/+ho7+0uPrnwPtjIsLEPAdbsZN//t6zVJ/wGjKoNeHgOG+uWU7kbd1+/f0ihcl3yiaI2DabgJdkyRrs6S+Z0815SlfD3KGAgjDNPbwzp/67uV9vfOHHhYvTcyqF2+m1D7+Dw==&lt;/diagram&gt;&lt;/mxfile&gt;" style="background-color: rgb(255, 255, 255);"><defs/><g><rect x="0" y="0" width="1051" height="394" fill="rgb(255, 255, 255)" stroke="none" pointer-events="all"/><rect x="802" y="9" width="240" height="210" rx="6.3" ry="6.3" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 1042 38.52 L 802 38.52" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><rect x="538" y="9.25" width="240" height="210" rx="6.3" ry="6.3" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 778 38.52 L 538 38.52" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><rect x="274" y="9.25" width="240" height="210" rx="6.3" ry="6.3" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><rect x="274" y="9.25" width="240" height="30" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 238px; height: 1px; padding-top: 24px; margin-left: 275px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;"><span style="font-size: 14px">Prepare campaign</span></div></div></div></foreignObject><text x="394" y="28" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="14px" text-anchor="middle" font-weight="bold">Prepare campaign</text></switch></g><rect x="8" y="9" width="240" height="375" rx="7.2" ry="7.2" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><rect x="708" y="354" width="160" height="30" rx="4.5" ry="4.5" fill="none" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 369px; margin-left: 709px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Required task</div></div></div></foreignObject><text x="788" y="373" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="14px" text-anchor="middle">Required task</text></switch></g><rect x="882" y="354" width="160" height="30" rx="4.5" ry="4.5" fill="none" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 369px; margin-left: 883px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Optional task</div></div></div></foreignObject><text x="962" y="373" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="14px" text-anchor="middle">Optional task</text></switch></g><path d="M 248 113.54 L 267.63 113.54" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 272.88 113.54 L 265.88 117.04 L 267.63 113.54 L 265.88 110.04 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 514 114.25 L 531.63 114.25" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 536.88 114.25 L 529.88 117.75 L 531.63 114.25 L 529.88 110.75 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 778 114.25 L 795.63 114.29" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 800.88 114.3 L 793.87 117.78 L 795.63 114.29 L 793.89 110.78 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 922 142.25 L 922 162.88" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 922 168.13 L 918.5 161.13 L 922 162.88 L 925.5 161.13 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><rect x="832" y="112.25" width="180" height="30" rx="4.5" ry="4.5" fill="none" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 127px; margin-left: 833px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#g-checking-the-coverage-of-the-fuzzing" style="font-size: 14px">Check coverage</a></div></div></div></foreignObject><text x="922" y="131" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="14px" text-anchor="middle">Check coverage</text></switch></g><path d="M 922 84.75 L 922 104.8 L 922 92.3 L 922 105.88" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 922 111.13 L 918.5 104.13 L 922 105.88 L 925.5 104.13 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><rect x="832" y="54.75" width="180" height="30" rx="4.5" ry="4.5" fill="none" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 70px; margin-left: 833px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#e-the-status-of-the-fuzz-campaign" style="font-size: 14px">Monitor status</a></div></div></div></foreignObject><text x="922" y="74" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="14px" text-anchor="middle">Monitor status</text></switch></g><rect x="832" y="169.25" width="180" height="30" rx="4.5" ry="4.5" fill="none" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 184px; margin-left: 833px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#4-triaging-crashes" style="font-size: 14px">Triage crashes</a></div></div></div></foreignObject><text x="922" y="188" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="14px" text-anchor="middle">Triage crashes</text></switch></g><path d="M 658 141.75 L 658 161.8 L 658 149.8 L 658 163.38" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 658 168.63 L 654.5 161.63 L 658 163.38 L 661.5 161.63 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><rect x="568" y="111.75" width="180" height="30" rx="4.5" ry="4.5" fill="none" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 127px; margin-left: 569px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#c-using-multiple-cores" style="font-size: 14px">Use multiple cores</a></div></div></div></foreignObject><text x="658" y="131" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="14px" text-anchor="middle">Use multiple cores</text></switch></g><rect x="568" y="169.75" width="180" height="31" rx="4.65" ry="4.65" fill="none" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 185px; margin-left: 569px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#d-using-multiple-machines-for-fuzzing" style="font-size: 14px">Use multiple machines</a></div></div></div></foreignObject><text x="658" y="189" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="14px" text-anchor="middle">Use multiple machines</text></switch></g><rect x="568" y="51.75" width="180" height="30" rx="4.5" ry="4.5" fill="none" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 67px; margin-left: 569px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#a-running-afl-fuzz" style="font-size: 14px">Run <font style="font-size: 14px">afl-fuzz</font></a></div></div></div></foreignObject><text x="658" y="71" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="14px" text-anchor="middle">Run afl-fuzz</text></switch></g><path d="M 658 81.75 L 658 101.8 L 658 91.8 L 658 105.38" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 658 110.63 L 654.5 103.63 L 658 105.38 L 661.5 103.63 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 394 141.75 L 394 161.8 L 394 150.8 L 394 164.38" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 394 169.63 L 390.5 162.63 L 394 164.38 L 397.5 162.63 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><rect x="304" y="111.75" width="180" height="30" rx="4.5" ry="4.5" fill="none" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 127px; margin-left: 305px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#b-making-the-input-corpus-unique" style="font-size: 14px">Make input corpus unique</a></div></div></div></foreignObject><text x="394" y="131" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="14px" text-anchor="middle">Make input corpus unique</text></switch></g><rect x="304" y="170.75" width="180" height="30" rx="4.5" ry="4.5" fill="none" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 186px; margin-left: 305px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#c-minimizing-all-corpus-files" style="font-size: 14px">Minimize corpus file</a></div></div></div></foreignObject><text x="394" y="190" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="14px" text-anchor="middle">Minimize corpus file</text></switch></g><rect x="304" y="51.75" width="180" height="30" rx="4.5" ry="4.5" fill="none" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 67px; margin-left: 305px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#a-collecting-inputs" style="font-size: 14px">Collect inputs</a></div></div></div></foreignObject><text x="394" y="71" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="14px" text-anchor="middle">Collect inputs</text></switch></g><path d="M 394 81.75 L 394 101.8 L 394 91.8 L 394 105.38" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 394 110.63 L 390.5 103.63 L 394 105.38 L 397.5 103.63 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 128 82 L 128 104.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 128 109.88 L 124.5 102.88 L 128 104.63 L 131.5 102.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="38" y="52" width="180" height="30" rx="4.5" ry="4.5" fill="none" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 67px; margin-left: 39px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#a-selecting-the-best-afl-compiler-for-instrumenting-the-target" style="font-size: 14px">Select compiler</a></div></div></div></foreignObject><text x="128" y="71" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="14px" text-anchor="middle">Select compiler</text></switch></g><path d="M 128 141 L 128 163.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 128 168.88 L 124.5 161.88 L 128 163.63 L 131.5 161.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="38" y="111" width="180" height="30" rx="4.5" ry="4.5" fill="none" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 126px; margin-left: 39px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#b-selecting-instrumentation-options" style="font-size: 14px">Select options</a></div></div></div></foreignObject><text x="128" y="130" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="14px" text-anchor="middle">Select options</text></switch></g><path d="M 128 200 L 128 222.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 128 227.88 L 124.5 220.88 L 128 222.63 L 131.5 220.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="38" y="170" width="180" height="30" rx="4.5" ry="4.5" fill="none" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 185px; margin-left: 39px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#c-selecting-sanitizers" style="font-size: 14px">Select sanitizer</a></div></div></div></foreignObject><text x="128" y="189" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="14px" text-anchor="middle">Select sanitizer</text></switch></g><path d="M 128 312 L 128 330.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 128 335.88 L 124.5 328.88 L 128 330.63 L 131.5 328.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="38" y="283" width="180" height="29" rx="4.35" ry="4.35" fill="none" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 298px; margin-left: 39px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#e-instrumenting-the-target" style="font-size: 14px">Compile target source code</a></div></div></div></foreignObject><text x="128" y="302" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="14px" text-anchor="middle">Compile target source code</text></switch></g><rect x="38" y="337" width="180" height="30" rx="4.5" ry="4.5" fill="none" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 352px; margin-left: 39px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#g-libfuzzer-fuzzer-harnesses-with-llvmfuzzertestoneinput" style="font-size: 14px">Write and compile harness</a></div></div></div></foreignObject><text x="128" y="356" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="14px" text-anchor="middle">Write and compile harness</text></switch></g><path d="M 128 259 L 128 276.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 128 281.88 L 124.5 274.88 L 128 276.63 L 131.5 274.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="38" y="229" width="180" height="30" rx="4.5" ry="4.5" fill="none" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 244px; margin-left: 39px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#d-modifying-the-target" style="font-size: 14px">Modify target</a></div></div></div></foreignObject><text x="128" y="248" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="14px" text-anchor="middle">Modify target</text></switch></g><rect x="8" y="9" width="240" height="30" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 238px; height: 1px; padding-top: 24px; margin-left: 9px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">Instrument target</div></div></div></foreignObject><text x="128" y="28" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="14px" text-anchor="middle" font-weight="bold">Instrument target</text></switch></g><rect x="538" y="9.25" width="240" height="30" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 238px; height: 1px; padding-top: 24px; margin-left: 539px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;"><span style="font-size: 14px">Fuzz target</span></div></div></div></foreignObject><text x="658" y="28" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="14px" text-anchor="middle" font-weight="bold">Fuzz target</text></switch></g><rect x="802" y="9" width="240" height="30" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 238px; height: 1px; padding-top: 24px; margin-left: 803px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;"><span style="font-size: 14px">Manage campaign</span></div></div></div></foreignObject><text x="922" y="28" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="14px" text-anchor="middle" font-weight="bold">Manage campaign</text></switch></g><path d="M 248 39 L 8 39" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 514 38.52 L 274 38.52" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Viewer does not support full SVG 1.1</text></a></switch></svg> \ No newline at end of file
diff --git a/docs/resources/1_instrument_target.drawio.svg b/docs/resources/1_instrument_target.drawio.svg
new file mode 100644
index 00000000..af6ac397
--- /dev/null
+++ b/docs/resources/1_instrument_target.drawio.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Do not edit this file with editors other than diagrams.net -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1041px" height="301px" viewBox="-0.5 -0.5 1041 301" content="&lt;mxfile host=&quot;Electron&quot; modified=&quot;2022-01-14T14:14:06.979Z&quot; agent=&quot;5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/16.1.2 Chrome/96.0.4664.55 Electron/16.0.5 Safari/537.36&quot; etag=&quot;SKxyD_wE9pHQQvyJq3sV&quot; version=&quot;16.1.2&quot; type=&quot;device&quot;&gt;&lt;diagram name=&quot;1 - instrument target&quot; id=&quot;y32N0Cs56pMhbVcY_pYT&quot;&gt;7Vttd6I4FP41nrPzgR5efP2oTm27o213nZlt90tPgADZBsKE0Gp//SYQRISK2mo9HT19ITfJDbnPzcPNDTaMoT+7oCD0JsSGuKGr9qxhfG3out7qafyfkMxTSbfTSgUuRXYq0nLBFL1AKVSlNEY2jAoNGSGYobAotEgQQIsVZIBS8lxs5hBcHDUELiwJphbAZek/yGaelGrtXl5xCZHryaG7eietMIH16FISB3K8hm44ySet9kGmS0408oBNnpdExnnDGFJCWHrlz4YQC9tmZruY3/9g19AaOffjqKOi7o19paTKRtt0WcyQwoDtrFo5DxXj7urbX5cPF1SfKt+mPVN2UZ8AjmFmhWSubJ7ZN7EQFErUhjF49hCD0xBYovaZexSXeczHvKTxy4hR8giHBBPKJQEJeLOBHANSBmcrmNXMSFuYmbsvJD5kdM77SS0KB1lOYF70yeclR1CbUugtOYGhSiGQ3ucutOcm5BfSiluApVdYtI2ZsE0IAn7tiuurgFsq9sXs+XIB1IUsa8ZHXW75NjwchPEKGg4J2FSqexUyQC250jVdFM2I4JjB/kKsLm5tMxAr8H8d1049rHo1qnsC1SiB+jf8FSPKYRDwRY9rUNK2XTUN4Z3iI8EaAR9hYYlLiJ8gQxYQiGDkBlxmcdtD3msgzMurcF9W+Mi2Max2AU7FDKBA9EuAXEF7b7g2280CrnqnYr22DwlsswTsTcgQCQB+F2BtEHmLtr8LynpPPTKUWyUUoc1jCFkklHnEFZif59JBkWbzNmNCQgnof5CxuTQpiBk54KJ+E5Zi8muRpBADhp6KAVYVKrLrLUHJg+xV/m72zlpFLRGJqQVlx+WopaTLqNWVPj9LuhJXWcxqd+/p1sdIB3Cn40a81ymj1G7vCHmvWa9sz5hnEccnoowj9xi9rW7kLu+GsHZC+LAIG1rvsAh/CE/DGWJ3ojt/SqWl+6WarzOpOSnMs0LAZ7rUSRTvl+vybkkp6/dbe1One1hvKu8BTwRyWMibvQM/IponAvnE3tRe0bHvkPJDdqG7eNNxbzU6RjGJpHWNHfcZtZr27RHtikdKmgQGIjVCoZNI279iccbAYWXiTKUvbkQfuYh5sXlmEZ8X+qNxiONI/JZKJiamSCozYHKf0kc2sYTYiV9eUOA+oODBhiHzznybEwBQIoihxXiNwjyomDBiCnCwwscJEYZUcQhV0CJ9nbVb5LDlvWbp62mirSGOf9L+S2lukOe4U5lJX5eMv99wLT6xYbnuj6oUu4VB4PJR5P9B8qOKsH/waqq9rOVLTdu1tzz+OXmPezbOuoe76Yvh8OF2/OPi6nq7W3cti3doHfRGea/huH998fqdEu6b9EuJeD88O88EfW+XtG1tTcVb5Gw1rVV8OrYqcrbdipytvreDNK1zfOxoLrFjzoFAnBgoJDk4iNZQYN5iJwYs61H5rcHARoIrVBKUu3DvX6ZeYZz6cYY3k9vhzc+q1RRg4TSS17gY+MKN07+i4vvNl41G8MMxcfc4gETpScx+BaeKUZNHy3AxrrjKWfCN5LH3E6BjY5LV5O3HE4l+HDv3N0XVaUy7rp3Mhsg4bI013j1OfxvLV52ufDDLW0ssH4EAMQ4bXUfsi0a7UvsEzM4SCodFbSqbh0IEgeWVe6FAIMJ/5TQE1XOqBAkxbET1/Wn/uoKeR1eV8nGldFIp/V4p/TFIxCdC3eZlGOPYCDXL4x/TmoVb7EmHaTyUs+WCX0WslO8jtl3F9XpLAZuaRmhmjLAtms8jBv0NFy/3Rwe5Ma3Y9wwn4LFCPIFRMuhADjdNhyu1S3ZNpWVaszCLq/h3WJmGdmwrUy+/z/T5Qp3FW8Z1oU7GU0cS6mSKj4k2bcUnNnLmdZQ5SVo1Kt5V3Y4hKQQMlqIWD9AARlG5vTlPagNBVg4RAZHJHS+JjKDjIAvBwJqfnQKKrWirpX8gbbXvx6Ydxrfqv+r1n8/+3eQFKUrVwlhlrcDuiy8L5NarfPRs/1pyLTksmaVVYZVM9tZjjVIGbsPz7fqDrlVF73eqUQmmfgKzlATZGcvVNykPjOUmmZPPjuXq/mtnLFs1C3zPWG4SGn52LFcffTtjadQs8D1j2TphWdp97YylVrPAd8aSF/NvB6bN869gGuf/Aw==&lt;/diagram&gt;&lt;/mxfile&gt;" style="background-color: rgb(255, 255, 255);"><defs/><g><rect x="0" y="0" width="1040" height="300" fill="rgb(255, 255, 255)" stroke="none" pointer-events="all"/><rect x="400" y="0" width="240" height="30" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 238px; height: 1px; padding-top: 15px; margin-left: 401px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;"><span>Instrument target</span></div></div></div></foreignObject><text x="520" y="19" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle" font-weight="bold">Instrument target</text></switch></g><rect x="696" y="260" width="160" height="30" rx="3.6" ry="3.6" fill="none" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 275px; margin-left: 697px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Required task</div></div></div></foreignObject><text x="776" y="279" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Required task</text></switch></g><rect x="870" y="260" width="160" height="30" rx="3.6" ry="3.6" fill="none" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 275px; margin-left: 871px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Optional task</div></div></div></foreignObject><text x="950" y="279" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Optional task</text></switch></g><path d="M 400 139.5 L 423.63 139.5" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 428.88 139.5 L 421.88 143 L 423.63 139.5 L 421.88 136 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 190 139.66 L 213.63 139.66" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 218.88 139.66 L 211.88 143.16 L 213.63 139.66 L 211.88 136.16 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="10" y="40" width="180" height="200" rx="9" ry="9" fill="none" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 47px; margin-left: 11px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#a-selecting-the-best-afl-compiler-for-instrumenting-the-target">Select compiler</a><br /><br />LTO mode<br />(<span>clang/clang++ 11+</span><span>)</span><br /><br />LLVM mode<br />(<span>clang/clang++ 3.8+</span><span>)</span><br /><br />GCC_PLUGIN mode<br />(<span>gcc 5+</span><span>)</span><br /><br />GCC/CLANG mode<br />(other)</div></div></div></foreignObject><text x="100" y="59" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Select compiler...</text></switch></g><rect x="220" y="40" width="180" height="200" rx="9" ry="9" fill="none" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 47px; margin-left: 221px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#b-selecting-instrumentation-options">Select options</a><br /><br />Select options depending on<br />the compiler:<br /><br />COMPCOV<br />(only LLVM &amp; LTO)<br /><br />CmpLog<br />(only LLVM &amp; LTO)<br /><br />selective instrumentation<br />(LTO, LLVM, GCC_PLUGIN)</div></div></div></foreignObject><text x="310" y="59" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Select options...</text></switch></g><path d="M 610 140 L 630 140 L 620 140 L 633.63 140" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 638.88 140 L 631.88 143.5 L 633.63 140 L 631.88 136.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="430" y="40" width="180" height="200" rx="9" ry="9" fill="none" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 47px; margin-left: 431px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#c-selecting-sanitizers">Select sanitizer</a><br /><br />Max. one sanitizer type each<br />in a fuzzing campaign:<br /><br />ASAN<br />CFISAN<br />LSAN<br />MSAN<br />TSAN<br />UBSAN</div></div></div></foreignObject><text x="520" y="59" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Select sanitizer...</text></switch></g><rect x="850" y="40" width="180" height="200" rx="9" ry="9" fill="none" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 47px; margin-left: 851px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#e-instrumenting-the-target">Compile target source code</a><br /><br />Compile target source code depending on the build system:<br /><br />configure<br />CMake<br />Meson Build System<br />other</div></div></div></foreignObject><text x="940" y="59" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Compile target source code...</text></switch></g><path d="M 820 140 L 840 140 L 830 140 L 843.63 140" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 848.88 140 L 841.88 143.5 L 843.63 140 L 841.88 136.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="640" y="40" width="180" height="200" rx="9" ry="9" fill="none" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 47px; margin-left: 641px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#d-modifying-the-target">Modify target</a><br /><br />Create a fuzzing harness<br />by hand for better efficiency.</div></div></div></foreignObject><text x="730" y="59" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Modify target...</text></switch></g><path d="M 10 68 L 190 68" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 220 68 L 400 68" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 430 68 L 610 68" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 640 68 L 820 68" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 850 68 L 1030 68" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Viewer does not support full SVG 1.1</text></a></switch></svg> \ No newline at end of file
diff --git a/docs/resources/2_prepare_campaign.drawio.svg b/docs/resources/2_prepare_campaign.drawio.svg
new file mode 100644
index 00000000..f4de62b9
--- /dev/null
+++ b/docs/resources/2_prepare_campaign.drawio.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Do not edit this file with editors other than diagrams.net -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="621px" height="182px" viewBox="-0.5 -0.5 621 182" content="&lt;mxfile host=&quot;Electron&quot; modified=&quot;2022-01-14T14:14:35.585Z&quot; agent=&quot;5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/16.1.2 Chrome/96.0.4664.55 Electron/16.0.5 Safari/537.36&quot; etag=&quot;WtgO4cGDnPsLQol1HfuR&quot; version=&quot;16.1.2&quot; type=&quot;device&quot;&gt;&lt;diagram name=&quot;2 - prepare campaign&quot; id=&quot;dejA2OcQ2wkmtmh7vij0&quot;&gt;7Vpbd9o4EP41PJrjC2DzCATaZJM0p9lLuy89wha2FtlyZDlAfv1KtnzD5pYAoW04J4k1Go2k+WY+jRxaxshffqIg9O6IA3FLV51ly7hq6bre7Wv8j5CsUolldlOBS5GTirRC8IheoBSqUhojB0YVRUYIZiisCm0SBNBmFRmglCyqajOCq7OGwIU1waMNcF36D3KYJ6Var190fIbI9eTUlm6mHVNgz11K4kDO19KNWfJJu32Q2ZIbjTzgkEVJZIxbxogSwtInfzmCWPg2c9sf99NvNzd31+x6aF4/9uhosTCV1NjkkCH5DikM2KtNQ4eM7a4+XCjKv3B+o+pWfC+HqM8AxzDzQrJXtsr8m3gICiNqyxguPMTgYwhs0bvgEcVlHvMxb2n8MWKUzOGIYEK5JCABVxvKOSBlcLmG2Y4dabmbefhC4kNGV3yctKJwkOUGVtWYXBSB0Mvg80oxoFlSCGTwubnxwoP8QTrxAKzMBof2MBOuCUHAn13x/ECh2LvICuCHALlBpsUnLSu+DY0ZwngNixkJ2KM0txEwQG2Z5x0xC5hGBMcMDnKxmi9tPwgb0N+Mat/cCareaQDVOBWm/RqmX+FTjCiHgXMdiOZbUNIOzRnOQmrykWBNgI+w8MRniJ8hQzYQiGARMsaVzX0P+aihcC/vwgPZ4SPHwbA5BDgRM4ACMe60QFpWpwpkt45knsFnQVKr892XkCESAHwUKB0QebnuL4urqakXhmt2pJdwgw6vEmSTUOYRV6A8LqTDKpUWOreEhBLC/yBjK8l5IGbkjIl7GHoRiakNt3nIkqUZoC7cZlCXbCf8tzUaKMSAoedqFXZ8ZK2NByoQ0UXhLJH2nmJRh3F4mKg7B2JWfeIi5sXTtk183hhMbkMcR+Kn1ppiMhVHLwNT7n194hBbiGfxywsK3B8o+OHAkHltn1O+MVV8MOdihXlQQUEYM8UmNIwjJQ7QE19mvprsGL8Dc3HYJ7pJKSy0+UOun539oDj4U9mUHiL5KxLTZHIRhaKiBjIyslWNeLAgHn26eg8X9cWCGVZsH5VLktRSNqtKgtpm2hdOnEzk9D6sWdQ+5kmLnE6VQ5so1Gqg0JMVrnq9ynn3RLMVHobIR6JLARhnacZh5DfOepalyrCcYUL1AvOL7Z9fyWY/0uvAEsW4sPTqdhvS6/wly5GriszLu6sK66KqCqPpvcc7kx3g7IYxtJkguyT5GyhulKpk9BAdj9oyiYOeK1GZrYBnHlMkD3A/qBjO2Lb1ifTnvwUL+oTCBkLbtALhKLGInW9A3ulufWlcp+X3r0shO+NduO2CrmPHozk59IGgpNbY9I5M761hmVK3HLYGZ76ONyBsfCB8XoQNrX9ehDvvgTBcIvZNDG93Zet7qedqKS0njVXWCPhOS4NE83u5rxiWtLJxv3U0mdZ5o+kyyt/fGfJO/8xHRO+DQH7haOqt2UivgCeLpk7/Z4mmCwPONNb+CWcZe9HAKywdLwS0ry/mxCbR+M+/V19ue9HsKX7Y57sKMHAG4islrfxOVgKzGg1Hhql01+o2XLUy2VvRrN319jzHdyf0uqETg6l/gFl7SWma7X75Y74S2u56jGy3e2KkOx9I1/7b8+qsNXsnylreLL7JlqoXXxc0xv8D&lt;/diagram&gt;&lt;/mxfile&gt;" style="background-color: rgb(255, 255, 255);"><defs/><g><rect x="0" y="0" width="620" height="180" fill="rgb(255, 255, 255)" stroke="none" pointer-events="all"/><rect x="190" y="0" width="240" height="30" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 238px; height: 1px; padding-top: 15px; margin-left: 191px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;"><span>Prepare campaign</span></div></div></div></foreignObject><text x="310" y="19" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle" font-weight="bold">Prepare campaign</text></switch></g><rect x="276" y="140" width="160" height="30" rx="4.5" ry="4.5" fill="none" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 155px; margin-left: 277px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Required task</div></div></div></foreignObject><text x="356" y="159" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Required task</text></switch></g><rect x="450" y="140" width="160" height="30" rx="4.5" ry="4.5" fill="none" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 155px; margin-left: 451px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Optional task</div></div></div></foreignObject><text x="530" y="159" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Optional task</text></switch></g><path d="M 400 80 L 420 80 L 410 80 L 423.63 80" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 428.88 80 L 421.88 83.5 L 423.63 80 L 421.88 76.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><rect x="220" y="40" width="180" height="80" rx="5.6" ry="5.6" fill="none" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 47px; margin-left: 221px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#b-making-the-input-corpus-unique">Make input corpus unique</a><br /><br /><br />Use <font face="Courier New">afl-cmin</font> on input corpus.</div></div></div></foreignObject><text x="310" y="59" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Make input corpus unique...</text></switch></g><rect x="430" y="40" width="180" height="80" rx="5.6" ry="5.6" fill="none" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 47px; margin-left: 431px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#c-minimizing-all-corpus-files">Minimize corpus file</a><br /><br /><br />Use <font face="Courier New">afl-tmin</font> on input files.</div></div></div></foreignObject><text x="520" y="59" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Minimize corpus file...</text></switch></g><path d="M 190 80 L 210 80 L 200 80 L 213.63 80" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 218.88 80 L 211.88 83.5 L 213.63 80 L 211.88 76.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="10" y="40" width="180" height="80" rx="5.6" ry="5.6" fill="none" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 47px; margin-left: 11px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#a-collecting-inputs">Collect inputs</a><br /><br /><br /><div style="text-align: left">Collect one or more input files.<br /></div></div></div></div></foreignObject><text x="100" y="59" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Collect inputs...</text></switch></g><path d="M 10 68 L 190 68" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 430 68 L 610 68" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 220 68 L 400 68" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Viewer does not support full SVG 1.1</text></a></switch></svg> \ No newline at end of file
diff --git a/docs/resources/3_fuzz_target.drawio.svg b/docs/resources/3_fuzz_target.drawio.svg
new file mode 100644
index 00000000..de5982ed
--- /dev/null
+++ b/docs/resources/3_fuzz_target.drawio.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Do not edit this file with editors other than diagrams.net -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="621px" height="291px" viewBox="-0.5 -0.5 621 291" content="&lt;mxfile host=&quot;Electron&quot; modified=&quot;2022-01-14T14:14:58.562Z&quot; agent=&quot;5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/16.1.2 Chrome/96.0.4664.55 Electron/16.0.5 Safari/537.36&quot; etag=&quot;b_nKMc5Gb5mpJqUsLJLV&quot; version=&quot;16.1.2&quot; type=&quot;device&quot;&gt;&lt;diagram name=&quot;3 - fuzz target&quot; id=&quot;5ivncerJTzjQBJIEBaCC&quot;&gt;7Vpbc6s4DP41eUwnQK6P6SWns9s2Pc3p7HZfOg4I8InB1Jjcfv3aYCCEpLk0TXPaZqYFy5KM9UmykakYF970B0OBe0stIBW9Zk0rxmVF1/VGRxMXSZkllHarkRAchq2EpOWEAZ6DItYUNcIWhAVGTinhOCgSTer7YPICDTFGJ0U2m5LiqAFyoEQYmIiUqf9gi7uKqjU7ecc1YMdVQ7f1VtIxRObIYTTy1XgV3bDjX9LtoVSXmmjoIotOFkjGVcW4YJTy5M6bXgCRtk3NdjHtPBlR6/y+/0JHz89Ncq5Nq4my3i4i2QwZ+Hxv1VcjZ3p320f9l+rE7A5uXh69mhKpjRGJILVCPFc+S+0bWwikklrFOJ+4mMMgQKbsnQiPEjSXe0S0NHEbckZHcEEJZYLiU1+wnasxgHGYLmG2YUZaZmbhvkA94Gwm5JSWqgBZTWBW9MlJ7gjNFD53wQf0jiIi5XxOpjy3oLhRRtwBK6Nk0F40n8uYQMwB/jbr2piQJdva1OcDpW4tAIiZKm7rchQ0DCmJOHQzci1DaTtIVqC5HqVOayNIen0FSMZ7YVQvYfQALxFmAgaJUzh6BSVt1xgQWaUW/xRYPeRhIi1xDWQMHJtIIkKw4wuaKWwPQupcmld0ka7q8LBlEVjtAiKxcoR9Kfe+QLbb9QKQerOMZBaRR0GyUUKyH3BMfUQOgqSFQjfj/bSwtrTaicHaLMEGlljzVZMy7lJHgnyVU8+LiTTnuaE0UAj+Bs5nKuOhiNMjhu1u4MnZvgodA4I4Hhd3QKtgUKL3FItxFyBfXjeb9bNGUUtII2aCElzcVpR0GRt1JWtfSVfsG9ms9neX1uZNzBH858QgLq26b4C4U/9oiNvfGeG47pItAhuc5VAAd74BPi7AhtY5KsDpJuO4CMMU83+luMhXSetpoedyqjTHjVna8MVMF4Rk82mxLxeLW6ncl/amVvu43pRucz92zf/KkNeXayjvDfmHIPydQI7kTc0lHe+8odSMP8WbTgy4llEsAmltY8+3io2aDucCP3+i0Gmi39FVv2WM768H9uxmZe27SbiMKlnoYGDH1OZLJCv8AkYuTzS68jn0noO5Gw3PTOqJRrd3E5AolH+l1pDQobiEHA2FD+k9i5qSbEfzOfadZ+w/WxBw98yzRMCb1SgU1KoXyfMTAlWTMgjzZxB3jrw+hkJVLeWqyMOVhI8kXD2Ucqa0IVtPURVqWXbK69S1iZhhmXdhTOyLSfkmJEbZPEw/1u8h7IuLnL9MWK9IyqQnOZPqXG6EC+FgWMjqtTuYlG1Tvc1GWadZ2j9Wvu5RB2BS30JxwCRP+vok933UQex/DCOfa2sf7qQrmFxmvm3Kl/kZRGPnpLbLYcNSqaKxopbZXlHL1A5xIrQyzazaqX5wmrGW04yHTFdgFVZtyqpKZousk4odOfFkw+6fd4Tvxf9DYON3TkPVil6/7g9+3XVvrz5LStps9MHMN4WmIfAJgDQ8dyGzd3j2ndV2O6IxTi2r6aeX1VCVRb4v8xqySZzFyu79EElfLMZI0rMg85rP75riHmTY2tiJGKRBkLP0Uq5wFnLwZLhSGZk04NiLzzDDAMA62yrgAjCxPcsiDftBxJOdYSBtWbMwA5NTNttKXdeypNvEcmZ8pLql4CDO4VLQA4/GXkywh/kbQ/4rRLmmNT4wzMePxn+o+RdmrcbTD/vXuGOP3W2+DwLf6srPuHLzLcBWfGM+8KvsglkaK6yS0t76xluCZcta5+aix7Kiw73wrgRzm5rpZwdz+f1gbyyXj9CPjOWq9ferYbm8K9oby8aGAD8clv7T0EBzw7k0m2z490sfRvNu9Y85GdvNTRLzb95Dqhe/jXyHK22uWRJFM/+aNwE3/2TauPof&lt;/diagram&gt;&lt;/mxfile&gt;" style="background-color: rgb(255, 255, 255);"><defs/><g><rect x="0" y="0" width="620" height="290" fill="rgb(255, 255, 255)" stroke="none" pointer-events="all"/><rect x="190" y="0" width="240" height="30" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 238px; height: 1px; padding-top: 15px; margin-left: 191px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">Fuzz target</div></div></div></foreignObject><text x="310" y="19" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle" font-weight="bold">Fuzz target</text></switch></g><rect x="276" y="250" width="160" height="30" rx="4.5" ry="4.5" fill="none" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 265px; margin-left: 277px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Required task</div></div></div></foreignObject><text x="356" y="269" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Required task</text></switch></g><rect x="450" y="250" width="160" height="30" rx="4.5" ry="4.5" fill="none" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 265px; margin-left: 451px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Optional task</div></div></div></foreignObject><text x="530" y="269" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Optional task</text></switch></g><path d="M 400 154.5 L 423.63 154.5" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 428.88 154.5 L 421.88 158 L 423.63 154.5 L 421.88 151 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 190 154.5 L 213.63 154.5" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 218.88 154.5 L 211.88 158 L 213.63 154.5 L 211.88 151 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="220" y="40" width="180" height="190" rx="9" ry="9" fill="none" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 47px; margin-left: 221px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#c-using-multiple-cores">Use multiple cores</a><br /><br />Fuzz one target with<br />multiple instances:<br /><br />One main fuzzer:<br /><font face="Courier New">-M main<br /></font><br />Secondary fuzzers:<br /><font face="Courier New">-S variant1</font></div></div></div></foreignObject><text x="310" y="59" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Use multiple cores...</text></switch></g><rect x="430" y="40" width="180" height="190" rx="9" ry="9" fill="none" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 47px; margin-left: 431px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#d-using-multiple-machines-for-fuzzing">Use multiple machines</a><br /><br />Fuzz one target with<br />multiple machines:<br /><br />One main fuzzer per server:<br /><font face="Courier New">-M main-$HOSTNAME<br /></font><br />Secondary fuzzers:<br /><font face="Courier New">-S variant1</font><br /><br />Sync between the servers.</div></div></div></foreignObject><text x="520" y="59" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Use multiple machines...</text></switch></g><rect x="10" y="40" width="180" height="190" rx="9" ry="9" fill="none" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 47px; margin-left: 11px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#a-running-afl-fuzz">Run <font>afl-fuzz</font></a><br /><br />Reconfigure the<br />system for optimal speed.<br /><br />Specify the input corpus directory.<br /><br />Add a dictionary.<br /><br />Set a memory limit.</div></div></div></foreignObject><text x="100" y="59" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Run afl-fuzz...</text></switch></g><path d="M 10 68 L 190 68" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 220 68 L 400 68" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 430 68 L 610 68" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Viewer does not support full SVG 1.1</text></a></switch></svg> \ No newline at end of file
diff --git a/docs/resources/4_manage_campaign.drawio.svg b/docs/resources/4_manage_campaign.drawio.svg
new file mode 100644
index 00000000..041a2a23
--- /dev/null
+++ b/docs/resources/4_manage_campaign.drawio.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Do not edit this file with editors other than diagrams.net -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="831px" height="278px" viewBox="-0.5 -0.5 831 278" content="&lt;mxfile host=&quot;Electron&quot; modified=&quot;2022-01-14T14:15:39.430Z&quot; agent=&quot;5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/16.1.2 Chrome/96.0.4664.55 Electron/16.0.5 Safari/537.36&quot; etag=&quot;IB5LFGdn0HXW6HpYxs12&quot; version=&quot;16.1.2&quot; type=&quot;device&quot;&gt;&lt;diagram name=&quot;4 - manage campaign&quot; id=&quot;Y3go6SgXnJCvyWpIHdu5&quot;&gt;7VvZdptIEP0aPeKDQGh5tGQrniSOJ6M4k8xLTgsaaLuhSdOKlq+fahaxarEW5MnY59iIoreqW3Wr1YVb+shbvOMocO+ZhWlLU61FS79paZpmDNpwkZJlLOn3jFjgcGLFonYmmJAVToRqIp0RC4eFhoIxKkhQFJrM97EpCjLEOZsXm9mMFmcNkIMrgomJaFX6N7GEm0jb3UH24A4Tx02m7mu9+MEUmc8OZzM/ma+l6Xb0Ez/2UDpWomjoIovNcyL9tqWPOGMi/uQtRphK26Zm8+n4/bvP5EH8pU+6Whj0R//YSjzY+CVd1hpy7IuDh6ajh+Gd0D+MbTT//D58uOZfB0kX9ReiM5xaIdJVLFP7RhbCchC1pQ/nLhF4EiBTPp2DR4HMFR6FuzZ8DAVnz3jEKOMg8ZkPzYbJHJgLvChhtkOj9trM4L6YeVjwJfRLRlEA5ESBZdEn55kj9PVE5uZ8QOslPoAS53PWg2cWhA+JEesN+hR+Xen88W7xKaCOPlkt58NHRa8xaJfCtEMk18CxHUm7P2fSbcB0QobJtZxUGztEuLPplck8uLkefwzoLJS/lbspZVO4hAJNASZtbDFTiu3ZakV85wfxf1g4EO6VZ4FTO4rpYvMZHijCxYrJAAmICYXZ0X3SKVsTfHLkdSR7RYEbd0gVgYlQ2iaVTflmyWMIXdVUbjNAHMI89qBs1hGbcYKhk/oJz6uLQTZVQpfNPfC4bB3xYOnEwDuSj7CorsEE2iuoAh6OBAkFMcOrRpWAJWxUoIs8GU/+NJQXqU1R4mAfli/kSpAPf+6+3H+EC8cB46LcmPk5ha+2hHV7d1hbKHTXbYsxDg6mRj+JWcbII1SG4x2mvzDYF0nFKXF8kJkQ7mAefSjJAB7R6+SBYHJGm1Ba4g7IGgIRX3aK+AdxM0lBxppZ9qORGgbazCyDTpFYjCqxtPs1xLIWHkMstTpoG4klDKQzxD50j/zYvU3wBSRtm/lavt1xLF+Dk4R+kgy3MRFk4HUiLKchozOBr9di9ZyY9ncnC61Tg6l+LkirueIv/HNGOMAAXIbC5+OC9hxx6hHLoni/UD0bkN1epwCk1ulVo7PbJJKdCpIPgSDMR/QkSJ6dfl8FrIaqvjJYjQps2ILvHskt5FyXORLk20w6LBJp1uYjkykuQvAJC7FMGA/NIM03F7YvA09quxU6jinson4Vv4nVwZB0/ZORaOOUQt4rU7I+uDKKo4SwpTJx0jH/9aYylr5zLIE47A4rY0W+sdbqcHfp7/4y1YD/vDKIB73TQVzelTUPcbpneKOEpvxF66p7ecvJEG6/Idwswnp70CzCF6FlvCDim+x+ZSR333NPbhbJyNHNMr3xQdNcJ3n7Pf8s6xbdpf3+197U6zfrTXUnfm8E0iTknUHDKaLzRiC/sTd1S2Oce0t5kW+Zh3jTKwPO0MrHQPvRwAEjnc4FaotGRk0KuXDRCEe1IVkkmYX5SpGSO1guVTfumU8E4624tiKnvHC9aO4iEc521YtkVUl+dnFu5Sqz17J1gWx9qN5sxSigTGzX4UVVInUODtOS1XwUuOFbYehlh5TttnHBypBDVf707fMT128erz+I+/fiYbRW4r907BRT8xZK7MbtYuLdorx66mRzVPW/+/qIvKMITpAjq/8ml9EaVlnmi2wRVQ3XLQ5n7iIZnYD/pF6b+S9hsyPnUUabZ7ApctJkwWd+aibpdQvgZqBaEtXaPWbhZjOD8Ii/ed3RogQORZS5wgzWbCV2lK5hFOKRVaTHCxRwrKmchUeJknBLgeAXy2rryEokcdbo3bAwNScChlmucp53ZDo6YwbK1bfVV5WRynWPyyekupfKLsyCrgK7PIUy+Q4UizeySEmSSyW0ZO3WI6sNr1G8iBEn0nvAXD4s0zdx5PiwK5VW53J8X27t1ABziEQv3mTOwcJ7ReEE1i97+5IeClPEnFhubxHbxpH7QdRG5en9Xn2aYCrf20wn2s4oUxBbKfnAmqS/1UT1jjguBn059rZEeTUq68O5odg0tAvG5vLb9OZWqGN1+EX7oz//ujT69bFZ3iz61rV8LzezYS0yZzgRyJnFqLFKKjv24KCyh9/zyHj32VF5oNOdG9SCuc/O/3cHs1wTPhjL8rsIDWOpvWFZ2cocjKWxI8DPjOU+JaHfHcty6jsYS31HgB+MJdxm/7wRN8/+Q0a//Rc=&lt;/diagram&gt;&lt;/mxfile&gt;" style="background-color: rgb(255, 255, 255);"><defs/><g><rect x="0" y="0" width="830" height="277" fill="rgb(255, 255, 255)" stroke="none" pointer-events="all"/><rect x="220" y="40" width="180" height="180" rx="9" ry="9" fill="none" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 47px; margin-left: 221px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#g-checking-the-coverage-of-the-fuzzing">Check coverage</a><br /><br />Use <font face="Courier New">afl-showmap</font> to get<br />code coverage statistics.<br /><br />Use <font face="Courier New">afl-cov</font> to generate an HTML report on coverage.</div></div></div></foreignObject><text x="310" y="59" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Check coverage...</text></switch></g><rect x="300" y="0" width="240" height="30" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 238px; height: 1px; padding-top: 15px; margin-left: 301px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;"><span>Manage campaign</span></div></div></div></foreignObject><text x="420" y="19" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle" font-weight="bold">Manage campaign</text></switch></g><rect x="486" y="237" width="160" height="30" rx="4.5" ry="4.5" fill="none" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 252px; margin-left: 487px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Required task</div></div></div></foreignObject><text x="566" y="256" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Required task</text></switch></g><rect x="660" y="237" width="160" height="30" rx="4.5" ry="4.5" fill="none" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 252px; margin-left: 661px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Optional task</div></div></div></foreignObject><text x="740" y="256" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Optional task</text></switch></g><path d="M 400 129.5 L 423.63 129.5" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 428.88 129.5 L 421.88 133 L 423.63 129.5 L 421.88 126 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 190 129.5 L 213.63 129.5" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 218.88 129.5 L 211.88 133 L 213.63 129.5 L 211.88 126 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="10" y="40" width="180" height="180" rx="9" ry="9" fill="none" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 47px; margin-left: 11px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#e-the-status-of-the-fuzz-campaign">Monitor status</a><br /><br />Use <font face="Courier New">afl-whatsup</font> to show the status of the fuzzing campaign.<br /><br />Use <font face="Courier New">afl-plot</font> to generate an HTML report with graphs.</div></div></div></foreignObject><text x="100" y="59" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Monitor status...</text></switch></g><path d="M 610 130 L 630 130 L 620 130 L 633.63 130" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 638.88 130 L 631.88 133.5 L 633.63 130 L 631.88 126.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="430" y="40" width="180" height="180" rx="9" ry="9" fill="none" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 47px; margin-left: 431px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#4-triaging-crashes">Triage crashes</a><br /><br />Use <font face="Courier New">afl-fuzz</font> with <font face="Courier New">-C</font> flag to run crash exploration mode.<br /><br />Use <font face="Courier New">afl-tmin</font> on test cases<br />for minimization.<br /><br />Use gdb or third-party<br />exploitable tools to analyze crashes.</div></div></div></foreignObject><text x="520" y="59" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Triage crashes...</text></switch></g><rect x="640" y="40" width="180" height="180" rx="9" ry="9" fill="none" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 47px; margin-left: 641px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><a href="https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#h-how-long-to-fuzz-a-target">Optimize campaign</a><br /><br />Stop instances that are not performing well.<br /><br />Start new instances with<br />different options.<br /><br />Select new test cases<br />based on insights.</div></div></div></foreignObject><text x="730" y="59" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Optimize campaign...</text></switch></g><path d="M 10 68 L 190 68" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 220 68 L 400 68" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 430 68 L 610 68" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 640 68 L 820 68" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Viewer does not support full SVG 1.1</text></a></switch></svg> \ No newline at end of file
diff --git a/docs/resources/afl_gzip.png b/docs/resources/afl_gzip.png
new file mode 100644
index 00000000..7c461d8f
--- /dev/null
+++ b/docs/resources/afl_gzip.png
Binary files differ
diff --git a/docs/resources/grafana-afl++.json b/docs/resources/grafana-afl++.json
new file mode 100644
index 00000000..910129a8
--- /dev/null
+++ b/docs/resources/grafana-afl++.json
@@ -0,0 +1,1816 @@
+{
+ "annotations": {
+ "list": [
+ {
+ "builtIn": 1,
+ "datasource": "-- Grafana --",
+ "enable": true,
+ "hide": true,
+ "iconColor": "rgba(0, 211, 255, 1)",
+ "name": "Annotations & Alerts",
+ "type": "dashboard"
+ }
+ ]
+ },
+ "editable": true,
+ "gnetId": null,
+ "graphTooltip": 0,
+ "id": 1,
+ "links": [],
+ "panels": [
+ {
+ "datasource": null,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 0
+ },
+ "id": 16,
+ "title": "Row title",
+ "type": "row"
+ },
+ {
+ "alert": {
+ "alertRuleTags": {},
+ "conditions": [
+ {
+ "evaluator": {
+ "params": [
+ 500
+ ],
+ "type": "lt"
+ },
+ "operator": {
+ "type": "and"
+ },
+ "query": {
+ "params": [
+ "A",
+ "5m",
+ "now"
+ ]
+ },
+ "reducer": {
+ "params": [],
+ "type": "avg"
+ },
+ "type": "query"
+ }
+ ],
+ "executionErrorState": "alerting",
+ "for": "5m",
+ "frequency": "1m",
+ "handler": 1,
+ "name": "Slow exec per sec",
+ "noDataState": "no_data",
+ "notifications": []
+ },
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": null,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {}
+ },
+ "overrides": []
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 6,
+ "w": 10,
+ "x": 0,
+ "y": 1
+ },
+ "hiddenSeries": false,
+ "id": 12,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "nullPointMode": "null",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.3.7",
+ "pointradius": 2,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "fuzzing{type=\"execs_per_sec\"}",
+ "interval": "",
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+ {
+ "colorMode": "critical",
+ "fill": true,
+ "line": true,
+ "op": "lt",
+ "value": 500
+ }
+ ],
+ "timeFrom": null,
+ "timeRegions": [
+ {
+ "colorMode": "background6",
+ "fill": true,
+ "fillColor": "rgba(234, 112, 112, 0.12)",
+ "line": false,
+ "lineColor": "rgba(237, 46, 24, 0.60)",
+ "op": "time"
+ }
+ ],
+ "timeShift": null,
+ "title": "Exec/s",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": "0",
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": null,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {}
+ },
+ "overrides": []
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 6,
+ "w": 10,
+ "x": 10,
+ "y": 1
+ },
+ "hiddenSeries": false,
+ "id": 8,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "nullPointMode": "null",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.3.7",
+ "pointradius": 2,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "fuzzing{type=\"total_crashes\"}",
+ "interval": "",
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Total Crashes",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": null,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {}
+ },
+ "overrides": []
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 5,
+ "w": 4,
+ "x": 20,
+ "y": 1
+ },
+ "hiddenSeries": false,
+ "id": 19,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "nullPointMode": "null",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.3.7",
+ "pointradius": 2,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "fuzzing{type=\"var_byte_count\"}",
+ "interval": "",
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [
+ {
+ "colorMode": "background6",
+ "fill": true,
+ "fillColor": "rgba(234, 112, 112, 0.12)",
+ "line": false,
+ "lineColor": "rgba(237, 46, 24, 0.60)",
+ "op": "time"
+ }
+ ],
+ "timeShift": null,
+ "title": "Var Byte Count",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": "0",
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": null,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {}
+ },
+ "overrides": []
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 6,
+ "w": 10,
+ "x": 0,
+ "y": 7
+ },
+ "hiddenSeries": false,
+ "id": 10,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "nullPointMode": "null",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.3.7",
+ "pointradius": 2,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "fuzzing{type=\"saved_crashes\"}",
+ "interval": "",
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Unique Crashes",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": null,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {}
+ },
+ "overrides": []
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 6,
+ "w": 10,
+ "x": 10,
+ "y": 7
+ },
+ "hiddenSeries": false,
+ "id": 14,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "nullPointMode": "null",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.3.7",
+ "pointradius": 2,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "fuzzing{type=\"saved_hangs\"}",
+ "interval": "",
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [
+ {
+ "colorMode": "background6",
+ "fill": true,
+ "fillColor": "rgba(234, 112, 112, 0.12)",
+ "line": false,
+ "lineColor": "rgba(237, 46, 24, 0.60)",
+ "op": "time"
+ }
+ ],
+ "timeShift": null,
+ "title": "Unique Hangs",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": null,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {}
+ },
+ "overrides": []
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 5,
+ "w": 5,
+ "x": 0,
+ "y": 13
+ },
+ "hiddenSeries": false,
+ "id": 23,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "nullPointMode": "null",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.3.7",
+ "pointradius": 2,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "fuzzing{type=\"slowest_exec_ms\"}",
+ "interval": "",
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [
+ {
+ "colorMode": "background6",
+ "fill": true,
+ "fillColor": "rgba(234, 112, 112, 0.12)",
+ "line": false,
+ "lineColor": "rgba(237, 46, 24, 0.60)",
+ "op": "time"
+ }
+ ],
+ "timeShift": null,
+ "title": "Slowest Exec Ms",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": "0",
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": null,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {}
+ },
+ "overrides": []
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 5,
+ "w": 5,
+ "x": 5,
+ "y": 13
+ },
+ "hiddenSeries": false,
+ "id": 4,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "nullPointMode": "null",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.3.7",
+ "pointradius": 2,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "fuzzing{type=\"cycle_done\"}",
+ "interval": "",
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Cycles dones",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": null,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {}
+ },
+ "overrides": []
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 5,
+ "w": 5,
+ "x": 10,
+ "y": 13
+ },
+ "hiddenSeries": false,
+ "id": 13,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "nullPointMode": "null",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.3.7",
+ "pointradius": 2,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "fuzzing{type=\"execs_done\"}",
+ "interval": "",
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [
+ {
+ "colorMode": "background6",
+ "fill": true,
+ "fillColor": "rgba(234, 112, 112, 0.12)",
+ "line": false,
+ "lineColor": "rgba(237, 46, 24, 0.60)",
+ "op": "time"
+ }
+ ],
+ "timeShift": null,
+ "title": "Total Execs",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": null,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {}
+ },
+ "overrides": []
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 5,
+ "w": 5,
+ "x": 15,
+ "y": 13
+ },
+ "hiddenSeries": false,
+ "id": 2,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "nullPointMode": "null",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.3.7",
+ "pointradius": 2,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "fuzzing{type=\"cur_item\"}",
+ "interval": "",
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Current fuzz item",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": null,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {}
+ },
+ "overrides": []
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 5,
+ "w": 5,
+ "x": 0,
+ "y": 18
+ },
+ "hiddenSeries": false,
+ "id": 6,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "nullPointMode": "null",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.3.7",
+ "pointradius": 2,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "fuzzing{type=\"cycles_wo_finds\"}",
+ "interval": "",
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Cycles done without find",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": null,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {}
+ },
+ "overrides": []
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 5,
+ "w": 5,
+ "x": 5,
+ "y": 18
+ },
+ "hiddenSeries": false,
+ "id": 25,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "nullPointMode": "null",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.3.7",
+ "pointradius": 2,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "fuzzing{type=\"corpus_favored\"}",
+ "interval": "",
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [
+ {
+ "colorMode": "background6",
+ "fill": true,
+ "fillColor": "rgba(234, 112, 112, 0.12)",
+ "line": false,
+ "lineColor": "rgba(237, 46, 24, 0.60)",
+ "op": "time"
+ }
+ ],
+ "timeShift": null,
+ "title": "Corpus Favored",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": "0",
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": null,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {}
+ },
+ "overrides": []
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 5,
+ "w": 5,
+ "x": 10,
+ "y": 18
+ },
+ "hiddenSeries": false,
+ "id": 22,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "nullPointMode": "null",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.3.7",
+ "pointradius": 2,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "fuzzing{type=\"havoc_expansion\"}",
+ "interval": "",
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [
+ {
+ "colorMode": "background6",
+ "fill": true,
+ "fillColor": "rgba(234, 112, 112, 0.12)",
+ "line": false,
+ "lineColor": "rgba(237, 46, 24, 0.60)",
+ "op": "time"
+ }
+ ],
+ "timeShift": null,
+ "title": "Havoc Expansion",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": "0",
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": null,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {}
+ },
+ "overrides": []
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 5,
+ "w": 5,
+ "x": 15,
+ "y": 18
+ },
+ "hiddenSeries": false,
+ "id": 17,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "nullPointMode": "null",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.3.7",
+ "pointradius": 2,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "fuzzing{type=\"edges_found\"}",
+ "interval": "",
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [
+ {
+ "colorMode": "background6",
+ "fill": true,
+ "fillColor": "rgba(234, 112, 112, 0.12)",
+ "line": false,
+ "lineColor": "rgba(237, 46, 24, 0.60)",
+ "op": "time"
+ }
+ ],
+ "timeShift": null,
+ "title": "Edges Found",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": "0",
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": null,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {}
+ },
+ "overrides": []
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 5,
+ "w": 5,
+ "x": 0,
+ "y": 23
+ },
+ "hiddenSeries": false,
+ "id": 24,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "nullPointMode": "null",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.3.7",
+ "pointradius": 2,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "fuzzing{type=\"corpus_imported\"}",
+ "interval": "",
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [
+ {
+ "colorMode": "background6",
+ "fill": true,
+ "fillColor": "rgba(234, 112, 112, 0.12)",
+ "line": false,
+ "lineColor": "rgba(237, 46, 24, 0.60)",
+ "op": "time"
+ }
+ ],
+ "timeShift": null,
+ "title": "Corpus Imported",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": "0",
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": null,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {}
+ },
+ "overrides": []
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 5,
+ "w": 5,
+ "x": 5,
+ "y": 23
+ },
+ "hiddenSeries": false,
+ "id": 21,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "nullPointMode": "null",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.3.7",
+ "pointradius": 2,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "fuzzing{type=\"pending_total\"}",
+ "interval": "",
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [
+ {
+ "colorMode": "background6",
+ "fill": true,
+ "fillColor": "rgba(234, 112, 112, 0.12)",
+ "line": false,
+ "lineColor": "rgba(237, 46, 24, 0.60)",
+ "op": "time"
+ }
+ ],
+ "timeShift": null,
+ "title": "Pending Total",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": "0",
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": null,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {}
+ },
+ "overrides": []
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 5,
+ "w": 5,
+ "x": 10,
+ "y": 23
+ },
+ "hiddenSeries": false,
+ "id": 20,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "nullPointMode": "null",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.3.7",
+ "pointradius": 2,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "fuzzing{type=\"pending_favs\"}",
+ "interval": "",
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [
+ {
+ "colorMode": "background6",
+ "fill": true,
+ "fillColor": "rgba(234, 112, 112, 0.12)",
+ "line": false,
+ "lineColor": "rgba(237, 46, 24, 0.60)",
+ "op": "time"
+ }
+ ],
+ "timeShift": null,
+ "title": "Pending favs",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": "0",
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": null,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {}
+ },
+ "overrides": []
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 5,
+ "w": 5,
+ "x": 15,
+ "y": 23
+ },
+ "hiddenSeries": false,
+ "id": 18,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "nullPointMode": "null",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.3.7",
+ "pointradius": 2,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "fuzzing{type=\"max_depth\"}",
+ "interval": "",
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [
+ {
+ "colorMode": "background6",
+ "fill": true,
+ "fillColor": "rgba(234, 112, 112, 0.12)",
+ "line": false,
+ "lineColor": "rgba(237, 46, 24, 0.60)",
+ "op": "time"
+ }
+ ],
+ "timeShift": null,
+ "title": "Max Depth",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": "0",
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ }
+ ],
+ "refresh": false,
+ "schemaVersion": 26,
+ "style": "dark",
+ "tags": [],
+ "templating": {
+ "list": []
+ },
+ "time": {
+ "from": "now-30m",
+ "to": "now"
+ },
+ "timepicker": {},
+ "timezone": "",
+ "title": "Fuzzing",
+ "uid": "sRI6PCfGz",
+ "version": 2
+} \ No newline at end of file
diff --git a/docs/resources/screenshot.png b/docs/resources/screenshot.png
new file mode 100644
index 00000000..75b88287
--- /dev/null
+++ b/docs/resources/screenshot.png
Binary files differ
diff --git a/docs/resources/statsd-grafana.png b/docs/resources/statsd-grafana.png
new file mode 100644
index 00000000..1bdc1722
--- /dev/null
+++ b/docs/resources/statsd-grafana.png
Binary files differ
diff --git a/docs/rpc_statsd.md b/docs/rpc_statsd.md
new file mode 100644
index 00000000..d8f0fb67
--- /dev/null
+++ b/docs/rpc_statsd.md
@@ -0,0 +1,190 @@
+# Remote monitoring and metrics visualization
+
+AFL++ can send out metrics as StatsD messages. For remote monitoring and
+visualization of the metrics, you can set up a tool chain. For example, with
+Prometheus and Grafana. All tools are free and open source.
+
+This enables you to create nice and readable dashboards containing all the
+information you need on your fuzzer instances. There is no need to write your
+own statistics parsing system, deploy and maintain it to all your instances, and
+sync with your graph rendering system.
+
+Compared to the default integrated UI of AFL++, this can help you to visualize
+trends and the fuzzing state over time. You might be able to see when the
+fuzzing process has reached a state of no progress and visualize what are the
+"best strategies" for your targets (according to your own criteria). You can do
+so without logging into each instance individually.
+
+![example visualization with Grafana](resources/statsd-grafana.png)
+
+This is an example visualization with Grafana. The dashboard can be imported
+with [this JSON template](resources/grafana-afl++.json).
+
+## AFL++ metrics and StatsD
+
+StatsD allows you to receive and aggregate metrics from a wide range of
+applications and retransmit them to a backend of your choice.
+
+From AFL++, StatsD can receive the following metrics:
+- cur_item
+- cycle_done
+- cycles_wo_finds
+- edges_found
+- execs_done
+- execs_per_sec
+- havoc_expansion
+- max_depth
+- corpus_favored
+- corpus_found
+- corpus_imported
+- corpus_count
+- pending_favs
+- pending_total
+- slowest_exec_ms
+- total_crashes
+- saved_crashes
+- saved_hangs
+- var_byte_count
+- corpus_variable
+
+Depending on your StatsD server, you will be able to monitor, trigger alerts, or
+perform actions based on these metrics (for example: alert on slow exec/s for a
+new build, threshold of crashes, time since last crash > X, and so on).
+
+## Setting environment variables in AFL++
+
+1. To enable the StatsD metrics collection on your fuzzer instances, set the
+ environment variable `AFL_STATSD=1`. By default, AFL++ will send the metrics
+ over UDP to 127.0.0.1:8125.
+
+2. To enable tags for each metric based on their format (banner and
+ afl_version), set the environment variable `AFL_STATSD_TAGS_FLAVOR`. By
+ default, no tags will be added to the metrics.
+
+ The available values are the following:
+ - `dogstatsd`
+ - `influxdb`
+ - `librato`
+ - `signalfx`
+
+ For more information on environment variables, see
+ [env_variables.md](env_variables.md).
+
+ Note: When using multiple fuzzer instances with StatsD it is *strongly*
+ recommended to set up `AFL_STATSD_TAGS_FLAVOR` to match your StatsD server.
+ This will allow you to see individual fuzzer performance, detect bad ones,
+ and see the progress of each strategy.
+
+3. Optional: To set the host and port of your StatsD daemon, set
+ `AFL_STATSD_HOST` and `AFL_STATSD_PORT`. The default values are `localhost`
+ and `8125`.
+
+## Installing and setting up StatsD, Prometheus, and Grafana
+
+The easiest way to install and set up the infrastructure is with Docker and
+Docker Compose.
+
+Depending on your fuzzing setup and infrastructure, you may not want to run
+these applications on your fuzzer instances. This setup may be modified before
+use in a production environment; for example, adding passwords, creating volumes
+for storage, tweaking the metrics gathering to get host metrics (CPU, RAM, and
+so on).
+
+For all your fuzzing instances, only one instance of Prometheus and Grafana is
+required. The
+[statsd exporter](https://registry.hub.docker.com/r/prom/statsd-exporter)
+converts the StatsD metrics to Prometheus. If you are using a provider that
+supports StatsD directly, you can skip this part of the setup."
+
+You can create and move the infrastructure files into a directory of your
+choice. The directory will store all the required configuration files.
+
+To install and set up Prometheus and Grafana:
+
+1. Install Docker and Docker Compose:
+
+ ```sh
+ curl -fsSL https://get.docker.com -o get-docker.sh
+ sh get-docker.sh
+ ```
+
+2. Create a `docker-compose.yml` containing the following:
+
+ ```yml
+ version: '3'
+
+ networks:
+ statsd-net:
+ driver: bridge
+
+ services:
+ prometheus:
+ image: prom/prometheus
+ container_name: prometheus
+ volumes:
+ - ./prometheus.yml:/prometheus.yml
+ command:
+ - '--config.file=/prometheus.yml'
+ restart: unless-stopped
+ ports:
+ - "9090:9090"
+ networks:
+ - statsd-net
+
+ statsd_exporter:
+ image: prom/statsd-exporter
+ container_name: statsd_exporter
+ volumes:
+ - ./statsd_mapping.yml:/statsd_mapping.yml
+ command:
+ - "--statsd.mapping-config=/statsd_mapping.yml"
+ ports:
+ - "9102:9102/tcp"
+ - "8125:9125/udp"
+ networks:
+ - statsd-net
+
+ grafana:
+ image: grafana/grafana
+ container_name: grafana
+ restart: unless-stopped
+ ports:
+ - "3000:3000"
+ networks:
+ - statsd-net
+ ```
+
+3. Create a `prometheus.yml` containing the following:
+
+ ```yml
+ global:
+ scrape_interval: 15s
+ evaluation_interval: 15s
+
+ scrape_configs:
+ - job_name: 'fuzzing_metrics'
+ static_configs:
+ - targets: ['statsd_exporter:9102']
+ ```
+
+4. Create a `statsd_mapping.yml` containing the following:
+
+ ```yml
+ mappings:
+ - match: "fuzzing.*"
+ name: "fuzzing"
+ labels:
+ type: "$1"
+ ```
+
+5. Run `docker-compose up -d`.
+
+## Running AFL++ with StatsD
+
+To run your fuzzing instances:
+
+```
+AFL_STATSD_TAGS_FLAVOR=dogstatsd AFL_STATSD=1 afl-fuzz -M test-fuzzer-1 -i i -o o [./bin/my-application] @@
+AFL_STATSD_TAGS_FLAVOR=dogstatsd AFL_STATSD=1 afl-fuzz -S test-fuzzer-2 -i i -o o [./bin/my-application] @@
+...
+``` \ No newline at end of file
diff --git a/docs/third_party_tools.md b/docs/third_party_tools.md
new file mode 100644
index 00000000..8d40c429
--- /dev/null
+++ b/docs/third_party_tools.md
@@ -0,0 +1,59 @@
+# Tools that help fuzzing with AFL++
+
+Speeding up fuzzing:
+* [libfiowrapper](https://github.com/marekzmyslowski/libfiowrapper) - if the
+ function you want to fuzz requires loading a file, this allows using the
+ shared memory test case feature :-) - recommended.
+
+Minimization of test cases:
+* [afl-pytmin](https://github.com/ilsani/afl-pytmin) - a wrapper for afl-tmin
+ that tries to speed up the process of minimization of a single test case by
+ using many CPU cores.
+* [afl-ddmin-mod](https://github.com/MarkusTeufelberger/afl-ddmin-mod) - a
+ variation of afl-tmin based on the ddmin algorithm.
+* [halfempty](https://github.com/googleprojectzero/halfempty) - is a fast
+ utility for minimizing test cases by Tavis Ormandy based on parallelization.
+
+Distributed execution:
+* [disfuzz-afl](https://github.com/MartijnB/disfuzz-afl) - distributed fuzzing
+ for AFL.
+* [AFLDFF](https://github.com/quantumvm/AFLDFF) - AFL distributed fuzzing
+ framework.
+* [afl-launch](https://github.com/bnagy/afl-launch) - a tool for the execution
+ of many AFL instances.
+* [afl-mothership](https://github.com/afl-mothership/afl-mothership) -
+ management and execution of many synchronized AFL fuzzers on AWS cloud.
+* [afl-in-the-cloud](https://github.com/abhisek/afl-in-the-cloud) - another
+ script for running AFL in AWS.
+
+Deployment, management, monitoring, reporting
+* [afl-utils](https://gitlab.com/rc0r/afl-utils) - a set of utilities for
+ automatic processing/analysis of crashes and reducing the number of test
+ cases.
+* [afl-other-arch](https://github.com/shellphish/afl-other-arch) - is a set of
+ patches and scripts for easily adding support for various non-x86
+ architectures for AFL.
+* [afl-trivia](https://github.com/bnagy/afl-trivia) - a few small scripts to
+ simplify the management of AFL.
+* [afl-monitor](https://github.com/reflare/afl-monitor) - a script for
+ monitoring AFL.
+* [afl-manager](https://github.com/zx1340/afl-manager) - a web server on Python
+ for managing multi-afl.
+* [afl-remote](https://github.com/block8437/afl-remote) - a web server for the
+ remote management of AFL instances.
+* [afl-extras](https://github.com/fekir/afl-extras) - shell scripts to
+ parallelize afl-tmin, startup, and data collection.
+
+Crash processing
+* [AFLTriage](https://github.com/quic/AFLTriage) -
+ triage crashing input files using gdb.
+* [afl-crash-analyzer](https://github.com/floyd-fuh/afl-crash-analyzer) -
+ another crash analyzer for AFL.
+* [fuzzer-utils](https://github.com/ThePatrickStar/fuzzer-utils) - a set of
+ scripts for the analysis of results.
+* [atriage](https://github.com/Ayrx/atriage) - a simple triage tool.
+* [afl-kit](https://github.com/kcwu/afl-kit) - afl-cmin on Python.
+* [AFLize](https://github.com/d33tah/aflize) - a tool that automatically
+ generates builds of debian packages suitable for AFL.
+* [afl-fid](https://github.com/FoRTE-Research/afl-fid) - a set of tools for
+ working with input data.
diff --git a/docs/tutorials.md b/docs/tutorials.md
new file mode 100644
index 00000000..64d2b376
--- /dev/null
+++ b/docs/tutorials.md
@@ -0,0 +1,40 @@
+# Tutorials
+
+Here are some good write-ups to show how to effectively use AFL++:
+
+* [https://aflplus.plus/docs/tutorials/libxml2_tutorial/](https://aflplus.plus/docs/tutorials/libxml2_tutorial/)
+* [https://bananamafia.dev/post/gb-fuzz/](https://bananamafia.dev/post/gb-fuzz/)
+* [https://securitylab.github.com/research/fuzzing-challenges-solutions-1](https://securitylab.github.com/research/fuzzing-challenges-solutions-1)
+* [https://securitylab.github.com/research/fuzzing-software-2](https://securitylab.github.com/research/fuzzing-software-2)
+* [https://securitylab.github.com/research/fuzzing-sockets-FTP](https://securitylab.github.com/research/fuzzing-sockets-FTP)
+* [https://securitylab.github.com/research/fuzzing-sockets-FreeRDP](https://securitylab.github.com/research/fuzzing-sockets-FreeRDP)
+* [https://securitylab.github.com/research/fuzzing-apache-1](https://securitylab.github.com/research/fuzzing-apache-1)
+* [https://mmmds.pl/fuzzing-map-parser-part-1-teeworlds/](https://mmmds.pl/fuzzing-map-parser-part-1-teeworlds/)
+
+If you do not want to follow a tutorial but rather try an exercise type of
+training, then we can highly recommend the following:
+
+* [https://github.com/antonio-morales/Fuzzing101](https://github.com/antonio-morales/Fuzzing101)
+
+If you are interested in fuzzing structured data (where you define what the
+structure is), these links have you covered:
+
+* libprotobuf for AFL++:
+ [https://github.com/P1umer/AFLplusplus-protobuf-mutator](https://github.com/P1umer/AFLplusplus-protobuf-mutator)
+* libprotobuf raw:
+ [https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator)
+* libprotobuf for old AFL++ API:
+ [https://github.com/thebabush/afl-libprotobuf-mutator](https://github.com/thebabush/afl-libprotobuf-mutator)
+* Superion for AFL++:
+ [https://github.com/adrian-rt/superion-mutator](https://github.com/adrian-rt/superion-mutator)
+
+## Video Tutorials
+* [Install AFL++ Ubuntu](https://www.youtube.com/watch?v=5dCvhkbi3RA)
+* [[Fuzzing with AFLplusplus] Installing AFLPlusplus and fuzzing a simple C program](https://www.youtube.com/watch?v=9wRVo0kYSlc)
+* [[Fuzzing with AFLplusplus] How to fuzz a binary with no source code on Linux in persistent mode](https://www.youtube.com/watch?v=LGPJdEO02p4)
+* [Blackbox Fuzzing #1: Start Binary-Only Fuzzing using AFL++ QEMU mode](https://www.youtube.com/watch?v=sjLFf9q2NRc)
+* [HOPE 2020 (2020): Hunting Bugs in Your Sleep - How to Fuzz (Almost) Anything With AFL/AFL++](https://www.youtube.com/watch?v=A8ex1hqaQ7E)
+* [How Fuzzing with AFL works!](https://www.youtube.com/watch?v=COHUWuLTbdk)
+* [WOOT '20 - AFL++ : Combining Incremental Steps of Fuzzing Research](https://www.youtube.com/watch?v=cZidm6I7KWU)
+
+If you find other good ones, please send them to us :-)
diff --git a/dynamic_list.txt b/dynamic_list.txt
new file mode 100644
index 00000000..7293ae77
--- /dev/null
+++ b/dynamic_list.txt
@@ -0,0 +1,56 @@
+{
+ "__afl_already_initialized_first";
+ "__afl_already_initialized_forkserver";
+ "__afl_already_initialized_second";
+ "__afl_already_initialized_shm";
+ "__afl_area_ptr";
+ "__afl_auto_early";
+ "__afl_auto_first";
+ "__afl_auto_init";
+ "__afl_auto_second";
+ "__afl_coverage_discard";
+ "__afl_coverage_interesting";
+ "__afl_coverage_off";
+ "__afl_coverage_on";
+ "__afl_coverage_skip";
+ "__afl_dictionary";
+ "__afl_dictionary_len";
+ "__afl_final_loc";
+ "__afl_fuzz_len";
+ "__afl_fuzz_ptr";
+ "__afl_manual_init";
+ "__afl_map_addr";
+ "__afl_persistent_loop";
+ "__afl_prev_caller";
+ "__afl_prev_ctx";
+ "__afl_prev_loc";
+ "__afl_selective_coverage";
+ "__afl_selective_coverage_start_off";
+ "__afl_selective_coverage_temp";
+ "__afl_sharedmem_fuzzing";
+ "__afl_trace";
+ "__cmplog_ins_hook1";
+ "__cmplog_ins_hook16";
+ "__cmplog_ins_hook2";
+ "__cmplog_ins_hook4";
+ "__cmplog_ins_hook8";
+ "__cmplog_ins_hookN";
+ "__cmplog_rtn_gcc_stdstring_cstring";
+ "__cmplog_rtn_gcc_stdstring_stdstring";
+ "__cmplog_rtn_hook";
+ "__cmplog_rtn_llvm_stdstring_cstring";
+ "__cmplog_rtn_llvm_stdstring_stdstring";
+ "__sanitizer_cov_trace_cmp1";
+ "__sanitizer_cov_trace_cmp16";
+ "__sanitizer_cov_trace_cmp2";
+ "__sanitizer_cov_trace_cmp4";
+ "__sanitizer_cov_trace_cmp8";
+ "__sanitizer_cov_trace_const_cmp1";
+ "__sanitizer_cov_trace_const_cmp16";
+ "__sanitizer_cov_trace_const_cmp2";
+ "__sanitizer_cov_trace_const_cmp4";
+ "__sanitizer_cov_trace_const_cmp8";
+ "__sanitizer_cov_trace_pc_guard";
+ "__sanitizer_cov_trace_pc_guard_init";
+ "__sanitizer_cov_trace_switch";
+};
diff --git a/include/afl-as.h b/include/afl-as.h
new file mode 100644
index 00000000..bbbd5582
--- /dev/null
+++ b/include/afl-as.h
@@ -0,0 +1,775 @@
+/*
+ american fuzzy lop++ - injectable parts
+ ---------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
+ Andrea Fioraldi <andreafioraldi@gmail.com>,
+ Dominik Maier <mail@dmnk.co>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ This file houses the assembly-level instrumentation injected into fuzzed
+ programs. The instrumentation stores XORed pairs of data: identifiers of the
+ currently executing branch and the one that executed immediately before.
+
+ TL;DR: the instrumentation does shm_trace_map[cur_loc ^ prev_loc]++
+
+ The code is designed for 32-bit and 64-bit x86 systems. Both modes should
+ work everywhere except for Apple systems. Apple does relocations differently
+ from everybody else, so since their OSes have been 64-bit for a longer while,
+ I didn't go through the mental effort of porting the 32-bit code.
+
+ In principle, similar code should be easy to inject into any well-behaved
+ binary-only code (e.g., using DynamoRIO). Conditional jumps offer natural
+ targets for instrumentation, and should offer comparable probe density.
+
+ */
+
+#ifndef _HAVE_AFL_AS_H
+#define _HAVE_AFL_AS_H
+
+#include "config.h"
+#include "types.h"
+
+/*
+ ------------------
+ Performances notes
+ ------------------
+
+ Contributions to make this code faster are appreciated! Here are some
+ rough notes that may help with the task:
+
+ - Only the trampoline_fmt and the non-setup __afl_maybe_log code paths are
+ really worth optimizing; the setup / fork server stuff matters a lot less
+ and should be mostly just kept readable.
+
+ - We're aiming for modern CPUs with out-of-order execution and large
+ pipelines; the code is mostly follows intuitive, human-readable
+ instruction ordering, because "textbook" manual reorderings make no
+ substantial difference.
+
+ - Interestingly, instrumented execution isn't a lot faster if we store a
+ variable pointer to the setup, log, or return routine and then do a reg
+ call from within trampoline_fmt. It does speed up non-instrumented
+ execution quite a bit, though, since that path just becomes
+ push-call-ret-pop.
+
+ - There is also not a whole lot to be gained by doing SHM attach at a
+ fixed address instead of retrieving __afl_area_ptr. Although it allows us
+ to have a shorter log routine inserted for conditional jumps and jump
+ labels (for a ~10% perf gain), there is a risk of bumping into other
+ allocations created by the program or by tools such as ASAN.
+
+ - popf is *awfully* slow, which is why we're doing the lahf / sahf +
+ overflow test trick. Unfortunately, this forces us to taint eax / rax, but
+ this dependency on a commonly-used register still beats the alternative of
+ using pushf / popf.
+
+ One possible optimization is to avoid touching flags by using a circular
+ buffer that stores just a sequence of current locations, with the XOR stuff
+ happening offline. Alas, this doesn't seem to have a huge impact:
+
+ https://groups.google.com/d/msg/afl-users/MsajVf4fRLo/2u6t88ntUBIJ
+
+ - Preforking one child a bit sooner, and then waiting for the "go" command
+ from within the child, doesn't offer major performance gains; fork() seems
+ to be relatively inexpensive these days. Preforking multiple children does
+ help, but badly breaks the "~1 core per fuzzer" design, making it harder to
+ scale up. Maybe there is some middle ground.
+
+ Perhaps of note: in the 64-bit version for all platforms except for Apple,
+ the instrumentation is done slightly differently than on 32-bit, with
+ __afl_prev_loc and __afl_area_ptr being local to the object file (.lcomm),
+ rather than global (.comm). This is to avoid GOTRELPC lookups in the critical
+ code path, which AFAICT, are otherwise unavoidable if we want gcc -shared to
+ work; simple relocations between .bss and .text won't work on most 64-bit
+ platforms in such a case.
+
+ (Fun fact: on Apple systems, .lcomm can segfault the linker.)
+
+ The side effect is that state transitions are measured in a somewhat
+ different way, with previous tuple being recorded separately within the scope
+ of every .c file. This should have no impact in any practical sense.
+
+ Another side effect of this design is that getenv() will be called once per
+ every .o file when running in non-instrumented mode; and since getenv() tends
+ to be optimized in funny ways, we need to be very careful to save every
+ oddball register it may touch.
+
+ */
+
+static const u8 *trampoline_fmt_32 =
+
+ "\n"
+ "/* --- AFL TRAMPOLINE (32-BIT) --- */\n"
+ "\n"
+ ".align 4\n"
+ "\n"
+ "leal -16(%%esp), %%esp\n"
+ "movl %%edi, 0(%%esp)\n"
+ "movl %%edx, 4(%%esp)\n"
+ "movl %%ecx, 8(%%esp)\n"
+ "movl %%eax, 12(%%esp)\n"
+ "movl $0x%08x, %%ecx\n"
+ "call __afl_maybe_log\n"
+ "movl 12(%%esp), %%eax\n"
+ "movl 8(%%esp), %%ecx\n"
+ "movl 4(%%esp), %%edx\n"
+ "movl 0(%%esp), %%edi\n"
+ "leal 16(%%esp), %%esp\n"
+ "\n"
+ "/* --- END --- */\n"
+ "\n";
+
+static const u8 *trampoline_fmt_64 =
+
+ "\n"
+ "/* --- AFL TRAMPOLINE (64-BIT) --- */\n"
+ "\n"
+ ".align 4\n"
+ "\n"
+ "leaq -(128+24)(%%rsp), %%rsp\n"
+ "movq %%rdx, 0(%%rsp)\n"
+ "movq %%rcx, 8(%%rsp)\n"
+ "movq %%rax, 16(%%rsp)\n"
+ "movq $0x%08x, %%rcx\n"
+ "call __afl_maybe_log\n"
+ "movq 16(%%rsp), %%rax\n"
+ "movq 8(%%rsp), %%rcx\n"
+ "movq 0(%%rsp), %%rdx\n"
+ "leaq (128+24)(%%rsp), %%rsp\n"
+ "\n"
+ "/* --- END --- */\n"
+ "\n";
+
+static const u8 *main_payload_32 =
+
+ "\n"
+ "/* --- AFL MAIN PAYLOAD (32-BIT) --- */\n"
+ "\n"
+ ".text\n"
+ ".att_syntax\n"
+ ".code32\n"
+ ".align 8\n"
+ "\n"
+
+ "__afl_maybe_log:\n"
+ "\n"
+ " lahf\n"
+ " seto %al\n"
+ "\n"
+ " /* Check if SHM region is already mapped. */\n"
+ "\n"
+ " movl __afl_area_ptr, %edx\n"
+ " testl %edx, %edx\n"
+ " je __afl_setup\n"
+ "\n"
+ "__afl_store:\n"
+ "\n"
+ " /* Calculate and store hit for the code location specified in ecx. There\n"
+ " is a double-XOR way of doing this without tainting another register,\n"
+ " and we use it on 64-bit systems; but it's slower for 32-bit ones. */\n"
+ "\n"
+#ifndef COVERAGE_ONLY
+ " movl __afl_prev_loc, %edi\n"
+ " xorl %ecx, %edi\n"
+ " shrl $1, %ecx\n"
+ " movl %ecx, __afl_prev_loc\n"
+#else
+ " movl %ecx, %edi\n"
+#endif /* ^!COVERAGE_ONLY */
+ "\n"
+#ifdef SKIP_COUNTS
+ " orb $1, (%edx, %edi, 1)\n"
+#else
+ " addb $1, (%edx, %edi, 1)\n"
+ " adcb $0, (%edx, %edi, 1)\n" // never zero counter implementation. slightly better path discovery and little performance impact
+#endif /* ^SKIP_COUNTS */
+ "\n"
+ "__afl_return:\n"
+ "\n"
+ " addb $127, %al\n"
+ " sahf\n"
+ " ret\n"
+ "\n"
+ ".align 8\n"
+ "\n"
+ "__afl_setup:\n"
+ "\n"
+ " /* Do not retry setup if we had previous failures. */\n"
+ "\n"
+ " cmpb $0, __afl_setup_failure\n"
+ " jne __afl_return\n"
+ "\n"
+ " /* Map SHM, jumping to __afl_setup_abort if something goes wrong.\n"
+ " We do not save FPU/MMX/SSE registers here, but hopefully, nobody\n"
+ " will notice this early in the game. */\n"
+ "\n"
+ " pushl %eax\n"
+ " pushl %ecx\n"
+ "\n"
+ " pushl $.AFL_SHM_ENV\n"
+ " call getenv\n"
+ " addl $4, %esp\n"
+ "\n"
+ " testl %eax, %eax\n"
+ " je __afl_setup_abort\n"
+ "\n"
+#ifdef USEMMAP
+ " pushl $384 /* shm_open mode 0600 */\n"
+ " pushl $2 /* flags O_RDWR */\n"
+ " pushl %eax /* SHM file path */\n"
+ " call shm_open\n"
+ " addl $12, %esp\n"
+ "\n"
+ " cmpl $-1, %eax\n"
+ " je __afl_setup_abort\n"
+ "\n"
+ " pushl $0 /* mmap off */\n"
+ " pushl %eax /* shm fd */\n"
+ " pushl $1 /* mmap flags */\n"
+ " pushl $3 /* mmap prot */\n"
+ " pushl $"STRINGIFY(MAP_SIZE)" /* mmap len */\n"
+ " pushl $0 /* mmap addr */\n"
+ " call mmap\n"
+ " addl $12, %esp\n"
+ "\n"
+ " cmpl $-1, %eax\n"
+ " je __afl_setup_abort\n"
+ "\n"
+#else
+ " pushl %eax\n"
+ " call atoi\n"
+ " addl $4, %esp\n"
+ "\n"
+ " pushl $0 /* shmat flags */\n"
+ " pushl $0 /* requested addr */\n"
+ " pushl %eax /* SHM ID */\n"
+ " call shmat\n"
+ " addl $12, %esp\n"
+ "\n"
+ " cmpl $-1, %eax\n"
+ " je __afl_setup_abort\n"
+ "\n"
+#endif
+ " movb $1, (%eax)\n"
+ " /* Store the address of the SHM region. */\n"
+ "\n"
+ " movl %eax, __afl_area_ptr\n"
+ " movl %eax, %edx\n"
+ "\n"
+ " popl %ecx\n"
+ " popl %eax\n"
+ "\n"
+ "__afl_forkserver:\n"
+ "\n"
+ " /* Enter the fork server mode to avoid the overhead of execve() calls. */\n"
+ "\n"
+ " pushl %eax\n"
+ " pushl %ecx\n"
+ " pushl %edx\n"
+ "\n"
+ " /* Phone home and tell the parent that we're OK. (Note that signals with\n"
+ " no SA_RESTART will mess it up). If this fails, assume that the fd is\n"
+ " closed because we were execve()d from an instrumented binary, or because\n"
+ " the parent doesn't want to use the fork server. */\n"
+ "\n"
+ " pushl $4 /* length */\n"
+ " pushl $__afl_temp /* data */\n"
+ " pushl $" STRINGIFY((FORKSRV_FD + 1)) " /* file desc */\n"
+ " call write\n"
+ " addl $12, %esp\n"
+ "\n"
+ " cmpl $4, %eax\n"
+ " jne __afl_fork_resume\n"
+ "\n"
+ "__afl_fork_wait_loop:\n"
+ "\n"
+ " /* Wait for parent by reading from the pipe. Abort if read fails. */\n"
+ "\n"
+ " pushl $4 /* length */\n"
+ " pushl $__afl_temp /* data */\n"
+ " pushl $" STRINGIFY(FORKSRV_FD) " /* file desc */\n"
+ " call read\n"
+ " addl $12, %esp\n"
+ "\n"
+ " cmpl $4, %eax\n"
+ " jne __afl_die\n"
+ "\n"
+ " /* Once woken up, create a clone of our process. This is an excellent use\n"
+ " case for syscall(__NR_clone, 0, CLONE_PARENT), but glibc boneheadedly\n"
+ " caches getpid() results and offers no way to update the value, breaking\n"
+ " abort(), raise(), and a bunch of other things :-( */\n"
+ "\n"
+ " call fork\n"
+ "\n"
+ " cmpl $0, %eax\n"
+ " jl __afl_die\n"
+ " je __afl_fork_resume\n"
+ "\n"
+ " /* In parent process: write PID to pipe, then wait for child. */\n"
+ "\n"
+ " movl %eax, __afl_fork_pid\n"
+ "\n"
+ " pushl $4 /* length */\n"
+ " pushl $__afl_fork_pid /* data */\n"
+ " pushl $" STRINGIFY((FORKSRV_FD + 1)) " /* file desc */\n"
+ " call write\n"
+ " addl $12, %esp\n"
+ "\n"
+ " pushl $0 /* no flags */\n"
+ " pushl $__afl_temp /* status */\n"
+ " pushl __afl_fork_pid /* PID */\n"
+ " call waitpid\n"
+ " addl $12, %esp\n"
+ "\n"
+ " cmpl $0, %eax\n"
+ " jle __afl_die\n"
+ "\n"
+ " /* Relay wait status to pipe, then loop back. */\n"
+ "\n"
+ " pushl $4 /* length */\n"
+ " pushl $__afl_temp /* data */\n"
+ " pushl $" STRINGIFY((FORKSRV_FD + 1)) " /* file desc */\n"
+ " call write\n"
+ " addl $12, %esp\n"
+ "\n"
+ " jmp __afl_fork_wait_loop\n"
+ "\n"
+ "__afl_fork_resume:\n"
+ "\n"
+ " /* In child process: close fds, resume execution. */\n"
+ "\n"
+ " pushl $" STRINGIFY(FORKSRV_FD) "\n"
+ " call close\n"
+ "\n"
+ " pushl $" STRINGIFY((FORKSRV_FD + 1)) "\n"
+ " call close\n"
+ "\n"
+ " addl $8, %esp\n"
+ "\n"
+ " popl %edx\n"
+ " popl %ecx\n"
+ " popl %eax\n"
+ " jmp __afl_store\n"
+ "\n"
+ "__afl_die:\n"
+ "\n"
+ " xorl %eax, %eax\n"
+ " call _exit\n"
+ "\n"
+ "__afl_setup_abort:\n"
+ "\n"
+ " /* Record setup failure so that we don't keep calling\n"
+ " shmget() / shmat() over and over again. */\n"
+ "\n"
+ " incb __afl_setup_failure\n"
+ " popl %ecx\n"
+ " popl %eax\n"
+ " jmp __afl_return\n"
+ "\n"
+ ".AFL_VARS:\n"
+ "\n"
+ " .comm __afl_area_ptr, 4, 32\n"
+ " .comm __afl_setup_failure, 1, 32\n"
+#ifndef COVERAGE_ONLY
+ " .comm __afl_prev_loc, 4, 32\n"
+#endif /* !COVERAGE_ONLY */
+ " .comm __afl_final_loc, 4, 32\n"
+ " .comm __afl_fork_pid, 4, 32\n"
+ " .comm __afl_temp, 4, 32\n"
+ "\n"
+ ".AFL_SHM_ENV:\n"
+ " .asciz \"" SHM_ENV_VAR "\"\n"
+ "\n"
+ "/* --- END --- */\n"
+ "\n";
+
+/* The OpenBSD hack is due to lahf and sahf not being recognized by some
+ versions of binutils: https://marc.info/?l=openbsd-cvs&m=141636589924400
+
+ The Apple code is a bit different when calling libc functions because
+ they are doing relocations differently from everybody else. We also need
+ to work around the crash issue with .lcomm and the fact that they don't
+ recognize .string. */
+
+#ifdef __APPLE__
+ #define CALL_L64(str) "call _" str "\n"
+#else
+ #define CALL_L64(str) "call " str "@PLT\n"
+#endif /* ^__APPLE__ */
+
+static const u8 *main_payload_64 =
+
+ "\n"
+ "/* --- AFL MAIN PAYLOAD (64-BIT) --- */\n"
+ "\n"
+ ".text\n"
+ ".att_syntax\n"
+ ".code64\n"
+ ".align 8\n"
+ "\n"
+ "__afl_maybe_log:\n"
+ "\n"
+#if defined(__OpenBSD__) || (defined(__FreeBSD__) && (__FreeBSD__ < 9))
+ " .byte 0x9f /* lahf */\n"
+#else
+ " lahf\n"
+#endif /* ^__OpenBSD__, etc */
+ " seto %al\n"
+ "\n"
+ " /* Check if SHM region is already mapped. */\n"
+ "\n"
+ " movq __afl_area_ptr(%rip), %rdx\n"
+ " testq %rdx, %rdx\n"
+ " je __afl_setup\n"
+ "\n"
+ "__afl_store:\n"
+ "\n"
+ " /* Calculate and store hit for the code location specified in rcx. */\n"
+ "\n"
+#ifndef COVERAGE_ONLY
+ " xorq __afl_prev_loc(%rip), %rcx\n"
+ " xorq %rcx, __afl_prev_loc(%rip)\n"
+ " shrq $1, __afl_prev_loc(%rip)\n"
+#endif /* ^!COVERAGE_ONLY */
+ "\n"
+#ifdef SKIP_COUNTS
+ " orb $1, (%rdx, %rcx, 1)\n"
+#else
+ " addb $1, (%rdx, %rcx, 1)\n"
+ " adcb $0, (%rdx, %rcx, 1)\n" // never zero counter implementation. slightly better path discovery and little performance impact
+#endif /* ^SKIP_COUNTS */
+ "\n"
+ "__afl_return:\n"
+ "\n"
+ " addb $127, %al\n"
+#if defined(__OpenBSD__) || (defined(__FreeBSD__) && (__FreeBSD__ < 9))
+ " .byte 0x9e /* sahf */\n"
+#else
+ " sahf\n"
+#endif /* ^__OpenBSD__, etc */
+ " ret\n"
+ "\n"
+ ".align 8\n"
+ "\n"
+ "__afl_setup:\n"
+ "\n"
+ " /* Do not retry setup if we had previous failures. */\n"
+ "\n"
+ " cmpb $0, __afl_setup_failure(%rip)\n"
+ " jne __afl_return\n"
+ "\n"
+ " /* Check out if we have a global pointer on file. */\n"
+ "\n"
+#ifndef __APPLE__
+ " movq __afl_global_area_ptr@GOTPCREL(%rip), %rdx\n"
+ " movq (%rdx), %rdx\n"
+#else
+ " movq __afl_global_area_ptr(%rip), %rdx\n"
+#endif /* !^__APPLE__ */
+ " testq %rdx, %rdx\n"
+ " je __afl_setup_first\n"
+ "\n"
+ " movq %rdx, __afl_area_ptr(%rip)\n"
+ " jmp __afl_store\n"
+ "\n"
+ "__afl_setup_first:\n"
+ "\n"
+ " /* Save everything that is not yet saved and that may be touched by\n"
+ " getenv() and several other libcalls we'll be relying on. */\n"
+ "\n"
+ " leaq -352(%rsp), %rsp\n"
+ "\n"
+ " movq %rax, 0(%rsp)\n"
+ " movq %rcx, 8(%rsp)\n"
+ " movq %rdi, 16(%rsp)\n"
+ " movq %rsi, 32(%rsp)\n"
+ " movq %r8, 40(%rsp)\n"
+ " movq %r9, 48(%rsp)\n"
+ " movq %r10, 56(%rsp)\n"
+ " movq %r11, 64(%rsp)\n"
+ "\n"
+ " movq %xmm0, 96(%rsp)\n"
+ " movq %xmm1, 112(%rsp)\n"
+ " movq %xmm2, 128(%rsp)\n"
+ " movq %xmm3, 144(%rsp)\n"
+ " movq %xmm4, 160(%rsp)\n"
+ " movq %xmm5, 176(%rsp)\n"
+ " movq %xmm6, 192(%rsp)\n"
+ " movq %xmm7, 208(%rsp)\n"
+ " movq %xmm8, 224(%rsp)\n"
+ " movq %xmm9, 240(%rsp)\n"
+ " movq %xmm10, 256(%rsp)\n"
+ " movq %xmm11, 272(%rsp)\n"
+ " movq %xmm12, 288(%rsp)\n"
+ " movq %xmm13, 304(%rsp)\n"
+ " movq %xmm14, 320(%rsp)\n"
+ " movq %xmm15, 336(%rsp)\n"
+ "\n"
+ " /* Map SHM, jumping to __afl_setup_abort if something goes wrong. */\n"
+ "\n"
+ " /* The 64-bit ABI requires 16-byte stack alignment. We'll keep the\n"
+ " original stack ptr in the callee-saved r12. */\n"
+ "\n"
+ " pushq %r12\n"
+ " movq %rsp, %r12\n"
+ " subq $16, %rsp\n"
+ " andq $0xfffffffffffffff0, %rsp\n"
+ "\n"
+ " leaq .AFL_SHM_ENV(%rip), %rdi\n"
+ CALL_L64("getenv")
+ "\n"
+ " testq %rax, %rax\n"
+ " je __afl_setup_abort\n"
+ "\n"
+#ifdef USEMMAP
+ " movl $384, %edx /* shm_open mode 0600 */\n"
+ " movl $2, %esi /* flags O_RDWR */\n"
+ " movq %rax, %rdi /* SHM file path */\n"
+ CALL_L64("shm_open")
+ "\n"
+ " cmpq $-1, %rax\n"
+ " je __afl_setup_abort\n"
+ "\n"
+ " movl $0, %r9d\n"
+ " movl %eax, %r8d\n"
+ " movl $1, %ecx\n"
+ " movl $3, %edx\n"
+ " movl $"STRINGIFY(MAP_SIZE)", %esi\n"
+ " movl $0, %edi\n"
+ CALL_L64("mmap")
+ "\n"
+ " cmpq $-1, %rax\n"
+ " je __afl_setup_abort\n"
+ "\n"
+#else
+ " movq %rax, %rdi\n"
+ CALL_L64("atoi")
+ "\n"
+ " xorq %rdx, %rdx /* shmat flags */\n"
+ " xorq %rsi, %rsi /* requested addr */\n"
+ " movq %rax, %rdi /* SHM ID */\n"
+ CALL_L64("shmat")
+ "\n"
+ " cmpq $-1, %rax\n"
+ " je __afl_setup_abort\n"
+ "\n"
+#endif
+ " movb $1, (%rax)\n"
+ " /* Store the address of the SHM region. */\n"
+ "\n"
+ " movq %rax, %rdx\n"
+ " movq %rax, __afl_area_ptr(%rip)\n"
+ "\n"
+#ifdef __APPLE__
+ " movq %rax, __afl_global_area_ptr(%rip)\n"
+#else
+ " movq __afl_global_area_ptr@GOTPCREL(%rip), %rdx\n"
+ " movq %rax, (%rdx)\n"
+#endif /* ^__APPLE__ */
+ " movq %rax, %rdx\n"
+ "\n"
+ "__afl_forkserver:\n"
+ "\n"
+ " /* Enter the fork server mode to avoid the overhead of execve() calls. We\n"
+ " push rdx (area ptr) twice to keep stack alignment neat. */\n"
+ "\n"
+ " pushq %rdx\n"
+ " pushq %rdx\n"
+ "\n"
+ " /* Phone home and tell the parent that we're OK. (Note that signals with\n"
+ " no SA_RESTART will mess it up). If this fails, assume that the fd is\n"
+ " closed because we were execve()d from an instrumented binary, or because\n"
+ " the parent doesn't want to use the fork server. */\n"
+ "\n"
+ " movq $4, %rdx /* length */\n"
+ " leaq __afl_temp(%rip), %rsi /* data */\n"
+ " movq $" STRINGIFY((FORKSRV_FD + 1)) ", %rdi /* file desc */\n"
+ CALL_L64("write")
+ "\n"
+ " cmpq $4, %rax\n"
+ " jne __afl_fork_resume\n"
+ "\n"
+ "__afl_fork_wait_loop:\n"
+ "\n"
+ " /* Wait for parent by reading from the pipe. Abort if read fails. */\n"
+ "\n"
+ " movq $4, %rdx /* length */\n"
+ " leaq __afl_temp(%rip), %rsi /* data */\n"
+ " movq $" STRINGIFY(FORKSRV_FD) ", %rdi /* file desc */\n"
+ CALL_L64("read")
+ " cmpq $4, %rax\n"
+ " jne __afl_die\n"
+ "\n"
+ " /* Once woken up, create a clone of our process. This is an excellent use\n"
+ " case for syscall(__NR_clone, 0, CLONE_PARENT), but glibc boneheadedly\n"
+ " caches getpid() results and offers no way to update the value, breaking\n"
+ " abort(), raise(), and a bunch of other things :-( */\n"
+ "\n"
+ CALL_L64("fork")
+ " cmpq $0, %rax\n"
+ " jl __afl_die\n"
+ " je __afl_fork_resume\n"
+ "\n"
+ " /* In parent process: write PID to pipe, then wait for child. */\n"
+ "\n"
+ " movl %eax, __afl_fork_pid(%rip)\n"
+ "\n"
+ " movq $4, %rdx /* length */\n"
+ " leaq __afl_fork_pid(%rip), %rsi /* data */\n"
+ " movq $" STRINGIFY((FORKSRV_FD + 1)) ", %rdi /* file desc */\n"
+ CALL_L64("write")
+ "\n"
+ " movq $0, %rdx /* no flags */\n"
+ " leaq __afl_temp(%rip), %rsi /* status */\n"
+ " movq __afl_fork_pid(%rip), %rdi /* PID */\n"
+ CALL_L64("waitpid")
+ " cmpq $0, %rax\n"
+ " jle __afl_die\n"
+ "\n"
+ " /* Relay wait status to pipe, then loop back. */\n"
+ "\n"
+ " movq $4, %rdx /* length */\n"
+ " leaq __afl_temp(%rip), %rsi /* data */\n"
+ " movq $" STRINGIFY((FORKSRV_FD + 1)) ", %rdi /* file desc */\n"
+ CALL_L64("write")
+ "\n"
+ " jmp __afl_fork_wait_loop\n"
+ "\n"
+ "__afl_fork_resume:\n"
+ "\n"
+ " /* In child process: close fds, resume execution. */\n"
+ "\n"
+ " movq $" STRINGIFY(FORKSRV_FD) ", %rdi\n"
+ CALL_L64("close")
+ "\n"
+ " movq $" STRINGIFY((FORKSRV_FD + 1)) ", %rdi\n"
+ CALL_L64("close")
+ "\n"
+ " popq %rdx\n"
+ " popq %rdx\n"
+ "\n"
+ " movq %r12, %rsp\n"
+ " popq %r12\n"
+ "\n"
+ " movq 0(%rsp), %rax\n"
+ " movq 8(%rsp), %rcx\n"
+ " movq 16(%rsp), %rdi\n"
+ " movq 32(%rsp), %rsi\n"
+ " movq 40(%rsp), %r8\n"
+ " movq 48(%rsp), %r9\n"
+ " movq 56(%rsp), %r10\n"
+ " movq 64(%rsp), %r11\n"
+ "\n"
+ " movq 96(%rsp), %xmm0\n"
+ " movq 112(%rsp), %xmm1\n"
+ " movq 128(%rsp), %xmm2\n"
+ " movq 144(%rsp), %xmm3\n"
+ " movq 160(%rsp), %xmm4\n"
+ " movq 176(%rsp), %xmm5\n"
+ " movq 192(%rsp), %xmm6\n"
+ " movq 208(%rsp), %xmm7\n"
+ " movq 224(%rsp), %xmm8\n"
+ " movq 240(%rsp), %xmm9\n"
+ " movq 256(%rsp), %xmm10\n"
+ " movq 272(%rsp), %xmm11\n"
+ " movq 288(%rsp), %xmm12\n"
+ " movq 304(%rsp), %xmm13\n"
+ " movq 320(%rsp), %xmm14\n"
+ " movq 336(%rsp), %xmm15\n"
+ "\n"
+ " leaq 352(%rsp), %rsp\n"
+ "\n"
+ " jmp __afl_store\n"
+ "\n"
+ "__afl_die:\n"
+ "\n"
+ " xorq %rax, %rax\n"
+ CALL_L64("_exit")
+ "\n"
+ "__afl_setup_abort:\n"
+ "\n"
+ " /* Record setup failure so that we don't keep calling\n"
+ " shmget() / shmat() over and over again. */\n"
+ "\n"
+ " incb __afl_setup_failure(%rip)\n"
+ "\n"
+ " movq %r12, %rsp\n"
+ " popq %r12\n"
+ "\n"
+ " movq 0(%rsp), %rax\n"
+ " movq 8(%rsp), %rcx\n"
+ " movq 16(%rsp), %rdi\n"
+ " movq 32(%rsp), %rsi\n"
+ " movq 40(%rsp), %r8\n"
+ " movq 48(%rsp), %r9\n"
+ " movq 56(%rsp), %r10\n"
+ " movq 64(%rsp), %r11\n"
+ "\n"
+ " movq 96(%rsp), %xmm0\n"
+ " movq 112(%rsp), %xmm1\n"
+ " movq 128(%rsp), %xmm2\n"
+ " movq 144(%rsp), %xmm3\n"
+ " movq 160(%rsp), %xmm4\n"
+ " movq 176(%rsp), %xmm5\n"
+ " movq 192(%rsp), %xmm6\n"
+ " movq 208(%rsp), %xmm7\n"
+ " movq 224(%rsp), %xmm8\n"
+ " movq 240(%rsp), %xmm9\n"
+ " movq 256(%rsp), %xmm10\n"
+ " movq 272(%rsp), %xmm11\n"
+ " movq 288(%rsp), %xmm12\n"
+ " movq 304(%rsp), %xmm13\n"
+ " movq 320(%rsp), %xmm14\n"
+ " movq 336(%rsp), %xmm15\n"
+ "\n"
+ " leaq 352(%rsp), %rsp\n"
+ "\n"
+ " jmp __afl_return\n"
+ "\n"
+ ".AFL_VARS:\n"
+ "\n"
+
+#ifdef __APPLE__
+
+ " .comm __afl_area_ptr, 8\n"
+ #ifndef COVERAGE_ONLY
+ " .comm __afl_prev_loc, 8\n"
+ #endif /* !COVERAGE_ONLY */
+ " .comm __afl_fork_pid, 4\n"
+ " .comm __afl_temp, 4\n"
+ " .comm __afl_setup_failure, 1\n"
+
+#else
+
+ " .lcomm __afl_area_ptr, 8\n"
+ #ifndef COVERAGE_ONLY
+ " .lcomm __afl_prev_loc, 8\n"
+ #endif /* !COVERAGE_ONLY */
+ " .lcomm __afl_fork_pid, 4\n"
+ " .lcomm __afl_temp, 4\n"
+ " .lcomm __afl_setup_failure, 1\n"
+
+#endif /* ^__APPLE__ */
+
+ " .comm __afl_global_area_ptr, 8, 8\n"
+ "\n"
+ ".AFL_SHM_ENV:\n"
+ " .asciz \"" SHM_ENV_VAR "\"\n"
+ "\n"
+ "/* --- END --- */\n"
+ "\n";
+
+#endif /* !_HAVE_AFL_AS_H */
+
diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h
new file mode 100644
index 00000000..9992e841
--- /dev/null
+++ b/include/afl-fuzz.h
@@ -0,0 +1,1269 @@
+/*
+ american fuzzy lop++ - fuzzer header
+ ------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
+ Andrea Fioraldi <andreafioraldi@gmail.com>,
+ Dominik Maier <mail@dmnk.co>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ This is the real deal: the program takes an instrumented binary and
+ attempts a variety of basic fuzzing tricks, paying close attention to
+ how they affect the execution path.
+
+ */
+
+#ifndef _AFL_FUZZ_H
+#define _AFL_FUZZ_H
+
+#define AFL_MAIN
+#define MESSAGES_TO_STDOUT
+
+#ifndef _GNU_SOURCE
+ #define _GNU_SOURCE 1
+#endif
+#ifndef _FILE_OFFSET_BITS
+ #define _FILE_OFFSET_BITS 64
+#endif
+
+#include "config.h"
+#include "types.h"
+#include "debug.h"
+#include "alloc-inl.h"
+#include "hash.h"
+#include "sharedmem.h"
+#include "forkserver.h"
+#include "common.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <signal.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <dlfcn.h>
+#include <sched.h>
+
+#include <netdb.h>
+#include <netinet/in.h>
+
+#include <sys/wait.h>
+#include <sys/time.h>
+#ifndef USEMMAP
+ #include <sys/shm.h>
+#endif
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <sys/types.h>
+
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
+ defined(__NetBSD__) || defined(__DragonFly__)
+ #include <sys/sysctl.h>
+#endif /* __APPLE__ || __FreeBSD__ || __OpenBSD__ */
+
+#if defined(__HAIKU__)
+ #include <kernel/OS.h>
+ #include <kernel/scheduler.h>
+#endif
+
+/* For systems that have sched_setaffinity; right now just Linux, but one
+ can hope... */
+
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
+ defined(__DragonFly__) || defined(__sun)
+ #define HAVE_AFFINITY 1
+ #if defined(__FreeBSD__) || defined(__DragonFly__)
+ #include <sys/param.h>
+ #if defined(__FreeBSD__)
+ #include <sys/cpuset.h>
+ #endif
+ #include <sys/user.h>
+ #include <pthread.h>
+ #include <pthread_np.h>
+ #define cpu_set_t cpuset_t
+ #elif defined(__NetBSD__)
+ #include <pthread.h>
+ #elif defined(__sun)
+ #include <sys/types.h>
+ #include <kstat.h>
+ #include <sys/sysinfo.h>
+ #include <sys/pset.h>
+ #include <strings.h>
+ #endif
+#endif /* __linux__ */
+
+#ifdef __APPLE__
+ #include <TargetConditionals.h>
+#endif
+
+#undef LIST_FOREACH /* clashes with FreeBSD */
+#include "list.h"
+#ifndef SIMPLE_FILES
+ #define CASE_PREFIX "id:"
+#else
+ #define CASE_PREFIX "id_"
+#endif /* ^!SIMPLE_FILES */
+
+#define STAGE_BUF_SIZE (64) /* usable size for stage name buf in afl_state */
+
+// Little helper to access the ptr to afl->##name_buf - for use in afl_realloc.
+#define AFL_BUF_PARAM(name) ((void **)&afl->name##_buf)
+
+#ifdef WORD_SIZE_64
+ #define AFL_RAND_RETURN u64
+#else
+ #define AFL_RAND_RETURN u32
+#endif
+
+extern s8 interesting_8[INTERESTING_8_LEN];
+extern s16 interesting_16[INTERESTING_8_LEN + INTERESTING_16_LEN];
+extern s32
+ interesting_32[INTERESTING_8_LEN + INTERESTING_16_LEN + INTERESTING_32_LEN];
+
+struct tainted {
+
+ u32 pos;
+ u32 len;
+ struct tainted *next;
+ struct tainted *prev;
+
+};
+
+struct queue_entry {
+
+ u8 *fname; /* File name for the test case */
+ u32 len; /* Input length */
+ u32 id; /* entry number in queue_buf */
+
+ u8 colorized, /* Do not run redqueen stage again */
+ cal_failed; /* Calibration failed? */
+ bool trim_done, /* Trimmed? */
+ was_fuzzed, /* historical, but needed for MOpt */
+ passed_det, /* Deterministic stages passed? */
+ has_new_cov, /* Triggers new coverage? */
+ var_behavior, /* Variable behavior? */
+ favored, /* Currently favored? */
+ fs_redundant, /* Marked as redundant in the fs? */
+ is_ascii, /* Is the input just ascii text? */
+ disabled; /* Is disabled from fuzz selection */
+
+ u32 bitmap_size, /* Number of bits set in bitmap */
+ fuzz_level, /* Number of fuzzing iterations */
+ n_fuzz_entry; /* offset in n_fuzz */
+
+ u64 exec_us, /* Execution time (us) */
+ handicap, /* Number of queue cycles behind */
+ depth, /* Path depth */
+ exec_cksum; /* Checksum of the execution trace */
+
+ u8 *trace_mini; /* Trace bytes, if kept */
+ u32 tc_ref; /* Trace bytes ref count */
+
+#ifdef INTROSPECTION
+ u32 bitsmap_size;
+#endif
+
+ double perf_score, /* performance score */
+ weight;
+
+ u8 *testcase_buf; /* The testcase buffer, if loaded. */
+
+ u8 * cmplog_colorinput; /* the result buf of colorization */
+ struct tainted *taint; /* Taint information from CmpLog */
+
+ struct queue_entry *mother; /* queue entry this based on */
+
+};
+
+struct extra_data {
+
+ u8 *data; /* Dictionary token data */
+ u32 len; /* Dictionary token length */
+ u32 hit_cnt; /* Use count in the corpus */
+
+};
+
+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 {
+
+ /* 00 */ STAGE_FLIP1,
+ /* 01 */ STAGE_FLIP2,
+ /* 02 */ STAGE_FLIP4,
+ /* 03 */ STAGE_FLIP8,
+ /* 04 */ STAGE_FLIP16,
+ /* 05 */ STAGE_FLIP32,
+ /* 06 */ STAGE_ARITH8,
+ /* 07 */ STAGE_ARITH16,
+ /* 08 */ STAGE_ARITH32,
+ /* 09 */ STAGE_INTEREST8,
+ /* 10 */ STAGE_INTEREST16,
+ /* 11 */ STAGE_INTEREST32,
+ /* 12 */ STAGE_EXTRAS_UO,
+ /* 13 */ STAGE_EXTRAS_UI,
+ /* 14 */ STAGE_EXTRAS_AO,
+ /* 15 */ STAGE_EXTRAS_AI,
+ /* 16 */ STAGE_HAVOC,
+ /* 17 */ STAGE_SPLICE,
+ /* 18 */ STAGE_PYTHON,
+ /* 19 */ STAGE_CUSTOM_MUTATOR,
+ /* 20 */ STAGE_COLORIZATION,
+ /* 21 */ STAGE_ITS,
+
+ STAGE_NUM_MAX
+
+};
+
+/* Stage value types */
+
+enum {
+
+ /* 00 */ STAGE_VAL_NONE,
+ /* 01 */ STAGE_VAL_LE,
+ /* 02 */ STAGE_VAL_BE
+
+};
+
+#define operator_num 19
+#define swarm_num 5
+#define period_core 500000
+
+#define RAND_C (rand() % 1000 * 0.001)
+#define v_max 1
+#define v_min 0.05
+#define limit_time_bound 1.1
+#define SPLICE_CYCLES_puppet_up 25
+#define SPLICE_CYCLES_puppet_low 5
+#define STAGE_RANDOMBYTE 12
+#define STAGE_DELETEBYTE 13
+#define STAGE_Clone75 14
+#define STAGE_OverWrite75 15
+#define STAGE_OverWriteExtra 16
+#define STAGE_InsertExtra 17
+#define STAGE_Splice 18
+#define period_pilot 50000
+
+enum {
+
+ /* 00 */ EXPLORE, /* AFL default, Exploration-based constant schedule */
+ /* 01 */ MMOPT, /* Modified MOPT schedule */
+ /* 02 */ EXPLOIT, /* AFL's exploitation-based const. */
+ /* 03 */ FAST, /* Exponential schedule */
+ /* 04 */ COE, /* Cut-Off Exponential schedule */
+ /* 05 */ LIN, /* Linear schedule */
+ /* 06 */ QUAD, /* Quadratic schedule */
+ /* 07 */ RARE, /* Rare edges */
+ /* 08 */ SEEK, /* EXPLORE that ignores timings */
+
+ POWER_SCHEDULES_NUM
+
+};
+
+/* Python stuff */
+#ifdef USE_PYTHON
+
+ // because Python sets stuff it should not ...
+ #ifdef _POSIX_C_SOURCE
+ #define _SAVE_POSIX_C_SOURCE _POSIX_C_SOURCE
+ #undef _POSIX_C_SOURCE
+ #endif
+ #ifdef _XOPEN_SOURCE
+ #define _SAVE_XOPEN_SOURCE _XOPEN_SOURCE
+ #undef _XOPEN_SOURCE
+ #endif
+
+ #include <Python.h>
+
+ #ifdef _SAVE_POSIX_C_SOURCE
+ #ifdef _POSIX_C_SOURCE
+ #undef _POSIX_C_SOURCE
+ #endif
+ #define _POSIX_C_SOURCE _SAVE_POSIX_C_SOURCE
+ #endif
+ #ifdef _SAVE_XOPEN_SOURCE
+ #ifdef _XOPEN_SOURCE
+ #undef _XOPEN_SOURCE
+ #endif
+ #define _XOPEN_SOURCE _SAVE_XOPEN_SOURCE
+ #endif
+
+enum {
+
+ /* 00 */ PY_FUNC_INIT,
+ /* 01 */ PY_FUNC_DEINIT,
+ /* FROM HERE ON BELOW ALL ARE OPTIONAL */
+ /* 02 */ PY_OPTIONAL = 2,
+ /* 02 */ PY_FUNC_FUZZ = 2,
+ /* 03 */ PY_FUNC_FUZZ_COUNT,
+ /* 04 */ PY_FUNC_POST_PROCESS,
+ /* 05 */ PY_FUNC_INIT_TRIM,
+ /* 06 */ PY_FUNC_POST_TRIM,
+ /* 07 */ PY_FUNC_TRIM,
+ /* 08 */ PY_FUNC_HAVOC_MUTATION,
+ /* 09 */ PY_FUNC_HAVOC_MUTATION_PROBABILITY,
+ /* 10 */ PY_FUNC_QUEUE_GET,
+ /* 11 */ PY_FUNC_QUEUE_NEW_ENTRY,
+ /* 12 */ PY_FUNC_INTROSPECTION,
+ /* 13 */ PY_FUNC_DESCRIBE,
+ PY_FUNC_COUNT
+
+};
+
+typedef struct py_mutator {
+
+ PyObject *py_module;
+ PyObject *py_functions[PY_FUNC_COUNT];
+ void * afl_state;
+ void * py_data;
+
+ u8 * fuzz_buf;
+ size_t fuzz_size;
+
+ Py_buffer post_process_buf;
+
+ u8 * trim_buf;
+ size_t trim_size;
+
+ u8 * havoc_buf;
+ size_t havoc_size;
+
+} py_mutator_t;
+
+#endif
+
+typedef struct MOpt_globals {
+
+ u64 * finds;
+ u64 * finds_v2;
+ u64 * cycles;
+ u64 * cycles_v2;
+ u64 * cycles_v3;
+ u32 is_pilot_mode;
+ u64 * pTime;
+ u64 period;
+ char *havoc_stagename;
+ char *splice_stageformat;
+ char *havoc_stagenameshort;
+ char *splice_stagenameshort;
+
+} MOpt_globals_t;
+
+extern char *power_names[POWER_SCHEDULES_NUM];
+
+typedef struct afl_env_vars {
+
+ u8 afl_skip_cpufreq, afl_exit_when_done, afl_no_affinity, afl_skip_bin_check,
+ afl_dumb_forksrv, afl_import_first, afl_custom_mutator_only, afl_no_ui,
+ afl_force_ui, afl_i_dont_care_about_missing_crashes, afl_bench_just_one,
+ afl_bench_until_crash, afl_debug_child, afl_autoresume, afl_cal_fast,
+ afl_cycle_schedules, afl_expand_havoc, afl_statsd, afl_cmplog_only_new,
+ afl_exit_on_seed_issues, afl_try_affinity, afl_ignore_problems,
+ afl_keep_timeouts, afl_pizza_mode;
+
+ u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path,
+ *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_preload,
+ *afl_max_det_extras, *afl_statsd_host, *afl_statsd_port,
+ *afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size,
+ *afl_testcache_entries, *afl_kill_signal, *afl_target_env,
+ *afl_persistent_record, *afl_exit_on_time;
+
+} afl_env_vars_t;
+
+struct afl_pass_stat {
+
+ u8 total;
+ u8 faileds;
+
+};
+
+struct foreign_sync {
+
+ u8 * dir;
+ time_t mtime;
+
+};
+
+typedef struct afl_state {
+
+ /* Position of this state in the global states list */
+ u32 _id;
+
+ afl_forkserver_t fsrv;
+ sharedmem_t shm;
+ sharedmem_t * shm_fuzz;
+ afl_env_vars_t afl_env;
+
+ char **argv; /* argv if needed */
+
+ /* MOpt:
+ Lots of globals, but mostly for the status UI and other things where it
+ really makes no sense to haul them around as function parameters. */
+ u64 orig_hit_cnt_puppet, last_limit_time_start, tmp_pilot_time,
+ total_pacemaker_time, total_puppet_find, temp_puppet_find, most_time_key,
+ most_time, most_execs_key, most_execs, old_hit_count, force_ui_update,
+ prev_run_time;
+
+ MOpt_globals_t mopt_globals_core, mopt_globals_pilot;
+
+ s32 limit_time_puppet, SPLICE_CYCLES_puppet, limit_time_sig, key_puppet,
+ key_module;
+
+ double w_init, w_end, w_now;
+
+ s32 g_now;
+ s32 g_max;
+
+ u64 tmp_core_time;
+ s32 swarm_now;
+
+ double x_now[swarm_num][operator_num], L_best[swarm_num][operator_num],
+ eff_best[swarm_num][operator_num], G_best[operator_num],
+ v_now[swarm_num][operator_num], probability_now[swarm_num][operator_num],
+ swarm_fitness[swarm_num];
+
+ u64 stage_finds_puppet[swarm_num][operator_num], /* Patterns found per
+ fuzz stage */
+ stage_finds_puppet_v2[swarm_num][operator_num],
+ stage_cycles_puppet_v2[swarm_num][operator_num],
+ stage_cycles_puppet_v3[swarm_num][operator_num],
+ stage_cycles_puppet[swarm_num][operator_num],
+ operator_finds_puppet[operator_num],
+ core_operator_finds_puppet[operator_num],
+ core_operator_finds_puppet_v2[operator_num],
+ core_operator_cycles_puppet[operator_num],
+ core_operator_cycles_puppet_v2[operator_num],
+ core_operator_cycles_puppet_v3[operator_num]; /* Execs per fuzz stage */
+
+ double period_pilot_tmp;
+ s32 key_lv;
+
+ u8 *in_dir, /* Input directory with test cases */
+ *out_dir, /* Working & output directory */
+ *tmp_dir, /* Temporary directory for input */
+ *sync_dir, /* Synchronization directory */
+ *sync_id, /* Fuzzer ID */
+ *power_name, /* Power schedule name */
+ *use_banner, /* Display banner */
+ *in_bitmap, /* Input bitmap */
+ *file_extension, /* File extension */
+ *orig_cmdline, /* Original command line */
+ *infoexec; /* Command to execute on a new crash */
+
+ u32 hang_tmout; /* Timeout used for hang det (ms) */
+
+ u8 havoc_stack_pow2, /* HAVOC_STACK_POW2 */
+ no_unlink, /* do not unlink cur_input */
+ debug, /* Debug mode */
+ custom_only, /* Custom mutator only mode */
+ is_main_node, /* if this is the main node */
+ is_secondary_node, /* if this is a secondary instance */
+ pizza_is_served; /* pizza mode */
+
+ u32 stats_update_freq; /* Stats update frequency (execs) */
+
+ u8 schedule; /* Power schedule (default: EXPLORE)*/
+ u8 havoc_max_mult;
+
+ u8 skip_deterministic, /* Skip deterministic stages? */
+ use_splicing, /* Recombine input files? */
+ non_instrumented_mode, /* Run in non-instrumented mode? */
+ score_changed, /* Scoring for favorites changed? */
+ resuming_fuzz, /* Resuming an older fuzzing job? */
+ timeout_given, /* Specific timeout given? */
+ not_on_tty, /* stdout is not a tty */
+ term_too_small, /* terminal dimensions too small */
+ no_forkserver, /* Disable forkserver? */
+ crash_mode, /* Crash mode! Yeah! */
+ in_place_resume, /* Attempt in-place resume? */
+ autoresume, /* Resume if afl->out_dir exists? */
+ auto_changed, /* Auto-generated tokens changed? */
+ no_cpu_meter_red, /* Feng shui on the status screen */
+ no_arith, /* Skip most arithmetic ops */
+ shuffle_queue, /* Shuffle input queue? */
+ bitmap_changed, /* Time to update bitmap? */
+ unicorn_mode, /* Running in Unicorn mode? */
+ use_wine, /* Use WINE with QEMU mode */
+ skip_requested, /* Skip request, via SIGUSR1 */
+ run_over10m, /* Run time over 10 minutes? */
+ persistent_mode, /* Running in persistent mode? */
+ deferred_mode, /* Deferred forkserver mode? */
+ fixed_seed, /* do not reseed */
+ fast_cal, /* Try to calibrate faster? */
+ disable_trim, /* Never trim in fuzz_one */
+ shmem_testcase_mode, /* If sharedmem testcases are used */
+ expand_havoc, /* perform expensive havoc after no find */
+ cycle_schedules, /* cycle power schedules? */
+ old_seed_selection, /* use vanilla afl seed selection */
+ reinit_table; /* reinit the queue weight table */
+
+ u8 *virgin_bits, /* Regions yet untouched by fuzzing */
+ *virgin_tmout, /* Bits we haven't seen in tmouts */
+ *virgin_crash; /* Bits we haven't seen in crashes */
+
+ double *alias_probability; /* alias weighted probabilities */
+ u32 * alias_table; /* alias weighted random lookup table */
+ u32 active_items; /* enabled entries in the queue */
+
+ u8 *var_bytes; /* Bytes that appear to be variable */
+
+#define N_FUZZ_SIZE (1 << 21)
+ u32 *n_fuzz;
+
+ volatile u8 stop_soon, /* Ctrl-C pressed? */
+ clear_screen; /* Window resized? */
+
+ u32 queued_items, /* Total number of queued testcases */
+ queued_variable, /* Testcases with variable behavior */
+ queued_at_start, /* Total number of initial inputs */
+ queued_discovered, /* Items discovered during this run */
+ queued_imported, /* Items imported via -S */
+ queued_favored, /* Paths deemed favorable */
+ queued_with_cov, /* Paths with new coverage bytes */
+ pending_not_fuzzed, /* Queued but not done yet */
+ pending_favored, /* Pending favored paths */
+ cur_skipped_items, /* Abandoned inputs in cur cycle */
+ cur_depth, /* Current path depth */
+ max_depth, /* Max path depth */
+ useless_at_start, /* Number of useless starting paths */
+ var_byte_count, /* Bitmap bytes with var behavior */
+ current_entry, /* Current queue entry ID */
+ havoc_div, /* Cycle count divisor for havoc */
+ max_det_extras; /* deterministic extra count (dicts)*/
+
+ u64 total_crashes, /* Total number of crashes */
+ saved_crashes, /* Crashes with unique signatures */
+ total_tmouts, /* Total number of timeouts */
+ saved_tmouts, /* Timeouts with unique signatures */
+ saved_hangs, /* Hangs with unique signatures */
+ last_crash_execs, /* Exec counter at last crash */
+ queue_cycle, /* Queue round counter */
+ cycles_wo_finds, /* Cycles without any new paths */
+ trim_execs, /* Execs done to trim input files */
+ bytes_trim_in, /* Bytes coming into the trimmer */
+ bytes_trim_out, /* Bytes coming outa the trimmer */
+ blocks_eff_total, /* Blocks subject to effector maps */
+ blocks_eff_select, /* Blocks selected as fuzzable */
+ start_time, /* Unix start time (ms) */
+ last_sync_time, /* Time of last sync */
+ last_sync_cycle, /* Cycle no. of the last sync */
+ last_find_time, /* Time for most recent path (ms) */
+ last_crash_time, /* Time for most recent crash (ms) */
+ last_hang_time, /* Time for most recent hang (ms) */
+ exit_on_time; /* Delay to exit if no new paths */
+
+ u32 slowest_exec_ms, /* Slowest testcase non hang in ms */
+ subseq_tmouts; /* Number of timeouts in a row */
+
+ u8 *stage_name, /* Name of the current fuzz stage */
+ *stage_short, /* Short stage name */
+ *syncing_party; /* Currently syncing with... */
+
+ u8 stage_name_buf[STAGE_BUF_SIZE]; /* reused stagename buf with len 64 */
+
+ u32 stage_cur, stage_max; /* Stage progression */
+ s32 splicing_with; /* Splicing with which test case? */
+
+ u32 main_node_id, main_node_max; /* Main instance job splitting */
+
+ u32 syncing_case; /* Syncing with case #... */
+
+ s32 stage_cur_byte, /* Byte offset of current stage op */
+ stage_cur_val; /* Value used for stage op */
+
+ u8 stage_val_type; /* Value type (STAGE_VAL_*) */
+
+ u64 stage_finds[32], /* Patterns found per fuzz stage */
+ stage_cycles[32]; /* Execs per fuzz stage */
+
+ u32 rand_cnt; /* Random number counter */
+
+ /* unsigned long rand_seed[3]; would also work */
+ AFL_RAND_RETURN rand_seed[3];
+ s64 init_seed;
+
+ u64 total_cal_us, /* Total calibration time (us) */
+ total_cal_cycles; /* Total calibration cycles */
+
+ u64 total_bitmap_size, /* Total bit count for all bitmaps */
+ total_bitmap_entries; /* Number of bitmaps counted */
+
+ s32 cpu_core_count, /* CPU core count */
+ cpu_to_bind; /* bind to specific CPU */
+
+#ifdef HAVE_AFFINITY
+ s32 cpu_aff; /* Selected CPU core */
+#endif /* HAVE_AFFINITY */
+
+ struct queue_entry *queue, /* Fuzzing queue (linked list) */
+ *queue_cur, /* Current offset within the queue */
+ *queue_top; /* Top of the list */
+
+ // growing buf
+ struct queue_entry **queue_buf;
+
+ struct queue_entry **top_rated; /* Top entries for bitmap bytes */
+
+ struct extra_data *extras; /* Extra tokens to fuzz with */
+ u32 extras_cnt; /* Total number of tokens read */
+
+ 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 */
+
+ /* CmpLog */
+
+ char * cmplog_binary;
+ afl_forkserver_t cmplog_fsrv; /* cmplog has its own little forkserver */
+
+ /* Custom mutators */
+ struct custom_mutator *mutator;
+
+ /* cmplog forkserver ids */
+ s32 cmplog_fsrv_ctl_fd, cmplog_fsrv_st_fd;
+ u32 cmplog_prev_timed_out;
+ u32 cmplog_max_filesize;
+ u32 cmplog_lvl;
+ u32 colorize_success;
+ u8 cmplog_enable_arith, cmplog_enable_transform;
+
+ struct afl_pass_stat *pass_stats;
+ struct cmp_map * orig_cmp_map;
+
+ u8 describe_op_buf_256[256]; /* describe_op will use this to return a string
+ up to 256 */
+
+ unsigned long long int last_avg_exec_update;
+ u32 last_avg_execs;
+ double last_avg_execs_saved;
+
+/* foreign sync */
+#define FOREIGN_SYNCS_MAX 32U
+ u8 foreign_sync_cnt;
+ struct foreign_sync foreign_syncs[FOREIGN_SYNCS_MAX];
+
+#ifdef _AFL_DOCUMENT_MUTATIONS
+ u8 do_document;
+ u32 document_counter;
+#endif
+
+ /* statistics file */
+ double last_bitmap_cvg, last_stability, last_eps;
+
+ /* plot file saves from last run */
+ u32 plot_prev_qp, plot_prev_pf, plot_prev_pnf, plot_prev_ce, plot_prev_md;
+ u64 plot_prev_qc, plot_prev_uc, plot_prev_uh, plot_prev_ed;
+
+ u64 stats_last_stats_ms, stats_last_plot_ms, stats_last_ms, stats_last_execs;
+
+ /* StatsD */
+ u64 statsd_last_send_ms;
+ struct sockaddr_in statsd_server;
+ int statsd_sock;
+ char * statsd_tags_flavor;
+ char * statsd_tags_format;
+ char * statsd_metric_format;
+ int statsd_metric_format_type;
+
+ double stats_avg_exec;
+
+ u8 *clean_trace;
+ u8 *clean_trace_custom;
+ u8 *first_trace;
+
+ /*needed for afl_fuzz_one */
+ // TODO: see which we can reuse
+ u8 *out_buf;
+
+ u8 *out_scratch_buf;
+
+ u8 *eff_buf;
+
+ u8 *in_buf;
+
+ u8 *in_scratch_buf;
+
+ u8 *ex_buf;
+
+ u8 *testcase_buf, *splicecase_buf;
+
+ u32 custom_mutators_count;
+
+ struct custom_mutator *current_custom_fuzz;
+
+ list_t custom_mutator_list;
+
+ /* this is a fixed buffer of size map_size that can be used by any function if
+ * they do not call another function */
+ u8 *map_tmp_buf;
+
+ /* queue entries ready for splicing count (len > 4) */
+ u32 ready_for_splicing_count;
+
+ /* min/max length for generated fuzzing inputs */
+ u32 min_length, max_length;
+
+ /* This is the user specified maximum size to use for the testcase cache */
+ u64 q_testcase_max_cache_size;
+
+ /* This is the user specified maximum entries in the testcase cache */
+ u32 q_testcase_max_cache_entries;
+
+ /* How much of the testcase cache is used so far */
+ u64 q_testcase_cache_size;
+
+ /* highest cache count so far */
+ u32 q_testcase_max_cache_count;
+
+ /* How many queue entries currently have cached testcases */
+ u32 q_testcase_cache_count;
+
+ /* the smallest id currently known free entry */
+ u32 q_testcase_smallest_free;
+
+ /* How often did we evict from the cache (for statistics only) */
+ u32 q_testcase_evictions;
+
+ /* Refs to each queue entry with cached testcase (for eviction, if cache_count
+ * is too large) */
+ struct queue_entry **q_testcase_cache;
+
+#ifdef INTROSPECTION
+ char mutation[8072];
+ char m_tmp[4096];
+ FILE *introspection_file;
+ u32 bitsmap_size;
+#endif
+
+} afl_state_t;
+
+struct custom_mutator {
+
+ const char *name;
+ char * name_short;
+ void * dh;
+ u8 * post_process_buf;
+ u8 stacked_custom_prob, stacked_custom;
+
+ void *data; /* custom mutator data ptr */
+
+ /* hooks for the custom mutator function */
+
+ /**
+ * Initialize the custom mutator.
+ *
+ * @param afl AFL instance.
+ * @param seed Seed used for the mutation.
+ * @return pointer to internal data or NULL on error
+ */
+ void *(*afl_custom_init)(afl_state_t *afl, unsigned int seed);
+
+ /**
+ * When afl-fuzz was compiled with INTROSPECTION=1 then custom mutators can
+ * also give introspection information back with this function.
+ *
+ * @param data pointer returned in afl_custom_init by this custom mutator
+ * @return pointer to a text string (const char*)
+ */
+ const char *(*afl_custom_introspection)(void *data);
+
+ /**
+ * This method is called just before fuzzing a queue entry with the custom
+ * mutator, and receives the initial buffer. It should return the number of
+ * fuzzes to perform.
+ *
+ * A value of 0 means no fuzzing of this queue entry.
+ *
+ * The function is now allowed to change the data.
+ *
+ * (Optional)
+ *
+ * @param data pointer returned in afl_custom_init by this custom mutator
+ * @param buf Buffer containing the test case
+ * @param buf_size Size of the test case
+ * @return The amount of fuzzes to perform on this queue entry, 0 = skip
+ */
+ u32 (*afl_custom_fuzz_count)(void *data, const u8 *buf, size_t buf_size);
+
+ /**
+ * Perform custom mutations on a given input
+ *
+ * (Optional for now. Required in the future)
+ *
+ * @param data pointer returned in afl_custom_init by this custom mutator
+ * @param[in] buf Pointer to the input data to be mutated and the mutated
+ * output
+ * @param[in] buf_size Size of the input/output data
+ * @param[out] out_buf the new buffer. We may reuse *buf if large enough.
+ * *out_buf = NULL is treated as FATAL.
+ * @param[in] add_buf Buffer containing the additional test case
+ * @param[in] add_buf_size Size of the additional test case
+ * @param[in] max_size Maximum size of the mutated output. The mutation must
+ * not produce data larger than max_size.
+ * @return Size of the mutated output.
+ */
+ size_t (*afl_custom_fuzz)(void *data, u8 *buf, size_t buf_size, u8 **out_buf,
+ u8 *add_buf, size_t add_buf_size, size_t max_size);
+
+ /**
+ * Describe the current testcase, generated by the last mutation.
+ * This will be called, for example, to give the written testcase a name
+ * after a crash ocurred. It can help to reproduce crashing mutations.
+ *
+ * (Optional)
+ *
+ * @param data pointer returned by afl_customm_init for this custom mutator
+ * @paramp[in] max_description_len maximum size avaliable for the description.
+ * A longer return string is legal, but will be truncated.
+ * @return A valid ptr to a 0-terminated string.
+ * An empty or NULL return will result in a default description
+ */
+ const char *(*afl_custom_describe)(void *data, size_t max_description_len);
+
+ /**
+ * A post-processing function to use right before AFL writes the test case to
+ * disk in order to execute the target.
+ *
+ * (Optional) If this functionality is not needed, simply don't define this
+ * function.
+ *
+ * @param[in] data pointer returned in afl_custom_init by this custom mutator
+ * @param[in] buf Buffer containing the test case to be executed
+ * @param[in] buf_size Size of the test case
+ * @param[out] out_buf Pointer to the buffer storing the test case after
+ * processing. External library should allocate memory for out_buf.
+ * It can chose to alter buf in-place, if the space is large enough.
+ * @return Size of the output buffer.
+ */
+ size_t (*afl_custom_post_process)(void *data, u8 *buf, size_t buf_size,
+ u8 **out_buf);
+
+ /**
+ * This method is called at the start of each trimming operation and receives
+ * the initial buffer. It should return the amount of iteration steps possible
+ * on this input (e.g. if your input has n elements and you want to remove
+ * them one by one, return n, if you do a binary search, return log(n),
+ * and so on...).
+ *
+ * If your trimming algorithm doesn't allow you to determine the amount of
+ * (remaining) steps easily (esp. while running), then you can alternatively
+ * return 1 here and always return 0 in post_trim until you are finished and
+ * no steps remain. In that case, returning 1 in post_trim will end the
+ * trimming routine. The whole current index/max iterations stuff is only used
+ * to show progress.
+ *
+ * (Optional)
+ *
+ * @param data pointer returned in afl_custom_init by this custom mutator
+ * @param buf Buffer containing the test case
+ * @param buf_size Size of the test case
+ * @return The amount of possible iteration steps to trim the input.
+ * Negative on error.
+ */
+ s32 (*afl_custom_init_trim)(void *data, u8 *buf, size_t buf_size);
+
+ /**
+ * This method is called for each trimming operation. It doesn't have any
+ * arguments because we already have the initial buffer from init_trim and we
+ * can memorize the current state in global variables. This can also save
+ * reparsing steps for each iteration. It should return the trimmed input
+ * buffer, where the returned data must not exceed the initial input data in
+ * length. Returning anything that is larger than the original data (passed
+ * to init_trim) will result in a fatal abort of AFLFuzz.
+ *
+ * (Optional)
+ *
+ * @param data pointer returned in afl_custom_init by this custom mutator
+ * @param[out] out_buf Pointer to the buffer containing the trimmed test case.
+ * The library can reuse a buffer for each call
+ * and will have to free the buf (for example in deinit)
+ * @return the size of the trimmed test case
+ */
+ size_t (*afl_custom_trim)(void *data, u8 **out_buf);
+
+ /**
+ * This method is called after each trim operation to inform you if your
+ * trimming step was successful or not (in terms of coverage). If you receive
+ * a failure here, you should reset your input to the last known good state.
+ *
+ * (Optional)
+ *
+ * @param data pointer returned in afl_custom_init by this custom mutator
+ * @param success Indicates if the last trim operation was successful.
+ * @return The next trim iteration index (from 0 to the maximum amount of
+ * steps returned in init_trim). Negative on error.
+ */
+ s32 (*afl_custom_post_trim)(void *data, u8 success);
+
+ /**
+ * Perform a single custom mutation on a given input.
+ * This mutation is stacked with the other muatations in havoc.
+ *
+ * (Optional)
+ *
+ * @param[in] data pointer returned in afl_custom_init by this custom mutator
+ * @param[in] buf Pointer to the input data to be mutated and the mutated
+ * output
+ * @param[in] buf_size Size of input data
+ * @param[out] out_buf The new buffer. It's legal to reuse *buf if it's <
+ * buf_size.
+ * @param[in] max_size Maximum size of the mutated output. The mutation must
+ * not produce data larger than max_size.
+ * @return Size of the mutated output (out_size).
+ */
+ size_t (*afl_custom_havoc_mutation)(void *data, u8 *buf, size_t buf_size,
+ u8 **out_buf, size_t max_size);
+
+ /**
+ * Return the probability (in percentage) that afl_custom_havoc_mutation
+ * is called in havoc. By default it is 6 %.
+ *
+ * (Optional)
+ *
+ * @param data pointer returned in afl_custom_init by this custom mutator
+ * @return The probability (0-100).
+ */
+ u8 (*afl_custom_havoc_mutation_probability)(void *data);
+
+ /**
+ * Determine whether the fuzzer should fuzz the current queue entry or not.
+ *
+ * (Optional)
+ *
+ * @param data pointer returned in afl_custom_init by this custom mutator
+ * @param filename File name of the test case in the queue entry
+ * @return Return True(1) if the fuzzer will fuzz the queue entry, and
+ * False(0) otherwise.
+ */
+ u8 (*afl_custom_queue_get)(void *data, const u8 *filename);
+
+ /**
+ * Allow for additional analysis (e.g. calling a different tool that does a
+ * different kind of coverage and saves this for the custom mutator).
+ *
+ * (Optional)
+ *
+ * @param data pointer returned in afl_custom_init by this custom mutator
+ * @param filename_new_queue File name of the new queue entry
+ * @param filename_orig_queue File name of the original queue entry. This
+ * argument can be NULL while initializing the fuzzer
+ */
+ u8 (*afl_custom_queue_new_entry)(void *data, const u8 *filename_new_queue,
+ const u8 *filename_orig_queue);
+ /**
+ * Deinitialize the custom mutator.
+ *
+ * @param data pointer returned in afl_custom_init by this custom mutator
+ */
+ void (*afl_custom_deinit)(void *data);
+
+};
+
+void afl_state_init(afl_state_t *, uint32_t map_size);
+void afl_state_deinit(afl_state_t *);
+
+/* Set stop_soon flag on all childs, kill all childs */
+void afl_states_stop(void);
+/* Set clear_screen flag on all states */
+void afl_states_clear_screen(void);
+/* Sets the skip flag on all states */
+void afl_states_request_skip(void);
+
+/* Setup shmem for testcase delivery */
+void setup_testcase_shmem(afl_state_t *afl);
+
+void read_afl_environment(afl_state_t *, char **);
+
+/**** Prototypes ****/
+
+/* Custom mutators */
+void setup_custom_mutators(afl_state_t *);
+void destroy_custom_mutators(afl_state_t *);
+u8 trim_case_custom(afl_state_t *, struct queue_entry *q, u8 *in_buf,
+ struct custom_mutator *mutator);
+void run_afl_custom_queue_new_entry(afl_state_t *, struct queue_entry *, u8 *,
+ u8 *);
+
+/* Python */
+#ifdef USE_PYTHON
+
+struct custom_mutator *load_custom_mutator_py(afl_state_t *, char *);
+void finalize_py_module(void *);
+
+u32 fuzz_count_py(void *, const u8 *, size_t);
+size_t post_process_py(void *, u8 *, size_t, u8 **);
+s32 init_trim_py(void *, u8 *, size_t);
+s32 post_trim_py(void *, u8);
+size_t trim_py(void *, u8 **);
+size_t havoc_mutation_py(void *, u8 *, size_t, u8 **, size_t);
+u8 havoc_mutation_probability_py(void *);
+u8 queue_get_py(void *, const u8 *);
+const char *introspection_py(void *);
+u8 queue_new_entry_py(void *, const u8 *, const u8 *);
+void deinit_py(void *);
+
+#endif
+
+/* Queue */
+
+void mark_as_det_done(afl_state_t *, struct queue_entry *);
+void mark_as_variable(afl_state_t *, struct queue_entry *);
+void mark_as_redundant(afl_state_t *, struct queue_entry *, u8);
+void add_to_queue(afl_state_t *, u8 *, u32, u8);
+void destroy_queue(afl_state_t *);
+void update_bitmap_score(afl_state_t *, struct queue_entry *);
+void cull_queue(afl_state_t *);
+u32 calculate_score(afl_state_t *, struct queue_entry *);
+
+/* Bitmap */
+
+void write_bitmap(afl_state_t *);
+u32 count_bits(afl_state_t *, u8 *);
+u32 count_bytes(afl_state_t *, u8 *);
+u32 count_non_255_bytes(afl_state_t *, u8 *);
+void simplify_trace(afl_state_t *, u8 *);
+void classify_counts(afl_forkserver_t *);
+#ifdef WORD_SIZE_64
+void discover_word(u8 *ret, u64 *current, u64 *virgin);
+#else
+void discover_word(u8 *ret, u32 *current, u32 *virgin);
+#endif
+void init_count_class16(void);
+void minimize_bits(afl_state_t *, u8 *, u8 *);
+#ifndef SIMPLE_FILES
+u8 *describe_op(afl_state_t *, u8, size_t);
+#endif
+u8 save_if_interesting(afl_state_t *, void *, u32, u8);
+u8 has_new_bits(afl_state_t *, u8 *);
+u8 has_new_bits_unclassified(afl_state_t *, u8 *);
+
+/* Extras */
+
+void load_extras_file(afl_state_t *, u8 *, u32 *, u32 *, u32);
+void load_extras(afl_state_t *, u8 *);
+void dedup_extras(afl_state_t *);
+void deunicode_extras(afl_state_t *);
+void add_extra(afl_state_t *afl, u8 *mem, u32 len);
+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 *);
+
+/* Stats */
+
+void load_stats_file(afl_state_t *);
+void write_setup_file(afl_state_t *, u32, char **);
+void write_stats_file(afl_state_t *, u32, double, double, double);
+void maybe_update_plot_file(afl_state_t *, u32, double, double);
+void show_stats(afl_state_t *);
+void show_stats_normal(afl_state_t *);
+void show_stats_pizza(afl_state_t *);
+void show_init_stats(afl_state_t *);
+
+/* StatsD */
+
+void statsd_setup_format(afl_state_t *afl);
+int statsd_socket_init(afl_state_t *afl);
+int statsd_send_metric(afl_state_t *afl);
+int statsd_format_metric(afl_state_t *afl, char *buff, size_t bufflen);
+
+/* Run */
+
+void sync_fuzzers(afl_state_t *);
+u32 write_to_testcase(afl_state_t *, void **, u32, u32);
+u8 calibrate_case(afl_state_t *, struct queue_entry *, u8 *, u32, u8);
+u8 trim_case(afl_state_t *, struct queue_entry *, u8 *);
+u8 common_fuzz_stuff(afl_state_t *, u8 *, u32);
+fsrv_run_result_t fuzz_run_target(afl_state_t *, afl_forkserver_t *fsrv, u32);
+
+/* Fuzz one */
+
+u8 fuzz_one_original(afl_state_t *);
+u8 pilot_fuzzing(afl_state_t *);
+u8 core_fuzzing(afl_state_t *);
+void pso_updating(afl_state_t *);
+u8 fuzz_one(afl_state_t *);
+
+/* Init */
+
+#ifdef HAVE_AFFINITY
+void bind_to_free_cpu(afl_state_t *);
+#endif
+void setup_post(afl_state_t *);
+void read_testcases(afl_state_t *, u8 *);
+void perform_dry_run(afl_state_t *);
+void pivot_inputs(afl_state_t *);
+u32 find_start_position(afl_state_t *);
+void find_timeout(afl_state_t *);
+double get_runnable_processes(void);
+void nuke_resume_dir(afl_state_t *);
+int check_main_node_exists(afl_state_t *);
+u32 select_next_queue_entry(afl_state_t *afl);
+void create_alias_table(afl_state_t *afl);
+void setup_dirs_fds(afl_state_t *);
+void setup_cmdline_file(afl_state_t *, char **);
+void setup_stdio_file(afl_state_t *);
+void check_crash_handling(void);
+void check_cpu_governor(afl_state_t *);
+void get_core_count(afl_state_t *);
+void fix_up_sync(afl_state_t *);
+void check_asan_opts(afl_state_t *);
+void check_binary(afl_state_t *, u8 *);
+void check_if_tty(afl_state_t *);
+void setup_signal_handlers(void);
+void save_cmdline(afl_state_t *, u32, char **);
+void read_foreign_testcases(afl_state_t *, int);
+void write_crash_readme(afl_state_t *afl);
+u8 check_if_text_buf(u8 *buf, u32 len);
+
+/* CmpLog */
+
+u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len);
+
+/* RedQueen */
+u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len);
+
+/* our RNG wrapper */
+AFL_RAND_RETURN rand_next(afl_state_t *afl);
+
+/* probability between 0.0 and 1.0 */
+double rand_next_percent(afl_state_t *afl);
+
+/**** Inline routines ****/
+
+/* Generate a random number (from 0 to limit - 1). This may
+ have slight bias. */
+
+static inline u32 rand_below(afl_state_t *afl, u32 limit) {
+
+ if (limit <= 1) return 0;
+
+ /* The boundary not being necessarily a power of 2,
+ we need to ensure the result uniformity. */
+ if (unlikely(!afl->rand_cnt--) && likely(!afl->fixed_seed)) {
+
+ ck_read(afl->fsrv.dev_urandom_fd, &afl->rand_seed, sizeof(afl->rand_seed),
+ "/dev/urandom");
+ // srandom(afl->rand_seed[0]);
+ afl->rand_cnt = (RESEED_RNG / 2) + (afl->rand_seed[1] % RESEED_RNG);
+
+ }
+
+ /* Modulo is biased - we don't want our fuzzing to be biased so let's do it
+ right. See:
+ https://stackoverflow.com/questions/10984974/why-do-people-say-there-is-modulo-bias-when-using-a-random-number-generator
+ */
+ u64 unbiased_rnd;
+ do {
+
+ unbiased_rnd = rand_next(afl);
+
+ } while (unlikely(unbiased_rnd >= (UINT64_MAX - (UINT64_MAX % limit))));
+
+ return unbiased_rnd % limit;
+
+}
+
+/* we prefer lower range values here */
+/* this is only called with normal havoc, not MOpt, to have an equalizer for
+ expand havoc mode */
+static inline u32 rand_below_datalen(afl_state_t *afl, u32 limit) {
+
+ if (limit <= 1) return 0;
+
+ switch (rand_below(afl, 3)) {
+
+ case 2:
+ return (rand_below(afl, limit) % (1 + rand_below(afl, limit - 1))) %
+ (1 + rand_below(afl, limit - 1));
+ break;
+ case 1:
+ return rand_below(afl, limit) % (1 + rand_below(afl, limit - 1));
+ break;
+ case 0:
+ return rand_below(afl, limit);
+ break;
+
+ }
+
+ return 1; // cannot be reached
+
+}
+
+static inline s64 rand_get_seed(afl_state_t *afl) {
+
+ if (unlikely(afl->fixed_seed)) { return afl->init_seed; }
+ return afl->rand_seed[0];
+
+}
+
+/* initialize randomness with a given seed. Can be called again at any time. */
+void rand_set_seed(afl_state_t *afl, s64 init_seed);
+
+/* Find first power of two greater or equal to val (assuming val under
+ 2^63). */
+
+static inline u64 next_p2(u64 val) {
+
+ u64 ret = 1;
+ while (val > ret) {
+
+ ret <<= 1;
+
+ }
+
+ return ret;
+
+}
+
+/* Returns the testcase buf from the file behind this queue entry.
+ Increases the refcount. */
+u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q);
+
+/* If trimming changes the testcase size we have to reload it */
+void queue_testcase_retake(afl_state_t *afl, struct queue_entry *q,
+ u32 old_len);
+
+/* If trimming changes the testcase size we have to replace it */
+void queue_testcase_retake_mem(afl_state_t *afl, struct queue_entry *q, u8 *in,
+ u32 len, u32 old_len);
+
+/* Add a new queue entry directly to the cache */
+
+void queue_testcase_store_mem(afl_state_t *afl, struct queue_entry *q, u8 *mem);
+
+#if TESTCASE_CACHE == 1
+ #error define of TESTCASE_CACHE must be zero or larger than 1
+#endif
+
+#endif
+
diff --git a/include/afl-prealloc.h b/include/afl-prealloc.h
new file mode 100644
index 00000000..bdf0d87f
--- /dev/null
+++ b/include/afl-prealloc.h
@@ -0,0 +1,143 @@
+/*
+ american fuzzy lop++ - prealloc a buffer to reuse small elements often
+ ----------------------------------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
+ Andrea Fioraldi <andreafioraldi@gmail.com>,
+ Dominik Maier <mail@dmnk.co>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ */
+
+/* If we know we'll reuse small elements often, we'll just preallocate a buffer,
+ * then fall back to malloc */
+// TODO: Replace free status check with bitmask+CLZ
+
+#ifndef AFL_PREALLOC_H
+#define AFL_PREALLOC_H
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include "debug.h"
+#include "alloc-inl.h"
+
+typedef enum prealloc_status {
+
+ PRE_STATUS_UNUSED = 0, /* free in buf */
+ PRE_STATUS_USED, /* used in buf */
+ PRE_STATUS_MALLOC /* system malloc */
+
+} pre_status_t;
+
+/* Adds the entry used for prealloc bookkeeping to this struct */
+
+/* prealloc status of this instance */
+#define PREALLOCABLE pre_status_t pre_status
+
+/* allocate an element of type *el_ptr, to this variable.
+ Uses (and reuses) the given prealloc_buf before hitting libc's malloc.
+ prealloc_buf must be the pointer to an array with type `type`.
+ `type` must be a struct with uses PREALLOCABLE (a pre_status_t pre_status
+ member). prealloc_size must be the array size. prealloc_counter must be a
+ variable initialized with 0 (of any name).
+ */
+
+#define PRE_ALLOC(el_ptr, prealloc_buf, prealloc_size, prealloc_counter) \
+ do { \
+ \
+ if ((prealloc_counter) >= (prealloc_size)) { \
+ \
+ el_ptr = (element_t *)malloc(sizeof(*el_ptr)); \
+ if (!el_ptr) { FATAL("error in list.h -> out of memory for element!"); } \
+ el_ptr->pre_status = PRE_STATUS_MALLOC; \
+ \
+ } else { \
+ \
+ /* Find one of our preallocated elements */ \
+ u32 i; \
+ for (i = 0; i < (prealloc_size); i++) { \
+ \
+ el_ptr = &((prealloc_buf)[i]); \
+ if (el_ptr->pre_status == PRE_STATUS_UNUSED) { \
+ \
+ (prealloc_counter)++; \
+ el_ptr->pre_status = PRE_STATUS_USED; \
+ break; \
+ \
+ } \
+ \
+ } \
+ \
+ } \
+ \
+ if (!el_ptr) { FATAL("BUG in list.h -> no element found or allocated!"); } \
+ \
+ } while (0);
+
+/* Take a chosen (free) element from the prealloc_buf directly */
+
+#define PRE_ALLOC_FORCE(el_ptr, prealloc_counter) \
+ do { \
+ \
+ if ((el_ptr)->pre_status != PRE_STATUS_UNUSED) { \
+ \
+ FATAL("PRE_ALLOC_FORCE element already allocated"); \
+ \
+ } \
+ (el_ptr)->pre_status = PRE_STATUS_USED; \
+ (prealloc_counter)++; \
+ \
+ } while (0);
+
+/* free an preallocated element */
+
+#define PRE_FREE(el_ptr, prealloc_counter) \
+ do { \
+ \
+ switch ((el_ptr)->pre_status) { \
+ \
+ case PRE_STATUS_USED: { \
+ \
+ (el_ptr)->pre_status = PRE_STATUS_UNUSED; \
+ (prealloc_counter)--; \
+ if ((prealloc_counter) < 0) { \
+ \
+ FATAL("Inconsistent data in PRE_FREE"); \
+ \
+ } \
+ break; \
+ \
+ } \
+ case PRE_STATUS_MALLOC: { \
+ \
+ (el_ptr)->pre_status = PRE_STATUS_UNUSED; \
+ DFL_ck_free((el_ptr)); \
+ break; \
+ \
+ } \
+ default: { \
+ \
+ FATAL("Double Free Detected"); \
+ break; \
+ \
+ } \
+ \
+ } \
+ \
+ } while (0);
+
+#endif
+
diff --git a/include/alloc-inl.h b/include/alloc-inl.h
new file mode 100644
index 00000000..6c2bafff
--- /dev/null
+++ b/include/alloc-inl.h
@@ -0,0 +1,779 @@
+/*
+ american fuzzy lop++ - error-checking, memory-zeroing alloc routines
+ --------------------------------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
+ Andrea Fioraldi <andreafioraldi@gmail.com>,
+ Dominik Maier <mail@dmnk.co>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ This allocator is not designed to resist malicious attackers (the canaries
+ are small and predictable), but provides a robust and portable way to detect
+ use-after-free, off-by-one writes, stale pointers, and so on.
+
+ */
+
+#ifndef _HAVE_ALLOC_INL_H
+#define _HAVE_ALLOC_INL_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+
+#include "config.h"
+#include "types.h"
+#include "debug.h"
+
+/* Initial size used for afl_realloc */
+#define INITIAL_GROWTH_SIZE (64)
+
+// Be careful! _WANT_ORIGINAL_AFL_ALLOC is not compatible with custom mutators
+
+#ifndef _WANT_ORIGINAL_AFL_ALLOC
+ // afl++ stuff without memory corruption checks - for speed
+
+ /* User-facing macro to sprintf() to a dynamically allocated buffer. */
+
+ #define alloc_printf(_str...) \
+ ({ \
+ \
+ u8 *_tmp; \
+ s32 _len = snprintf(NULL, 0, _str); \
+ if (_len < 0) FATAL("Whoa, snprintf() fails?!"); \
+ _tmp = ck_alloc(_len + 1); \
+ snprintf((char *)_tmp, _len + 1, _str); \
+ _tmp; \
+ \
+ })
+
+ /* Macro to enforce allocation limits as a last-resort defense against
+ integer overflows. */
+
+ #define ALLOC_CHECK_SIZE(_s) \
+ do { \
+ \
+ if ((_s) > MAX_ALLOC) ABORT("Bad alloc request: %u bytes", (_s)); \
+ \
+ } while (0)
+
+ /* Macro to check malloc() failures and the like. */
+
+ #define ALLOC_CHECK_RESULT(_r, _s) \
+ do { \
+ \
+ if (!(_r)) ABORT("Out of memory: can't allocate %u bytes", (_s)); \
+ \
+ } while (0)
+
+/* Allocate a buffer, explicitly not zeroing it. Returns NULL for zero-sized
+ requests. */
+
+static inline void *DFL_ck_alloc_nozero(u32 size) {
+
+ void *ret;
+
+ if (!size) { return NULL; }
+
+ ALLOC_CHECK_SIZE(size);
+ ret = malloc(size);
+ ALLOC_CHECK_RESULT(ret, size);
+
+ return (void *)ret;
+
+}
+
+/* Allocate a buffer, returning zeroed memory.
+ Returns null for 0 size */
+
+static inline void *DFL_ck_alloc(u32 size) {
+
+ void *mem;
+
+ if (!size) { return NULL; }
+ mem = DFL_ck_alloc_nozero(size);
+
+ return memset(mem, 0, size);
+
+}
+
+/* Free memory, checking for double free and corrupted heap. When DEBUG_BUILD
+ is set, the old memory will be also clobbered with 0xFF. */
+
+static inline void DFL_ck_free(void *mem) {
+
+ if (!mem) { return; }
+
+ free(mem);
+
+}
+
+/* Re-allocate a buffer, checking for issues and zeroing any newly-added tail.
+ With DEBUG_BUILD, the buffer is always reallocated to a new addresses and the
+ old memory is clobbered with 0xFF. */
+
+static inline void *DFL_ck_realloc(void *orig, u32 size) {
+
+ void *ret;
+
+ if (!size) {
+
+ DFL_ck_free(orig);
+ return NULL;
+
+ }
+
+ ALLOC_CHECK_SIZE(size);
+
+ /* Catch pointer issues sooner: force relocation and make sure that the
+ original buffer is wiped. */
+
+ ret = realloc(orig, size);
+
+ ALLOC_CHECK_RESULT(ret, size);
+
+ return (void *)ret;
+
+}
+
+/* Create a buffer with a copy of a string. Returns NULL for NULL inputs. */
+
+static inline u8 *DFL_ck_strdup(u8 *str) {
+
+ u8 *ret;
+ u32 size;
+
+ if (!str) { return NULL; }
+
+ size = strlen((char *)str) + 1;
+
+ ALLOC_CHECK_SIZE(size);
+ ret = (u8 *)malloc(size);
+ ALLOC_CHECK_RESULT(ret, size);
+
+ return (u8 *)memcpy(ret, str, size);
+
+}
+
+ /* In non-debug mode, we just do straightforward aliasing of the above
+ functions to user-visible names such as ck_alloc(). */
+
+ #define ck_alloc DFL_ck_alloc
+ #define ck_alloc_nozero DFL_ck_alloc_nozero
+ #define ck_realloc DFL_ck_realloc
+ #define ck_strdup DFL_ck_strdup
+ #define ck_free DFL_ck_free
+
+ #define alloc_report()
+
+#else
+ // This is the original alloc-inl of stock afl
+
+ /* User-facing macro to sprintf() to a dynamically allocated buffer. */
+
+ #define alloc_printf(_str...) \
+ ({ \
+ \
+ u8 *_tmp; \
+ s32 _len = snprintf(NULL, 0, _str); \
+ if (_len < 0) FATAL("Whoa, snprintf() fails?!"); \
+ _tmp = ck_alloc(_len + 1); \
+ snprintf((char *)_tmp, _len + 1, _str); \
+ _tmp; \
+ \
+ })
+
+ /* Macro to enforce allocation limits as a last-resort defense against
+ integer overflows. */
+ #define ALLOC_CHECK_SIZE(_s) \
+ do { \
+ \
+ if ((_s) > MAX_ALLOC) ABORT("Bad alloc request: %u bytes", (_s)); \
+ \
+ } while (0)
+
+ /* Macro to check malloc() failures and the like. */
+
+ #define ALLOC_CHECK_RESULT(_r, _s) \
+ do { \
+ \
+ if (!(_r)) ABORT("Out of memory: can't allocate %u bytes", (_s)); \
+ \
+ } while (0)
+
+ /* Magic tokens used to mark used / freed chunks. */
+
+ #define ALLOC_MAGIC_C1 0xFF00FF00 /* Used head (dword) */
+ #define ALLOC_MAGIC_F 0xFE00FE00 /* Freed head (dword) */
+ #define ALLOC_MAGIC_C2 0xF0 /* Used tail (byte) */
+
+ /* Positions of guard tokens in relation to the user-visible pointer. */
+
+ #define ALLOC_C1(_ptr) (((u32 *)(_ptr))[-2])
+ #define ALLOC_S(_ptr) (((u32 *)(_ptr))[-1])
+ #define ALLOC_C2(_ptr) (((u8 *)(_ptr))[ALLOC_S(_ptr)])
+
+ #define ALLOC_OFF_HEAD 8
+ #define ALLOC_OFF_TOTAL (ALLOC_OFF_HEAD + 1)
+
+ /* Sanity-checking macros for pointers. */
+
+ #define CHECK_PTR(_p) \
+ do { \
+ \
+ if (_p) { \
+ \
+ if (ALLOC_C1(_p) ^ ALLOC_MAGIC_C1) { \
+ \
+ if (ALLOC_C1(_p) == ALLOC_MAGIC_F) \
+ ABORT("Use after free."); \
+ else \
+ ABORT("Corrupted head alloc canary."); \
+ \
+ } \
+ if (ALLOC_C2(_p) ^ ALLOC_MAGIC_C2) \
+ ABORT("Corrupted tail alloc canary."); \
+ \
+ } \
+ \
+ } while (0)
+
+ #define CHECK_PTR_EXPR(_p) \
+ ({ \
+ \
+ typeof(_p) _tmp = (_p); \
+ CHECK_PTR(_tmp); \
+ _tmp; \
+ \
+ })
+
+/* Allocate a buffer, explicitly not zeroing it. Returns NULL for zero-sized
+ requests. */
+
+static inline void *DFL_ck_alloc_nozero(u32 size) {
+
+ void *ret;
+
+ if (!size) return NULL;
+
+ ALLOC_CHECK_SIZE(size);
+ ret = malloc(size + ALLOC_OFF_TOTAL);
+ ALLOC_CHECK_RESULT(ret, size);
+
+ ret = (char *)ret + ALLOC_OFF_HEAD;
+
+ ALLOC_C1(ret) = ALLOC_MAGIC_C1;
+ ALLOC_S(ret) = size;
+ ALLOC_C2(ret) = ALLOC_MAGIC_C2;
+
+ return ret;
+
+}
+
+/* Allocate a buffer, returning zeroed memory. */
+
+static inline void *DFL_ck_alloc(u32 size) {
+
+ void *mem;
+
+ if (!size) return NULL;
+ mem = DFL_ck_alloc_nozero(size);
+
+ return memset(mem, 0, size);
+
+}
+
+/* Free memory, checking for double free and corrupted heap. When DEBUG_BUILD
+ is set, the old memory will be also clobbered with 0xFF. */
+
+static inline void DFL_ck_free(void *mem) {
+
+ if (!mem) return;
+
+ CHECK_PTR(mem);
+ #ifdef DEBUG_BUILD
+
+ /* Catch pointer issues sooner. */
+ memset(mem, 0xFF, ALLOC_S(mem));
+
+ #endif /* DEBUG_BUILD */
+
+ ALLOC_C1(mem) = ALLOC_MAGIC_F;
+
+ free((char *)mem - ALLOC_OFF_HEAD);
+
+}
+
+/* Re-allocate a buffer, checking for issues and zeroing any newly-added tail.
+ With DEBUG_BUILD, the buffer is always reallocated to a new addresses and the
+ old memory is clobbered with 0xFF. */
+
+static inline void *DFL_ck_realloc(void *orig, u32 size) {
+
+ void *ret;
+ u32 old_size = 0;
+
+ if (!size) {
+
+ DFL_ck_free(orig);
+ return NULL;
+
+ }
+
+ if (orig) {
+
+ CHECK_PTR(orig);
+
+ #ifndef DEBUG_BUILD
+ ALLOC_C1(orig) = ALLOC_MAGIC_F;
+ #endif /* !DEBUG_BUILD */
+
+ old_size = ALLOC_S(orig);
+ orig = (char *)orig - ALLOC_OFF_HEAD;
+
+ ALLOC_CHECK_SIZE(old_size);
+
+ }
+
+ ALLOC_CHECK_SIZE(size);
+
+ #ifndef DEBUG_BUILD
+
+ ret = realloc(orig, size + ALLOC_OFF_TOTAL);
+ ALLOC_CHECK_RESULT(ret, size);
+
+ #else
+
+ /* Catch pointer issues sooner: force relocation and make sure that the
+ original buffer is wiped. */
+
+ ret = malloc(size + ALLOC_OFF_TOTAL);
+ ALLOC_CHECK_RESULT(ret, size);
+
+ if (orig) {
+
+ memcpy((char *)ret + ALLOC_OFF_HEAD, (char *)orig + ALLOC_OFF_HEAD,
+ MIN(size, old_size));
+ memset((char *)orig + ALLOC_OFF_HEAD, 0xFF, old_size);
+
+ ALLOC_C1((char *)orig + ALLOC_OFF_HEAD) = ALLOC_MAGIC_F;
+
+ free(orig);
+
+ }
+
+ #endif /* ^!DEBUG_BUILD */
+
+ ret = (char *)ret + ALLOC_OFF_HEAD;
+
+ ALLOC_C1(ret) = ALLOC_MAGIC_C1;
+ ALLOC_S(ret) = size;
+ ALLOC_C2(ret) = ALLOC_MAGIC_C2;
+
+ if (size > old_size) memset((char *)ret + old_size, 0, size - old_size);
+
+ return ret;
+
+}
+
+/* Create a buffer with a copy of a string. Returns NULL for NULL inputs. */
+
+static inline u8 *DFL_ck_strdup(u8 *str) {
+
+ void *ret;
+ u32 size;
+
+ if (!str) return NULL;
+
+ size = strlen((char *)str) + 1;
+
+ ALLOC_CHECK_SIZE(size);
+ ret = malloc(size + ALLOC_OFF_TOTAL);
+ ALLOC_CHECK_RESULT(ret, size);
+
+ ret = (char *)ret + ALLOC_OFF_HEAD;
+
+ ALLOC_C1(ret) = ALLOC_MAGIC_C1;
+ ALLOC_S(ret) = size;
+ ALLOC_C2(ret) = ALLOC_MAGIC_C2;
+
+ return memcpy(ret, str, size);
+
+}
+
+ #ifndef DEBUG_BUILD
+
+ /* In non-debug mode, we just do straightforward aliasing of the above
+ functions to user-visible names such as ck_alloc(). */
+
+ #define ck_alloc DFL_ck_alloc
+ #define ck_alloc_nozero DFL_ck_alloc_nozero
+ #define ck_realloc DFL_ck_realloc
+ #define ck_strdup DFL_ck_strdup
+ #define ck_free DFL_ck_free
+
+ #define alloc_report()
+
+ #else
+
+ /* In debugging mode, we also track allocations to detect memory leaks, and
+ the flow goes through one more layer of indirection. */
+
+ /* Alloc tracking data structures: */
+
+ #define ALLOC_BUCKETS 4096
+
+struct TRK_obj {
+
+ void *ptr;
+ char *file, *func;
+ u32 line;
+
+};
+
+ #ifdef AFL_MAIN
+
+struct TRK_obj *TRK[ALLOC_BUCKETS];
+u32 TRK_cnt[ALLOC_BUCKETS];
+
+ #define alloc_report() TRK_report()
+
+ #else
+
+extern struct TRK_obj *TRK[ALLOC_BUCKETS];
+extern u32 TRK_cnt[ALLOC_BUCKETS];
+
+ #define alloc_report()
+
+ #endif /* ^AFL_MAIN */
+
+ /* Bucket-assigning function for a given pointer: */
+
+ #define TRKH(_ptr) (((((u32)(_ptr)) >> 16) ^ ((u32)(_ptr))) % ALLOC_BUCKETS)
+
+/* Add a new entry to the list of allocated objects. */
+
+static inline void TRK_alloc_buf(void *ptr, const char *file, const char *func,
+ u32 line) {
+
+ u32 i, bucket;
+
+ if (!ptr) return;
+
+ bucket = TRKH(ptr);
+
+ /* Find a free slot in the list of entries for that bucket. */
+
+ for (i = 0; i < TRK_cnt[bucket]; i++)
+
+ if (!TRK[bucket][i].ptr) {
+
+ TRK[bucket][i].ptr = ptr;
+ TRK[bucket][i].file = (char *)file;
+ TRK[bucket][i].func = (char *)func;
+ TRK[bucket][i].line = line;
+ return;
+
+ }
+
+ /* No space available - allocate more. */
+
+ TRK[bucket] = DFL_ck_realloc(TRK[bucket],
+ (TRK_cnt[bucket] + 1) * sizeof(struct TRK_obj));
+
+ TRK[bucket][i].ptr = ptr;
+ TRK[bucket][i].file = (char *)file;
+ TRK[bucket][i].func = (char *)func;
+ TRK[bucket][i].line = line;
+
+ TRK_cnt[bucket]++;
+
+}
+
+/* Remove entry from the list of allocated objects. */
+
+static inline void TRK_free_buf(void *ptr, const char *file, const char *func,
+ u32 line) {
+
+ u32 i, bucket;
+
+ if (!ptr) return;
+
+ bucket = TRKH(ptr);
+
+ /* Find the element on the list... */
+
+ for (i = 0; i < TRK_cnt[bucket]; i++)
+
+ if (TRK[bucket][i].ptr == ptr) {
+
+ TRK[bucket][i].ptr = 0;
+ return;
+
+ }
+
+ WARNF("ALLOC: Attempt to free non-allocated memory in %s (%s:%u)", func, file,
+ line);
+
+}
+
+/* Do a final report on all non-deallocated objects. */
+
+static inline void TRK_report(void) {
+
+ u32 i, bucket;
+
+ fflush(0);
+
+ for (bucket = 0; bucket < ALLOC_BUCKETS; bucket++)
+ for (i = 0; i < TRK_cnt[bucket]; i++)
+ if (TRK[bucket][i].ptr)
+ WARNF("ALLOC: Memory never freed, created in %s (%s:%u)",
+ TRK[bucket][i].func, TRK[bucket][i].file, TRK[bucket][i].line);
+
+}
+
+/* Simple wrappers for non-debugging functions: */
+
+static inline void *TRK_ck_alloc(u32 size, const char *file, const char *func,
+ u32 line) {
+
+ void *ret = DFL_ck_alloc(size);
+ TRK_alloc_buf(ret, file, func, line);
+ return ret;
+
+}
+
+static inline void *TRK_ck_realloc(void *orig, u32 size, const char *file,
+ const char *func, u32 line) {
+
+ void *ret = DFL_ck_realloc(orig, size);
+ TRK_free_buf(orig, file, func, line);
+ TRK_alloc_buf(ret, file, func, line);
+ return ret;
+
+}
+
+static inline void *TRK_ck_strdup(u8 *str, const char *file, const char *func,
+ u32 line) {
+
+ void *ret = DFL_ck_strdup(str);
+ 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) {
+
+ TRK_free_buf(ptr, file, func, line);
+ DFL_ck_free(ptr);
+
+}
+
+ /* Aliasing user-facing names to tracking functions: */
+
+ #define ck_alloc(_p1) TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
+
+ #define ck_alloc_nozero(_p1) \
+ TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
+
+ #define ck_realloc(_p1, _p2) \
+ TRK_ck_realloc(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
+
+ #define ck_strdup(_p1) TRK_ck_strdup(_p1, __FILE__, __FUNCTION__, __LINE__)
+
+ #define ck_free(_p1) TRK_ck_free(_p1, __FILE__, __FUNCTION__, __LINE__)
+
+ #endif /* ^!DEBUG_BUILD */
+
+#endif /* _WANT_ORIGINAL_AFL_ALLOC */
+
+/* This function calculates the next power of 2 greater or equal its argument.
+ @return The rounded up power of 2 (if no overflow) or 0 on overflow.
+*/
+static inline size_t next_pow2(size_t in) {
+
+ // Commented this out as this behavior doesn't change, according to unittests
+ // if (in == 0 || in > (size_t)-1) {
+
+ //
+ // return 0; /* avoid undefined behaviour under-/overflow
+ // */
+ //
+ // }
+
+ size_t out = in - 1;
+ out |= out >> 1;
+ out |= out >> 2;
+ out |= out >> 4;
+ out |= out >> 8;
+ out |= out >> 16;
+ return out + 1;
+
+}
+
+/* AFL alloc buffer, the struct is here so we don't need to do fancy ptr
+ * arithmetics */
+struct afl_alloc_buf {
+
+ /* The complete allocated size, including the header of len
+ * AFL_ALLOC_SIZE_OFFSET */
+ size_t complete_size;
+ /* ptr to the first element of the actual buffer */
+ u8 buf[0];
+
+};
+
+#define AFL_ALLOC_SIZE_OFFSET (offsetof(struct afl_alloc_buf, buf))
+
+/* Returns the container element to this ptr */
+static inline struct afl_alloc_buf *afl_alloc_bufptr(void *buf) {
+
+ return (struct afl_alloc_buf *)((u8 *)buf - AFL_ALLOC_SIZE_OFFSET);
+
+}
+
+/* Gets the maximum size of the buf contents (ptr->complete_size -
+ * AFL_ALLOC_SIZE_OFFSET) */
+static inline size_t afl_alloc_bufsize(void *buf) {
+
+ return afl_alloc_bufptr(buf)->complete_size - AFL_ALLOC_SIZE_OFFSET;
+
+}
+
+/* This function makes sure *size is > size_needed after call.
+ It will realloc *buf otherwise.
+ *size will grow exponentially as per:
+ https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/
+ Will return NULL and free *buf if size_needed is <1 or realloc failed.
+ @return For convenience, this function returns *buf.
+ */
+static inline void *afl_realloc(void **buf, size_t size_needed) {
+
+ struct afl_alloc_buf *new_buf = NULL;
+
+ size_t current_size = 0;
+ size_t next_size = 0;
+
+ if (likely(*buf)) {
+
+ /* the size is always stored at buf - 1*size_t */
+ new_buf = (struct afl_alloc_buf *)afl_alloc_bufptr(*buf);
+ current_size = new_buf->complete_size;
+
+ }
+
+ size_needed += AFL_ALLOC_SIZE_OFFSET;
+
+ /* No need to realloc */
+ if (likely(current_size >= size_needed)) { return *buf; }
+
+ /* No initial size was set */
+ if (size_needed < INITIAL_GROWTH_SIZE) {
+
+ next_size = INITIAL_GROWTH_SIZE;
+
+ } else {
+
+ /* grow exponentially */
+ next_size = next_pow2(size_needed);
+
+ /* handle overflow: fall back to the original size_needed */
+ if (unlikely(!next_size)) { next_size = size_needed; }
+
+ }
+
+ /* alloc */
+ struct afl_alloc_buf *newer_buf =
+ (struct afl_alloc_buf *)realloc(new_buf, next_size);
+ if (unlikely(!newer_buf)) {
+
+ free(new_buf); // avoid a leak
+ *buf = NULL;
+ return NULL;
+
+ } else {
+
+ new_buf = newer_buf;
+
+ }
+
+ new_buf->complete_size = next_size;
+ *buf = (void *)(new_buf->buf);
+ return *buf;
+
+}
+
+/* afl_realloc_exact uses afl alloc buffers but sets it to a specific size */
+
+static inline void *afl_realloc_exact(void **buf, size_t size_needed) {
+
+ struct afl_alloc_buf *new_buf = NULL;
+
+ size_t current_size = 0;
+
+ if (likely(*buf)) {
+
+ /* the size is always stored at buf - 1*size_t */
+ new_buf = (struct afl_alloc_buf *)afl_alloc_bufptr(*buf);
+ current_size = new_buf->complete_size;
+
+ }
+
+ size_needed += AFL_ALLOC_SIZE_OFFSET;
+
+ /* No need to realloc */
+ if (unlikely(current_size == size_needed)) { return *buf; }
+
+ /* alloc */
+ struct afl_alloc_buf *newer_buf =
+ (struct afl_alloc_buf *)realloc(new_buf, size_needed);
+ if (unlikely(!newer_buf)) {
+
+ free(new_buf); // avoid a leak
+ *buf = NULL;
+ return NULL;
+
+ } else {
+
+ new_buf = newer_buf;
+
+ }
+
+ new_buf->complete_size = size_needed;
+ *buf = (void *)(new_buf->buf);
+ return *buf;
+
+}
+
+static inline void afl_free(void *buf) {
+
+ if (buf) { free(afl_alloc_bufptr(buf)); }
+
+}
+
+/* Swaps buf1 ptr and buf2 ptr, as well as their sizes */
+static inline void afl_swap_bufs(void **buf1, void **buf2) {
+
+ void *scratch_buf = *buf1;
+ *buf1 = *buf2;
+ *buf2 = scratch_buf;
+
+}
+
+#undef INITIAL_GROWTH_SIZE
+
+#endif /* ! _HAVE_ALLOC_INL_H */
+
diff --git a/include/android-ashmem.h b/include/android-ashmem.h
new file mode 100644
index 00000000..1bfd3220
--- /dev/null
+++ b/include/android-ashmem.h
@@ -0,0 +1,84 @@
+#ifdef __ANDROID__
+ #ifndef _ANDROID_ASHMEM_H
+ #define _ANDROID_ASHMEM_H
+
+ #define _GNU_SOURCE
+ #include <sys/syscall.h>
+ #include <unistd.h>
+ #include <fcntl.h>
+ #include <linux/ashmem.h>
+ #include <sys/ioctl.h>
+ #include <sys/mman.h>
+ #include <sys/shm.h>
+ #include <stdio.h>
+ #define ASHMEM_DEVICE "/dev/ashmem"
+
+int shmdt(const void *address) {
+
+ #if defined(SYS_shmdt)
+ return syscall(SYS_shmdt, address);
+ #else
+ return syscall(SYS_ipc, SHMDT, 0, 0, 0, address, 0);
+ #endif
+
+}
+
+int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf) {
+
+ int ret = 0;
+ if (__cmd == IPC_RMID) {
+
+ int length = ioctl(__shmid, ASHMEM_GET_SIZE, NULL);
+ struct ashmem_pin pin = {0, length};
+ ret = ioctl(__shmid, ASHMEM_UNPIN, &pin);
+ close(__shmid);
+
+ }
+
+ return ret;
+
+}
+
+int shmget(key_t __key, size_t __size, int __shmflg) {
+
+ (void)__shmflg;
+ int fd, ret;
+ char ourkey[11];
+
+ fd = open(ASHMEM_DEVICE, O_RDWR);
+ if (fd < 0) return fd;
+
+ sprintf(ourkey, "%d", __key);
+ ret = ioctl(fd, ASHMEM_SET_NAME, ourkey);
+ if (ret < 0) goto error;
+
+ ret = ioctl(fd, ASHMEM_SET_SIZE, __size);
+ if (ret < 0) goto error;
+
+ return fd;
+
+error:
+ close(fd);
+ return ret;
+
+}
+
+void *shmat(int __shmid, const void *__shmaddr, int __shmflg) {
+
+ (void)__shmflg;
+ int size;
+ void *ptr;
+
+ size = ioctl(__shmid, ASHMEM_GET_SIZE, NULL);
+ if (size < 0) { return NULL; }
+
+ ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, __shmid, 0);
+ if (ptr == MAP_FAILED) { return NULL; }
+
+ return ptr;
+
+}
+
+ #endif /* !_ANDROID_ASHMEM_H */
+#endif /* !__ANDROID__ */
+
diff --git a/include/cmplog.h b/include/cmplog.h
new file mode 100644
index 00000000..c6d2957e
--- /dev/null
+++ b/include/cmplog.h
@@ -0,0 +1,89 @@
+/*
+ american fuzzy lop++ - cmplog header
+ ------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Forkserver design by Jann Horn <jannhorn@googlemail.com>
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
+ Andrea Fioraldi <andreafioraldi@gmail.com>,
+ Dominik Maier <mail@dmnk.co>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ Shared code to handle the shared memory. This is used by the fuzzer
+ as well the other components like afl-tmin, afl-showmap, etc...
+
+ */
+
+#ifndef _AFL_CMPLOG_H
+#define _AFL_CMPLOG_H
+
+#include "config.h"
+
+#define CMPLOG_LVL_MAX 3
+
+#define CMP_MAP_W 65536
+#define CMP_MAP_H 32
+#define CMP_MAP_RTN_H (CMP_MAP_H / 4)
+
+#define SHAPE_BYTES(x) (x + 1)
+
+#define CMP_TYPE_INS 1
+#define CMP_TYPE_RTN 2
+
+struct cmp_header {
+
+ unsigned hits : 24;
+ unsigned id : 24;
+ unsigned shape : 5;
+ unsigned type : 2;
+ unsigned attribute : 4;
+ unsigned overflow : 1;
+ unsigned reserved : 4;
+
+} __attribute__((packed));
+
+struct cmp_operands {
+
+ u64 v0;
+ u64 v1;
+ u64 v0_128;
+ u64 v1_128;
+
+} __attribute__((packed));
+
+struct cmpfn_operands {
+
+ u8 v0[31];
+ u8 v0_len;
+ u8 v1[31];
+ u8 v1_len;
+
+} __attribute__((packed));
+
+typedef struct cmp_operands cmp_map_list[CMP_MAP_H];
+
+struct cmp_map {
+
+ struct cmp_header headers[CMP_MAP_W];
+ struct cmp_operands log[CMP_MAP_W][CMP_MAP_H];
+
+};
+
+/* Execs the child */
+
+struct afl_forkserver;
+void cmplog_exec_child(struct afl_forkserver *fsrv, char **argv);
+
+#endif
+
diff --git a/include/common.h b/include/common.h
new file mode 100644
index 00000000..896c5fb2
--- /dev/null
+++ b/include/common.h
@@ -0,0 +1,136 @@
+/*
+ american fuzzy lop++ - common routines header
+ ---------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
+ Andrea Fioraldi <andreafioraldi@gmail.com>,
+ Dominik Maier <mail@dmnk.co>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ Gather some functions common to multiple executables
+
+ - detect_file_args
+
+ */
+
+#ifndef __AFLCOMMON_H
+#define __AFLCOMMON_H
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <stdbool.h>
+#include "types.h"
+
+/* STRINGIFY_VAL_SIZE_MAX will fit all stringify_ strings. */
+
+#define STRINGIFY_VAL_SIZE_MAX (16)
+
+u32 check_binary_signatures(u8 *fn);
+void detect_file_args(char **argv, u8 *prog_in, bool *use_stdin);
+void print_suggested_envs(char *mispelled_env);
+void check_environment_vars(char **env);
+
+char **argv_cpy_dup(int argc, char **argv);
+void argv_cpy_free(char **argv);
+
+char **get_cs_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv);
+char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv);
+char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv);
+char * get_afl_env(char *env);
+
+/* Extract env vars from input string and set them using setenv()
+ For use with AFL_TARGET_ENV, ... */
+bool extract_and_set_env(u8 *env_str);
+
+extern u8 be_quiet;
+extern u8 *doc_path; /* path to documentation dir */
+
+/* Find binary, used by analyze, showmap, tmin
+ @returns the path, allocating the string */
+
+u8 *find_binary(u8 *fname);
+
+/* find an afl binary */
+
+u8 *find_afl_binary(u8 *own_loc, u8 *fname);
+
+/* Parses the kill signal environment variable, FATALs on error.
+ If the env is not set, sets the env to default_signal for the signal handlers
+ and returns the default_signal. */
+int parse_afl_kill_signal_env(u8 *afl_kill_signal_env, int default_signal);
+
+/* Read a bitmap from file fname to memory
+ This is for the -B option again. */
+
+void read_bitmap(u8 *fname, u8 *map, size_t len);
+
+/* Get unix time in milliseconds */
+
+u64 get_cur_time(void);
+
+/* Get unix time in microseconds */
+
+u64 get_cur_time_us(void);
+
+/* Describe integer. The buf should be
+ at least 6 bytes to fit all ints we randomly see.
+ Will return buf for convenience. */
+
+u8 *stringify_int(u8 *buf, size_t len, u64 val);
+
+/* Describe float. Similar as int. */
+
+u8 *stringify_float(u8 *buf, size_t len, double val);
+
+/* Describe integer as memory size. */
+
+u8 *stringify_mem_size(u8 *buf, size_t len, u64 val);
+
+/* Describe time delta as string.
+ Returns a pointer to buf for convenience. */
+
+u8 *stringify_time_diff(u8 *buf, size_t len, u64 cur_ms, u64 event_ms);
+
+/* Unsafe Describe integer. The buf sizes are not checked.
+ This is unsafe but fast.
+ Will return buf for convenience. */
+
+u8 *u_stringify_int(u8 *buf, u64 val);
+
+/* Unsafe describe float. Similar as unsafe int. */
+
+u8 *u_stringify_float(u8 *buf, double val);
+
+/* Unsafe describe integer as memory size. */
+
+u8 *u_stringify_mem_size(u8 *buf, u64 val);
+
+/* Unsafe describe time delta as string.
+ Returns a pointer to buf for convenience. */
+
+u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms);
+
+/* Reads the map size from ENV */
+u32 get_map_size(void);
+
+/* create a stream file */
+FILE *create_ffile(u8 *fn);
+
+/* create a file */
+s32 create_file(u8 *fn);
+
+#endif
+
diff --git a/include/config.h b/include/config.h
new file mode 100644
index 00000000..9fc92b06
--- /dev/null
+++ b/include/config.h
@@ -0,0 +1,510 @@
+/*
+ american fuzzy lop++ - vaguely configurable bits
+ ------------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
+ Andrea Fioraldi <andreafioraldi@gmail.com>,
+ Dominik Maier <mail@dmnk.co>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ */
+
+#ifndef _HAVE_CONFIG_H
+#define _HAVE_CONFIG_H
+
+/* Version string: */
+
+// c = release, a = volatile github dev, e = experimental branch
+#define VERSION "++4.01a"
+
+/******************************************************
+ * *
+ * Settings that may be of interest to power users: *
+ * *
+ ******************************************************/
+
+/* Default shared memory map size. Most targets just need a coverage map
+ between 20-250kb. Plus there is an auto-detection feature in afl-fuzz.
+ However if a target has problematic constructors and init arrays then
+ this can fail. Hence afl-fuzz deploys a larger default map. The largest
+ map seen so far is the xlsx fuzzer for libreoffice which is 5MB.
+ At runtime this value can be overriden via AFL_MAP_SIZE.
+ Default: 8MB (defined in bytes) */
+#define DEFAULT_SHMEM_SIZE (8 * 1024 * 1024)
+
+/* Default file permission umode when creating files (default: 0600) */
+#define DEFAULT_PERMISSION 0600
+
+/* CMPLOG/REDQUEEN TUNING
+ *
+ * Here you can modify tuning and solving options for CMPLOG.
+ * Note that these are run-time options for afl-fuzz, no target
+ * recompilation required.
+ *
+ */
+
+/* if TRANSFORM is enabled with '-l T', this additionally enables base64
+ encoding/decoding */
+// #define CMPLOG_SOLVE_TRANSFORM_BASE64
+
+/* If a redqueen pass finds more than one solution, try to combine them? */
+#define CMPLOG_COMBINE
+
+/* Minimum % of the corpus to perform cmplog on. Default: 10% */
+#define CMPLOG_CORPUS_PERCENT 5U
+
+/* Number of potential positions from which we decide if cmplog becomes
+ useless, default 8096 */
+#define CMPLOG_POSITIONS_MAX (12 * 1024)
+
+/* Maximum allowed fails per CMP value. Default: 128 */
+#define CMPLOG_FAIL_MAX 96
+
+/* -------------------------------------*/
+/* Now non-cmplog configuration options */
+/* -------------------------------------*/
+
+/* If a persistent target keeps state and found crashes are not reproducable
+ then enable this option and set the AFL_PERSISTENT_RECORD env variable
+ to a number. These number of testcases prior and including the crash case
+ will be kept and written to the crash/ directory as RECORD:... files.
+ Note that every crash will be written, not only unique ones! */
+
+//#define AFL_PERSISTENT_RECORD
+
+/* console output colors: There are three ways to configure its behavior
+ * 1. default: colored outputs fixed on: defined USE_COLOR && defined
+ * ALWAYS_COLORED The env var. AFL_NO_COLOR will have no effect
+ * 2. defined USE_COLOR && !defined ALWAYS_COLORED
+ * -> depending on env var AFL_NO_COLOR=1 colors can be switched off
+ * at run-time. Default is to use colors.
+ * 3. colored outputs fixed off: !defined USE_COLOR
+ * The env var. AFL_NO_COLOR will have no effect
+ */
+
+/* Comment out to disable terminal colors (note that this makes afl-analyze
+ a lot less nice): */
+
+#define USE_COLOR
+
+#ifdef USE_COLOR
+ /* Comment in to always enable terminal colors */
+ /* Comment out to enable runtime controlled terminal colors via AFL_NO_COLOR
+ */
+ #define ALWAYS_COLORED 1
+#endif
+
+/* StatsD config
+ Config can be adjusted via AFL_STATSD_HOST and AFL_STATSD_PORT environment
+ variable.
+*/
+#define STATSD_UPDATE_SEC 1
+#define STATSD_DEFAULT_PORT 8125
+#define STATSD_DEFAULT_HOST "127.0.0.1"
+
+/* If you want to have the original afl internal memory corruption checks.
+ Disabled by default for speed. it is better to use "make ASAN_BUILD=1". */
+
+// #define _WANT_ORIGINAL_AFL_ALLOC
+
+/* Comment out to disable fancy ANSI boxes and use poor man's 7-bit UI: */
+
+#ifndef ANDROID_DISABLE_FANCY // Fancy boxes are ugly from adb
+ #define FANCY_BOXES
+#endif
+
+/* Default timeout for fuzzed code (milliseconds). This is the upper bound,
+ also used for detecting hangs; the actual value is auto-scaled: */
+
+#define EXEC_TIMEOUT 1000U
+
+/* Timeout rounding factor when auto-scaling (milliseconds): */
+
+#define EXEC_TM_ROUND 20U
+
+/* 64bit arch MACRO */
+#if (defined(__x86_64__) || defined(__arm64__) || defined(__aarch64__))
+ #define WORD_SIZE_64 1
+#endif
+
+/* Default memory limit for child process (MB) 0 = disabled : */
+
+#define MEM_LIMIT 0U
+
+/* Default memory limit when running in QEMU mode (MB) 0 = disabled : */
+
+#define MEM_LIMIT_QEMU 0U
+
+/* Default memory limit when running in Unicorn mode (MB) 0 = disabled : */
+
+#define MEM_LIMIT_UNICORN 0U
+
+/* Number of calibration cycles per every new test case (and for test
+ cases that show variable behavior): */
+
+#define CAL_CYCLES 8U
+#define CAL_CYCLES_LONG 20U
+
+/* Number of subsequent timeouts before abandoning an input file: */
+
+#define TMOUT_LIMIT 250U
+
+/* Maximum number of unique hangs or crashes to record: */
+
+#define KEEP_UNIQUE_HANG 500U
+#define KEEP_UNIQUE_CRASH 10000U
+
+/* Baseline number of random tweaks during a single 'havoc' stage: */
+
+#define HAVOC_CYCLES 256U
+#define HAVOC_CYCLES_INIT 1024U
+
+/* Maximum multiplier for the above (should be a power of two, beware
+ of 32-bit int overflows): */
+
+#define HAVOC_MAX_MULT 64U
+#define HAVOC_MAX_MULT_MOPT 64U
+
+/* Absolute minimum number of havoc cycles (after all adjustments): */
+
+#define HAVOC_MIN 12U
+
+/* Power Schedule Divisor */
+#define POWER_BETA 1U
+#define MAX_FACTOR (POWER_BETA * 32)
+
+/* Maximum stacking for havoc-stage tweaks. The actual value is calculated
+ like this:
+
+ n = random between 1 and HAVOC_STACK_POW2
+ stacking = 2^n
+
+ In other words, the default (n = 4) produces 2, 4, 8, 16
+ stacked tweaks: */
+
+#define HAVOC_STACK_POW2 4U
+
+/* Caps on block sizes for cloning and deletion operations. Each of these
+ ranges has a 33% probability of getting picked, except for the first
+ two cycles where smaller blocks are favored: */
+
+#define HAVOC_BLK_SMALL 32U
+#define HAVOC_BLK_MEDIUM 128U
+#define HAVOC_BLK_LARGE 1500U
+
+/* Extra-large blocks, selected very rarely (<5% of the time): */
+
+#define HAVOC_BLK_XL 32768U
+
+/* Probabilities of skipping non-favored entries in the queue, expressed as
+ percentages: */
+
+#define SKIP_TO_NEW_PROB 99 /* ...when there are new, pending favorites */
+#define SKIP_NFAV_OLD_PROB 95 /* ...no new favs, cur entry already fuzzed */
+#define SKIP_NFAV_NEW_PROB 75 /* ...no new favs, cur entry not fuzzed yet */
+
+/* Splicing cycle count: */
+
+#define SPLICE_CYCLES 15
+
+/* Nominal per-splice havoc cycle length: */
+
+#define SPLICE_HAVOC 32
+
+/* Maximum offset for integer addition / subtraction stages: */
+
+#define ARITH_MAX 35
+
+/* Limits for the test case trimmer. The absolute minimum chunk size; and
+ the starting and ending divisors for chopping up the input file: */
+
+#define TRIM_MIN_BYTES 4
+#define TRIM_START_STEPS 16
+#define TRIM_END_STEPS 1024
+
+/* Maximum size of input file, in bytes (keep under 100MB, default 1MB):
+ (note that if this value is changed, several areas in afl-cc.c, afl-fuzz.c
+ and afl-fuzz-state.c have to be changed as well! */
+
+#define MAX_FILE (1 * 1024 * 1024L)
+
+/* The same, for the test case minimizer: */
+
+#define TMIN_MAX_FILE (10 * 1024 * 1024L)
+
+/* Block normalization steps for afl-tmin: */
+
+#define TMIN_SET_MIN_SIZE 4
+#define TMIN_SET_STEPS 128
+
+/* Maximum dictionary token size (-x), in bytes: */
+
+#define MAX_DICT_FILE 128
+
+/* Length limits for auto-detected dictionary tokens: */
+
+#define MIN_AUTO_EXTRA 3
+#define MAX_AUTO_EXTRA 32
+
+/* Maximum number of user-specified dictionary tokens to use in deterministic
+ steps; past this point, the "extras/user" step will be still carried out,
+ but with proportionally lower odds: */
+
+#define MAX_DET_EXTRAS 256
+
+/* Maximum number of auto-extracted dictionary tokens to actually use in fuzzing
+ (first value), and to keep in memory as candidates. The latter should be much
+ higher than the former. */
+
+#define USE_AUTO_EXTRAS 4096
+#define MAX_AUTO_EXTRAS (USE_AUTO_EXTRAS * 8)
+
+/* Scaling factor for the effector map used to skip some of the more
+ expensive deterministic steps. The actual divisor is set to
+ 2^EFF_MAP_SCALE2 bytes: */
+
+#define EFF_MAP_SCALE2 3
+
+/* Minimum input file length at which the effector logic kicks in: */
+
+#define EFF_MIN_LEN 128
+
+/* Maximum effector density past which everything is just fuzzed
+ unconditionally (%): */
+
+#define EFF_MAX_PERC 90
+
+/* UI refresh frequency (Hz): */
+
+#define UI_TARGET_HZ 5
+
+/* Fuzzer stats file and plot update intervals (sec): */
+
+#define STATS_UPDATE_SEC 60
+#define PLOT_UPDATE_SEC 5
+
+/* Smoothing divisor for CPU load and exec speed stats (1 - no smoothing). */
+
+#define AVG_SMOOTHING 16
+
+/* Sync interval (every n havoc cycles): */
+
+#define SYNC_INTERVAL 8
+
+/* Sync time (minimum time between syncing in ms, time is halfed for -M main
+ nodes) - default is 30 minutes: */
+
+#define SYNC_TIME (30 * 60 * 1000)
+
+/* Output directory reuse grace period (minutes): */
+
+#define OUTPUT_GRACE 25
+
+/* Uncomment to use simple file names (id_NNNNNN): */
+
+// #define SIMPLE_FILES
+
+/* List of interesting values to use in fuzzing. */
+
+#define INTERESTING_8 \
+ -128, /* Overflow signed 8-bit when decremented */ \
+ -1, /* */ \
+ 0, /* */ \
+ 1, /* */ \
+ 16, /* One-off with common buffer size */ \
+ 32, /* One-off with common buffer size */ \
+ 64, /* One-off with common buffer size */ \
+ 100, /* One-off with common buffer size */ \
+ 127 /* Overflow signed 8-bit when incremented */
+
+#define INTERESTING_8_LEN 9
+
+#define INTERESTING_16 \
+ -32768, /* Overflow signed 16-bit when decremented */ \
+ -129, /* Overflow signed 8-bit */ \
+ 128, /* Overflow signed 8-bit */ \
+ 255, /* Overflow unsig 8-bit when incremented */ \
+ 256, /* Overflow unsig 8-bit */ \
+ 512, /* One-off with common buffer size */ \
+ 1000, /* One-off with common buffer size */ \
+ 1024, /* One-off with common buffer size */ \
+ 4096, /* One-off with common buffer size */ \
+ 32767 /* Overflow signed 16-bit when incremented */
+
+#define INTERESTING_16_LEN 10
+
+#define INTERESTING_32 \
+ -2147483648LL, /* Overflow signed 32-bit when decremented */ \
+ -100663046, /* Large negative number (endian-agnostic) */ \
+ -32769, /* Overflow signed 16-bit */ \
+ 32768, /* Overflow signed 16-bit */ \
+ 65535, /* Overflow unsig 16-bit when incremented */ \
+ 65536, /* Overflow unsig 16 bit */ \
+ 100663045, /* Large positive number (endian-agnostic) */ \
+ 2147483647 /* Overflow signed 32-bit when incremented */
+
+#define INTERESTING_32_LEN 8
+
+/***********************************************************
+ * *
+ * Really exotic stuff you probably don't want to touch: *
+ * *
+ ***********************************************************/
+
+/* Call count interval between reseeding the libc PRNG from /dev/urandom: */
+
+#define RESEED_RNG 100000
+
+/* The default maximum testcase cache size in MB, 0 = disable.
+ A value between 50 and 250 is a good default value. Note that the
+ number of entries will be auto assigned if not specified via the
+ AFL_TESTCACHE_ENTRIES env variable */
+
+#define TESTCASE_CACHE_SIZE 50
+
+/* Maximum line length passed from GCC to 'as' and used for parsing
+ configuration files: */
+
+#define MAX_LINE 8192
+
+/* Environment variable used to pass SHM ID to the called program. */
+
+#define SHM_ENV_VAR "__AFL_SHM_ID"
+
+/* Environment variable used to pass SHM FUZZ ID to the called program. */
+
+#define SHM_FUZZ_ENV_VAR "__AFL_SHM_FUZZ_ID"
+
+/* Other less interesting, internal-only variables. */
+
+#define CLANG_ENV_VAR "__AFL_CLANG_MODE"
+#define AS_LOOP_ENV_VAR "__AFL_AS_LOOPCHECK"
+#define PERSIST_ENV_VAR "__AFL_PERSISTENT"
+#define DEFER_ENV_VAR "__AFL_DEFER_FORKSRV"
+
+/* In-code signatures for deferred and persistent mode. */
+
+#define PERSIST_SIG "##SIG_AFL_PERSISTENT##"
+#define DEFER_SIG "##SIG_AFL_DEFER_FORKSRV##"
+
+/* Distinctive bitmap signature used to indicate failed execution: */
+
+#define EXEC_FAIL_SIG 0xfee1dead
+
+/* Distinctive exit code used to indicate MSAN trip condition: */
+
+#define MSAN_ERROR 86
+
+/* Distinctive exit code used to indicate LSAN trip condition: */
+
+#define LSAN_ERROR 23
+
+/* Designated file descriptors for forkserver commands (the application will
+ use FORKSRV_FD and FORKSRV_FD + 1): */
+
+#define FORKSRV_FD 198
+
+/* Fork server init timeout multiplier: we'll wait the user-selected
+ timeout plus this much for the fork server to spin up. */
+
+#define FORK_WAIT_MULT 10
+
+/* Calibration timeout adjustments, to be a bit more generous when resuming
+ fuzzing sessions or trying to calibrate already-added internal finds.
+ The first value is a percentage, the other is in milliseconds: */
+
+#define CAL_TMOUT_PERC 125
+#define CAL_TMOUT_ADD 50
+
+/* Number of chances to calibrate a case before giving up: */
+
+#define CAL_CHANCES 3
+
+/* Map size for the traced binary (2^MAP_SIZE_POW2). Must be greater than
+ 2; you probably want to keep it under 18 or so for performance reasons
+ (adjusting AFL_INST_RATIO when compiling is probably a better way to solve
+ problems with complex programs). You need to recompile the target binary
+ after changing this - otherwise, SEGVs may ensue. */
+
+#define MAP_SIZE_POW2 16
+#define MAP_SIZE (1U << MAP_SIZE_POW2)
+
+/* Maximum allocator request size (keep well under INT_MAX): */
+
+#define MAX_ALLOC 0x40000000
+
+/* A made-up hashing seed: */
+
+#define HASH_CONST 0xa5b35705
+
+/* Constants for afl-gotcpu to control busy loop timing: */
+
+#define CTEST_TARGET_MS 5000
+#define CTEST_CORE_TRG_MS 1000
+#define CTEST_BUSY_CYCLES (10 * 1000 * 1000)
+
+/* Enable NeverZero counters in QEMU mode */
+
+#define AFL_QEMU_NOT_ZERO
+
+/* AFL RedQueen */
+
+#define CMPLOG_SHM_ENV_VAR "__AFL_CMPLOG_SHM_ID"
+
+/* CPU Affinity lockfile env var */
+
+#define CPU_AFFINITY_ENV_VAR "__AFL_LOCKFILE"
+
+/* Uncomment this to use inferior block-coverage-based instrumentation. Note
+ that you need to recompile the target binary for this to have any effect: */
+
+// #define COVERAGE_ONLY
+
+/* Uncomment this to ignore hit counts and output just one bit per tuple.
+ As with the previous setting, you will need to recompile the target
+ binary: */
+
+// #define SKIP_COUNTS
+
+/* Uncomment this to use instrumentation data to record newly discovered paths,
+ but do not use them as seeds for fuzzing. This is useful for conveniently
+ measuring coverage that could be attained by a "dumb" fuzzing algorithm: */
+
+// #define IGNORE_FINDS
+
+/* Text mutations */
+
+/* Minimum length of a queue input to be evaluated for "is_ascii"? */
+
+#define AFL_TXT_MIN_LEN 12
+
+/* What is the minimum percentage of ascii characters present to be classifed
+ as "is_ascii"? */
+
+#define AFL_TXT_MIN_PERCENT 94
+
+/* How often to perform ASCII mutations 0 = disable, 1-8 are good values */
+
+#define AFL_TXT_BIAS 6
+
+/* Maximum length of a string to tamper with */
+
+#define AFL_TXT_STRING_MAX_LEN 1024
+
+/* Maximum mutations on a string */
+
+#define AFL_TXT_STRING_MAX_MUTATIONS 6
+
+#endif /* ! _HAVE_CONFIG_H */
+
diff --git a/include/coverage-32.h b/include/coverage-32.h
new file mode 100644
index 00000000..89c08cdf
--- /dev/null
+++ b/include/coverage-32.h
@@ -0,0 +1,112 @@
+#include "config.h"
+#include "types.h"
+
+u32 skim(const u32 *virgin, const u32 *current, const u32 *current_end);
+u32 classify_word(u32 word);
+
+inline u32 classify_word(u32 word) {
+
+ u16 mem16[2];
+ memcpy(mem16, &word, sizeof(mem16));
+
+ mem16[0] = count_class_lookup16[mem16[0]];
+ mem16[1] = count_class_lookup16[mem16[1]];
+
+ memcpy(&word, mem16, sizeof(mem16));
+ return word;
+
+}
+
+void simplify_trace(afl_state_t *afl, u8 *bytes) {
+
+ u32 *mem = (u32 *)bytes;
+ u32 i = (afl->fsrv.map_size >> 2);
+
+ while (i--) {
+
+ /* Optimize for sparse bitmaps. */
+
+ if (unlikely(*mem)) {
+
+ u8 *mem8 = (u8 *)mem;
+
+ mem8[0] = simplify_lookup[mem8[0]];
+ mem8[1] = simplify_lookup[mem8[1]];
+ mem8[2] = simplify_lookup[mem8[2]];
+ mem8[3] = simplify_lookup[mem8[3]];
+
+ } else
+
+ *mem = 0x01010101;
+
+ mem++;
+
+ }
+
+}
+
+inline void classify_counts(afl_forkserver_t *fsrv) {
+
+ u32 *mem = (u32 *)fsrv->trace_bits;
+ u32 i = (fsrv->map_size >> 2);
+
+ while (i--) {
+
+ /* Optimize for sparse bitmaps. */
+
+ if (unlikely(*mem)) { *mem = classify_word(*mem); }
+
+ mem++;
+
+ }
+
+}
+
+/* Updates the virgin bits, then reflects whether a new count or a new tuple is
+ * seen in ret. */
+inline void discover_word(u8 *ret, u32 *current, u32 *virgin) {
+
+ /* Optimize for (*current & *virgin) == 0 - i.e., no bits in current bitmap
+ that have not been already cleared from the virgin map - since this will
+ almost always be the case. */
+
+ if (unlikely(*current & *virgin)) {
+
+ if (likely(*ret < 2)) {
+
+ u8 *cur = (u8 *)current;
+ u8 *vir = (u8 *)virgin;
+
+ /* Looks like we have not found any new bytes yet; see if any non-zero
+ bytes in current[] are pristine in virgin[]. */
+
+ if (unlikely((cur[0] && vir[0] == 0xff) || (cur[1] && vir[1] == 0xff) ||
+ (cur[2] && vir[2] == 0xff) || (cur[3] && vir[3] == 0xff)))
+ *ret = 2;
+ else
+ *ret = 1;
+
+ }
+
+ *virgin &= ~*current;
+
+ }
+
+}
+
+#define PACK_SIZE 16
+inline u32 skim(const u32 *virgin, const u32 *current, const u32 *current_end) {
+
+ for (; current < current_end; virgin += 4, current += 4) {
+
+ if (unlikely(current[0] && classify_word(current[0]) & virgin[0])) return 1;
+ if (unlikely(current[1] && classify_word(current[1]) & virgin[1])) return 1;
+ if (unlikely(current[2] && classify_word(current[2]) & virgin[2])) return 1;
+ if (unlikely(current[3] && classify_word(current[3]) & virgin[3])) return 1;
+
+ }
+
+ return 0;
+
+}
+
diff --git a/include/coverage-64.h b/include/coverage-64.h
new file mode 100644
index 00000000..aab79d79
--- /dev/null
+++ b/include/coverage-64.h
@@ -0,0 +1,194 @@
+#include "config.h"
+#include "types.h"
+
+#if (defined(__AVX512F__) && defined(__AVX512DQ__)) || defined(__AVX2__)
+ #include <immintrin.h>
+#endif
+
+u32 skim(const u64 *virgin, const u64 *current, const u64 *current_end);
+u64 classify_word(u64 word);
+
+inline u64 classify_word(u64 word) {
+
+ u16 mem16[4];
+ memcpy(mem16, &word, sizeof(mem16));
+
+ mem16[0] = count_class_lookup16[mem16[0]];
+ mem16[1] = count_class_lookup16[mem16[1]];
+ mem16[2] = count_class_lookup16[mem16[2]];
+ mem16[3] = count_class_lookup16[mem16[3]];
+
+ memcpy(&word, mem16, sizeof(mem16));
+ return word;
+
+}
+
+void simplify_trace(afl_state_t *afl, u8 *bytes) {
+
+ u64 *mem = (u64 *)bytes;
+ u32 i = (afl->fsrv.map_size >> 3);
+
+ while (i--) {
+
+ /* Optimize for sparse bitmaps. */
+
+ if (unlikely(*mem)) {
+
+ u8 *mem8 = (u8 *)mem;
+
+ mem8[0] = simplify_lookup[mem8[0]];
+ mem8[1] = simplify_lookup[mem8[1]];
+ mem8[2] = simplify_lookup[mem8[2]];
+ mem8[3] = simplify_lookup[mem8[3]];
+ mem8[4] = simplify_lookup[mem8[4]];
+ mem8[5] = simplify_lookup[mem8[5]];
+ mem8[6] = simplify_lookup[mem8[6]];
+ mem8[7] = simplify_lookup[mem8[7]];
+
+ } else
+
+ *mem = 0x0101010101010101ULL;
+
+ mem++;
+
+ }
+
+}
+
+inline void classify_counts(afl_forkserver_t *fsrv) {
+
+ u64 *mem = (u64 *)fsrv->trace_bits;
+ u32 i = (fsrv->map_size >> 3);
+
+ while (i--) {
+
+ /* Optimize for sparse bitmaps. */
+
+ if (unlikely(*mem)) { *mem = classify_word(*mem); }
+
+ mem++;
+
+ }
+
+}
+
+/* Updates the virgin bits, then reflects whether a new count or a new tuple is
+ * seen in ret. */
+inline void discover_word(u8 *ret, u64 *current, u64 *virgin) {
+
+ /* Optimize for (*current & *virgin) == 0 - i.e., no bits in current bitmap
+ that have not been already cleared from the virgin map - since this will
+ almost always be the case. */
+
+ if (*current & *virgin) {
+
+ if (likely(*ret < 2)) {
+
+ u8 *cur = (u8 *)current;
+ u8 *vir = (u8 *)virgin;
+
+ /* Looks like we have not found any new bytes yet; see if any non-zero
+ bytes in current[] are pristine in virgin[]. */
+
+ if ((cur[0] && vir[0] == 0xff) || (cur[1] && vir[1] == 0xff) ||
+ (cur[2] && vir[2] == 0xff) || (cur[3] && vir[3] == 0xff) ||
+ (cur[4] && vir[4] == 0xff) || (cur[5] && vir[5] == 0xff) ||
+ (cur[6] && vir[6] == 0xff) || (cur[7] && vir[7] == 0xff))
+ *ret = 2;
+ else
+ *ret = 1;
+
+ }
+
+ *virgin &= ~*current;
+
+ }
+
+}
+
+#if defined(__AVX512F__) && defined(__AVX512DQ__)
+ #define PACK_SIZE 64
+inline u32 skim(const u64 *virgin, const u64 *current, const u64 *current_end) {
+
+ for (; current != current_end; virgin += 8, current += 8) {
+
+ __m512i value = *(__m512i *)current;
+ __mmask8 mask = _mm512_testn_epi64_mask(value, value);
+
+ /* All bytes are zero. */
+ if (likely(mask == 0xff)) continue;
+
+ /* Look for nonzero bytes and check for new bits. */
+ #define UNROLL(x) \
+ if (unlikely(!(mask & (1 << x)) && classify_word(current[x]) & virgin[x])) \
+ return 1
+ UNROLL(0);
+ UNROLL(1);
+ UNROLL(2);
+ UNROLL(3);
+ UNROLL(4);
+ UNROLL(5);
+ UNROLL(6);
+ UNROLL(7);
+ #undef UNROLL
+
+ }
+
+ return 0;
+
+}
+
+#endif
+
+#if !defined(PACK_SIZE) && defined(__AVX2__)
+ #define PACK_SIZE 32
+inline u32 skim(const u64 *virgin, const u64 *current, const u64 *current_end) {
+
+ __m256i zeroes = _mm256_setzero_si256();
+
+ for (; current < current_end; virgin += 4, current += 4) {
+
+ __m256i value = *(__m256i *)current;
+ __m256i cmp = _mm256_cmpeq_epi64(value, zeroes);
+ u32 mask = _mm256_movemask_epi8(cmp);
+
+ /* All bytes are zero. */
+ if (likely(mask == (u32)-1)) continue;
+
+ /* Look for nonzero bytes and check for new bits. */
+ if (unlikely(!(mask & 0xff) && classify_word(current[0]) & virgin[0]))
+ return 1;
+ if (unlikely(!(mask & 0xff00) && classify_word(current[1]) & virgin[1]))
+ return 1;
+ if (unlikely(!(mask & 0xff0000) && classify_word(current[2]) & virgin[2]))
+ return 1;
+ if (unlikely(!(mask & 0xff000000) && classify_word(current[3]) & virgin[3]))
+ return 1;
+
+ }
+
+ return 0;
+
+}
+
+#endif
+
+#if !defined(PACK_SIZE)
+ #define PACK_SIZE 32
+inline u32 skim(const u64 *virgin, const u64 *current, const u64 *current_end) {
+
+ for (; current < current_end; virgin += 4, current += 4) {
+
+ if (unlikely(current[0] && classify_word(current[0]) & virgin[0])) return 1;
+ if (unlikely(current[1] && classify_word(current[1]) & virgin[1])) return 1;
+ if (unlikely(current[2] && classify_word(current[2]) & virgin[2])) return 1;
+ if (unlikely(current[3] && classify_word(current[3]) & virgin[3])) return 1;
+
+ }
+
+ return 0;
+
+}
+
+#endif
+
diff --git a/include/debug.h b/include/debug.h
new file mode 100644
index 00000000..c2f20f0f
--- /dev/null
+++ b/include/debug.h
@@ -0,0 +1,405 @@
+/*
+ american fuzzy lop++ - debug / error handling macros
+ ----------------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
+ Andrea Fioraldi <andreafioraldi@gmail.com>,
+ Dominik Maier <mail@dmnk.co>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ */
+
+#ifndef _HAVE_DEBUG_H
+#define _HAVE_DEBUG_H
+
+#include <errno.h>
+
+#include "types.h"
+#include "config.h"
+
+/*******************
+ * Terminal colors *
+ *******************/
+
+#ifndef MESSAGES_TO_STDOUT
+ #define MESSAGES_TO_STDOUT
+#endif
+
+#ifdef USE_COLOR
+
+ #define cBLK "\x1b[0;30m"
+ #define cRED "\x1b[0;31m"
+ #define cGRN "\x1b[0;32m"
+ #define cBRN "\x1b[0;33m"
+ #define cBLU "\x1b[0;34m"
+ #define cMGN "\x1b[0;35m"
+ #define cCYA "\x1b[0;36m"
+ #define cLGR "\x1b[0;37m"
+ #define cGRA "\x1b[1;90m"
+ #define cLRD "\x1b[1;91m"
+ #define cLGN "\x1b[1;92m"
+ #define cYEL "\x1b[1;93m"
+ #define cLBL "\x1b[1;94m"
+ #define cPIN "\x1b[1;95m"
+ #define cLCY "\x1b[1;96m"
+ #define cBRI "\x1b[1;97m"
+ #define cRST "\x1b[0m"
+
+ #define bgBLK "\x1b[40m"
+ #define bgRED "\x1b[41m"
+ #define bgGRN "\x1b[42m"
+ #define bgBRN "\x1b[43m"
+ #define bgBLU "\x1b[44m"
+ #define bgMGN "\x1b[45m"
+ #define bgCYA "\x1b[46m"
+ #define bgLGR "\x1b[47m"
+ #define bgGRA "\x1b[100m"
+ #define bgLRD "\x1b[101m"
+ #define bgLGN "\x1b[102m"
+ #define bgYEL "\x1b[103m"
+ #define bgLBL "\x1b[104m"
+ #define bgPIN "\x1b[105m"
+ #define bgLCY "\x1b[106m"
+ #define bgBRI "\x1b[107m"
+
+#else
+
+ #define cBLK ""
+ #define cRED ""
+ #define cGRN ""
+ #define cBRN ""
+ #define cBLU ""
+ #define cMGN ""
+ #define cCYA ""
+ #define cLGR ""
+ #define cGRA ""
+ #define cLRD ""
+ #define cLGN ""
+ #define cYEL ""
+ #define cLBL ""
+ #define cPIN ""
+ #define cLCY ""
+ #define cBRI ""
+ #define cRST ""
+
+ #define bgBLK ""
+ #define bgRED ""
+ #define bgGRN ""
+ #define bgBRN ""
+ #define bgBLU ""
+ #define bgMGN ""
+ #define bgCYA ""
+ #define bgLGR ""
+ #define bgGRA ""
+ #define bgLRD ""
+ #define bgLGN ""
+ #define bgYEL ""
+ #define bgLBL ""
+ #define bgPIN ""
+ #define bgLCY ""
+ #define bgBRI ""
+
+#endif /* ^USE_COLOR */
+
+/*************************
+ * Box drawing sequences *
+ *************************/
+
+#ifdef FANCY_BOXES
+
+ #define SET_G1 "\x1b)0" /* Set G1 for box drawing */
+ #define RESET_G1 "\x1b)B" /* Reset G1 to ASCII */
+ #define bSTART "\x0e" /* Enter G1 drawing mode */
+ #define bSTOP "\x0f" /* Leave G1 drawing mode */
+ #define bH "q" /* Horizontal line */
+ #define bV "x" /* Vertical line */
+ #define bLT "l" /* Left top corner */
+ #define bRT "k" /* Right top corner */
+ #define bLB "m" /* Left bottom corner */
+ #define bRB "j" /* Right bottom corner */
+ #define bX "n" /* Cross */
+ #define bVR "t" /* Vertical, branch right */
+ #define bVL "u" /* Vertical, branch left */
+ #define bHT "v" /* Horizontal, branch top */
+ #define bHB "w" /* Horizontal, branch bottom */
+
+#else
+
+ #define SET_G1 ""
+ #define RESET_G1 ""
+ #define bSTART ""
+ #define bSTOP ""
+ #define bH "-"
+ #define bV "|"
+ #define bLT "+"
+ #define bRT "+"
+ #define bLB "+"
+ #define bRB "+"
+ #define bX "+"
+ #define bVR "+"
+ #define bVL "+"
+ #define bHT "+"
+ #define bHB "+"
+
+#endif /* ^FANCY_BOXES */
+
+/***********************
+ * Misc terminal codes *
+ ***********************/
+
+#define TERM_HOME "\x1b[H"
+#define TERM_CLEAR TERM_HOME "\x1b[2J"
+#define cEOL "\x1b[0K"
+#define CURSOR_HIDE "\x1b[?25l"
+#define CURSOR_SHOW "\x1b[?25h"
+
+/************************
+ * Debug & error macros *
+ ************************/
+
+#if defined USE_COLOR && !defined ALWAYS_COLORED
+ #include <unistd.h>
+ #pragma GCC diagnostic ignored "-Wformat-security"
+static inline const char *colorfilter(const char *x) {
+
+ static int once = 1;
+ static int disabled = 0;
+
+ if (once) {
+
+ /* when there is no tty -> we always want filtering
+ * when AFL_NO_UI is set filtering depends on AFL_NO_COLOR
+ * otherwise we want always colors
+ */
+ disabled =
+ isatty(2) && (!getenv("AFL_NO_UI") ||
+ (!getenv("AFL_NO_COLOR") && !getenv("AFL_NO_COLOUR")));
+ once = 0;
+
+ }
+
+ if (likely(disabled)) return x;
+
+ static char monochromestring[4096];
+ char * d = monochromestring;
+ int in_seq = 0;
+
+ while (*x) {
+
+ if (in_seq && *x == 'm') {
+
+ in_seq = 0;
+
+ } else {
+
+ if (!in_seq && *x == '\x1b') { in_seq = 1; }
+ if (!in_seq) { *d++ = *x; }
+
+ }
+
+ ++x;
+
+ }
+
+ *d = '\0';
+ return monochromestring;
+
+}
+
+#else
+ #define colorfilter(x) x /* no filtering necessary */
+#endif
+
+/* macro magic to transform the first parameter to SAYF
+ * through colorfilter which strips coloring */
+#define GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, \
+ _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, \
+ _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, \
+ _39, _40, NAME, ...) \
+ NAME
+
+#define SAYF(...) \
+ GET_MACRO(__VA_ARGS__, SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, \
+ SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, \
+ SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, \
+ SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, \
+ SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, \
+ SAYF_N, SAYF_1) \
+ (__VA_ARGS__)
+
+#define SAYF_1(x) MY_SAYF(colorfilter(x))
+#define SAYF_N(x, ...) MY_SAYF(colorfilter(x), __VA_ARGS__)
+
+/* Just print stuff to the appropriate stream. */
+#ifdef MESSAGES_TO_STDOUT
+ #define MY_SAYF(x...) printf(x)
+#else
+ #define MY_SAYF(x...) fprintf(stderr, x)
+#endif /* ^MESSAGES_TO_STDOUT */
+
+/* Show a prefixed warning. */
+
+#define WARNF(x...) \
+ do { \
+ \
+ SAYF(cYEL "[!] " cBRI "WARNING: " cRST x); \
+ SAYF(cRST "\n"); \
+ \
+ } while (0)
+
+/* Show a prefixed "doing something" message. */
+
+#define ACTF(x...) \
+ do { \
+ \
+ SAYF(cLBL "[*] " cRST x); \
+ SAYF(cRST "\n"); \
+ \
+ } while (0)
+
+/* Show a prefixed "success" message. */
+
+#define OKF(x...) \
+ do { \
+ \
+ SAYF(cLGN "[+] " cRST x); \
+ SAYF(cRST "\n"); \
+ \
+ } while (0)
+
+/* Show a prefixed fatal error message (not used in afl). */
+
+#define BADF(x...) \
+ do { \
+ \
+ SAYF(cLRD "\n[-] " cRST x); \
+ SAYF(cRST "\n"); \
+ \
+ } while (0)
+
+/* Die with a verbose non-OS fatal error message. */
+
+#define FATAL(x...) \
+ do { \
+ \
+ SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \
+ "\n[-] PROGRAM ABORT : " cRST x); \
+ SAYF(cLRD "\n Location : " cRST "%s(), %s:%u\n\n", __func__, \
+ __FILE__, (u32)__LINE__); \
+ exit(1); \
+ \
+ } while (0)
+
+/* Die by calling abort() to provide a core dump. */
+
+#define ABORT(x...) \
+ do { \
+ \
+ SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \
+ "\n[-] PROGRAM ABORT : " cRST x); \
+ SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n\n", __func__, \
+ __FILE__, (u32)__LINE__); \
+ abort(); \
+ \
+ } while (0)
+
+/* Die while also including the output of perror(). */
+
+#define PFATAL(x...) \
+ do { \
+ \
+ fflush(stdout); \
+ SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \
+ "\n[-] SYSTEM ERROR : " cRST x); \
+ SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n", __func__, \
+ __FILE__, (u32)__LINE__); \
+ SAYF(cLRD " OS message : " cRST "%s\n", strerror(errno)); \
+ exit(1); \
+ \
+ } while (0)
+
+/* Die with FATAL() or PFATAL() depending on the value of res (used to
+ interpret different failure modes for read(), write(), etc). */
+
+#define RPFATAL(res, x...) \
+ do { \
+ \
+ if (res < 0) \
+ PFATAL(x); \
+ else \
+ FATAL(x); \
+ \
+ } while (0)
+
+/* Show a prefixed debug output. */
+
+#define DEBUGF(x...) \
+ do { \
+ \
+ fprintf(stderr, cMGN "[D] " cBRI "DEBUG: " cRST x); \
+ fprintf(stderr, cRST ""); \
+ \
+ } while (0)
+
+/* Error-checking versions of read() and write() that call RPFATAL() as
+ appropriate. */
+
+#define ck_write(fd, buf, len, fn) \
+ do { \
+ \
+ if (len <= 0) break; \
+ int _fd = (fd); \
+ s32 _written = 0, _off = 0, _len = (s32)(len); \
+ \
+ do { \
+ \
+ s32 _res = write(_fd, (buf) + _off, _len); \
+ if (_res != _len && (_res > 0 && _written + _res != _len)) { \
+ \
+ if (_res > 0) { \
+ \
+ _written += _res; \
+ _len -= _res; \
+ _off += _res; \
+ \
+ } else { \
+ \
+ RPFATAL(_res, "Short write to %s, fd %d (%d of %d bytes)", fn, _fd, \
+ _res, _len); \
+ \
+ } \
+ \
+ } else { \
+ \
+ break; \
+ \
+ } \
+ \
+ } while (1); \
+ \
+ \
+ \
+ } while (0)
+
+#define ck_read(fd, buf, len, fn) \
+ do { \
+ \
+ s32 _len = (s32)(len); \
+ s32 _res = read(fd, buf, _len); \
+ if (_res != _len) RPFATAL(_res, "Short read from %s", fn); \
+ \
+ } while (0)
+
+#endif /* ! _HAVE_DEBUG_H */
+
diff --git a/include/envs.h b/include/envs.h
new file mode 100644
index 00000000..25b792fa
--- /dev/null
+++ b/include/envs.h
@@ -0,0 +1,236 @@
+#ifndef _ENVS_H
+
+#define _ENVS_H
+
+static char *afl_environment_deprecated[] = {
+
+ "AFL_LLVM_WHITELIST",
+ "AFL_GCC_WHITELIST",
+ "AFL_DEBUG_CHILD_OUTPUT",
+ "AFL_DEFER_FORKSRV",
+ "AFL_POST_LIBRARY",
+ "AFL_PERSISTENT",
+ NULL
+
+};
+
+static char *afl_environment_variables[] = {
+
+ "AFL_ALIGNED_ALLOC",
+ "AFL_ALLOW_TMP",
+ "AFL_ANALYZE_HEX",
+ "AFL_AS",
+ "AFL_AUTORESUME",
+ "AFL_AS_FORCE_INSTRUMENT",
+ "AFL_BENCH_JUST_ONE",
+ "AFL_BENCH_UNTIL_CRASH",
+ "AFL_CAL_FAST",
+ "AFL_CC",
+ "AFL_CC_COMPILER",
+ "AFL_CMIN_ALLOW_ANY",
+ "AFL_CMIN_CRASHES_ONLY",
+ "AFL_CMPLOG_ONLY_NEW",
+ "AFL_CODE_END",
+ "AFL_CODE_START",
+ "AFL_COMPCOV_BINNAME",
+ "AFL_COMPCOV_LEVEL",
+ "AFL_CRASH_EXITCODE",
+ "AFL_CUSTOM_MUTATOR_LIBRARY",
+ "AFL_CUSTOM_MUTATOR_ONLY",
+ "AFL_CXX",
+ "AFL_CYCLE_SCHEDULES",
+ "AFL_DEBUG",
+ "AFL_DEBUG_CHILD",
+ "AFL_DEBUG_GDB",
+ "AFL_DISABLE_TRIM",
+ "AFL_DISABLE_LLVM_INSTRUMENTATION",
+ "AFL_DONT_OPTIMIZE",
+ "AFL_DRIVER_STDERR_DUPLICATE_FILENAME",
+ "AFL_DUMB_FORKSRV",
+ "AFL_EARLY_FORKSERVER",
+ "AFL_ENTRYPOINT",
+ "AFL_EXIT_WHEN_DONE",
+ "AFL_EXIT_ON_TIME",
+ "AFL_EXIT_ON_SEED_ISSUES",
+ "AFL_FAST_CAL",
+ "AFL_FORCE_UI",
+ "AFL_FRIDA_DEBUG_MAPS",
+ "AFL_FRIDA_DRIVER_NO_HOOK",
+ "AFL_FRIDA_EXCLUDE_RANGES",
+ "AFL_FRIDA_INST_CACHE_SIZE",
+ "AFL_FRIDA_INST_COVERAGE_FILE",
+ "AFL_FRIDA_INST_DEBUG_FILE",
+ "AFL_FRIDA_INST_INSN",
+ "AFL_FRIDA_INST_JIT",
+ "AFL_FRIDA_INST_NO_CACHE",
+ "AFL_FRIDA_INST_NO_OPTIMIZE",
+ "AFL_FRIDA_INST_NO_PREFETCH",
+ "AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH",
+ "AFL_FRIDA_INST_RANGES",
+ "AFL_FRIDA_INST_SEED",
+ "AFL_FRIDA_INST_TRACE",
+ "AFL_FRIDA_INST_TRACE_UNIQUE",
+ "AFL_FRIDA_INST_UNSTABLE_COVERAGE_FILE",
+ "AFL_FRIDA_JS_SCRIPT",
+ "AFL_FRIDA_OUTPUT_STDOUT",
+ "AFL_FRIDA_OUTPUT_STDERR",
+ "AFL_FRIDA_PERSISTENT_ADDR",
+ "AFL_FRIDA_PERSISTENT_CNT",
+ "AFL_FRIDA_PERSISTENT_DEBUG",
+ "AFL_FRIDA_PERSISTENT_HOOK",
+ "AFL_FRIDA_PERSISTENT_RET",
+ "AFL_FRIDA_STALKER_ADJACENT_BLOCKS",
+ "AFL_FRIDA_STALKER_IC_ENTRIES",
+ "AFL_FRIDA_STALKER_NO_BACKPATCH",
+ "AFL_FRIDA_STATS_FILE",
+ "AFL_FRIDA_STATS_INTERVAL",
+ "AFL_FRIDA_TRACEABLE",
+ "AFL_FRIDA_VERBOSE",
+ "AFL_FUZZER_ARGS", // oss-fuzz
+ "AFL_GDB",
+ "AFL_GCC_ALLOWLIST",
+ "AFL_GCC_DENYLIST",
+ "AFL_GCC_BLOCKLIST",
+ "AFL_GCC_INSTRUMENT_FILE",
+ "AFL_GCC_OUT_OF_LINE",
+ "AFL_GCC_SKIP_NEVERZERO",
+ "AFL_GCJ",
+ "AFL_HANG_TMOUT",
+ "AFL_FORKSRV_INIT_TMOUT",
+ "AFL_HARDEN",
+ "AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES",
+ "AFL_IGNORE_PROBLEMS",
+ "AFL_IGNORE_UNKNOWN_ENVS",
+ "AFL_IMPORT_FIRST",
+ "AFL_INPUT_LEN_MIN",
+ "AFL_INPUT_LEN_MAX",
+ "AFL_INST_LIBS",
+ "AFL_INST_RATIO",
+ "AFL_KEEP_TIMEOUTS",
+ "AFL_KILL_SIGNAL",
+ "AFL_KEEP_TRACES",
+ "AFL_KEEP_ASSEMBLY",
+ "AFL_LD_HARD_FAIL",
+ "AFL_LD_LIMIT_MB",
+ "AFL_LD_NO_CALLOC_OVER",
+ "AFL_LD_PASSTHROUGH",
+ "AFL_REAL_LD",
+ "AFL_LD_PRELOAD",
+ "AFL_LD_VERBOSE",
+ "AFL_LLVM_ALLOWLIST",
+ "AFL_LLVM_DENYLIST",
+ "AFL_LLVM_BLOCKLIST",
+ "AFL_LLVM_CMPLOG",
+ "AFL_LLVM_INSTRIM",
+ "AFL_LLVM_CALLER",
+ "AFL_LLVM_CTX",
+ "AFL_LLVM_CTX_K",
+ "AFL_LLVM_DICT2FILE",
+ "AFL_LLVM_DOCUMENT_IDS",
+ "AFL_LLVM_INSTRIM_LOOPHEAD",
+ "AFL_LLVM_INSTRUMENT",
+ "AFL_LLVM_LTO_AUTODICTIONARY",
+ "AFL_LLVM_AUTODICTIONARY",
+ "AFL_LLVM_SKIPSINGLEBLOCK",
+ "AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK",
+ "AFL_LLVM_LAF_SPLIT_COMPARES",
+ "AFL_LLVM_LAF_SPLIT_COMPARES_BITW",
+ "AFL_LLVM_LAF_SPLIT_FLOATS",
+ "AFL_LLVM_LAF_SPLIT_SWITCHES",
+ "AFL_LLVM_LAF_ALL",
+ "AFL_LLVM_LAF_TRANSFORM_COMPARES",
+ "AFL_LLVM_MAP_ADDR",
+ "AFL_LLVM_MAP_DYNAMIC",
+ "AFL_LLVM_NGRAM_SIZE",
+ "AFL_NGRAM_SIZE",
+ "AFL_LLVM_NOT_ZERO",
+ "AFL_LLVM_INSTRUMENT_FILE",
+ "AFL_LLVM_THREADSAFE_INST",
+ "AFL_LLVM_SKIP_NEVERZERO",
+ "AFL_NO_AFFINITY",
+ "AFL_TRY_AFFINITY",
+ "AFL_LLVM_LTO_STARTID",
+ "AFL_LLVM_LTO_DONTWRITEID",
+ "AFL_NO_ARITH",
+ "AFL_NO_AUTODICT",
+ "AFL_NO_BUILTIN",
+#if defined USE_COLOR && !defined ALWAYS_COLORED
+ "AFL_NO_COLOR",
+ "AFL_NO_COLOUR",
+#endif
+ "AFL_NO_CPU_RED",
+ "AFL_NO_FORKSRV",
+ "AFL_NO_UI",
+ "AFL_NO_PYTHON",
+ "AFL_UNTRACER_FILE",
+ "AFL_LLVM_USE_TRACE_PC",
+ "AFL_MAP_SIZE",
+ "AFL_MAPSIZE",
+ "AFL_MAX_DET_EXTRAS",
+ "AFL_NO_X86", // not really an env but we dont want to warn on it
+ "AFL_NOOPT",
+ "AFL_PASSTHROUGH",
+ "AFL_PATH",
+ "AFL_PERFORMANCE_FILE",
+ "AFL_PERSISTENT_RECORD",
+ "AFL_PRELOAD",
+ "AFL_TARGET_ENV",
+ "AFL_PYTHON_MODULE",
+ "AFL_QEMU_CUSTOM_BIN",
+ "AFL_QEMU_COMPCOV",
+ "AFL_QEMU_COMPCOV_DEBUG",
+ "AFL_QEMU_DEBUG_MAPS",
+ "AFL_QEMU_DISABLE_CACHE",
+ "AFL_QEMU_DRIVER_NO_HOOK",
+ "AFL_QEMU_FORCE_DFL",
+ "AFL_QEMU_PERSISTENT_ADDR",
+ "AFL_QEMU_PERSISTENT_CNT",
+ "AFL_QEMU_PERSISTENT_GPR",
+ "AFL_QEMU_PERSISTENT_HOOK",
+ "AFL_QEMU_PERSISTENT_MEM",
+ "AFL_QEMU_PERSISTENT_RET",
+ "AFL_QEMU_PERSISTENT_RETADDR_OFFSET",
+ "AFL_QEMU_PERSISTENT_EXITS",
+ "AFL_QEMU_INST_RANGES",
+ "AFL_QEMU_EXCLUDE_RANGES",
+ "AFL_QEMU_SNAPSHOT",
+ "AFL_QUIET",
+ "AFL_RANDOM_ALLOC_CANARY",
+ "AFL_REAL_PATH",
+ "AFL_SHUFFLE_QUEUE",
+ "AFL_SKIP_BIN_CHECK",
+ "AFL_SKIP_CPUFREQ",
+ "AFL_SKIP_CRASHES",
+ "AFL_SKIP_OSSFUZZ",
+ "AFL_STATSD",
+ "AFL_STATSD_HOST",
+ "AFL_STATSD_PORT",
+ "AFL_STATSD_TAGS_FLAVOR",
+ "AFL_TESTCACHE_SIZE",
+ "AFL_TESTCACHE_ENTRIES",
+ "AFL_TMIN_EXACT",
+ "AFL_TMPDIR",
+ "AFL_TOKEN_FILE",
+ "AFL_TRACE_PC",
+ "AFL_USE_ASAN",
+ "AFL_USE_MSAN",
+ "AFL_USE_TRACE_PC",
+ "AFL_USE_UBSAN",
+ "AFL_USE_TSAN",
+ "AFL_USE_CFISAN",
+ "AFL_USE_LSAN",
+ "AFL_WINE_PATH",
+ "AFL_NO_SNAPSHOT",
+ "AFL_EXPAND_HAVOC_NOW",
+ "AFL_USE_FASAN",
+ "AFL_USE_QASAN",
+ "AFL_PRINT_FILENAMES",
+ "AFL_PIZZA_MODE",
+ NULL
+
+};
+
+extern char *afl_environment_variables[];
+
+#endif
+
diff --git a/include/forkserver.h b/include/forkserver.h
new file mode 100644
index 00000000..5b66e7ec
--- /dev/null
+++ b/include/forkserver.h
@@ -0,0 +1,225 @@
+/*
+ american fuzzy lop++ - forkserver header
+ ----------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Forkserver design by Jann Horn <jannhorn@googlemail.com>
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
+ Andrea Fioraldi <andreafioraldi@gmail.com>,
+ Dominik Maier <mail@dmnk.co>>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ Shared code that implements a forkserver. This is used by the fuzzer
+ as well the other components like afl-tmin.
+
+ */
+
+#ifndef __AFL_FORKSERVER_H
+#define __AFL_FORKSERVER_H
+
+#include <stdio.h>
+#include <stdbool.h>
+
+#include "types.h"
+
+#ifdef __linux__
+/**
+ * Nyx related typedefs taken from libnyx.h
+ */
+
+typedef enum NyxReturnValue {
+
+ Normal,
+ Crash,
+ Asan,
+ Timout,
+ InvalidWriteToPayload,
+ Error,
+ IoError,
+ Abort,
+
+} NyxReturnValue;
+
+typedef struct {
+
+ void *(*nyx_new)(const char *sharedir, const char *workdir, uint32_t cpu_id,
+ uint32_t input_buffer_size,
+ bool input_buffer_write_protection);
+ void *(*nyx_new_parent)(const char *sharedir, const char *workdir,
+ uint32_t cpu_id, uint32_t input_buffer_size,
+ bool input_buffer_write_protection);
+ void *(*nyx_new_child)(const char *sharedir, const char *workdir,
+ uint32_t cpu_id, uint32_t worker_id);
+ void (*nyx_shutdown)(void *qemu_process);
+ void (*nyx_option_set_reload_mode)(void *qemu_process, bool enable);
+ void (*nyx_option_set_timeout)(void *qemu_process, uint8_t timeout_sec,
+ uint32_t timeout_usec);
+ void (*nyx_option_apply)(void *qemu_process);
+ void (*nyx_set_afl_input)(void *qemu_process, uint8_t *buffer, uint32_t size);
+ enum NyxReturnValue (*nyx_exec)(void *qemu_process);
+ uint8_t *(*nyx_get_bitmap_buffer)(void *qemu_process);
+ size_t (*nyx_get_bitmap_buffer_size)(void *qemu_process);
+ uint32_t (*nyx_get_aux_string)(void *nyx_process, uint8_t *buffer,
+ uint32_t size);
+
+} nyx_plugin_handler_t;
+
+#endif
+
+typedef struct afl_forkserver {
+
+ /* a program that includes afl-forkserver needs to define these */
+
+ u8 *trace_bits; /* SHM with instrumentation bitmap */
+
+ s32 fsrv_pid, /* PID of the fork server */
+ child_pid, /* PID of the fuzzed program */
+ child_status, /* waitpid result for the child */
+ out_dir_fd; /* FD of the lock file */
+
+ s32 out_fd, /* Persistent fd for fsrv->out_file */
+ dev_urandom_fd, /* Persistent fd for /dev/urandom */
+
+ dev_null_fd, /* Persistent fd for /dev/null */
+ fsrv_ctl_fd, /* Fork server control pipe (write) */
+ fsrv_st_fd; /* Fork server status pipe (read) */
+
+ u32 exec_tmout; /* Configurable exec timeout (ms) */
+ u32 init_tmout; /* Configurable init timeout (ms) */
+ u32 map_size; /* map size used by the target */
+ u32 real_map_size; /* real map size, unaligned */
+ u32 snapshot; /* is snapshot feature used */
+ u64 mem_limit; /* Memory cap for child (MB) */
+
+ u64 total_execs; /* How often run_target was called */
+
+ u8 *out_file, /* File to fuzz, if any */
+ *target_path; /* Path of the target */
+
+ FILE *plot_file; /* Gnuplot output file */
+
+ /* Note: last_run_timed_out is u32 to send it to the child as 4 byte array */
+ u32 last_run_timed_out; /* Traced process timed out? */
+
+ u8 last_kill_signal; /* Signal that killed the child */
+
+ bool use_shmem_fuzz; /* use shared mem for test cases */
+
+ bool support_shmem_fuzz; /* set by afl-fuzz */
+
+ bool use_fauxsrv; /* Fauxsrv for non-forking targets? */
+
+ bool qemu_mode; /* if running in qemu mode or not */
+
+ bool frida_mode; /* if running in frida mode or not */
+
+ bool frida_asan; /* if running with asan in frida mode */
+
+ bool cs_mode; /* if running in CoreSight mode or not */
+
+ bool use_stdin; /* use stdin for sending data */
+
+ bool no_unlink; /* do not unlink cur_input */
+
+ bool uses_asan; /* Target uses ASAN? */
+
+ bool debug; /* debug mode? */
+
+ bool uses_crash_exitcode; /* Custom crash exitcode specified? */
+ u8 crash_exitcode; /* The crash exitcode specified */
+
+ u32 *shmem_fuzz_len; /* length of the fuzzing test case */
+
+ u8 *shmem_fuzz; /* allocated memory for fuzzing */
+
+ char *cmplog_binary; /* the name of the cmplog binary */
+
+ /* persistent mode replay functionality */
+ u32 persistent_record; /* persistent replay setting */
+#ifdef AFL_PERSISTENT_RECORD
+ u32 persistent_record_idx; /* persistent replay cache ptr */
+ u32 persistent_record_cnt; /* persistent replay counter */
+ u8 * persistent_record_dir;
+ u8 **persistent_record_data;
+ u32 *persistent_record_len;
+ s32 persistent_record_pid;
+#endif
+
+ /* Function to kick off the forkserver child */
+ void (*init_child_func)(struct afl_forkserver *fsrv, char **argv);
+
+ u8 *afl_ptr; /* for autodictionary: afl ptr */
+
+ void (*add_extra_func)(void *afl_ptr, u8 *mem, u32 len);
+
+ u8 kill_signal;
+ u8 persistent_mode;
+
+#ifdef __linux__
+ nyx_plugin_handler_t *nyx_handlers;
+ char * out_dir_path; /* path to the output directory */
+ u8 nyx_mode; /* if running in nyx mode or not */
+ bool nyx_parent; /* create initial snapshot */
+ bool nyx_standalone; /* don't serialize the snapshot */
+ void * nyx_runner; /* nyx runner object */
+ u32 nyx_id; /* nyx runner id (0 -> master) */
+ u32 nyx_bind_cpu_id; /* nyx runner cpu id */
+ char * nyx_aux_string;
+#endif
+
+} afl_forkserver_t;
+
+typedef enum fsrv_run_result {
+
+ /* 00 */ FSRV_RUN_OK = 0,
+ /* 01 */ FSRV_RUN_TMOUT,
+ /* 02 */ FSRV_RUN_CRASH,
+ /* 03 */ FSRV_RUN_ERROR,
+ /* 04 */ FSRV_RUN_NOINST,
+ /* 05 */ FSRV_RUN_NOBITS,
+
+} fsrv_run_result_t;
+
+void afl_fsrv_init(afl_forkserver_t *fsrv);
+void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from);
+void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
+ volatile u8 *stop_soon_p, u8 debug_child_output);
+u32 afl_fsrv_get_mapsize(afl_forkserver_t *fsrv, char **argv,
+ volatile u8 *stop_soon_p, u8 debug_child_output);
+void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len);
+fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
+ volatile u8 *stop_soon_p);
+void afl_fsrv_killall(void);
+void afl_fsrv_deinit(afl_forkserver_t *fsrv);
+void afl_fsrv_kill(afl_forkserver_t *fsrv);
+
+#ifdef __APPLE__
+ #define MSG_FORK_ON_APPLE \
+ " - On MacOS X, the semantics of fork() syscalls are non-standard and " \
+ "may\n" \
+ " break afl-fuzz performance optimizations when running " \
+ "platform-specific\n" \
+ " targets. To fix this, set AFL_NO_FORKSRV=1 in the environment.\n\n"
+#else
+ #define MSG_FORK_ON_APPLE ""
+#endif
+
+#ifdef RLIMIT_AS
+ #define MSG_ULIMIT_USAGE " ( ulimit -Sv $[%llu << 10];"
+#else
+ #define MSG_ULIMIT_USAGE " ( ulimit -Sd $[%llu << 10];"
+#endif /* ^RLIMIT_AS */
+
+#endif
+
diff --git a/include/hash.h b/include/hash.h
new file mode 100644
index 00000000..d8fef70c
--- /dev/null
+++ b/include/hash.h
@@ -0,0 +1,114 @@
+/*
+ american fuzzy lop++ - hashing function
+ ---------------------------------------
+
+ The hash32() function is a variant of MurmurHash3, a good
+ non-cryptosafe hashing function developed by Austin Appleby.
+
+ For simplicity, this variant does *NOT* accept buffer lengths
+ that are not divisible by 8 bytes. The 32-bit version is otherwise
+ similar to the original; the 64-bit one is a custom hack with
+ mostly-unproven properties.
+
+ Austin's original code is public domain.
+
+ Other code written by Michal Zalewski
+
+ Copyright 2016 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ */
+
+#ifndef _HAVE_HASH_H
+#define _HAVE_HASH_H
+
+#include "types.h"
+
+u32 hash32(u8 *key, u32 len, u32 seed);
+u64 hash64(u8 *key, u32 len, u64 seed);
+
+#if 0
+
+The following code is disabled because xxh3 is 30% faster
+
+ #ifdef __x86_64__
+
+ #define ROL64(_x, _r) ((((u64)(_x)) << (_r)) | (((u64)(_x)) >> (64 - (_r))))
+
+static inline u32 hash32(u8 *key, u32 len, u32 seed) {
+
+ const u64 *data = (u64 *)key;
+ u64 h1 = seed ^ len;
+
+ len >>= 3;
+
+ while (len--) {
+
+ u64 k1 = *data++;
+
+ k1 *= 0x87c37b91114253d5ULL;
+ k1 = ROL64(k1, 31);
+ k1 *= 0x4cf5ad432745937fULL;
+
+ h1 ^= k1;
+ h1 = ROL64(h1, 27);
+ h1 = h1 * 5 + 0x52dce729;
+
+ }
+
+ h1 ^= h1 >> 33;
+ h1 *= 0xff51afd7ed558ccdULL;
+ h1 ^= h1 >> 33;
+ h1 *= 0xc4ceb9fe1a85ec53ULL;
+ h1 ^= h1 >> 33;
+
+ return h1;
+
+}
+
+ #else
+
+ #define ROL32(_x, _r) ((((u32)(_x)) << (_r)) | (((u32)(_x)) >> (32 - (_r))))
+
+static inline u32 hash32(const void *key, u32 len, u32 seed) {
+
+ const u32 *data = (u32 *)key;
+ u32 h1 = seed ^ len;
+
+ len >>= 2;
+
+ while (len--) {
+
+ u32 k1 = *data++;
+
+ k1 *= 0xcc9e2d51;
+ k1 = ROL32(k1, 15);
+ k1 *= 0x1b873593;
+
+ h1 ^= k1;
+ h1 = ROL32(h1, 13);
+ h1 = h1 * 5 + 0xe6546b64;
+
+ }
+
+ h1 ^= h1 >> 16;
+ h1 *= 0x85ebca6b;
+ h1 ^= h1 >> 13;
+ h1 *= 0xc2b2ae35;
+ h1 ^= h1 >> 16;
+
+ return h1;
+
+}
+
+ #endif /* ^__x86_64__ */
+#endif
+
+#endif /* !_HAVE_HASH_H */
+
diff --git a/include/list.h b/include/list.h
new file mode 100644
index 00000000..a6223564
--- /dev/null
+++ b/include/list.h
@@ -0,0 +1,183 @@
+/*
+ american fuzzy lop++ - linked list code
+ ---------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
+ Andrea Fioraldi <andreafioraldi@gmail.com>,
+ Dominik Maier <mail@dmnk.co>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ This allocator is not designed to resist malicious attackers (the canaries
+ are small and predictable), but provides a robust and portable way to detect
+ use-after-free, off-by-one writes, stale pointers, and so on.
+
+ */
+
+#ifndef AFL_LIST
+#define AFL_LIST
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include "debug.h"
+#include "afl-prealloc.h"
+
+/* How many elements to allocate before malloc is needed */
+#define LIST_PREALLOC_SIZE (64)
+
+typedef struct list_element {
+
+ PREALLOCABLE;
+
+ struct list_element *prev;
+ struct list_element *next;
+ void * data;
+
+} element_t;
+
+typedef struct list {
+
+ element_t element_prealloc_buf[LIST_PREALLOC_SIZE];
+ s32 element_prealloc_count;
+
+} list_t;
+
+static inline element_t *get_head(list_t *list) {
+
+ /* The first element is the head */
+ return list->element_prealloc_buf;
+
+}
+
+static inline void list_free_el(list_t *list, element_t *el) {
+
+ PRE_FREE(el, list->element_prealloc_count);
+
+}
+
+static inline void list_append(list_t *list, void *el) {
+
+ element_t *head = get_head(list);
+ if (!head->next) {
+
+ /* initialize */
+
+ memset(list, 0, sizeof(list_t));
+ PRE_ALLOC_FORCE(head, list->element_prealloc_count);
+ head->next = head->prev = head;
+
+ }
+
+ element_t *el_box = NULL;
+
+ PRE_ALLOC(el_box, list->element_prealloc_buf, LIST_PREALLOC_SIZE,
+ list->element_prealloc_count);
+ if (!el_box) { FATAL("failed to allocate list element"); }
+ el_box->data = el;
+ el_box->next = head;
+ el_box->prev = head->prev;
+ head->prev->next = el_box;
+ head->prev = el_box;
+
+}
+
+/* Simple foreach.
+ Pointer to the current element is in `el`,
+ casted to (a pointer) of the given `type`.
+ A return from this block will return from calling func.
+*/
+
+#define LIST_FOREACH(list, type, block) \
+ do { \
+ \
+ list_t * li = (list); \
+ element_t *head = get_head((li)); \
+ element_t *el_box = (head)->next; \
+ if (!el_box) FATAL("foreach over uninitialized list"); \
+ while (el_box != head) { \
+ \
+ __attribute__((unused)) type *el = (type *)((el_box)->data); \
+ /* get next so el_box can be unlinked */ \
+ element_t *next = el_box->next; \
+ {block}; \
+ el_box = next; \
+ \
+ } \
+ \
+ } while (0);
+
+/* In foreach: remove the current el from the list */
+
+#define LIST_REMOVE_CURRENT_EL_IN_FOREACH() \
+ do { \
+ \
+ el_box->prev->next = next; \
+ el_box->next->prev = el_box->prev; \
+ list_free_el(li, el_box); \
+ \
+ } while (0);
+
+/* Same as foreach, but will clear list in the process */
+
+#define LIST_FOREACH_CLEAR(list, type, block) \
+ do { \
+ \
+ LIST_FOREACH((list), type, { \
+ \
+ {block}; \
+ LIST_REMOVE_CURRENT_EL_IN_FOREACH(); \
+ \
+ }); \
+ \
+ } while (0);
+
+/* remove an item from the list */
+
+static inline void list_remove(list_t *list, void *remove_me) {
+
+ LIST_FOREACH(list, void, {
+
+ if (el == remove_me) {
+
+ el_box->prev->next = el_box->next;
+ el_box->next->prev = el_box->prev;
+ el_box->data = NULL;
+ list_free_el(list, el_box);
+ return;
+
+ }
+
+ });
+
+ FATAL("List item to be removed not in list");
+
+}
+
+/* Returns true if el is in list */
+
+static inline bool list_contains(list_t *list, void *contains_me) {
+
+ LIST_FOREACH(list, void, {
+
+ if (el == contains_me) return true;
+
+ });
+
+ return false;
+
+}
+
+#endif
+
diff --git a/include/sharedmem.h b/include/sharedmem.h
new file mode 100644
index 00000000..e646b73f
--- /dev/null
+++ b/include/sharedmem.h
@@ -0,0 +1,63 @@
+/*
+ american fuzzy lop++ - shared memory related header
+ ---------------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Forkserver design by Jann Horn <jannhorn@googlemail.com>
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
+ Andrea Fioraldi <andreafioraldi@gmail.com>,
+ Dominik Maier <mail@dmnk.co>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ Shared code to handle the shared memory. This is used by the fuzzer
+ as well the other components like afl-tmin, afl-showmap, etc...
+
+ */
+
+#ifndef __AFL_SHAREDMEM_H
+#define __AFL_SHAREDMEM_H
+
+#include "types.h"
+
+typedef struct sharedmem {
+
+ // extern unsigned char *trace_bits;
+
+#ifdef USEMMAP
+ /* ================ Proteas ================ */
+ int g_shm_fd;
+ char g_shm_file_path[L_tmpnam];
+ int cmplog_g_shm_fd;
+ char cmplog_g_shm_file_path[L_tmpnam];
+/* ========================================= */
+#else
+ s32 shm_id; /* ID of the SHM region */
+ s32 cmplog_shm_id;
+#endif
+
+ u8 *map; /* shared memory region */
+
+ size_t map_size; /* actual allocated size */
+
+ int cmplog_mode;
+ int shmemfuzz_mode;
+ struct cmp_map *cmp_map;
+
+} sharedmem_t;
+
+u8 * afl_shm_init(sharedmem_t *, size_t, unsigned char non_instrumented_mode);
+void afl_shm_deinit(sharedmem_t *);
+
+#endif
+
diff --git a/include/snapshot-inl.h b/include/snapshot-inl.h
new file mode 100644
index 00000000..8d2f41ff
--- /dev/null
+++ b/include/snapshot-inl.h
@@ -0,0 +1,115 @@
+/*
+ american fuzzy lop++ - snapshot helpers routines
+ ------------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Forkserver design by Jann Horn <jannhorn@googlemail.com>
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
+ Andrea Fioraldi <andreafioraldi@gmail.com>,
+ Dominik Maier <mail@dmnk.co>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ */
+
+// From AFL-Snapshot-LKM/include/afl_snapshot.h (must be kept synced)
+
+#include <sys/ioctl.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+#define AFL_SNAPSHOT_FILE_NAME "/dev/afl_snapshot"
+
+#define AFL_SNAPSHOT_IOCTL_MAGIC 44313
+
+#define AFL_SNAPSHOT_IOCTL_DO _IO(AFL_SNAPSHOT_IOCTL_MAGIC, 1)
+#define AFL_SNAPSHOT_IOCTL_CLEAN _IO(AFL_SNAPSHOT_IOCTL_MAGIC, 2)
+#define AFL_SNAPSHOT_EXCLUDE_VMRANGE \
+ _IOR(AFL_SNAPSHOT_IOCTL_MAGIC, 3, struct afl_snapshot_vmrange_args *)
+#define AFL_SNAPSHOT_INCLUDE_VMRANGE \
+ _IOR(AFL_SNAPSHOT_IOCTL_MAGIC, 4, struct afl_snapshot_vmrange_args *)
+#define AFL_SNAPSHOT_IOCTL_TAKE _IOR(AFL_SNAPSHOT_IOCTL_MAGIC, 5, int)
+#define AFL_SNAPSHOT_IOCTL_RESTORE _IO(AFL_SNAPSHOT_IOCTL_MAGIC, 6)
+
+// Trace new mmaped ares and unmap them on restore.
+#define AFL_SNAPSHOT_MMAP 1
+// Do not snapshot any page (by default all writeable not-shared pages
+// are shanpshotted.
+#define AFL_SNAPSHOT_BLOCK 2
+// Snapshot file descriptor state, close newly opened descriptors
+#define AFL_SNAPSHOT_FDS 4
+// Snapshot registers state
+#define AFL_SNAPSHOT_REGS 8
+// Perform a restore when exit_group is invoked
+#define AFL_SNAPSHOT_EXIT 16
+// TODO(andrea) allow not COW snapshots (high perf on small processes)
+// Disable COW, restore all the snapshotted pages
+#define AFL_SNAPSHOT_NOCOW 32
+// Do not snapshot Stack pages
+#define AFL_SNAPSHOT_NOSTACK 64
+
+struct afl_snapshot_vmrange_args {
+
+ unsigned long start, end;
+
+};
+
+static int afl_snapshot_dev_fd;
+
+static int afl_snapshot_init(void) {
+
+ afl_snapshot_dev_fd = open(AFL_SNAPSHOT_FILE_NAME, 0);
+ return afl_snapshot_dev_fd;
+
+}
+
+static void afl_snapshot_exclude_vmrange(void *start, void *end) {
+
+ struct afl_snapshot_vmrange_args args = {(unsigned long)start,
+ (unsigned long)end};
+ ioctl(afl_snapshot_dev_fd, AFL_SNAPSHOT_EXCLUDE_VMRANGE, &args);
+
+}
+
+static void afl_snapshot_include_vmrange(void *start, void *end) {
+
+ struct afl_snapshot_vmrange_args args = {(unsigned long)start,
+ (unsigned long)end};
+ ioctl(afl_snapshot_dev_fd, AFL_SNAPSHOT_INCLUDE_VMRANGE, &args);
+
+}
+
+static int afl_snapshot_take(int config) {
+
+ return ioctl(afl_snapshot_dev_fd, AFL_SNAPSHOT_IOCTL_TAKE, config);
+
+}
+
+static int afl_snapshot_do(void) {
+
+ return ioctl(afl_snapshot_dev_fd, AFL_SNAPSHOT_IOCTL_DO);
+
+}
+
+static void afl_snapshot_restore(void) {
+
+ ioctl(afl_snapshot_dev_fd, AFL_SNAPSHOT_IOCTL_RESTORE);
+
+}
+
+static void afl_snapshot_clean(void) {
+
+ ioctl(afl_snapshot_dev_fd, AFL_SNAPSHOT_IOCTL_CLEAN);
+
+}
+
diff --git a/include/types.h b/include/types.h
new file mode 100644
index 00000000..4a68b1b0
--- /dev/null
+++ b/include/types.h
@@ -0,0 +1,196 @@
+/*
+ american fuzzy lop++ - type definitions and minor macros
+ --------------------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
+ Andrea Fioraldi <andreafioraldi@gmail.com>,
+ Dominik Maier <mail@dmnk.co>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ */
+
+#ifndef _HAVE_TYPES_H
+#define _HAVE_TYPES_H
+
+#include <stdint.h>
+#include <stdlib.h>
+#include "config.h"
+
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+#ifdef WORD_SIZE_64
+typedef unsigned __int128 uint128_t;
+typedef uint128_t u128;
+#endif
+
+/* Extended forkserver option values */
+
+/* Reporting errors */
+#define FS_OPT_ERROR 0xf800008f
+#define FS_OPT_GET_ERROR(x) ((x & 0x00ffff00) >> 8)
+#define FS_OPT_SET_ERROR(x) ((x & 0x0000ffff) << 8)
+#define FS_ERROR_MAP_SIZE 1
+#define FS_ERROR_MAP_ADDR 2
+#define FS_ERROR_SHM_OPEN 4
+#define FS_ERROR_SHMAT 8
+#define FS_ERROR_MMAP 16
+#define FS_ERROR_OLD_CMPLOG 32
+#define FS_ERROR_OLD_CMPLOG_QEMU 64
+
+/* Reporting options */
+#define FS_OPT_ENABLED 0x80000001
+#define FS_OPT_MAPSIZE 0x40000000
+#define FS_OPT_SNAPSHOT 0x20000000
+#define FS_OPT_AUTODICT 0x10000000
+#define FS_OPT_SHDMEM_FUZZ 0x01000000
+#define FS_OPT_NEWCMPLOG 0x02000000
+#define FS_OPT_OLD_AFLPP_WORKAROUND 0x0f000000
+// FS_OPT_MAX_MAPSIZE is 8388608 = 0x800000 = 2^23 = 1 << 22
+#define FS_OPT_MAX_MAPSIZE ((0x00fffffeU >> 1) + 1)
+#define FS_OPT_GET_MAPSIZE(x) (((x & 0x00fffffe) >> 1) + 1)
+#define FS_OPT_SET_MAPSIZE(x) \
+ (x <= 1 || x > FS_OPT_MAX_MAPSIZE ? 0 : ((x - 1) << 1))
+
+typedef unsigned long long u64;
+
+typedef int8_t s8;
+typedef int16_t s16;
+typedef int32_t s32;
+typedef int64_t s64;
+#ifdef WORD_SIZE_64
+typedef __int128 int128_t;
+typedef int128_t s128;
+#endif
+
+#ifndef MIN
+ #define MIN(a, b) \
+ ({ \
+ \
+ __typeof__(a) _a = (a); \
+ __typeof__(b) _b = (b); \
+ _a < _b ? _a : _b; \
+ \
+ })
+
+ #define MAX(a, b) \
+ ({ \
+ \
+ __typeof__(a) _a = (a); \
+ __typeof__(b) _b = (b); \
+ _a > _b ? _a : _b; \
+ \
+ })
+
+#endif /* !MIN */
+
+#define SWAP16(_x) \
+ ({ \
+ \
+ u16 _ret = (_x); \
+ (u16)((_ret << 8) | (_ret >> 8)); \
+ \
+ })
+
+#define SWAP32(_x) \
+ ({ \
+ \
+ u32 _ret = (_x); \
+ (u32)((_ret << 24) | (_ret >> 24) | ((_ret << 8) & 0x00FF0000) | \
+ ((_ret >> 8) & 0x0000FF00)); \
+ \
+ })
+
+#define SWAP64(_x) \
+ ({ \
+ \
+ u64 _ret = (_x); \
+ _ret = \
+ (_ret & 0x00000000FFFFFFFF) << 32 | (_ret & 0xFFFFFFFF00000000) >> 32; \
+ _ret = \
+ (_ret & 0x0000FFFF0000FFFF) << 16 | (_ret & 0xFFFF0000FFFF0000) >> 16; \
+ _ret = \
+ (_ret & 0x00FF00FF00FF00FF) << 8 | (_ret & 0xFF00FF00FF00FF00) >> 8; \
+ _ret; \
+ \
+ })
+
+// It is impossible to define 128 bit constants, so ...
+#ifdef WORD_SIZE_64
+ #define SWAPN(_x, _l) \
+ ({ \
+ \
+ u128 _res = (_x), _ret; \
+ char *d = (char *)&_ret, *s = (char *)&_res; \
+ int i; \
+ for (i = 0; i < 16; i++) \
+ d[15 - i] = s[i]; \
+ u32 sr = 128U - ((_l) << 3U); \
+ (_ret >>= sr); \
+ (u128) _ret; \
+ \
+ })
+#endif
+
+#define SWAPNN(_x, _y, _l) \
+ ({ \
+ \
+ char *d = (char *)(_x), *s = (char *)(_y); \
+ u32 i, l = (_l)-1; \
+ for (i = 0; i <= l; i++) \
+ d[l - i] = s[i]; \
+ \
+ })
+
+#ifdef AFL_LLVM_PASS
+ #if defined(__linux__) || !defined(__ANDROID__)
+ #define AFL_SR(s) (srandom(s))
+ #define AFL_R(x) (random() % (x))
+ #else
+ #define AFL_SR(s) ((void)s)
+ #define AFL_R(x) (arc4random_uniform(x))
+ #endif
+#else
+ #if defined(__linux__) || !defined(__ANDROID__)
+ #define SR(s) (srandom(s))
+ #define R(x) (random() % (x))
+ #else
+ #define SR(s) ((void)s)
+ #define R(x) (arc4random_uniform(x))
+ #endif
+#endif /* ^AFL_LLVM_PASS */
+
+#define STRINGIFY_INTERNAL(x) #x
+#define STRINGIFY(x) STRINGIFY_INTERNAL(x)
+
+#define MEM_BARRIER() __asm__ volatile("" ::: "memory")
+
+#if __GNUC__ < 6
+ #ifndef likely
+ #define likely(_x) (_x)
+ #endif
+ #ifndef unlikely
+ #define unlikely(_x) (_x)
+ #endif
+#else
+ #ifndef likely
+ #define likely(_x) __builtin_expect(!!(_x), 1)
+ #endif
+ #ifndef unlikely
+ #define unlikely(_x) __builtin_expect(!!(_x), 0)
+ #endif
+#endif
+
+#endif /* ! _HAVE_TYPES_H */
+
diff --git a/include/xxhash.h b/include/xxhash.h
new file mode 100644
index 00000000..4f101003
--- /dev/null
+++ b/include/xxhash.h
@@ -0,0 +1,6269 @@
+/*
+ * xxHash - Extremely Fast Hash algorithm
+ * Header File
+ * Copyright (C) 2012-2022 Yann Collet
+ *
+ * BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You can contact the author at:
+ * - xxHash homepage: https://www.xxhash.com
+ * - xxHash source repository: https://github.com/Cyan4973/xxHash
+ */
+/*!
+ * @mainpage xxHash
+ *
+ * @file xxhash.h
+ * xxHash prototypes and implementation
+ */
+/* TODO: update */
+/* Notice extracted from xxHash homepage:
+
+xxHash is an extremely fast hash algorithm, running at RAM speed limits.
+It also successfully passes all tests from the SMHasher suite.
+
+Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo
+@3GHz)
+
+Name Speed Q.Score Author
+xxHash 5.4 GB/s 10
+CrapWow 3.2 GB/s 2 Andrew
+MurmurHash 3a 2.7 GB/s 10 Austin Appleby
+SpookyHash 2.0 GB/s 10 Bob Jenkins
+SBox 1.4 GB/s 9 Bret Mulvey
+Lookup3 1.2 GB/s 9 Bob Jenkins
+SuperFastHash 1.2 GB/s 1 Paul Hsieh
+CityHash64 1.05 GB/s 10 Pike & Alakuijala
+FNV 0.55 GB/s 5 Fowler, Noll, Vo
+CRC32 0.43 GB/s 9
+MD5-32 0.33 GB/s 10 Ronald L. Rivest
+SHA1-32 0.28 GB/s 10
+
+Q.Score is a measure of quality of the hash function.
+It depends on successfully passing SMHasher test set.
+10 is a perfect score.
+
+Note: SMHasher's CRC32 implementation is not the fastest one.
+Other speed-oriented implementations can be faster,
+especially in combination with PCLMUL instruction:
+https://fastcompression.blogspot.com/2019/03/presenting-xxh3.html?showComment=1552696407071#c3490092340461170735
+
+A 64-bit version, named XXH64, is available since r35.
+It offers much better speed, but for 64-bit applications only.
+Name Speed on 64 bits Speed on 32 bits
+XXH64 13.8 GB/s 1.9 GB/s
+XXH32 6.8 GB/s 6.0 GB/s
+*/
+
+#if defined(__cplusplus)
+extern "C" {
+
+#endif
+
+/* ****************************
+ * INLINE mode
+ ******************************/
+/*!
+ * XXH_INLINE_ALL (and XXH_PRIVATE_API)
+ * Use these build macros to inline xxhash into the target unit.
+ * Inlining improves performance on small inputs, especially when the length is
+ * expressed as a compile-time constant:
+ *
+ * https://fastcompression.blogspot.com/2018/03/xxhash-for-small-keys-impressive-power.html
+ *
+ * It also keeps xxHash symbols private to the unit, so they are not exported.
+ *
+ * Usage:
+ * #define XXH_INLINE_ALL
+ * #include "xxhash.h"
+ *
+ * Do not compile and link xxhash.o as a separate object, as it is not useful.
+ */
+#if (defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)) && \
+ !defined(XXH_INLINE_ALL_31684351384)
+/* this section should be traversed only once */
+ #define XXH_INLINE_ALL_31684351384
+/* give access to the advanced API, required to compile implementations */
+ #undef XXH_STATIC_LINKING_ONLY /* avoid macro redef */
+ #define XXH_STATIC_LINKING_ONLY
+/* make all functions private */
+ #undef XXH_PUBLIC_API
+ #if defined(__GNUC__)
+ #define XXH_PUBLIC_API static __inline __attribute__((unused))
+ #elif defined(__cplusplus) || \
+ (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
+ #define XXH_PUBLIC_API static inline
+ #elif defined(_MSC_VER)
+ #define XXH_PUBLIC_API static __inline
+ #else
+ /* note: this version may generate warnings for unused static functions */
+ #define XXH_PUBLIC_API static
+ #endif
+
+/*
+ * This part deals with the special case where a unit wants to inline xxHash,
+ * but "xxhash.h" has previously been included without XXH_INLINE_ALL,
+ * such as part of some previously included *.h header file.
+ * Without further action, the new include would just be ignored,
+ * and functions would effectively _not_ be inlined (silent failure).
+ * The following macros solve this situation by prefixing all inlined names,
+ * avoiding naming collision with previous inclusions.
+ */
+/* Before that, we unconditionally #undef all symbols,
+ * in case they were already defined with XXH_NAMESPACE.
+ * They will then be redefined for XXH_INLINE_ALL
+ */
+ #undef XXH_versionNumber
+/* XXH32 */
+ #undef XXH32
+ #undef XXH32_createState
+ #undef XXH32_freeState
+ #undef XXH32_reset
+ #undef XXH32_update
+ #undef XXH32_digest
+ #undef XXH32_copyState
+ #undef XXH32_canonicalFromHash
+ #undef XXH32_hashFromCanonical
+/* XXH64 */
+ #undef XXH64
+ #undef XXH64_createState
+ #undef XXH64_freeState
+ #undef XXH64_reset
+ #undef XXH64_update
+ #undef XXH64_digest
+ #undef XXH64_copyState
+ #undef XXH64_canonicalFromHash
+ #undef XXH64_hashFromCanonical
+/* XXH3_64bits */
+ #undef XXH3_64bits
+ #undef XXH3_64bits_withSecret
+ #undef XXH3_64bits_withSeed
+ #undef XXH3_createState
+ #undef XXH3_freeState
+ #undef XXH3_copyState
+ #undef XXH3_64bits_reset
+ #undef XXH3_64bits_reset_withSeed
+ #undef XXH3_64bits_reset_withSecret
+ #undef XXH3_64bits_update
+ #undef XXH3_64bits_digest
+ #undef XXH3_generateSecret
+/* XXH3_128bits */
+ #undef XXH128
+ #undef XXH3_128bits
+ #undef XXH3_128bits_withSeed
+ #undef XXH3_128bits_withSecret
+ #undef XXH3_128bits_reset
+ #undef XXH3_128bits_reset_withSeed
+ #undef XXH3_128bits_reset_withSecret
+ #undef XXH3_128bits_update
+ #undef XXH3_128bits_digest
+ #undef XXH128_isEqual
+ #undef XXH128_cmp
+ #undef XXH128_canonicalFromHash
+ #undef XXH128_hashFromCanonical
+/* Finally, free the namespace itself */
+ #undef XXH_NAMESPACE
+
+/* employ the namespace for XXH_INLINE_ALL */
+ #define XXH_NAMESPACE XXH_INLINE_
+/*
+ * Some identifiers (enums, type names) are not symbols,
+ * but they must nonetheless be renamed to avoid redeclaration.
+ * Alternative solution: do not redeclare them.
+ * However, this requires some #ifdefs, and has a more dispersed impact.
+ * Meanwhile, renaming can be achieved in a single place.
+ */
+ #define XXH_IPREF(Id) XXH_NAMESPACE##Id
+ #define XXH_OK XXH_IPREF(XXH_OK)
+ #define XXH_ERROR XXH_IPREF(XXH_ERROR)
+ #define XXH_errorcode XXH_IPREF(XXH_errorcode)
+ #define XXH32_canonical_t XXH_IPREF(XXH32_canonical_t)
+ #define XXH64_canonical_t XXH_IPREF(XXH64_canonical_t)
+ #define XXH128_canonical_t XXH_IPREF(XXH128_canonical_t)
+ #define XXH32_state_s XXH_IPREF(XXH32_state_s)
+ #define XXH32_state_t XXH_IPREF(XXH32_state_t)
+ #define XXH64_state_s XXH_IPREF(XXH64_state_s)
+ #define XXH64_state_t XXH_IPREF(XXH64_state_t)
+ #define XXH3_state_s XXH_IPREF(XXH3_state_s)
+ #define XXH3_state_t XXH_IPREF(XXH3_state_t)
+ #define XXH128_hash_t XXH_IPREF(XXH128_hash_t)
+/* Ensure the header is parsed again, even if it was previously included */
+ #undef XXHASH_H_5627135585666179
+ #undef XXHASH_H_STATIC_13879238742
+#endif /* XXH_INLINE_ALL || XXH_PRIVATE_API */
+
+/* ****************************************************************
+ * Stable API
+ *****************************************************************/
+#ifndef XXHASH_H_5627135585666179
+ #define XXHASH_H_5627135585666179 1
+
+ /*!
+ * @defgroup public Public API
+ * Contains details on the public xxHash functions.
+ * @{
+
+ */
+ /* specific declaration modes for Windows */
+ #if !defined(XXH_INLINE_ALL) && !defined(XXH_PRIVATE_API)
+ #if defined(WIN32) && defined(_MSC_VER) && \
+ (defined(XXH_IMPORT) || defined(XXH_EXPORT))
+ #ifdef XXH_EXPORT
+ #define XXH_PUBLIC_API __declspec(dllexport)
+ #elif XXH_IMPORT
+ #define XXH_PUBLIC_API __declspec(dllimport)
+ #endif
+ #else
+ #define XXH_PUBLIC_API /* do nothing */
+ #endif
+ #endif
+
+ #ifdef XXH_DOXYGEN
+ /*!
+ * @brief Emulate a namespace by transparently prefixing all symbols.
+ *
+ * If you want to include _and expose_ xxHash functions from within your own
+ * library, but also want to avoid symbol collisions with other libraries
+ * which may also include xxHash, you can use XXH_NAMESPACE to automatically
+ * prefix any public symbol from xxhash library with the value of
+ * XXH_NAMESPACE (therefore, avoid empty or numeric values).
+ *
+ * Note that no change is required within the calling program as long as it
+ * includes `xxhash.h`: Regular symbol names will be automatically
+ * translated by this header.
+ */
+ #define XXH_NAMESPACE /* YOUR NAME HERE */
+ #undef XXH_NAMESPACE
+ #endif
+
+ #ifdef XXH_NAMESPACE
+ #define XXH_CAT(A, B) A##B
+ #define XXH_NAME2(A, B) XXH_CAT(A, B)
+ #define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber)
+ /* XXH32 */
+ #define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32)
+ #define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState)
+ #define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState)
+ #define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset)
+ #define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update)
+ #define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest)
+ #define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState)
+ #define XXH32_canonicalFromHash \
+ XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash)
+ #define XXH32_hashFromCanonical \
+ XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical)
+ /* XXH64 */
+ #define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64)
+ #define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState)
+ #define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState)
+ #define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset)
+ #define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update)
+ #define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest)
+ #define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState)
+ #define XXH64_canonicalFromHash \
+ XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash)
+ #define XXH64_hashFromCanonical \
+ XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical)
+ /* XXH3_64bits */
+ #define XXH3_64bits XXH_NAME2(XXH_NAMESPACE, XXH3_64bits)
+ #define XXH3_64bits_withSecret \
+ XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSecret)
+ #define XXH3_64bits_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSeed)
+ #define XXH3_createState XXH_NAME2(XXH_NAMESPACE, XXH3_createState)
+ #define XXH3_freeState XXH_NAME2(XXH_NAMESPACE, XXH3_freeState)
+ #define XXH3_copyState XXH_NAME2(XXH_NAMESPACE, XXH3_copyState)
+ #define XXH3_64bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset)
+ #define XXH3_64bits_reset_withSeed \
+ XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSeed)
+ #define XXH3_64bits_reset_withSecret \
+ XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSecret)
+ #define XXH3_64bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_update)
+ #define XXH3_64bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_digest)
+ #define XXH3_generateSecret XXH_NAME2(XXH_NAMESPACE, XXH3_generateSecret)
+ /* XXH3_128bits */
+ #define XXH128 XXH_NAME2(XXH_NAMESPACE, XXH128)
+ #define XXH3_128bits XXH_NAME2(XXH_NAMESPACE, XXH3_128bits)
+ #define XXH3_128bits_withSeed \
+ XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSeed)
+ #define XXH3_128bits_withSecret \
+ XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSecret)
+ #define XXH3_128bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset)
+ #define XXH3_128bits_reset_withSeed \
+ XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSeed)
+ #define XXH3_128bits_reset_withSecret \
+ XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSecret)
+ #define XXH3_128bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_update)
+ #define XXH3_128bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_digest)
+ #define XXH128_isEqual XXH_NAME2(XXH_NAMESPACE, XXH128_isEqual)
+ #define XXH128_cmp XXH_NAME2(XXH_NAMESPACE, XXH128_cmp)
+ #define XXH128_canonicalFromHash \
+ XXH_NAME2(XXH_NAMESPACE, XXH128_canonicalFromHash)
+ #define XXH128_hashFromCanonical \
+ XXH_NAME2(XXH_NAMESPACE, XXH128_hashFromCanonical)
+ #endif
+
+ /* *************************************
+ * Version
+ ***************************************/
+ #define XXH_VERSION_MAJOR 0
+ #define XXH_VERSION_MINOR 8
+ #define XXH_VERSION_RELEASE 1
+ #define XXH_VERSION_NUMBER \
+ (XXH_VERSION_MAJOR * 100 * 100 + XXH_VERSION_MINOR * 100 + \
+ XXH_VERSION_RELEASE)
+
+/*!
+ * @brief Obtains the xxHash version.
+ *
+ * This is only useful when xxHash is compiled as a shared library, as it is
+ * independent of the version defined in the header.
+ *
+ * @return `XXH_VERSION_NUMBER` as of when the libray was compiled.
+ */
+XXH_PUBLIC_API unsigned XXH_versionNumber(void);
+
+ /* ****************************
+ * Definitions
+ ******************************/
+ #include <stddef.h> /* size_t */
+typedef enum { XXH_OK = 0, XXH_ERROR } XXH_errorcode;
+
+ /*-**********************************************************************
+ * 32-bit hash
+ ************************************************************************/
+ #if defined(XXH_DOXYGEN) /* Don't show <stdint.h> include */
+/*!
+ * @brief An unsigned 32-bit integer.
+ *
+ * Not necessarily defined to `uint32_t` but functionally equivalent.
+ */
+typedef uint32_t XXH32_hash_t;
+
+ #elif !defined(__VMS) && \
+ (defined(__cplusplus) || \
+ (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */))
+ #include <stdint.h>
+typedef uint32_t XXH32_hash_t;
+
+ #else
+ #include <limits.h>
+ #if UINT_MAX == 0xFFFFFFFFUL
+typedef unsigned int XXH32_hash_t;
+ #else
+ #if ULONG_MAX == 0xFFFFFFFFUL
+typedef unsigned long XXH32_hash_t;
+ #else
+ #error "unsupported platform: need a 32-bit type"
+ #endif
+ #endif
+ #endif
+
+/*!
+ * @}
+ *
+ * @defgroup xxh32_family XXH32 family
+ * @ingroup public
+ * Contains functions used in the classic 32-bit xxHash algorithm.
+ *
+ * @note
+ * XXH32 is considered rather weak by today's standards.
+ * The @ref xxh3_family provides competitive speed for both 32-bit and 64-bit
+ * systems, and offers true 64/128 bit hash results. It provides a superior
+ * level of dispersion, and greatly reduces the risks of collisions.
+ *
+ * @see @ref xxh64_family, @ref xxh3_family : Other xxHash families
+ * @see @ref xxh32_impl for implementation details
+ * @{
+
+ */
+
+/*!
+ * @brief Calculates the 32-bit hash of @p input using xxHash32.
+ *
+ * Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark): 5.4 GB/s
+ *
+ * @param input The block of data to be hashed, at least @p length bytes in
+ * size.
+ * @param length The length of @p input, in bytes.
+ * @param seed The 32-bit seed to alter the hash's output predictably.
+ *
+ * @pre
+ * The memory between @p input and @p input + @p length must be valid,
+ * readable, contiguous memory. However, if @p length is `0`, @p input may be
+ * `NULL`. In C++, this also must be *TriviallyCopyable*.
+ *
+ * @return The calculated 32-bit hash value.
+ *
+ * @see
+ * XXH64(), XXH3_64bits_withSeed(), XXH3_128bits_withSeed(), XXH128():
+ * Direct equivalents for the other variants of xxHash.
+ * @see
+ * XXH32_createState(), XXH32_update(), XXH32_digest(): Streaming version.
+ */
+XXH_PUBLIC_API XXH32_hash_t XXH32(const void *input, size_t length,
+ XXH32_hash_t seed);
+
+/*!
+ * Streaming functions generate the xxHash value from an incremental input.
+ * This method is slower than single-call functions, due to state management.
+ * For small inputs, prefer `XXH32()` and `XXH64()`, which are better optimized.
+ *
+ * An XXH state must first be allocated using `XXH*_createState()`.
+ *
+ * Start a new hash by initializing the state with a seed using `XXH*_reset()`.
+ *
+ * Then, feed the hash state by calling `XXH*_update()` as many times as
+ * necessary.
+ *
+ * The function returns an error code, with 0 meaning OK, and any other value
+ * meaning there is an error.
+ *
+ * Finally, a hash value can be produced anytime, by using `XXH*_digest()`.
+ * This function returns the nn-bits hash as an int or long long.
+ *
+ * It's still possible to continue inserting input into the hash state after a
+ * digest, and generate new hash values later on by invoking `XXH*_digest()`.
+ *
+ * When done, release the state using `XXH*_freeState()`.
+ *
+ * Example code for incrementally hashing a file:
+ * @code{.c}
+ * #include <stdio.h>
+ * #include <xxhash.h>
+ * #define BUFFER_SIZE 256
+ *
+ * // Note: XXH64 and XXH3 use the same interface.
+ * XXH32_hash_t
+ * hashFile(FILE* stream)
+ * {
+
+ * XXH32_state_t* state;
+ * unsigned char buf[BUFFER_SIZE];
+ * size_t amt;
+ * XXH32_hash_t hash;
+ *
+ * state = XXH32_createState(); // Create a state
+ * assert(state != NULL); // Error check here
+ * XXH32_reset(state, 0xbaad5eed); // Reset state with our seed
+ * while ((amt = fread(buf, 1, sizeof(buf), stream)) != 0) {
+
+ * XXH32_update(state, buf, amt); // Hash the file in chunks
+ * }
+ * hash = XXH32_digest(state); // Finalize the hash
+ * XXH32_freeState(state); // Clean up
+ * return hash;
+ * }
+ * @endcode
+ */
+
+/*!
+ * @typedef struct XXH32_state_s XXH32_state_t
+ * @brief The opaque state struct for the XXH32 streaming API.
+ *
+ * @see XXH32_state_s for details.
+ */
+typedef struct XXH32_state_s XXH32_state_t;
+
+/*!
+ * @brief Allocates an @ref XXH32_state_t.
+ *
+ * Must be freed with XXH32_freeState().
+ * @return An allocated XXH32_state_t on success, `NULL` on failure.
+ */
+XXH_PUBLIC_API XXH32_state_t *XXH32_createState(void);
+/*!
+ * @brief Frees an @ref XXH32_state_t.
+ *
+ * Must be allocated with XXH32_createState().
+ * @param statePtr A pointer to an @ref XXH32_state_t allocated with @ref
+ * XXH32_createState().
+ * @return XXH_OK.
+ */
+XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t *statePtr);
+/*!
+ * @brief Copies one @ref XXH32_state_t to another.
+ *
+ * @param dst_state The state to copy to.
+ * @param src_state The state to copy from.
+ * @pre
+ * @p dst_state and @p src_state must not be `NULL` and must not overlap.
+ */
+XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t * dst_state,
+ const XXH32_state_t *src_state);
+
+/*!
+ * @brief Resets an @ref XXH32_state_t to begin a new hash.
+ *
+ * This function resets and seeds a state. Call it before @ref XXH32_update().
+ *
+ * @param statePtr The state struct to reset.
+ * @param seed The 32-bit seed to alter the hash result predictably.
+ *
+ * @pre
+ * @p statePtr must not be `NULL`.
+ *
+ * @return @ref XXH_OK on success, @ref XXH_ERROR on failure.
+ */
+XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t *statePtr,
+ XXH32_hash_t seed);
+
+/*!
+ * @brief Consumes a block of @p input to an @ref XXH32_state_t.
+ *
+ * Call this to incrementally consume blocks of data.
+ *
+ * @param statePtr The state struct to update.
+ * @param input The block of data to be hashed, at least @p length bytes in
+ * size.
+ * @param length The length of @p input, in bytes.
+ *
+ * @pre
+ * @p statePtr must not be `NULL`.
+ * @pre
+ * The memory between @p input and @p input + @p length must be valid,
+ * readable, contiguous memory. However, if @p length is `0`, @p input may be
+ * `NULL`. In C++, this also must be *TriviallyCopyable*.
+ *
+ * @return @ref XXH_OK on success, @ref XXH_ERROR on failure.
+ */
+XXH_PUBLIC_API XXH_errorcode XXH32_update(XXH32_state_t *statePtr,
+ const void *input, size_t length);
+
+/*!
+ * @brief Returns the calculated hash value from an @ref XXH32_state_t.
+ *
+ * @note
+ * Calling XXH32_digest() will not affect @p statePtr, so you can update,
+ * digest, and update again.
+ *
+ * @param statePtr The state struct to calculate the hash from.
+ *
+ * @pre
+ * @p statePtr must not be `NULL`.
+ *
+ * @return The calculated xxHash32 value from that state.
+ */
+XXH_PUBLIC_API XXH32_hash_t XXH32_digest(const XXH32_state_t *statePtr);
+
+/******* Canonical representation *******/
+
+/*
+ * The default return values from XXH functions are unsigned 32 and 64 bit
+ * integers.
+ * This the simplest and fastest format for further post-processing.
+ *
+ * However, this leaves open the question of what is the order on the byte
+ * level, since little and big endian conventions will store the same number
+ * differently.
+ *
+ * The canonical representation settles this issue by mandating big-endian
+ * convention, the same convention as human-readable numbers (large digits
+ * first).
+ *
+ * When writing hash values to storage, sending them over a network, or printing
+ * them, it's highly recommended to use the canonical representation to ensure
+ * portability across a wider range of systems, present and future.
+ *
+ * The following functions allow transformation of hash values to and from
+ * canonical format.
+ */
+
+/*!
+ * @brief Canonical (big endian) representation of @ref XXH32_hash_t.
+ */
+typedef struct {
+
+ unsigned char digest[4]; /*!< Hash bytes, big endian */
+
+} XXH32_canonical_t;
+
+/*!
+ * @brief Converts an @ref XXH32_hash_t to a big endian @ref XXH32_canonical_t.
+ *
+ * @param dst The @ref XXH32_canonical_t pointer to be stored to.
+ * @param hash The @ref XXH32_hash_t to be converted.
+ *
+ * @pre
+ * @p dst must not be `NULL`.
+ */
+XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t *dst,
+ XXH32_hash_t hash);
+
+/*!
+ * @brief Converts an @ref XXH32_canonical_t to a native @ref XXH32_hash_t.
+ *
+ * @param src The @ref XXH32_canonical_t to convert.
+ *
+ * @pre
+ * @p src must not be `NULL`.
+ *
+ * @return The converted hash.
+ */
+XXH_PUBLIC_API XXH32_hash_t
+XXH32_hashFromCanonical(const XXH32_canonical_t *src);
+
+ #ifdef __has_attribute
+ #define XXH_HAS_ATTRIBUTE(x) __has_attribute(x)
+ #else
+ #define XXH_HAS_ATTRIBUTE(x) 0
+ #endif
+
+ /* C-language Attributes are added in C23. */
+ #if defined(__STDC_VERSION__) && (__STDC_VERSION__ > 201710L) && \
+ defined(__has_c_attribute)
+ #define XXH_HAS_C_ATTRIBUTE(x) __has_c_attribute(x)
+ #else
+ #define XXH_HAS_C_ATTRIBUTE(x) 0
+ #endif
+
+ #if defined(__cplusplus) && defined(__has_cpp_attribute)
+ #define XXH_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
+ #else
+ #define XXH_HAS_CPP_ATTRIBUTE(x) 0
+ #endif
+
+ /*
+ Define XXH_FALLTHROUGH macro for annotating switch case with the 'fallthrough'
+ attribute introduced in CPP17 and C23. CPP17 :
+ https://en.cppreference.com/w/cpp/language/attributes/fallthrough C23 :
+ https://en.cppreference.com/w/c/language/attributes/fallthrough
+ */
+ #if XXH_HAS_C_ATTRIBUTE(x)
+ #define XXH_FALLTHROUGH [[fallthrough]]
+ #elif XXH_HAS_CPP_ATTRIBUTE(x)
+ #define XXH_FALLTHROUGH [[fallthrough]]
+ #elif XXH_HAS_ATTRIBUTE(__fallthrough__)
+ #define XXH_FALLTHROUGH __attribute__((fallthrough))
+ #else
+ #define XXH_FALLTHROUGH
+ #endif
+
+/*!
+ * @}
+ * @ingroup public
+ * @{
+
+ */
+
+ #ifndef XXH_NO_LONG_LONG
+ /*-**********************************************************************
+ * 64-bit hash
+ ************************************************************************/
+ #if defined(XXH_DOXYGEN) /* don't include <stdint.h> */
+/*!
+ * @brief An unsigned 64-bit integer.
+ *
+ * Not necessarily defined to `uint64_t` but functionally equivalent.
+ */
+typedef uint64_t XXH64_hash_t;
+ #elif !defined(__VMS) && \
+ (defined(__cplusplus) || (defined(__STDC_VERSION__) && \
+ (__STDC_VERSION__ >= 199901L) /* C99 */))
+ #include <stdint.h>
+typedef uint64_t XXH64_hash_t;
+ #else
+ #include <limits.h>
+ #if defined(__LP64__) && ULONG_MAX == 0xFFFFFFFFFFFFFFFFULL
+/* LP64 ABI says uint64_t is unsigned long */
+typedef unsigned long XXH64_hash_t;
+ #else
+/* the following type must have a width of 64-bit */
+typedef unsigned long long XXH64_hash_t;
+ #endif
+ #endif
+
+/*!
+ * @}
+ *
+ * @defgroup xxh64_family XXH64 family
+ * @ingroup public
+ * @{
+
+ * Contains functions used in the classic 64-bit xxHash algorithm.
+ *
+ * @note
+ * XXH3 provides competitive speed for both 32-bit and 64-bit systems,
+ * and offers true 64/128 bit hash results. It provides a superior level of
+ * dispersion, and greatly reduces the risks of collisions.
+ */
+
+/*!
+ * @brief Calculates the 64-bit hash of @p input using xxHash64.
+ *
+ * This function usually runs faster on 64-bit systems, but slower on 32-bit
+ * systems (see benchmark).
+ *
+ * @param input The block of data to be hashed, at least @p length bytes in
+ * size.
+ * @param length The length of @p input, in bytes.
+ * @param seed The 64-bit seed to alter the hash's output predictably.
+ *
+ * @pre
+ * The memory between @p input and @p input + @p length must be valid,
+ * readable, contiguous memory. However, if @p length is `0`, @p input may be
+ * `NULL`. In C++, this also must be *TriviallyCopyable*.
+ *
+ * @return The calculated 64-bit hash.
+ *
+ * @see
+ * XXH32(), XXH3_64bits_withSeed(), XXH3_128bits_withSeed(), XXH128():
+ * Direct equivalents for the other variants of xxHash.
+ * @see
+ * XXH64_createState(), XXH64_update(), XXH64_digest(): Streaming version.
+ */
+XXH_PUBLIC_API XXH64_hash_t XXH64(const void *input, size_t length,
+ XXH64_hash_t seed);
+
+/******* Streaming *******/
+/*!
+ * @brief The opaque state struct for the XXH64 streaming API.
+ *
+ * @see XXH64_state_s for details.
+ */
+typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */
+XXH_PUBLIC_API XXH64_state_t *XXH64_createState(void);
+XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t *statePtr);
+XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t * dst_state,
+ const XXH64_state_t *src_state);
+
+XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t *statePtr,
+ XXH64_hash_t seed);
+XXH_PUBLIC_API XXH_errorcode XXH64_update(XXH64_state_t *statePtr,
+ const void *input, size_t length);
+XXH_PUBLIC_API XXH64_hash_t XXH64_digest(const XXH64_state_t *statePtr);
+
+/******* Canonical representation *******/
+typedef struct {
+
+ unsigned char digest[sizeof(XXH64_hash_t)];
+
+} XXH64_canonical_t;
+
+XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t *dst,
+ XXH64_hash_t hash);
+XXH_PUBLIC_API XXH64_hash_t
+XXH64_hashFromCanonical(const XXH64_canonical_t *src);
+
+/*!
+ * @}
+ * ************************************************************************
+ * @defgroup xxh3_family XXH3 family
+ * @ingroup public
+ * @{
+
+ *
+ * XXH3 is a more recent hash algorithm featuring:
+ * - Improved speed for both small and large inputs
+ * - True 64-bit and 128-bit outputs
+ * - SIMD acceleration
+ * - Improved 32-bit viability
+ *
+ * Speed analysis methodology is explained here:
+ *
+ * https://fastcompression.blogspot.com/2019/03/presenting-xxh3.html
+ *
+ * Compared to XXH64, expect XXH3 to run approximately
+ * ~2x faster on large inputs and >3x faster on small ones,
+ * exact differences vary depending on platform.
+ *
+ * XXH3's speed benefits greatly from SIMD and 64-bit arithmetic,
+ * but does not require it.
+ * Any 32-bit and 64-bit targets that can run XXH32 smoothly
+ * can run XXH3 at competitive speeds, even without vector support.
+ * Further details are explained in the implementation.
+ *
+ * Optimized implementations are provided for AVX512, AVX2, SSE2, NEON, POWER8,
+ * ZVector and scalar targets. This can be controlled via the XXH_VECTOR macro.
+ *
+ * XXH3 implementation is portable:
+ * it has a generic C90 formulation that can be compiled on any platform,
+ * all implementations generage exactly the same hash value on all platforms.
+ * Starting from v0.8.0, it's also labelled "stable", meaning that
+ * any future version will also generate the same hash value.
+ *
+ * XXH3 offers 2 variants, _64bits and _128bits.
+ *
+ * When only 64 bits are needed, prefer invoking the _64bits variant, as it
+ * reduces the amount of mixing, resulting in faster speed on small inputs.
+ * It's also generally simpler to manipulate a scalar return type than a struct.
+ *
+ * The API supports one-shot hashing, streaming mode, and custom secrets.
+ */
+
+/*-**********************************************************************
+ * XXH3 64-bit variant
+ ************************************************************************/
+
+/* XXH3_64bits():
+ * default 64-bit variant, using default secret and default seed of 0.
+ * It's the fastest variant. */
+XXH_PUBLIC_API XXH64_hash_t XXH3_64bits(const void *data, size_t len);
+
+/*
+ * XXH3_64bits_withSeed():
+ * This variant generates a custom secret on the fly
+ * based on default secret altered using the `seed` value.
+ * While this operation is decently fast, note that it's not completely free.
+ * Note: seed==0 produces the same results as XXH3_64bits().
+ */
+XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSeed(const void *data, size_t len,
+ XXH64_hash_t seed);
+
+ /*!
+ * The bare minimum size for a custom secret.
+ *
+ * @see
+ * XXH3_64bits_withSecret(), XXH3_64bits_reset_withSecret(),
+ * XXH3_128bits_withSecret(), XXH3_128bits_reset_withSecret().
+ */
+ #define XXH3_SECRET_SIZE_MIN 136
+
+/*
+ * XXH3_64bits_withSecret():
+ * It's possible to provide any blob of bytes as a "secret" to generate the
+ * hash. This makes it more difficult for an external actor to prepare an
+ * intentional collision. The main condition is that secretSize *must* be large
+ * enough (>= XXH3_SECRET_SIZE_MIN). However, the quality of produced hash
+ * values depends on secret's entropy. Technically, the secret must look like a
+ * bunch of random bytes. Avoid "trivial" or structured data such as repeated
+ * sequences or a text document. Whenever unsure about the "randomness" of the
+ * blob of bytes, consider relabelling it as a "custom seed" instead, and employ
+ * "XXH3_generateSecret()" (see below) to generate a high entropy secret derived
+ * from the custom seed.
+ */
+XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSecret(const void *data, size_t len,
+ const void *secret,
+ size_t secretSize);
+
+/******* Streaming *******/
+/*
+ * Streaming requires state maintenance.
+ * This operation costs memory and CPU.
+ * As a consequence, streaming is slower than one-shot hashing.
+ * For better performance, prefer one-shot functions whenever applicable.
+ */
+
+/*!
+ * @brief The state struct for the XXH3 streaming API.
+ *
+ * @see XXH3_state_s for details.
+ */
+typedef struct XXH3_state_s XXH3_state_t;
+XXH_PUBLIC_API XXH3_state_t *XXH3_createState(void);
+XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t *statePtr);
+XXH_PUBLIC_API void XXH3_copyState(XXH3_state_t * dst_state,
+ const XXH3_state_t *src_state);
+
+/*
+ * XXH3_64bits_reset():
+ * Initialize with default parameters.
+ * digest will be equivalent to `XXH3_64bits()`.
+ */
+XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset(XXH3_state_t *statePtr);
+/*
+ * XXH3_64bits_reset_withSeed():
+ * Generate a custom secret from `seed`, and store it into `statePtr`.
+ * digest will be equivalent to `XXH3_64bits_withSeed()`.
+ */
+XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSeed(XXH3_state_t *statePtr,
+ XXH64_hash_t seed);
+/*
+ * XXH3_64bits_reset_withSecret():
+ * `secret` is referenced, it _must outlive_ the hash streaming session.
+ * Similar to one-shot API, `secretSize` must be >= `XXH3_SECRET_SIZE_MIN`,
+ * and the quality of produced hash values depends on secret's entropy
+ * (secret's content should look like a bunch of random bytes).
+ * When in doubt about the randomness of a candidate `secret`,
+ * consider employing `XXH3_generateSecret()` instead (see below).
+ */
+XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSecret(
+ XXH3_state_t *statePtr, const void *secret, size_t secretSize);
+
+XXH_PUBLIC_API XXH_errorcode XXH3_64bits_update(XXH3_state_t *statePtr,
+ const void * input,
+ size_t length);
+XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest(const XXH3_state_t *statePtr);
+
+/* note : canonical representation of XXH3 is the same as XXH64
+ * since they both produce XXH64_hash_t values */
+
+/*-**********************************************************************
+ * XXH3 128-bit variant
+ ************************************************************************/
+
+/*!
+ * @brief The return value from 128-bit hashes.
+ *
+ * Stored in little endian order, although the fields themselves are in native
+ * endianness.
+ */
+typedef struct {
+
+ XXH64_hash_t low64; /*!< `value & 0xFFFFFFFFFFFFFFFF` */
+ XXH64_hash_t high64; /*!< `value >> 64` */
+
+} XXH128_hash_t;
+
+XXH_PUBLIC_API XXH128_hash_t XXH3_128bits(const void *data, size_t len);
+XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSeed(const void *data, size_t len,
+ XXH64_hash_t seed);
+XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSecret(const void *data,
+ size_t len,
+ const void *secret,
+ size_t secretSize);
+
+/******* Streaming *******/
+/*
+ * Streaming requires state maintenance.
+ * This operation costs memory and CPU.
+ * As a consequence, streaming is slower than one-shot hashing.
+ * For better performance, prefer one-shot functions whenever applicable.
+ *
+ * XXH3_128bits uses the same XXH3_state_t as XXH3_64bits().
+ * Use already declared XXH3_createState() and XXH3_freeState().
+ *
+ * All reset and streaming functions have same meaning as their 64-bit
+ * counterpart.
+ */
+
+XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset(XXH3_state_t *statePtr);
+XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSeed(XXH3_state_t *statePtr,
+ XXH64_hash_t seed);
+XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecret(
+ XXH3_state_t *statePtr, const void *secret, size_t secretSize);
+
+XXH_PUBLIC_API XXH_errorcode XXH3_128bits_update(XXH3_state_t *statePtr,
+ const void * input,
+ size_t length);
+XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest(const XXH3_state_t *statePtr);
+
+/* Following helper functions make it possible to compare XXH128_hast_t values.
+ * Since XXH128_hash_t is a structure, this capability is not offered by the
+ * language.
+ * Note: For better performance, these functions can be inlined using
+ * XXH_INLINE_ALL */
+
+/*!
+ * XXH128_isEqual():
+ * Return: 1 if `h1` and `h2` are equal, 0 if they are not.
+ */
+XXH_PUBLIC_API int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2);
+
+/*!
+ * XXH128_cmp():
+ *
+ * This comparator is compatible with stdlib's `qsort()`/`bsearch()`.
+ *
+ * return: >0 if *h128_1 > *h128_2
+ * =0 if *h128_1 == *h128_2
+ * <0 if *h128_1 < *h128_2
+ */
+XXH_PUBLIC_API int XXH128_cmp(const void *h128_1, const void *h128_2);
+
+/******* Canonical representation *******/
+typedef struct {
+
+ unsigned char digest[sizeof(XXH128_hash_t)];
+
+} XXH128_canonical_t;
+
+XXH_PUBLIC_API void XXH128_canonicalFromHash(XXH128_canonical_t *dst,
+ XXH128_hash_t hash);
+XXH_PUBLIC_API XXH128_hash_t
+XXH128_hashFromCanonical(const XXH128_canonical_t *src);
+
+ #endif /* XXH_NO_LONG_LONG */
+
+/*!
+ * @}
+ */
+#endif /* XXHASH_H_5627135585666179 */
+
+#if defined(XXH_STATIC_LINKING_ONLY) && !defined(XXHASH_H_STATIC_13879238742)
+ #define XXHASH_H_STATIC_13879238742
+/* ****************************************************************************
+ * This section contains declarations which are not guaranteed to remain stable.
+ * They may change in future versions, becoming incompatible with a different
+ * version of the library.
+ * These declarations should only be used with static linking.
+ * Never use them in association with dynamic linking!
+ *****************************************************************************
+ */
+
+/*
+ * These definitions are only present to allow static allocation
+ * of XXH states, on stack or in a struct, for example.
+ * Never **ever** access their members directly.
+ */
+
+/*!
+ * @internal
+ * @brief Structure for XXH32 streaming API.
+ *
+ * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY,
+ * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. Otherwise it is
+ * an opaque type. This allows fields to safely be changed.
+ *
+ * Typedef'd to @ref XXH32_state_t.
+ * Do not access the members of this struct directly.
+ * @see XXH64_state_s, XXH3_state_s
+ */
+struct XXH32_state_s {
+
+ XXH32_hash_t total_len_32; /*!< Total length hashed, modulo 2^32 */
+ XXH32_hash_t large_len; /*!< Whether the hash is >= 16 (handles @ref
+ total_len_32 overflow) */
+ XXH32_hash_t v1; /*!< First accumulator lane */
+ XXH32_hash_t v2; /*!< Second accumulator lane */
+ XXH32_hash_t v3; /*!< Third accumulator lane */
+ XXH32_hash_t v4; /*!< Fourth accumulator lane */
+ XXH32_hash_t mem32[4]; /*!< Internal buffer for partial reads. Treated as
+ unsigned char[16]. */
+ XXH32_hash_t memsize; /*!< Amount of data in @ref mem32 */
+ XXH32_hash_t reserved; /*!< Reserved field. Do not read or write to it, it may
+ be removed. */
+
+}; /* typedef'd to XXH32_state_t */
+
+ #ifndef XXH_NO_LONG_LONG /* defined when there is no 64-bit support */
+
+/*!
+ * @internal
+ * @brief Structure for XXH64 streaming API.
+ *
+ * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY,
+ * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. Otherwise it is
+ * an opaque type. This allows fields to safely be changed.
+ *
+ * Typedef'd to @ref XXH64_state_t.
+ * Do not access the members of this struct directly.
+ * @see XXH32_state_s, XXH3_state_s
+ */
+struct XXH64_state_s {
+
+ XXH64_hash_t total_len; /*!< Total length hashed. This is always 64-bit. */
+ XXH64_hash_t v1; /*!< First accumulator lane */
+ XXH64_hash_t v2; /*!< Second accumulator lane */
+ XXH64_hash_t v3; /*!< Third accumulator lane */
+ XXH64_hash_t v4; /*!< Fourth accumulator lane */
+ XXH64_hash_t mem64[4]; /*!< Internal buffer for partial reads. Treated as
+ unsigned char[32]. */
+ XXH32_hash_t memsize; /*!< Amount of data in @ref mem64 */
+ XXH32_hash_t reserved32; /*!< Reserved field, needed for padding anyways*/
+ XXH64_hash_t reserved64; /*!< Reserved field. Do not read or write to it, it
+ may be removed. */
+
+}; /* typedef'd to XXH64_state_t */
+
+ #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* >= C11 \
+ */
+ #include <stdalign.h>
+ #define XXH_ALIGN(n) alignas(n)
+ #elif defined(__cplusplus) && (__cplusplus >= 201103L) /* >= C++11 */
+ /* In C++ alignas() is a keyword */
+ #define XXH_ALIGN(n) alignas(n)
+ #elif defined(__GNUC__)
+ #define XXH_ALIGN(n) __attribute__((aligned(n)))
+ #elif defined(_MSC_VER)
+ #define XXH_ALIGN(n) __declspec(align(n))
+ #else
+ #define XXH_ALIGN(n) /* disabled */
+ #endif
+
+ /* Old GCC versions only accept the attribute after the type in structures.
+ */
+ #if !(defined(__STDC_VERSION__) && \
+ (__STDC_VERSION__ >= 201112L)) /* C11+ */ \
+ && !(defined(__cplusplus) && (__cplusplus >= 201103L)) /* >= C++11 */ \
+ && defined(__GNUC__)
+ #define XXH_ALIGN_MEMBER(align, type) type XXH_ALIGN(align)
+ #else
+ #define XXH_ALIGN_MEMBER(align, type) XXH_ALIGN(align) type
+ #endif
+
+ /*!
+ * @brief The size of the internal XXH3 buffer.
+ *
+ * This is the optimal update size for incremental hashing.
+ *
+ * @see XXH3_64b_update(), XXH3_128b_update().
+ */
+ #define XXH3_INTERNALBUFFER_SIZE 256
+
+ /*!
+ * @brief Default size of the secret buffer (and @ref XXH3_kSecret).
+ *
+ * This is the size used in @ref XXH3_kSecret and the seeded functions.
+ *
+ * Not to be confused with @ref XXH3_SECRET_SIZE_MIN.
+ */
+ #define XXH3_SECRET_DEFAULT_SIZE 192
+
+/*!
+ * @internal
+ * @brief Structure for XXH3 streaming API.
+ *
+ * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY,
+ * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined.
+ * Otherwise it is an opaque type.
+ * Never use this definition in combination with dynamic library.
+ * This allows fields to safely be changed in the future.
+ *
+ * @note ** This structure has a strict alignment requirement of 64 bytes!! **
+ * Do not allocate this with `malloc()` or `new`,
+ * it will not be sufficiently aligned.
+ * Use @ref XXH3_createState() and @ref XXH3_freeState(), or stack allocation.
+ *
+ * Typedef'd to @ref XXH3_state_t.
+ * Do never access the members of this struct directly.
+ *
+ * @see XXH3_INITSTATE() for stack initialization.
+ * @see XXH3_createState(), XXH3_freeState().
+ * @see XXH32_state_s, XXH64_state_s
+ */
+struct XXH3_state_s {
+
+ XXH_ALIGN_MEMBER(64, XXH64_hash_t acc[8]);
+ /*!< The 8 accumulators. Similar to `vN` in @ref XXH32_state_s::v1 and @ref
+ * XXH64_state_s */
+ XXH_ALIGN_MEMBER(64, unsigned char customSecret[XXH3_SECRET_DEFAULT_SIZE]);
+ /*!< Used to store a custom secret generated from a seed. */
+ XXH_ALIGN_MEMBER(64, unsigned char buffer[XXH3_INTERNALBUFFER_SIZE]);
+ /*!< The internal buffer. @see XXH32_state_s::mem32 */
+ XXH32_hash_t bufferedSize;
+ /*!< The amount of memory in @ref buffer, @see XXH32_state_s::memsize */
+ XXH32_hash_t reserved32;
+ /*!< Reserved field. Needed for padding on 64-bit. */
+ size_t nbStripesSoFar;
+ /*!< Number or stripes processed. */
+ XXH64_hash_t totalLen;
+ /*!< Total length hashed. 64-bit even on 32-bit targets. */
+ size_t nbStripesPerBlock;
+ /*!< Number of stripes per block. */
+ size_t secretLimit;
+ /*!< Size of @ref customSecret or @ref extSecret */
+ XXH64_hash_t seed;
+ /*!< Seed for _withSeed variants. Must be zero otherwise, @see
+ * XXH3_INITSTATE() */
+ XXH64_hash_t reserved64;
+ /*!< Reserved field. */
+ const unsigned char *extSecret;
+ /*!< Reference to an external secret for the _withSecret variants, NULL
+ * for other variants. */
+ /* note: there may be some padding at the end due to alignment on 64 bytes */
+
+}; /* typedef'd to XXH3_state_t */
+
+ #undef XXH_ALIGN_MEMBER
+
+ /*!
+ * @brief Initializes a stack-allocated `XXH3_state_s`.
+ *
+ * When the @ref XXH3_state_t structure is merely emplaced on stack,
+ * it should be initialized with XXH3_INITSTATE() or a memset()
+ * in case its first reset uses XXH3_NNbits_reset_withSeed().
+ * This init can be omitted if the first reset uses default or _withSecret
+ * mode. This operation isn't necessary when the state is created with
+ * XXH3_createState(). Note that this doesn't prepare the state for a
+ * streaming operation, it's still necessary to use XXH3_NNbits_reset*()
+ * afterwards.
+ */
+ #define XXH3_INITSTATE(XXH3_state_ptr) \
+ { (XXH3_state_ptr)->seed = 0; }
+
+/* === Experimental API === */
+/* Symbols defined below must be considered tied to a specific library version.
+ */
+
+/*
+ * XXH3_generateSecret():
+ *
+ * Derive a high-entropy secret from any user-defined content, named customSeed.
+ * The generated secret can be used in combination with `*_withSecret()`
+ * functions. The `_withSecret()` variants are useful to provide a higher level
+ * of protection than 64-bit seed, as it becomes much more difficult for an
+ * external actor to guess how to impact the calculation logic.
+ *
+ * The function accepts as input a custom seed of any length and any content,
+ * and derives from it a high-entropy secret of length XXH3_SECRET_DEFAULT_SIZE
+ * into an already allocated buffer secretBuffer.
+ * The generated secret is _always_ XXH_SECRET_DEFAULT_SIZE bytes long.
+ *
+ * The generated secret can then be used with any `*_withSecret()` variant.
+ * Functions `XXH3_128bits_withSecret()`, `XXH3_64bits_withSecret()`,
+ * `XXH3_128bits_reset_withSecret()` and `XXH3_64bits_reset_withSecret()`
+ * are part of this list. They all accept a `secret` parameter
+ * which must be very long for implementation reasons (>= XXH3_SECRET_SIZE_MIN)
+ * _and_ feature very high entropy (consist of random-looking bytes).
+ * These conditions can be a high bar to meet, so
+ * this function can be used to generate a secret of proper quality.
+ *
+ * customSeed can be anything. It can have any size, even small ones,
+ * and its content can be anything, even stupidly "low entropy" source such as a
+ * bunch of zeroes. The resulting `secret` will nonetheless provide all expected
+ * qualities.
+ *
+ * Supplying NULL as the customSeed copies the default secret into
+ * `secretBuffer`. When customSeedSize > 0, supplying NULL as customSeed is
+ * undefined behavior.
+ */
+XXH_PUBLIC_API void XXH3_generateSecret(void * secretBuffer,
+ const void *customSeed,
+ size_t customSeedSize);
+
+/* simple short-cut to pre-selected XXH3_128bits variant */
+XXH_PUBLIC_API XXH128_hash_t XXH128(const void *data, size_t len,
+ XXH64_hash_t seed);
+
+ #endif /* XXH_NO_LONG_LONG */
+ #if defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)
+ #define XXH_IMPLEMENTATION
+ #endif
+
+#endif /* defined(XXH_STATIC_LINKING_ONLY) && \
+ !defined(XXHASH_H_STATIC_13879238742) */
+
+/* ======================================================================== */
+/* ======================================================================== */
+/* ======================================================================== */
+
+/*-**********************************************************************
+ * xxHash implementation
+ *-**********************************************************************
+ * xxHash's implementation used to be hosted inside xxhash.c.
+ *
+ * However, inlining requires implementation to be visible to the compiler,
+ * hence be included alongside the header.
+ * Previously, implementation was hosted inside xxhash.c,
+ * which was then #included when inlining was activated.
+ * This construction created issues with a few build and install systems,
+ * as it required xxhash.c to be stored in /include directory.
+ *
+ * xxHash implementation is now directly integrated within xxhash.h.
+ * As a consequence, xxhash.c is no longer needed in /include.
+ *
+ * xxhash.c is still available and is still useful.
+ * In a "normal" setup, when xxhash is not inlined,
+ * xxhash.h only exposes the prototypes and public symbols,
+ * while xxhash.c can be built into an object file xxhash.o
+ * which can then be linked into the final binary.
+ ************************************************************************/
+
+#if (defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API) || \
+ defined(XXH_IMPLEMENTATION)) && \
+ !defined(XXH_IMPLEM_13a8737387)
+ #define XXH_IMPLEM_13a8737387
+
+ /* *************************************
+ * Tuning parameters
+ ***************************************/
+
+ /*!
+ * @defgroup tuning Tuning parameters
+ * @{
+
+ *
+ * Various macros to control xxHash's behavior.
+ */
+ #ifdef XXH_DOXYGEN
+ /*!
+ * @brief Define this to disable 64-bit code.
+ *
+ * Useful if only using the @ref xxh32_family and you have a strict C90
+ * compiler.
+ */
+ #define XXH_NO_LONG_LONG
+ #undef XXH_NO_LONG_LONG /* don't actually */
+ /*!
+ * @brief Controls how unaligned memory is accessed.
+ *
+ * By default, access to unaligned memory is controlled by `memcpy()`, which
+ * is safe and portable.
+ *
+ * Unfortunately, on some target/compiler combinations, the generated
+ * assembly is sub-optimal.
+ *
+ * The below switch allow selection of a different access method
+ * in the search for improved performance.
+ *
+ * @par Possible options:
+ *
+ * - `XXH_FORCE_MEMORY_ACCESS=0` (default): `memcpy`
+ * @par
+ * Use `memcpy()`. Safe and portable. Note that most modern compilers
+ * will eliminate the function call and treat it as an unaligned access.
+ *
+ * - `XXH_FORCE_MEMORY_ACCESS=1`: `__attribute__((packed))`
+ * @par
+ * Depends on compiler extensions and is therefore not portable.
+ * This method is safe _if_ your compiler supports it,
+ * and *generally* as fast or faster than `memcpy`.
+ *
+ * - `XXH_FORCE_MEMORY_ACCESS=2`: Direct cast
+ * @par
+ * Casts directly and dereferences. This method doesn't depend on the
+ * compiler, but it violates the C standard as it directly dereferences
+ * an unaligned pointer. It can generate buggy code on targets which do not
+ * support unaligned memory accesses, but in some circumstances, it's
+ * the only known way to get the most performance.
+ *
+ * - `XXH_FORCE_MEMORY_ACCESS=3`: Byteshift
+ * @par
+ * Also portable. This can generate the best code on old compilers which
+ * don't inline small `memcpy()` calls, and it might also be faster on
+ * big-endian systems which lack a native byteswap instruction. However,
+ * some compilers will emit literal byteshifts even if the target supports
+ * unaligned access.
+ * .
+ *
+ * @warning
+ * Methods 1 and 2 rely on implementation-defined behavior. Use these with
+ * care, as what works on one compiler/platform/optimization level may
+ * cause another to read garbage data or even crash.
+ *
+ * See https://stackoverflow.com/a/32095106/646947 for details.
+ *
+ * Prefer these methods in priority order (0 > 3 > 1 > 2)
+ */
+ #define XXH_FORCE_MEMORY_ACCESS 0
+ /*!
+ * @def XXH_ACCEPT_NULL_INPUT_POINTER
+ * @brief Whether to add explicit `NULL` checks.
+ *
+ * If the input pointer is `NULL` and the length is non-zero, xxHash's
+ * default behavior is to dereference it, triggering a segfault.
+ *
+ * When this macro is enabled, xxHash actively checks the input for a null
+ * pointer. If it is, the result for null input pointers is the same as a
+ * zero-length input.
+ */
+ #define XXH_ACCEPT_NULL_INPUT_POINTER 0
+ /*!
+ * @def XXH_FORCE_ALIGN_CHECK
+ * @brief If defined to non-zero, adds a special path for aligned inputs
+ * (XXH32() and XXH64() only).
+ *
+ * This is an important performance trick for architectures without decent
+ * unaligned memory access performance.
+ *
+ * It checks for input alignment, and when conditions are met, uses a "fast
+ * path" employing direct 32-bit/64-bit reads, resulting in _dramatically
+ * faster_ read speed.
+ *
+ * The check costs one initial branch per hash, which is generally
+ * negligible, but not zero.
+ *
+ * Moreover, it's not useful to generate an additional code path if memory
+ * access uses the same instruction for both aligned and unaligned
+ * addresses (e.g. x86 and aarch64).
+ *
+ * In these cases, the alignment check can be removed by setting this macro
+ * to 0. Then the code will always use unaligned memory access. Align check
+ * is automatically disabled on x86, x64 & arm64, which are platforms known
+ * to offer good unaligned memory accesses performance.
+ *
+ * This option does not affect XXH3 (only XXH32 and XXH64).
+ */
+ #define XXH_FORCE_ALIGN_CHECK 0
+
+ /*!
+ * @def XXH_NO_INLINE_HINTS
+ * @brief When non-zero, sets all functions to `static`.
+ *
+ * By default, xxHash tries to force the compiler to inline almost all
+ * internal functions.
+ *
+ * This can usually improve performance due to reduced jumping and improved
+ * constant folding, but significantly increases the size of the binary
+ * which might not be favorable.
+ *
+ * Additionally, sometimes the forced inlining can be detrimental to
+ * performance, depending on the architecture.
+ *
+ * XXH_NO_INLINE_HINTS marks all internal functions as static, giving the
+ * compiler full control on whether to inline or not.
+ *
+ * When not optimizing (-O0), optimizing for size (-Os, -Oz), or using
+ * -fno-inline with GCC or Clang, this will automatically be defined.
+ */
+ #define XXH_NO_INLINE_HINTS 0
+
+ /*!
+ * @def XXH_REROLL
+ * @brief Whether to reroll `XXH32_finalize`.
+ *
+ * For performance, `XXH32_finalize` uses an unrolled loop
+ * in the form of a switch statement.
+ *
+ * This is not always desirable, as it generates larger code,
+ * and depending on the architecture, may even be slower
+ *
+ * This is automatically defined with `-Os`/`-Oz` on GCC and Clang.
+ */
+ #define XXH_REROLL 0
+
+ /*!
+ * @internal
+ * @brief Redefines old internal names.
+ *
+ * For compatibility with code that uses xxHash's internals before the names
+ * were changed to improve namespacing. There is no other reason to use
+ * this.
+ */
+ #define XXH_OLD_NAMES
+ #undef XXH_OLD_NAMES /* don't actually use, it is ugly. */
+ #endif /* XXH_DOXYGEN */
+ /*!
+ * @}
+ */
+
+ #ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command \
+ line for example */
+ /* prefer __packed__ structures (method 1) for gcc on armv7+ and mips */
+ #if !defined(__clang__) && \
+ ((defined(__INTEL_COMPILER) && !defined(_WIN32)) || \
+ (defined(__GNUC__) && \
+ ((defined(__ARM_ARCH) && __ARM_ARCH >= 7) || \
+ (defined(__mips__) && (__mips <= 5 || __mips_isa_rev < 6) && \
+ (!defined(__mips16) || defined(__mips_mips16e2))))))
+ #define XXH_FORCE_MEMORY_ACCESS 1
+ #endif
+ #endif
+
+ #ifndef XXH_ACCEPT_NULL_INPUT_POINTER /* can be defined externally */
+ #define XXH_ACCEPT_NULL_INPUT_POINTER 0
+ #endif
+
+ #ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */
+ #if defined(__i386) || defined(__x86_64__) || defined(__aarch64__) || \
+ defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM64) /* visual */
+ #define XXH_FORCE_ALIGN_CHECK 0
+ #else
+ #define XXH_FORCE_ALIGN_CHECK 1
+ #endif
+ #endif
+
+ #ifndef XXH_NO_INLINE_HINTS
+ #if defined(__OPTIMIZE_SIZE__) /* -Os, -Oz */ \
+ || defined(__NO_INLINE__) /* -O0, -fno-inline */
+ #define XXH_NO_INLINE_HINTS 1
+ #else
+ #define XXH_NO_INLINE_HINTS 0
+ #endif
+ #endif
+
+ #ifndef XXH_REROLL
+ #if defined(__OPTIMIZE_SIZE__) /* -Os, -Oz */ || \
+ (defined(__GNUC__) && !defined(__clang__))
+ /* The if/then loop is preferable to switch/case on gcc (on x64) */
+ #define XXH_REROLL 1
+ #else
+ #define XXH_REROLL 0
+ #endif
+ #endif
+
+ /*!
+ * @defgroup impl Implementation
+ * @{
+
+ */
+
+ /* *************************************
+ * Includes & Memory related functions
+ ***************************************/
+ /*
+ * Modify the local functions below should you wish to use
+ * different memory routines for malloc() and free()
+ */
+ #include <stdlib.h>
+
+/*!
+ * @internal
+ * @brief Modify this function to use a different routine than malloc().
+ */
+static void *XXH_malloc(size_t s) {
+
+ return malloc(s);
+
+}
+
+/*!
+ * @internal
+ * @brief Modify this function to use a different routine than free().
+ */
+static void XXH_free(void *p) {
+
+ free(p);
+
+}
+
+ #include <string.h>
+
+/*!
+ * @internal
+ * @brief Modify this function to use a different routine than memcpy().
+ */
+static void *XXH_memcpy(void *dest, const void *src, size_t size) {
+
+ return memcpy(dest, src, size);
+
+}
+
+ #include <limits.h> /* ULLONG_MAX */
+
+ /* *************************************
+ * Compiler Specific Options
+ ***************************************/
+ #ifdef _MSC_VER /* Visual Studio warning fix */
+ #pragma warning(disable : 4127) /* disable: C4127: conditional expression \
+ is constant */
+ #endif
+
+ #if XXH_NO_INLINE_HINTS /* disable inlining hints */
+ #if defined(__GNUC__)
+ #define XXH_FORCE_INLINE static __attribute__((unused))
+ #else
+ #define XXH_FORCE_INLINE static
+ #endif
+ #define XXH_NO_INLINE static
+ /* enable inlining hints */
+ #elif defined(_MSC_VER) /* Visual Studio */
+ #define XXH_FORCE_INLINE static __forceinline
+ #define XXH_NO_INLINE static __declspec(noinline)
+ #elif defined(__GNUC__)
+ #define XXH_FORCE_INLINE \
+ static __inline__ __attribute__((always_inline, unused))
+ #define XXH_NO_INLINE static __attribute__((noinline))
+ #elif defined(__cplusplus) || \
+ (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) /* C99 */
+ #define XXH_FORCE_INLINE static inline
+ #define XXH_NO_INLINE static
+ #else
+ #define XXH_FORCE_INLINE static
+ #define XXH_NO_INLINE static
+ #endif
+
+ /* *************************************
+ * Debug
+ ***************************************/
+ /*!
+ * @ingroup tuning
+ * @def XXH_DEBUGLEVEL
+ * @brief Sets the debugging level.
+ *
+ * XXH_DEBUGLEVEL is expected to be defined externally, typically via the
+ * compiler's command line options. The value must be a number.
+ */
+ #ifndef XXH_DEBUGLEVEL
+ #ifdef DEBUGLEVEL /* backwards compat */
+ #define XXH_DEBUGLEVEL DEBUGLEVEL
+ #else
+ #define XXH_DEBUGLEVEL 0
+ #endif
+ #endif
+
+ #if (XXH_DEBUGLEVEL >= 1)
+ #include <assert.h> /* note: can still be disabled with NDEBUG */
+ #define XXH_ASSERT(c) assert(c)
+ #else
+ #define XXH_ASSERT(c) ((void)0)
+ #endif
+
+ /* note: use after variable declarations */
+ #ifndef XXH_STATIC_ASSERT
+ #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* C11 */
+ #include <assert.h>
+ #define XXH_STATIC_ASSERT_WITH_MESSAGE(c, m) \
+ do { \
+ \
+ static_assert((c), m); \
+ \
+ } while (0)
+
+ #elif defined(__cplusplus) && (__cplusplus >= 201103L) /* C++11 */
+ #define XXH_STATIC_ASSERT_WITH_MESSAGE(c, m) \
+ do { \
+ \
+ static_assert((c), m); \
+ \
+ } while (0)
+
+ #else
+ #define XXH_STATIC_ASSERT_WITH_MESSAGE(c, m) \
+ do { \
+ \
+ struct xxh_sa { \
+ \
+ char x[(c) ? 1 : -1]; \
+ \
+ }; \
+ \
+ } while (0)
+
+ #endif
+ #define XXH_STATIC_ASSERT(c) XXH_STATIC_ASSERT_WITH_MESSAGE((c), #c)
+ #endif
+
+ /*!
+ * @internal
+ * @def XXH_COMPILER_GUARD(var)
+ * @brief Used to prevent unwanted optimizations for @p var.
+ *
+ * It uses an empty GCC inline assembly statement with a register constraint
+ * which forces @p var into a general purpose register (eg eax, ebx, ecx
+ * on x86) and marks it as modified.
+ *
+ * This is used in a few places to avoid unwanted autovectorization (e.g.
+ * XXH32_round()). All vectorization we want is explicit via intrinsics,
+ * and _usually_ isn't wanted elsewhere.
+ *
+ * We also use it to prevent unwanted constant folding for AArch64 in
+ * XXH3_initCustomSecret_scalar().
+ */
+ #ifdef __GNUC__
+ #define XXH_COMPILER_GUARD(var) __asm__ __volatile__("" : "+r"(var))
+ #else
+ #define XXH_COMPILER_GUARD(var) ((void)0)
+ #endif
+
+ /* *************************************
+ * Basic Types
+ ***************************************/
+ #if !defined(__VMS) && \
+ (defined(__cplusplus) || \
+ (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */))
+ #include <stdint.h>
+typedef uint8_t xxh_u8;
+ #else
+typedef unsigned char xxh_u8;
+ #endif
+typedef XXH32_hash_t xxh_u32;
+
+ #ifdef XXH_OLD_NAMES
+ #define BYTE xxh_u8
+ #define U8 xxh_u8
+ #define U32 xxh_u32
+ #endif
+
+/* *** Memory access *** */
+
+/*!
+ * @internal
+ * @fn xxh_u32 XXH_read32(const void* ptr)
+ * @brief Reads an unaligned 32-bit integer from @p ptr in native endianness.
+ *
+ * Affected by @ref XXH_FORCE_MEMORY_ACCESS.
+ *
+ * @param ptr The pointer to read from.
+ * @return The 32-bit native endian integer from the bytes at @p ptr.
+ */
+
+/*!
+ * @internal
+ * @fn xxh_u32 XXH_readLE32(const void* ptr)
+ * @brief Reads an unaligned 32-bit little endian integer from @p ptr.
+ *
+ * Affected by @ref XXH_FORCE_MEMORY_ACCESS.
+ *
+ * @param ptr The pointer to read from.
+ * @return The 32-bit little endian integer from the bytes at @p ptr.
+ */
+
+/*!
+ * @internal
+ * @fn xxh_u32 XXH_readBE32(const void* ptr)
+ * @brief Reads an unaligned 32-bit big endian integer from @p ptr.
+ *
+ * Affected by @ref XXH_FORCE_MEMORY_ACCESS.
+ *
+ * @param ptr The pointer to read from.
+ * @return The 32-bit big endian integer from the bytes at @p ptr.
+ */
+
+/*!
+ * @internal
+ * @fn xxh_u32 XXH_readLE32_align(const void* ptr, XXH_alignment align)
+ * @brief Like @ref XXH_readLE32(), but has an option for aligned reads.
+ *
+ * Affected by @ref XXH_FORCE_MEMORY_ACCESS.
+ * Note that when @ref XXH_FORCE_ALIGN_CHECK == 0, the @p align parameter is
+ * always @ref XXH_alignment::XXH_unaligned.
+ *
+ * @param ptr The pointer to read from.
+ * @param align Whether @p ptr is aligned.
+ * @pre
+ * If @p align == @ref XXH_alignment::XXH_aligned, @p ptr must be 4 byte
+ * aligned.
+ * @return The 32-bit little endian integer from the bytes at @p ptr.
+ */
+
+ #if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS == 3))
+ /*
+ * Manual byteshift. Best for old compilers which don't inline memcpy.
+ * We actually directly use XXH_readLE32 and XXH_readBE32.
+ */
+ #elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS == 2))
+
+/*
+ * Force direct memory access. Only works on CPU which support unaligned memory
+ * access in hardware.
+ */
+static xxh_u32 XXH_read32(const void *memPtr) {
+
+ return *(const xxh_u32 *)memPtr;
+
+}
+
+ #elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS == 1))
+
+ /*
+ * __pack instructions are safer but compiler specific, hence potentially
+ * problematic for some compilers.
+ *
+ * Currently only defined for GCC and ICC.
+ */
+ #ifdef XXH_OLD_NAMES
+typedef union {
+
+ xxh_u32 u32;
+
+} __attribute__((packed)) unalign;
+
+ #endif
+static xxh_u32 XXH_read32(const void *ptr) {
+
+ typedef union {
+
+ xxh_u32 u32;
+
+ } __attribute__((packed)) xxh_unalign;
+
+ return ((const xxh_unalign *)ptr)->u32;
+
+}
+
+ #else
+
+/*
+ * Portable and safe solution. Generally efficient.
+ * see: https://stackoverflow.com/a/32095106/646947
+ */
+static xxh_u32 XXH_read32(const void *memPtr) {
+
+ xxh_u32 val;
+ memcpy(&val, memPtr, sizeof(val));
+ return val;
+
+}
+
+ #endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */
+
+ /* *** Endianness *** */
+
+ /*!
+ * @ingroup tuning
+ * @def XXH_CPU_LITTLE_ENDIAN
+ * @brief Whether the target is little endian.
+ *
+ * Defined to 1 if the target is little endian, or 0 if it is big endian.
+ * It can be defined externally, for example on the compiler command line.
+ *
+ * If it is not defined,
+ * a runtime check (which is usually constant folded) is used instead.
+ *
+ * @note
+ * This is not necessarily defined to an integer constant.
+ *
+ * @see XXH_isLittleEndian() for the runtime check.
+ */
+ #ifndef XXH_CPU_LITTLE_ENDIAN
+ /*
+ * Try to detect endianness automatically, to avoid the nonstandard behavior
+ * in `XXH_isLittleEndian()`
+ */
+ #if defined(_WIN32) /* Windows is always little endian */ \
+ || defined(__LITTLE_ENDIAN__) || \
+ (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+ #define XXH_CPU_LITTLE_ENDIAN 1
+ #elif defined(__BIG_ENDIAN__) || \
+ (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+ #define XXH_CPU_LITTLE_ENDIAN 0
+ #else
+/*!
+ * @internal
+ * @brief Runtime check for @ref XXH_CPU_LITTLE_ENDIAN.
+ *
+ * Most compilers will constant fold this.
+ */
+static int XXH_isLittleEndian(void) {
+
+ /*
+ * Portable and well-defined behavior.
+ * Don't use static: it is detrimental to performance.
+ */
+ const union {
+
+ xxh_u32 u;
+ xxh_u8 c[4];
+
+ } one = {1};
+
+ return one.c[0];
+
+}
+
+ #define XXH_CPU_LITTLE_ENDIAN XXH_isLittleEndian()
+ #endif
+ #endif
+
+ /* ****************************************
+ * Compiler-specific Functions and Macros
+ ******************************************/
+ #define XXH_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
+
+ #ifdef __has_builtin
+ #define XXH_HAS_BUILTIN(x) __has_builtin(x)
+ #else
+ #define XXH_HAS_BUILTIN(x) 0
+ #endif
+
+ /*!
+ * @internal
+ * @def XXH_rotl32(x,r)
+ * @brief 32-bit rotate left.
+ *
+ * @param x The 32-bit integer to be rotated.
+ * @param r The number of bits to rotate.
+ * @pre
+ * @p r > 0 && @p r < 32
+ * @note
+ * @p x and @p r may be evaluated multiple times.
+ * @return The rotated result.
+ */
+ #if !defined(NO_CLANG_BUILTIN) && XXH_HAS_BUILTIN(__builtin_rotateleft32) && \
+ XXH_HAS_BUILTIN(__builtin_rotateleft64)
+ #define XXH_rotl32 __builtin_rotateleft32
+ #define XXH_rotl64 __builtin_rotateleft64
+ /* Note: although _rotl exists for minGW (GCC under windows), performance
+ * seems poor */
+ #elif defined(_MSC_VER)
+ #define XXH_rotl32(x, r) _rotl(x, r)
+ #define XXH_rotl64(x, r) _rotl64(x, r)
+ #else
+ #define XXH_rotl32(x, r) (((x) << (r)) | ((x) >> (32 - (r))))
+ #define XXH_rotl64(x, r) (((x) << (r)) | ((x) >> (64 - (r))))
+ #endif
+
+ /*!
+ * @internal
+ * @fn xxh_u32 XXH_swap32(xxh_u32 x)
+ * @brief A 32-bit byteswap.
+ *
+ * @param x The 32-bit integer to byteswap.
+ * @return @p x, byteswapped.
+ */
+ #if defined(_MSC_VER) /* Visual Studio */
+ #define XXH_swap32 _byteswap_ulong
+ #elif XXH_GCC_VERSION >= 403
+ #define XXH_swap32 __builtin_bswap32
+ #else
+static xxh_u32 XXH_swap32(xxh_u32 x) {
+
+ return ((x << 24) & 0xff000000) | ((x << 8) & 0x00ff0000) |
+ ((x >> 8) & 0x0000ff00) | ((x >> 24) & 0x000000ff);
+
+}
+
+ #endif
+
+/* ***************************
+ * Memory reads
+ *****************************/
+
+/*!
+ * @internal
+ * @brief Enum to indicate whether a pointer is aligned.
+ */
+typedef enum {
+
+ XXH_aligned, /*!< Aligned */
+ XXH_unaligned /*!< Possibly unaligned */
+
+} XXH_alignment;
+
+ /*
+ * XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load.
+ *
+ * This is ideal for older compilers which don't inline memcpy.
+ */
+ #if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS == 3))
+
+XXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void *memPtr) {
+
+ const xxh_u8 *bytePtr = (const xxh_u8 *)memPtr;
+ return bytePtr[0] | ((xxh_u32)bytePtr[1] << 8) | ((xxh_u32)bytePtr[2] << 16) |
+ ((xxh_u32)bytePtr[3] << 24);
+
+}
+
+XXH_FORCE_INLINE xxh_u32 XXH_readBE32(const void *memPtr) {
+
+ const xxh_u8 *bytePtr = (const xxh_u8 *)memPtr;
+ return bytePtr[3] | ((xxh_u32)bytePtr[2] << 8) | ((xxh_u32)bytePtr[1] << 16) |
+ ((xxh_u32)bytePtr[0] << 24);
+
+}
+
+ #else
+XXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void *ptr) {
+
+ return XXH_CPU_LITTLE_ENDIAN ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr));
+
+}
+
+static xxh_u32 XXH_readBE32(const void *ptr) {
+
+ return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr);
+
+}
+
+ #endif
+
+XXH_FORCE_INLINE xxh_u32 XXH_readLE32_align(const void * ptr,
+ XXH_alignment align) {
+
+ if (align == XXH_unaligned) {
+
+ return XXH_readLE32(ptr);
+
+ } else {
+
+ return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u32 *)ptr
+ : XXH_swap32(*(const xxh_u32 *)ptr);
+
+ }
+
+}
+
+/* *************************************
+ * Misc
+ ***************************************/
+/*! @ingroup public */
+XXH_PUBLIC_API unsigned XXH_versionNumber(void) {
+
+ return XXH_VERSION_NUMBER;
+
+}
+
+/* *******************************************************************
+ * 32-bit hash functions
+ *********************************************************************/
+/*!
+ * @}
+ * @defgroup xxh32_impl XXH32 implementation
+ * @ingroup impl
+ * @{
+
+ */
+/* #define instead of static const, to be used as initializers */
+ #define XXH_PRIME32_1 0x9E3779B1U /*!< 0b10011110001101110111100110110001 */
+ #define XXH_PRIME32_2 0x85EBCA77U /*!< 0b10000101111010111100101001110111 */
+ #define XXH_PRIME32_3 0xC2B2AE3DU /*!< 0b11000010101100101010111000111101 */
+ #define XXH_PRIME32_4 0x27D4EB2FU /*!< 0b00100111110101001110101100101111 */
+ #define XXH_PRIME32_5 0x165667B1U /*!< 0b00010110010101100110011110110001 */
+
+ #ifdef XXH_OLD_NAMES
+ #define PRIME32_1 XXH_PRIME32_1
+ #define PRIME32_2 XXH_PRIME32_2
+ #define PRIME32_3 XXH_PRIME32_3
+ #define PRIME32_4 XXH_PRIME32_4
+ #define PRIME32_5 XXH_PRIME32_5
+ #endif
+
+/*!
+ * @internal
+ * @brief Normal stripe processing routine.
+ *
+ * This shuffles the bits so that any bit from @p input impacts several bits in
+ * @p acc.
+ *
+ * @param acc The accumulator lane.
+ * @param input The stripe of input to mix.
+ * @return The mixed accumulator lane.
+ */
+static xxh_u32 XXH32_round(xxh_u32 acc, xxh_u32 input) {
+
+ acc += input * XXH_PRIME32_2;
+ acc = XXH_rotl32(acc, 13);
+ acc *= XXH_PRIME32_1;
+ #if (defined(__SSE4_1__) || defined(__aarch64__)) && \
+ !defined(XXH_ENABLE_AUTOVECTORIZE)
+ /*
+ * UGLY HACK:
+ * A compiler fence is the only thing that prevents GCC and Clang from
+ * autovectorizing the XXH32 loop (pragmas and attributes don't work for some
+ * reason) without globally disabling SSE4.1.
+ *
+ * The reason we want to avoid vectorization is because despite working on
+ * 4 integers at a time, there are multiple factors slowing XXH32 down on
+ * SSE4:
+ * - There's a ridiculous amount of lag from pmulld (10 cycles of latency on
+ * newer chips!) making it slightly slower to multiply four integers at
+ * once compared to four integers independently. Even when pmulld was
+ * fastest, Sandy/Ivy Bridge, it is still not worth it to go into SSE
+ * just to multiply unless doing a long operation.
+ *
+ * - Four instructions are required to rotate,
+ * movqda tmp, v // not required with VEX encoding
+ * pslld tmp, 13 // tmp <<= 13
+ * psrld v, 19 // x >>= 19
+ * por v, tmp // x |= tmp
+ * compared to one for scalar:
+ * roll v, 13 // reliably fast across the board
+ * shldl v, v, 13 // Sandy Bridge and later prefer this for some reason
+ *
+ * - Instruction level parallelism is actually more beneficial here because
+ * the SIMD actually serializes this operation: While v1 is rotating, v2
+ * can load data, while v3 can multiply. SSE forces them to operate
+ * together.
+ *
+ * This is also enabled on AArch64, as Clang autovectorizes it incorrectly
+ * and it is pointless writing a NEON implementation that is basically the
+ * same speed as scalar for XXH32.
+ */
+ XXH_COMPILER_GUARD(acc);
+ #endif
+ return acc;
+
+}
+
+/*!
+ * @internal
+ * @brief Mixes all bits to finalize the hash.
+ *
+ * The final mix ensures that all input bits have a chance to impact any bit in
+ * the output digest, resulting in an unbiased distribution.
+ *
+ * @param h32 The hash to avalanche.
+ * @return The avalanched hash.
+ */
+static xxh_u32 XXH32_avalanche(xxh_u32 h32) {
+
+ h32 ^= h32 >> 15;
+ h32 *= XXH_PRIME32_2;
+ h32 ^= h32 >> 13;
+ h32 *= XXH_PRIME32_3;
+ h32 ^= h32 >> 16;
+ return (h32);
+
+}
+
+ #define XXH_get32bits(p) XXH_readLE32_align(p, align)
+
+ #define XXH_PROCESS1 \
+ do { \
+ \
+ h32 += (*ptr++) * XXH_PRIME32_5; \
+ h32 = XXH_rotl32(h32, 11) * XXH_PRIME32_1; \
+ \
+ } while (0)
+
+ #define XXH_PROCESS4 \
+ do { \
+ \
+ h32 += XXH_get32bits(ptr) * XXH_PRIME32_3; \
+ ptr += 4; \
+ h32 = XXH_rotl32(h32, 17) * XXH_PRIME32_4; \
+ \
+ } while (0)
+
+/*!
+ * @internal
+ * @brief Processes the last 0-15 bytes of @p ptr.
+ *
+ * There may be up to 15 bytes remaining to consume from the input.
+ * This final stage will digest them to ensure that all input bytes are present
+ * in the final mix.
+ *
+ * @param h32 The hash to finalize.
+ * @param ptr The pointer to the remaining input.
+ * @param len The remaining length, modulo 16.
+ * @param align Whether @p ptr is aligned.
+ * @return The finalized hash.
+ */
+static xxh_u32 XXH32_finalize(xxh_u32 h32, const xxh_u8 *ptr, size_t len,
+ XXH_alignment align) {
+
+ /* Compact rerolled version */
+ if (XXH_REROLL) {
+
+ len &= 15;
+ while (len >= 4) {
+
+ XXH_PROCESS4;
+ len -= 4;
+
+ }
+
+ while (len > 0) {
+
+ XXH_PROCESS1;
+ --len;
+
+ }
+
+ return XXH32_avalanche(h32);
+
+ } else {
+
+ switch (len & 15) /* or switch(bEnd - p) */ {
+
+ case 12:
+ XXH_PROCESS4;
+ XXH_FALLTHROUGH;
+ case 8:
+ XXH_PROCESS4;
+ XXH_FALLTHROUGH;
+ case 4:
+ XXH_PROCESS4;
+ return XXH32_avalanche(h32);
+
+ case 13:
+ XXH_PROCESS4;
+ XXH_FALLTHROUGH;
+ case 9:
+ XXH_PROCESS4;
+ XXH_FALLTHROUGH;
+ case 5:
+ XXH_PROCESS4;
+ XXH_PROCESS1;
+ return XXH32_avalanche(h32);
+
+ case 14:
+ XXH_PROCESS4;
+ XXH_FALLTHROUGH;
+ case 10:
+ XXH_PROCESS4;
+ XXH_FALLTHROUGH;
+ case 6:
+ XXH_PROCESS4;
+ XXH_PROCESS1;
+ XXH_PROCESS1;
+ return XXH32_avalanche(h32);
+
+ case 15:
+ XXH_PROCESS4;
+ XXH_FALLTHROUGH;
+ case 11:
+ XXH_PROCESS4;
+ XXH_FALLTHROUGH;
+ case 7:
+ XXH_PROCESS4;
+ XXH_FALLTHROUGH;
+ case 3:
+ XXH_PROCESS1;
+ XXH_FALLTHROUGH;
+ case 2:
+ XXH_PROCESS1;
+ XXH_FALLTHROUGH;
+ case 1:
+ XXH_PROCESS1;
+ XXH_FALLTHROUGH;
+ case 0:
+ return XXH32_avalanche(h32);
+
+ }
+
+ XXH_ASSERT(0);
+ return h32; /* reaching this point is deemed impossible */
+
+ }
+
+}
+
+ #ifdef XXH_OLD_NAMES
+ #define PROCESS1 XXH_PROCESS1
+ #define PROCESS4 XXH_PROCESS4
+ #else
+ #undef XXH_PROCESS1
+ #undef XXH_PROCESS4
+ #endif
+
+/*!
+ * @internal
+ * @brief The implementation for @ref XXH32().
+ *
+ * @param input, len, seed Directly passed from @ref XXH32().
+ * @param align Whether @p input is aligned.
+ * @return The calculated hash.
+ */
+XXH_FORCE_INLINE xxh_u32 XXH32_endian_align(const xxh_u8 *input, size_t len,
+ xxh_u32 seed, XXH_alignment align) {
+
+ const xxh_u8 *bEnd = input ? input + len : NULL;
+ xxh_u32 h32;
+
+ #if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && \
+ (XXH_ACCEPT_NULL_INPUT_POINTER >= 1)
+ if (input == NULL) {
+
+ len = 0;
+ bEnd = input = (const xxh_u8 *)(size_t)16;
+
+ }
+
+ #endif
+
+ if (len >= 16) {
+
+ const xxh_u8 *const limit = bEnd - 15;
+ xxh_u32 v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2;
+ xxh_u32 v2 = seed + XXH_PRIME32_2;
+ xxh_u32 v3 = seed + 0;
+ xxh_u32 v4 = seed - XXH_PRIME32_1;
+
+ do {
+
+ v1 = XXH32_round(v1, XXH_get32bits(input));
+ input += 4;
+ v2 = XXH32_round(v2, XXH_get32bits(input));
+ input += 4;
+ v3 = XXH32_round(v3, XXH_get32bits(input));
+ input += 4;
+ v4 = XXH32_round(v4, XXH_get32bits(input));
+ input += 4;
+
+ } while (input < limit);
+
+ h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) +
+ XXH_rotl32(v4, 18);
+
+ } else {
+
+ h32 = seed + XXH_PRIME32_5;
+
+ }
+
+ h32 += (xxh_u32)len;
+
+ return XXH32_finalize(h32, input, len & 15, align);
+
+}
+
+/*! @ingroup xxh32_family */
+XXH_PUBLIC_API XXH32_hash_t XXH32(const void *input, size_t len,
+ XXH32_hash_t seed) {
+
+ #if 0
+ /* Simple version, good for code maintenance, but unfortunately slow for small inputs */
+ XXH32_state_t state;
+ XXH32_reset(&state, seed);
+ XXH32_update(&state, (const xxh_u8*)input, len);
+ return XXH32_digest(&state);
+ #else
+ if (XXH_FORCE_ALIGN_CHECK) {
+
+ if ((((size_t)input) & 3) ==
+ 0) { /* Input is 4-bytes aligned, leverage the speed benefit */
+ return XXH32_endian_align((const xxh_u8 *)input, len, seed, XXH_aligned);
+
+ }
+
+ }
+
+ return XXH32_endian_align((const xxh_u8 *)input, len, seed, XXH_unaligned);
+ #endif
+
+}
+
+/******* Hash streaming *******/
+/*!
+ * @ingroup xxh32_family
+ */
+XXH_PUBLIC_API XXH32_state_t *XXH32_createState(void) {
+
+ return (XXH32_state_t *)XXH_malloc(sizeof(XXH32_state_t));
+
+}
+
+/*! @ingroup xxh32_family */
+XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t *statePtr) {
+
+ XXH_free(statePtr);
+ return XXH_OK;
+
+}
+
+/*! @ingroup xxh32_family */
+XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t * dstState,
+ const XXH32_state_t *srcState) {
+
+ memcpy(dstState, srcState, sizeof(*dstState));
+
+}
+
+/*! @ingroup xxh32_family */
+XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t *statePtr,
+ XXH32_hash_t seed) {
+
+ XXH32_state_t state; /* using a local state to memcpy() in order to avoid
+ strict-aliasing warnings */
+ memset(&state, 0, sizeof(state));
+ state.v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2;
+ state.v2 = seed + XXH_PRIME32_2;
+ state.v3 = seed + 0;
+ state.v4 = seed - XXH_PRIME32_1;
+ /* do not write into reserved, planned to be removed in a future version */
+ memcpy(statePtr, &state, sizeof(state) - sizeof(state.reserved));
+ return XXH_OK;
+
+}
+
+/*! @ingroup xxh32_family */
+XXH_PUBLIC_API XXH_errorcode XXH32_update(XXH32_state_t *state,
+ const void *input, size_t len) {
+
+ if (input == NULL)
+ #if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && \
+ (XXH_ACCEPT_NULL_INPUT_POINTER >= 1)
+ return XXH_OK;
+ #else
+ return XXH_ERROR;
+ #endif
+
+ {
+
+ const xxh_u8 * p = (const xxh_u8 *)input;
+ const xxh_u8 *const bEnd = p + len;
+
+ state->total_len_32 += (XXH32_hash_t)len;
+ state->large_len |=
+ (XXH32_hash_t)((len >= 16) | (state->total_len_32 >= 16));
+
+ if (state->memsize + len < 16) { /* fill in tmp buffer */
+ XXH_memcpy((xxh_u8 *)(state->mem32) + state->memsize, input, len);
+ state->memsize += (XXH32_hash_t)len;
+ return XXH_OK;
+
+ }
+
+ if (state->memsize) { /* some data left from previous update */
+ XXH_memcpy((xxh_u8 *)(state->mem32) + state->memsize, input,
+ 16 - state->memsize);
+ {
+
+ const xxh_u32 *p32 = state->mem32;
+ state->v1 = XXH32_round(state->v1, XXH_readLE32(p32));
+ p32++;
+ state->v2 = XXH32_round(state->v2, XXH_readLE32(p32));
+ p32++;
+ state->v3 = XXH32_round(state->v3, XXH_readLE32(p32));
+ p32++;
+ state->v4 = XXH32_round(state->v4, XXH_readLE32(p32));
+
+ }
+
+ p += 16 - state->memsize;
+ state->memsize = 0;
+
+ }
+
+ if (p <= bEnd - 16) {
+
+ const xxh_u8 *const limit = bEnd - 16;
+ xxh_u32 v1 = state->v1;
+ xxh_u32 v2 = state->v2;
+ xxh_u32 v3 = state->v3;
+ xxh_u32 v4 = state->v4;
+
+ do {
+
+ v1 = XXH32_round(v1, XXH_readLE32(p));
+ p += 4;
+ v2 = XXH32_round(v2, XXH_readLE32(p));
+ p += 4;
+ v3 = XXH32_round(v3, XXH_readLE32(p));
+ p += 4;
+ v4 = XXH32_round(v4, XXH_readLE32(p));
+ p += 4;
+
+ } while (p <= limit);
+
+ state->v1 = v1;
+ state->v2 = v2;
+ state->v3 = v3;
+ state->v4 = v4;
+
+ }
+
+ if (p < bEnd) {
+
+ XXH_memcpy(state->mem32, p, (size_t)(bEnd - p));
+ state->memsize = (unsigned)(bEnd - p);
+
+ }
+
+ }
+
+ return XXH_OK;
+
+}
+
+/*! @ingroup xxh32_family */
+XXH_PUBLIC_API XXH32_hash_t XXH32_digest(const XXH32_state_t *state) {
+
+ xxh_u32 h32;
+
+ if (state->large_len) {
+
+ h32 = XXH_rotl32(state->v1, 1) + XXH_rotl32(state->v2, 7) +
+ XXH_rotl32(state->v3, 12) + XXH_rotl32(state->v4, 18);
+
+ } else {
+
+ h32 = state->v3 /* == seed */ + XXH_PRIME32_5;
+
+ }
+
+ h32 += state->total_len_32;
+
+ return XXH32_finalize(h32, (const xxh_u8 *)state->mem32, state->memsize,
+ XXH_aligned);
+
+}
+
+/******* Canonical representation *******/
+
+/*!
+ * @ingroup xxh32_family
+ * The default return values from XXH functions are unsigned 32 and 64 bit
+ * integers.
+ *
+ * The canonical representation uses big endian convention, the same convention
+ * as human-readable numbers (large digits first).
+ *
+ * This way, hash values can be written into a file or buffer, remaining
+ * comparable across different systems.
+ *
+ * The following functions allow transformation of hash values to and from their
+ * canonical format.
+ */
+XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t *dst,
+ XXH32_hash_t hash) {
+
+ XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t));
+ if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash);
+ memcpy(dst, &hash, sizeof(*dst));
+
+}
+
+/*! @ingroup xxh32_family */
+XXH_PUBLIC_API XXH32_hash_t
+XXH32_hashFromCanonical(const XXH32_canonical_t *src) {
+
+ return XXH_readBE32(src);
+
+}
+
+ #ifndef XXH_NO_LONG_LONG
+
+/* *******************************************************************
+ * 64-bit hash functions
+ *********************************************************************/
+/*!
+ * @}
+ * @ingroup impl
+ * @{
+
+ */
+/******* Memory access *******/
+
+typedef XXH64_hash_t xxh_u64;
+
+ #ifdef XXH_OLD_NAMES
+ #define U64 xxh_u64
+ #endif
+
+ #if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS == 3))
+ /*
+ * Manual byteshift. Best for old compilers which don't inline memcpy.
+ * We actually directly use XXH_readLE64 and XXH_readBE64.
+ */
+ #elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS == 2))
+
+/* Force direct memory access. Only works on CPU which support unaligned memory
+ * access in hardware */
+static xxh_u64 XXH_read64(const void *memPtr) {
+
+ return *(const xxh_u64 *)memPtr;
+
+}
+
+ #elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS == 1))
+
+ /*
+ * __pack instructions are safer, but compiler specific, hence potentially
+ * problematic for some compilers.
+ *
+ * Currently only defined for GCC and ICC.
+ */
+ #ifdef XXH_OLD_NAMES
+typedef union {
+
+ xxh_u32 u32;
+ xxh_u64 u64;
+
+} __attribute__((packed)) unalign64;
+
+ #endif
+static xxh_u64 XXH_read64(const void *ptr) {
+
+ typedef union {
+
+ xxh_u32 u32;
+ xxh_u64 u64;
+
+ } __attribute__((packed)) xxh_unalign64;
+
+ return ((const xxh_unalign64 *)ptr)->u64;
+
+}
+
+ #else
+
+/*
+ * Portable and safe solution. Generally efficient.
+ * see: https://stackoverflow.com/a/32095106/646947
+ */
+static xxh_u64 XXH_read64(const void *memPtr) {
+
+ xxh_u64 val;
+ memcpy(&val, memPtr, sizeof(val));
+ return val;
+
+}
+
+ #endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */
+
+ #if defined(_MSC_VER) /* Visual Studio */
+ #define XXH_swap64 _byteswap_uint64
+ #elif XXH_GCC_VERSION >= 403
+ #define XXH_swap64 __builtin_bswap64
+ #else
+static xxh_u64 XXH_swap64(xxh_u64 x) {
+
+ return ((x << 56) & 0xff00000000000000ULL) |
+ ((x << 40) & 0x00ff000000000000ULL) |
+ ((x << 24) & 0x0000ff0000000000ULL) |
+ ((x << 8) & 0x000000ff00000000ULL) |
+ ((x >> 8) & 0x00000000ff000000ULL) |
+ ((x >> 24) & 0x0000000000ff0000ULL) |
+ ((x >> 40) & 0x000000000000ff00ULL) |
+ ((x >> 56) & 0x00000000000000ffULL);
+
+}
+
+ #endif
+
+ /* XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load. */
+ #if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS == 3))
+
+XXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void *memPtr) {
+
+ const xxh_u8 *bytePtr = (const xxh_u8 *)memPtr;
+ return bytePtr[0] | ((xxh_u64)bytePtr[1] << 8) | ((xxh_u64)bytePtr[2] << 16) |
+ ((xxh_u64)bytePtr[3] << 24) | ((xxh_u64)bytePtr[4] << 32) |
+ ((xxh_u64)bytePtr[5] << 40) | ((xxh_u64)bytePtr[6] << 48) |
+ ((xxh_u64)bytePtr[7] << 56);
+
+}
+
+XXH_FORCE_INLINE xxh_u64 XXH_readBE64(const void *memPtr) {
+
+ const xxh_u8 *bytePtr = (const xxh_u8 *)memPtr;
+ return bytePtr[7] | ((xxh_u64)bytePtr[6] << 8) | ((xxh_u64)bytePtr[5] << 16) |
+ ((xxh_u64)bytePtr[4] << 24) | ((xxh_u64)bytePtr[3] << 32) |
+ ((xxh_u64)bytePtr[2] << 40) | ((xxh_u64)bytePtr[1] << 48) |
+ ((xxh_u64)bytePtr[0] << 56);
+
+}
+
+ #else
+XXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void *ptr) {
+
+ return XXH_CPU_LITTLE_ENDIAN ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr));
+
+}
+
+static xxh_u64 XXH_readBE64(const void *ptr) {
+
+ return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr);
+
+}
+
+ #endif
+
+XXH_FORCE_INLINE xxh_u64 XXH_readLE64_align(const void * ptr,
+ XXH_alignment align) {
+
+ if (align == XXH_unaligned)
+ return XXH_readLE64(ptr);
+ else
+ return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u64 *)ptr
+ : XXH_swap64(*(const xxh_u64 *)ptr);
+
+}
+
+ /******* xxh64 *******/
+ /*!
+ * @}
+ * @defgroup xxh64_impl XXH64 implementation
+ * @ingroup impl
+ * @{
+
+ */
+ /* #define rather that static const, to be used as initializers */
+ #define XXH_PRIME64_1 \
+ 0x9E3779B185EBCA87ULL /*!< \
+ 0b1001111000110111011110011011000110000101111010111100101010000111 \
+ */
+ #define XXH_PRIME64_2 \
+ 0xC2B2AE3D27D4EB4FULL /*!< \
+ 0b1100001010110010101011100011110100100111110101001110101101001111 \
+ */
+ #define XXH_PRIME64_3 \
+ 0x165667B19E3779F9ULL /*!< \
+ 0b0001011001010110011001111011000110011110001101110111100111111001 \
+ */
+ #define XXH_PRIME64_4 \
+ 0x85EBCA77C2B2AE63ULL /*!< \
+ 0b1000010111101011110010100111011111000010101100101010111001100011 \
+ */
+ #define XXH_PRIME64_5 \
+ 0x27D4EB2F165667C5ULL /*!< \
+ 0b0010011111010100111010110010111100010110010101100110011111000101 \
+ */
+
+ #ifdef XXH_OLD_NAMES
+ #define PRIME64_1 XXH_PRIME64_1
+ #define PRIME64_2 XXH_PRIME64_2
+ #define PRIME64_3 XXH_PRIME64_3
+ #define PRIME64_4 XXH_PRIME64_4
+ #define PRIME64_5 XXH_PRIME64_5
+ #endif
+
+static xxh_u64 XXH64_round(xxh_u64 acc, xxh_u64 input) {
+
+ acc += input * XXH_PRIME64_2;
+ acc = XXH_rotl64(acc, 31);
+ acc *= XXH_PRIME64_1;
+ return acc;
+
+}
+
+static xxh_u64 XXH64_mergeRound(xxh_u64 acc, xxh_u64 val) {
+
+ val = XXH64_round(0, val);
+ acc ^= val;
+ acc = acc * XXH_PRIME64_1 + XXH_PRIME64_4;
+ return acc;
+
+}
+
+static xxh_u64 XXH64_avalanche(xxh_u64 h64) {
+
+ h64 ^= h64 >> 33;
+ h64 *= XXH_PRIME64_2;
+ h64 ^= h64 >> 29;
+ h64 *= XXH_PRIME64_3;
+ h64 ^= h64 >> 32;
+ return h64;
+
+}
+
+ #define XXH_get64bits(p) XXH_readLE64_align(p, align)
+
+static xxh_u64 XXH64_finalize(xxh_u64 h64, const xxh_u8 *ptr, size_t len,
+ XXH_alignment align) {
+
+ len &= 31;
+ while (len >= 8) {
+
+ xxh_u64 const k1 = XXH64_round(0, XXH_get64bits(ptr));
+ ptr += 8;
+ h64 ^= k1;
+ h64 = XXH_rotl64(h64, 27) * XXH_PRIME64_1 + XXH_PRIME64_4;
+ len -= 8;
+
+ }
+
+ if (len >= 4) {
+
+ h64 ^= (xxh_u64)(XXH_get32bits(ptr)) * XXH_PRIME64_1;
+ ptr += 4;
+ h64 = XXH_rotl64(h64, 23) * XXH_PRIME64_2 + XXH_PRIME64_3;
+ len -= 4;
+
+ }
+
+ while (len > 0) {
+
+ h64 ^= (*ptr++) * XXH_PRIME64_5;
+ h64 = XXH_rotl64(h64, 11) * XXH_PRIME64_1;
+ --len;
+
+ }
+
+ return XXH64_avalanche(h64);
+
+}
+
+ #ifdef XXH_OLD_NAMES
+ #define PROCESS1_64 XXH_PROCESS1_64
+ #define PROCESS4_64 XXH_PROCESS4_64
+ #define PROCESS8_64 XXH_PROCESS8_64
+ #else
+ #undef XXH_PROCESS1_64
+ #undef XXH_PROCESS4_64
+ #undef XXH_PROCESS8_64
+ #endif
+
+XXH_FORCE_INLINE xxh_u64 XXH64_endian_align(const xxh_u8 *input, size_t len,
+ xxh_u64 seed, XXH_alignment align) {
+
+ const xxh_u8 *bEnd = input ? input + len : NULL;
+ xxh_u64 h64;
+
+ #if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && \
+ (XXH_ACCEPT_NULL_INPUT_POINTER >= 1)
+ if (input == NULL) {
+
+ len = 0;
+ bEnd = input = (const xxh_u8 *)(size_t)32;
+
+ }
+
+ #endif
+
+ if (len >= 32) {
+
+ const xxh_u8 *const limit = bEnd - 32;
+ xxh_u64 v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2;
+ xxh_u64 v2 = seed + XXH_PRIME64_2;
+ xxh_u64 v3 = seed + 0;
+ xxh_u64 v4 = seed - XXH_PRIME64_1;
+
+ do {
+
+ v1 = XXH64_round(v1, XXH_get64bits(input));
+ input += 8;
+ v2 = XXH64_round(v2, XXH_get64bits(input));
+ input += 8;
+ v3 = XXH64_round(v3, XXH_get64bits(input));
+ input += 8;
+ v4 = XXH64_round(v4, XXH_get64bits(input));
+ input += 8;
+
+ } while (input <= limit);
+
+ h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) +
+ XXH_rotl64(v4, 18);
+ h64 = XXH64_mergeRound(h64, v1);
+ h64 = XXH64_mergeRound(h64, v2);
+ h64 = XXH64_mergeRound(h64, v3);
+ h64 = XXH64_mergeRound(h64, v4);
+
+ } else {
+
+ h64 = seed + XXH_PRIME64_5;
+
+ }
+
+ h64 += (xxh_u64)len;
+
+ return XXH64_finalize(h64, input, len, align);
+
+}
+
+/*! @ingroup xxh64_family */
+XXH_PUBLIC_API XXH64_hash_t XXH64(const void *input, size_t len,
+ XXH64_hash_t seed) {
+
+ #if 0
+ /* Simple version, good for code maintenance, but unfortunately slow for small inputs */
+ XXH64_state_t state;
+ XXH64_reset(&state, seed);
+ XXH64_update(&state, (const xxh_u8*)input, len);
+ return XXH64_digest(&state);
+ #else
+ if (XXH_FORCE_ALIGN_CHECK) {
+
+ if ((((size_t)input) & 7) ==
+ 0) { /* Input is aligned, let's leverage the speed advantage */
+ return XXH64_endian_align((const xxh_u8 *)input, len, seed, XXH_aligned);
+
+ }
+
+ }
+
+ return XXH64_endian_align((const xxh_u8 *)input, len, seed, XXH_unaligned);
+
+ #endif
+
+}
+
+/******* Hash Streaming *******/
+
+/*! @ingroup xxh64_family*/
+XXH_PUBLIC_API XXH64_state_t *XXH64_createState(void) {
+
+ return (XXH64_state_t *)XXH_malloc(sizeof(XXH64_state_t));
+
+}
+
+/*! @ingroup xxh64_family */
+XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t *statePtr) {
+
+ XXH_free(statePtr);
+ return XXH_OK;
+
+}
+
+/*! @ingroup xxh64_family */
+XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t * dstState,
+ const XXH64_state_t *srcState) {
+
+ memcpy(dstState, srcState, sizeof(*dstState));
+
+}
+
+/*! @ingroup xxh64_family */
+XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t *statePtr,
+ XXH64_hash_t seed) {
+
+ XXH64_state_t state; /* use a local state to memcpy() in order to avoid
+ strict-aliasing warnings */
+ memset(&state, 0, sizeof(state));
+ state.v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2;
+ state.v2 = seed + XXH_PRIME64_2;
+ state.v3 = seed + 0;
+ state.v4 = seed - XXH_PRIME64_1;
+ /* do not write into reserved64, might be removed in a future version */
+ memcpy(statePtr, &state, sizeof(state) - sizeof(state.reserved64));
+ return XXH_OK;
+
+}
+
+/*! @ingroup xxh64_family */
+XXH_PUBLIC_API XXH_errorcode XXH64_update(XXH64_state_t *state,
+ const void *input, size_t len) {
+
+ if (input == NULL)
+ #if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && \
+ (XXH_ACCEPT_NULL_INPUT_POINTER >= 1)
+ return XXH_OK;
+ #else
+ return XXH_ERROR;
+ #endif
+
+ {
+
+ const xxh_u8 * p = (const xxh_u8 *)input;
+ const xxh_u8 *const bEnd = p + len;
+
+ state->total_len += len;
+
+ if (state->memsize + len < 32) { /* fill in tmp buffer */
+ XXH_memcpy(((xxh_u8 *)state->mem64) + state->memsize, input, len);
+ state->memsize += (xxh_u32)len;
+ return XXH_OK;
+
+ }
+
+ if (state->memsize) { /* tmp buffer is full */
+ XXH_memcpy(((xxh_u8 *)state->mem64) + state->memsize, input,
+ 32 - state->memsize);
+ state->v1 = XXH64_round(state->v1, XXH_readLE64(state->mem64 + 0));
+ state->v2 = XXH64_round(state->v2, XXH_readLE64(state->mem64 + 1));
+ state->v3 = XXH64_round(state->v3, XXH_readLE64(state->mem64 + 2));
+ state->v4 = XXH64_round(state->v4, XXH_readLE64(state->mem64 + 3));
+ p += 32 - state->memsize;
+ state->memsize = 0;
+
+ }
+
+ if (p + 32 <= bEnd) {
+
+ const xxh_u8 *const limit = bEnd - 32;
+ xxh_u64 v1 = state->v1;
+ xxh_u64 v2 = state->v2;
+ xxh_u64 v3 = state->v3;
+ xxh_u64 v4 = state->v4;
+
+ do {
+
+ v1 = XXH64_round(v1, XXH_readLE64(p));
+ p += 8;
+ v2 = XXH64_round(v2, XXH_readLE64(p));
+ p += 8;
+ v3 = XXH64_round(v3, XXH_readLE64(p));
+ p += 8;
+ v4 = XXH64_round(v4, XXH_readLE64(p));
+ p += 8;
+
+ } while (p <= limit);
+
+ state->v1 = v1;
+ state->v2 = v2;
+ state->v3 = v3;
+ state->v4 = v4;
+
+ }
+
+ if (p < bEnd) {
+
+ XXH_memcpy(state->mem64, p, (size_t)(bEnd - p));
+ state->memsize = (unsigned)(bEnd - p);
+
+ }
+
+ }
+
+ return XXH_OK;
+
+}
+
+/*! @ingroup xxh64_family */
+XXH_PUBLIC_API XXH64_hash_t XXH64_digest(const XXH64_state_t *state) {
+
+ xxh_u64 h64;
+
+ if (state->total_len >= 32) {
+
+ xxh_u64 const v1 = state->v1;
+ xxh_u64 const v2 = state->v2;
+ xxh_u64 const v3 = state->v3;
+ xxh_u64 const v4 = state->v4;
+
+ h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) +
+ XXH_rotl64(v4, 18);
+ h64 = XXH64_mergeRound(h64, v1);
+ h64 = XXH64_mergeRound(h64, v2);
+ h64 = XXH64_mergeRound(h64, v3);
+ h64 = XXH64_mergeRound(h64, v4);
+
+ } else {
+
+ h64 = state->v3 /*seed*/ + XXH_PRIME64_5;
+
+ }
+
+ h64 += (xxh_u64)state->total_len;
+
+ return XXH64_finalize(h64, (const xxh_u8 *)state->mem64,
+ (size_t)state->total_len, XXH_aligned);
+
+}
+
+/******* Canonical representation *******/
+
+/*! @ingroup xxh64_family */
+XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t *dst,
+ XXH64_hash_t hash) {
+
+ XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t));
+ if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash);
+ memcpy(dst, &hash, sizeof(*dst));
+
+}
+
+/*! @ingroup xxh64_family */
+XXH_PUBLIC_API XXH64_hash_t
+XXH64_hashFromCanonical(const XXH64_canonical_t *src) {
+
+ return XXH_readBE64(src);
+
+}
+
+ #ifndef XXH_NO_XXH3
+
+ /* *********************************************************************
+ * XXH3
+ * New generation hash designed for speed on small keys and vectorization
+ ************************************************************************ */
+ /*!
+ * @}
+ * @defgroup xxh3_impl XXH3 implementation
+ * @ingroup impl
+ * @{
+
+ */
+
+ /* === Compiler specifics === */
+
+ #if ((defined(sun) || defined(__sun)) && \
+ __cplusplus) /* Solaris includes __STDC_VERSION__ with C++. Tested \
+ with GCC 5.5 */
+ #define XXH_RESTRICT /* disable */
+ #elif defined(__STDC_VERSION__) && \
+ __STDC_VERSION__ >= 199901L /* >= C99 */
+ #define XXH_RESTRICT restrict
+ #else
+ /* Note: it might be useful to define __restrict or __restrict__ for
+ * some C++ compilers */
+ #define XXH_RESTRICT /* disable */
+ #endif
+
+ #if (defined(__GNUC__) && (__GNUC__ >= 3)) || \
+ (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || \
+ defined(__clang__)
+ #define XXH_likely(x) __builtin_expect(x, 1)
+ #define XXH_unlikely(x) __builtin_expect(x, 0)
+ #else
+ #define XXH_likely(x) (x)
+ #define XXH_unlikely(x) (x)
+ #endif
+
+ #if defined(__GNUC__)
+ #if defined(__AVX2__)
+ #include <immintrin.h>
+ #elif defined(__SSE2__)
+ #include <emmintrin.h>
+ #elif defined(__ARM_NEON__) || defined(__ARM_NEON)
+ #define inline __inline__ /* circumvent a clang bug */
+ #include <arm_neon.h>
+ #undef inline
+ #endif
+ #elif defined(_MSC_VER)
+ #include <intrin.h>
+ #endif
+
+ /*
+ * One goal of XXH3 is to make it fast on both 32-bit and 64-bit, while
+ * remaining a true 64-bit/128-bit hash function.
+ *
+ * This is done by prioritizing a subset of 64-bit operations that can be
+ * emulated without too many steps on the average 32-bit machine.
+ *
+ * For example, these two lines seem similar, and run equally fast on
+ * 64-bit:
+ *
+ * xxh_u64 x;
+ * x ^= (x >> 47); // good
+ * x ^= (x >> 13); // bad
+ *
+ * However, to a 32-bit machine, there is a major difference.
+ *
+ * x ^= (x >> 47) looks like this:
+ *
+ * x.lo ^= (x.hi >> (47 - 32));
+ *
+ * while x ^= (x >> 13) looks like this:
+ *
+ * // note: funnel shifts are not usually cheap.
+ * x.lo ^= (x.lo >> 13) | (x.hi << (32 - 13));
+ * x.hi ^= (x.hi >> 13);
+ *
+ * The first one is significantly faster than the second, simply because
+ * the shift is larger than 32. This means:
+ * - All the bits we need are in the upper 32 bits, so we can ignore the
+ * lower 32 bits in the shift.
+ * - The shift result will always fit in the lower 32 bits, and
+ * therefore, we can ignore the upper 32 bits in the xor.
+ *
+ * Thanks to this optimization, XXH3 only requires these features to be
+ * efficient:
+ *
+ * - Usable unaligned access
+ * - A 32-bit or 64-bit ALU
+ * - If 32-bit, a decent ADC instruction
+ * - A 32 or 64-bit multiply with a 64-bit result
+ * - For the 128-bit variant, a decent byteswap helps short inputs.
+ *
+ * The first two are already required by XXH32, and almost all 32-bit and
+ * 64-bit platforms which can run XXH32 can run XXH3 efficiently.
+ *
+ * Thumb-1, the classic 16-bit only subset of ARM's instruction set, is
+ * one notable exception.
+ *
+ * First of all, Thumb-1 lacks support for the UMULL instruction which
+ * performs the important long multiply. This means numerous __aeabi_lmul
+ * calls.
+ *
+ * Second of all, the 8 functional registers are just not enough.
+ * Setup for __aeabi_lmul, byteshift loads, pointers, and all arithmetic
+ * need Lo registers, and this shuffling results in thousands more MOVs
+ * than A32.
+ *
+ * A32 and T32 don't have this limitation. They can access all 14
+ * registers, do a 32->64 multiply with UMULL, and the flexible operand
+ * allowing free shifts is helpful, too.
+ *
+ * Therefore, we do a quick sanity check.
+ *
+ * If compiling Thumb-1 for a target which supports ARM instructions, we
+ * will emit a warning, as it is not a "sane" platform to compile for.
+ *
+ * Usually, if this happens, it is because of an accident and you probably
+ * need to specify -march, as you likely meant to compile for a newer
+ * architecture.
+ *
+ * Credit: large sections of the vectorial and asm source code paths
+ * have been contributed by @easyaspi314
+ */
+ #if defined(__thumb__) && !defined(__thumb2__) && \
+ defined(__ARM_ARCH_ISA_ARM)
+ #warning "XXH3 is highly inefficient without ARM or Thumb-2."
+ #endif
+
+ /* ==========================================
+ * Vectorization detection
+ * ========================================== */
+
+ #ifdef XXH_DOXYGEN
+ /*!
+ * @ingroup tuning
+ * @brief Overrides the vectorization implementation chosen for XXH3.
+ *
+ * Can be defined to 0 to disable SIMD or any of the values mentioned in
+ * @ref XXH_VECTOR_TYPE.
+ *
+ * If this is not defined, it uses predefined macros to determine the
+ * best implementation.
+ */
+ #define XXH_VECTOR XXH_SCALAR
+/*!
+ * @ingroup tuning
+ * @brief Possible values for @ref XXH_VECTOR.
+ *
+ * Note that these are actually implemented as macros.
+ *
+ * If this is not defined, it is detected automatically.
+ * @ref XXH_X86DISPATCH overrides this.
+ */
+enum XXH_VECTOR_TYPE /* fake enum */ {
+
+ XXH_SCALAR = 0, /*!< Portable scalar version */
+ XXH_SSE2 = 1, /*!<
+ * SSE2 for Pentium 4, Opteron, all x86_64.
+ *
+ * @note SSE2 is also guaranteed on Windows 10, macOS, and
+ * Android x86.
+ */
+ XXH_AVX2 = 2, /*!< AVX2 for Haswell and Bulldozer */
+ XXH_AVX512 = 3, /*!< AVX512 for Skylake and Icelake */
+ XXH_NEON = 4, /*!< NEON for most ARMv7-A and all AArch64 */
+ XXH_VSX = 5, /*!< VSX and ZVector for POWER8/z13 (64-bit) */
+
+};
+
+ /*!
+ * @ingroup tuning
+ * @brief Selects the minimum alignment for XXH3's accumulators.
+ *
+ * When using SIMD, this should match the alignment reqired for said
+ * vector type, so, for example, 32 for AVX2.
+ *
+ * Default: Auto detected.
+ */
+ #define XXH_ACC_ALIGN 8
+ #endif
+
+ /* Actual definition */
+ #ifndef XXH_DOXYGEN
+ #define XXH_SCALAR 0
+ #define XXH_SSE2 1
+ #define XXH_AVX2 2
+ #define XXH_AVX512 3
+ #define XXH_NEON 4
+ #define XXH_VSX 5
+ #endif
+
+ #ifndef XXH_VECTOR /* can be defined on command line */
+ #if defined(__AVX512F__)
+ #define XXH_VECTOR XXH_AVX512
+ #elif defined(__AVX2__)
+ #define XXH_VECTOR XXH_AVX2
+ #elif defined(__SSE2__) || defined(_M_AMD64) || defined(_M_X64) || \
+ (defined(_M_IX86_FP) && (_M_IX86_FP == 2))
+ #define XXH_VECTOR XXH_SSE2
+ #elif defined(__GNUC__) /* msvc support maybe later */ \
+ && (defined(__ARM_NEON__) || defined(__ARM_NEON)) && \
+ (defined( \
+ __LITTLE_ENDIAN__) /* We only support little endian NEON */ \
+ || (defined(__BYTE_ORDER__) && \
+ __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
+ #define XXH_VECTOR XXH_NEON
+ #elif (defined(__PPC64__) && defined(__POWER8_VECTOR__)) || \
+ (defined(__s390x__) && defined(__VEC__)) && \
+ defined(__GNUC__) /* TODO: IBM XL */
+ #define XXH_VECTOR XXH_VSX
+ #else
+ #define XXH_VECTOR XXH_SCALAR
+ #endif
+ #endif
+
+ /*
+ * Controls the alignment of the accumulator,
+ * for compatibility with aligned vector loads, which are usually faster.
+ */
+ #ifndef XXH_ACC_ALIGN
+ #if defined(XXH_X86DISPATCH)
+ #define XXH_ACC_ALIGN 64 /* for compatibility with avx512 */
+ #elif XXH_VECTOR == XXH_SCALAR /* scalar */
+ #define XXH_ACC_ALIGN 8
+ #elif XXH_VECTOR == XXH_SSE2 /* sse2 */
+ #define XXH_ACC_ALIGN 16
+ #elif XXH_VECTOR == XXH_AVX2 /* avx2 */
+ #define XXH_ACC_ALIGN 32
+ #elif XXH_VECTOR == XXH_NEON /* neon */
+ #define XXH_ACC_ALIGN 16
+ #elif XXH_VECTOR == XXH_VSX /* vsx */
+ #define XXH_ACC_ALIGN 16
+ #elif XXH_VECTOR == XXH_AVX512 /* avx512 */
+ #define XXH_ACC_ALIGN 64
+ #endif
+ #endif
+
+ #if defined(XXH_X86DISPATCH) || XXH_VECTOR == XXH_SSE2 || \
+ XXH_VECTOR == XXH_AVX2 || XXH_VECTOR == XXH_AVX512
+ #define XXH_SEC_ALIGN XXH_ACC_ALIGN
+ #else
+ #define XXH_SEC_ALIGN 8
+ #endif
+
+ /*
+ * UGLY HACK:
+ * GCC usually generates the best code with -O3 for xxHash.
+ *
+ * However, when targeting AVX2, it is overzealous in its unrolling
+ * resulting in code roughly 3/4 the speed of Clang.
+ *
+ * There are other issues, such as GCC splitting _mm256_loadu_si256 into
+ * _mm_loadu_si128 + _mm256_inserti128_si256. This is an optimization
+ * which only applies to Sandy and Ivy Bridge... which don't even support
+ * AVX2.
+ *
+ * That is why when compiling the AVX2 version, it is recommended to use
+ * either -O2 -mavx2 -march=haswell or -O2 -mavx2
+ * -mno-avx256-split-unaligned-load for decent performance, or to use
+ * Clang instead.
+ *
+ * Fortunately, we can control the first one with a pragma that forces GCC
+ * into -O2, but the other one we can't control without "failed to inline
+ * always inline function due to target mismatch" warnings.
+ */
+ #if XXH_VECTOR == XXH_AVX2 /* AVX2 */ \
+ && defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \
+ && defined(__OPTIMIZE__) && \
+ !defined(__OPTIMIZE_SIZE__) /* respect -O0 and -Os */
+ #pragma GCC push_options
+ #pragma GCC optimize("-O2")
+ #endif
+
+ #if XXH_VECTOR == XXH_NEON
+ /*
+ * NEON's setup for vmlal_u32 is a little more complicated than it is on
+ * SSE2, AVX2, and VSX.
+ *
+ * While PMULUDQ and VMULEUW both perform a mask, VMLAL.U32 performs an
+ * upcast.
+ *
+ * To do the same operation, the 128-bit 'Q' register needs to be split
+ * into two 64-bit 'D' registers, performing this operation::
+ *
+ * [ a | b ] |
+ * '---------. .--------' | | x |
+ * | .---------' '--------. |
+ * [ a & 0xFFFFFFFF | b & 0xFFFFFFFF ],[ a >> 32 | b >> 32
+ * ]
+ *
+ * Due to significant changes in aarch64, the fastest method for aarch64
+ * is completely different than the fastest method for ARMv7-A.
+ *
+ * ARMv7-A treats D registers as unions overlaying Q registers, so
+ * modifying D11 will modify the high half of Q5. This is similar to how
+ * modifying AH will only affect bits 8-15 of AX on x86.
+ *
+ * VZIP takes two registers, and puts even lanes in one register and odd
+ * lanes in the other.
+ *
+ * On ARMv7-A, this strangely modifies both parameters in place instead
+ * of taking the usual 3-operand form.
+ *
+ * Therefore, if we want to do this, we can simply use a D-form VZIP.32
+ * on the lower and upper halves of the Q register to end up with the
+ * high and low halves where we want - all in one instruction.
+ *
+ * vzip.32 d10, d11 @ d10 = { d10[0], d11[0] }; d11 = {
+
+ * d10[1], d11[1] }
+ *
+ * Unfortunately we need inline assembly for this: Instructions
+ * modifying two registers at once is not possible in GCC or Clang's IR,
+ * and they have to create a copy.
+ *
+ * aarch64 requires a different approach.
+ *
+ * In order to make it easier to write a decent compiler for aarch64,
+ * many quirks were removed, such as conditional execution.
+ *
+ * NEON was also affected by this.
+ *
+ * aarch64 cannot access the high bits of a Q-form register, and writes
+ * to a D-form register zero the high bits, similar to how writes to
+ * W-form scalar registers (or DWORD registers on x86_64) work.
+ *
+ * The formerly free vget_high intrinsics now require a vext (with a few
+ * exceptions)
+ *
+ * Additionally, VZIP was replaced by ZIP1 and ZIP2, which are the
+ * equivalent of PUNPCKL* and PUNPCKH* in SSE, respectively, in order to
+ * only modify one operand.
+ *
+ * The equivalent of the VZIP.32 on the lower and upper halves would be
+ * this mess:
+ *
+ * ext v2.4s, v0.4s, v0.4s, #2 // v2 = { v0[2], v0[3], v0[0],
+ * v0[1] } zip1 v1.2s, v0.2s, v2.2s // v1 = { v0[0], v2[0] } zip2
+ * v0.2s, v0.2s, v1.2s // v0 = { v0[1], v2[1] }
+ *
+ * Instead, we use a literal downcast, vmovn_u64 (XTN), and vshrn_n_u64
+ * (SHRN):
+ *
+ * shrn v1.2s, v0.2d, #32 // v1 = (uint32x2_t)(v0 >> 32);
+ * xtn v0.2s, v0.2d // v0 = (uint32x2_t)(v0 & 0xFFFFFFFF);
+ *
+ * This is available on ARMv7-A, but is less efficient than a single
+ * VZIP.32.
+ */
+
+ /*!
+ * Function-like macro:
+ * void XXH_SPLIT_IN_PLACE(uint64x2_t &in, uint32x2_t &outLo, uint32x2_t
+ * &outHi)
+ * {
+
+ * outLo = (uint32x2_t)(in & 0xFFFFFFFF);
+ * outHi = (uint32x2_t)(in >> 32);
+ * in = UNDEFINED;
+ * }
+ */
+ #if !defined(XXH_NO_VZIP_HACK) /* define to disable */ \
+ && defined(__GNUC__) && !defined(__aarch64__) && \
+ !defined(__arm64__)
+ #define XXH_SPLIT_IN_PLACE(in, outLo, outHi) \
+ do { \
+ \
+ /* Undocumented GCC/Clang operand modifier: %e0 = lower D half, \
+ * %f0 = upper D half */ \
+ /* https://github.com/gcc-mirror/gcc/blob/38cf91e5/gcc/config/arm/arm.c#L22486 \
+ */ \
+ /* https://github.com/llvm-mirror/llvm/blob/2c4ca683/lib/Target/ARM/ARMAsmPrinter.cpp#L399 \
+ */ \
+ __asm__("vzip.32 %e0, %f0" : "+w"(in)); \
+ (outLo) = vget_low_u32(vreinterpretq_u32_u64(in)); \
+ (outHi) = vget_high_u32(vreinterpretq_u32_u64(in)); \
+ \
+ } while (0)
+
+ #else
+ #define XXH_SPLIT_IN_PLACE(in, outLo, outHi) \
+ do { \
+ \
+ (outLo) = vmovn_u64(in); \
+ (outHi) = vshrn_n_u64((in), 32); \
+ \
+ } while (0)
+
+ #endif
+ #endif /* XXH_VECTOR == XXH_NEON */
+
+ /*
+ * VSX and Z Vector helpers.
+ *
+ * This is very messy, and any pull requests to clean this up are welcome.
+ *
+ * There are a lot of problems with supporting VSX and s390x, due to
+ * inconsistent intrinsics, spotty coverage, and multiple endiannesses.
+ */
+ #if XXH_VECTOR == XXH_VSX
+ #if defined(__s390x__)
+ #include <s390intrin.h>
+ #else
+ /* gcc's altivec.h can have the unwanted consequence to
+ * unconditionally #define bool, vector, and pixel keywords, with bad
+ * consequences for programs already using these keywords for other
+ * purposes. The paragraph defining these macros is skipped when
+ * __APPLE_ALTIVEC__ is defined.
+ * __APPLE_ALTIVEC__ is _generally_ defined automatically by the
+ * compiler, but it seems that, in some cases, it isn't. Force the
+ * build macro to be defined, so that keywords are not altered.
+ */
+ #if defined(__GNUC__) && !defined(__APPLE_ALTIVEC__)
+ #define __APPLE_ALTIVEC__
+ #endif
+ #include <altivec.h>
+ #endif
+
+typedef __vector unsigned long long xxh_u64x2;
+typedef __vector unsigned char xxh_u8x16;
+typedef __vector unsigned xxh_u32x4;
+
+ #ifndef XXH_VSX_BE
+ #if defined(__BIG_ENDIAN__) || \
+ (defined(__BYTE_ORDER__) && \
+ __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+ #define XXH_VSX_BE 1
+ #elif defined(__VEC_ELEMENT_REG_ORDER__) && \
+ __VEC_ELEMENT_REG_ORDER__ == __ORDER_BIG_ENDIAN__
+ #warning \
+ "-maltivec=be is not recommended. Please use native endianness."
+ #define XXH_VSX_BE 1
+ #else
+ #define XXH_VSX_BE 0
+ #endif
+ #endif /* !defined(XXH_VSX_BE) */
+
+ #if XXH_VSX_BE
+ #if defined(__POWER9_VECTOR__) || \
+ (defined(__clang__) && defined(__s390x__))
+ #define XXH_vec_revb vec_revb
+ #else
+/*!
+ * A polyfill for POWER9's vec_revb().
+ */
+XXH_FORCE_INLINE xxh_u64x2 XXH_vec_revb(xxh_u64x2 val) {
+
+ xxh_u8x16 const vByteSwap = {0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08};
+ return vec_perm(val, val, vByteSwap);
+
+}
+
+ #endif
+ #endif /* XXH_VSX_BE */
+
+/*!
+ * Performs an unaligned vector load and byte swaps it on big endian.
+ */
+XXH_FORCE_INLINE xxh_u64x2 XXH_vec_loadu(const void *ptr) {
+
+ xxh_u64x2 ret;
+ memcpy(&ret, ptr, sizeof(xxh_u64x2));
+ #if XXH_VSX_BE
+ ret = XXH_vec_revb(ret);
+ #endif
+ return ret;
+
+}
+
+ /*
+ * vec_mulo and vec_mule are very problematic intrinsics on PowerPC
+ *
+ * These intrinsics weren't added until GCC 8, despite existing for a
+ * while, and they are endian dependent. Also, their meaning swap
+ * depending on version.
+ * */
+ #if defined(__s390x__)
+ /* s390x is always big endian, no issue on this platform */
+ #define XXH_vec_mulo vec_mulo
+ #define XXH_vec_mule vec_mule
+ #elif defined(__clang__) && XXH_HAS_BUILTIN(__builtin_altivec_vmuleuw)
+ /* Clang has a better way to control this, we can just use the builtin
+ * which doesn't swap. */
+ #define XXH_vec_mulo __builtin_altivec_vmulouw
+ #define XXH_vec_mule __builtin_altivec_vmuleuw
+ #else
+/* gcc needs inline assembly */
+/* Adapted from
+ * https://github.com/google/highwayhash/blob/master/highwayhash/hh_vsx.h. */
+XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mulo(xxh_u32x4 a, xxh_u32x4 b) {
+
+ xxh_u64x2 result;
+ __asm__("vmulouw %0, %1, %2" : "=v"(result) : "v"(a), "v"(b));
+ return result;
+
+}
+
+XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mule(xxh_u32x4 a, xxh_u32x4 b) {
+
+ xxh_u64x2 result;
+ __asm__("vmuleuw %0, %1, %2" : "=v"(result) : "v"(a), "v"(b));
+ return result;
+
+}
+
+ #endif /* XXH_vec_mulo, XXH_vec_mule */
+ #endif /* XXH_VECTOR == XXH_VSX */
+
+ /* prefetch
+ * can be disabled, by declaring XXH_NO_PREFETCH build macro */
+ #if defined(XXH_NO_PREFETCH)
+ #define XXH_PREFETCH(ptr) (void)(ptr) /* disabled */
+ #else
+ #if defined(_MSC_VER) && \
+ (defined(_M_X64) || \
+ defined( \
+ _M_IX86)) /* _mm_prefetch() not defined outside of x86/x64 */
+ #include <mmintrin.h> /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */
+ #define XXH_PREFETCH(ptr) \
+ _mm_prefetch((const char *)(ptr), _MM_HINT_T0)
+ #elif defined(__GNUC__) && \
+ ((__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)))
+ #define XXH_PREFETCH(ptr) \
+ __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */)
+ #else
+ #define XXH_PREFETCH(ptr) (void)(ptr) /* disabled */
+ #endif
+ #endif /* XXH_NO_PREFETCH */
+
+ /* ==========================================
+ * XXH3 default settings
+ * ========================================== */
+
+ #define XXH_SECRET_DEFAULT_SIZE 192 /* minimum XXH3_SECRET_SIZE_MIN */
+
+ #if (XXH_SECRET_DEFAULT_SIZE < XXH3_SECRET_SIZE_MIN)
+ #error "default keyset is not large enough"
+ #endif
+
+/*! Pseudorandom secret taken directly from FARSH. */
+XXH_ALIGN(64)
+static const xxh_u8 XXH3_kSecret[XXH_SECRET_DEFAULT_SIZE] = {
+
+ 0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c,
+ 0xf7, 0x21, 0xad, 0x1c, 0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb,
+ 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f, 0xcb, 0x79, 0xe6, 0x4e,
+ 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21,
+ 0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0, 0x35, 0x90, 0xe6,
+ 0x81, 0x3a, 0x26, 0x4c, 0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb,
+ 0x88, 0xd0, 0x65, 0x8b, 0x1b, 0x53, 0x2e, 0xa3, 0x71, 0x64, 0x48, 0x97,
+ 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac, 0xd8,
+ 0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7,
+ 0xc7, 0x0b, 0x4f, 0x1d, 0x8a, 0x51, 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31,
+ 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64, 0xea, 0xc5, 0xac, 0x83,
+ 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb,
+ 0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26,
+ 0x29, 0xd4, 0x68, 0x9e, 0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc,
+ 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce, 0x45, 0xcb, 0x3a, 0x8f,
+ 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e,
+
+};
+
+ #ifdef XXH_OLD_NAMES
+ #define kSecret XXH3_kSecret
+ #endif
+
+ #ifdef XXH_DOXYGEN
+/*!
+ * @brief Calculates a 32-bit to 64-bit long multiply.
+ *
+ * Implemented as a macro.
+ *
+ * Wraps `__emulu` on MSVC x86 because it tends to call `__allmul` when it
+ * doesn't need to (but it shouldn't need to anyways, it is about 7 instructions
+ * to do a 64x64 multiply...). Since we know that this will _always_ emit
+ * `MULL`, we use that instead of the normal method.
+ *
+ * If you are compiling for platforms like Thumb-1 and don't have a better
+ * option, you may also want to write your own long multiply routine here.
+ *
+ * @param x, y Numbers to be multiplied
+ * @return 64-bit product of the low 32 bits of @p x and @p y.
+ */
+XXH_FORCE_INLINE xxh_u64 XXH_mult32to64(xxh_u64 x, xxh_u64 y) {
+
+ return (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF);
+
+}
+
+ #elif defined(_MSC_VER) && defined(_M_IX86)
+ #include <intrin.h>
+ #define XXH_mult32to64(x, y) __emulu((unsigned)(x), (unsigned)(y))
+ #else
+ /*
+ * Downcast + upcast is usually better than masking on older compilers
+ * like GCC 4.2 (especially 32-bit ones), all without affecting newer
+ * compilers.
+ *
+ * The other method, (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF), will AND both
+ * operands and perform a full 64x64 multiply -- entirely redundant on
+ * 32-bit.
+ */
+ #define XXH_mult32to64(x, y) \
+ ((xxh_u64)(xxh_u32)(x) * (xxh_u64)(xxh_u32)(y))
+ #endif
+
+/*!
+ * @brief Calculates a 64->128-bit long multiply.
+ *
+ * Uses `__uint128_t` and `_umul128` if available, otherwise uses a scalar
+ * version.
+ *
+ * @param lhs, rhs The 64-bit integers to be multiplied
+ * @return The 128-bit result represented in an @ref XXH128_hash_t.
+ */
+static XXH128_hash_t XXH_mult64to128(xxh_u64 lhs, xxh_u64 rhs) {
+
+ /*
+ * GCC/Clang __uint128_t method.
+ *
+ * On most 64-bit targets, GCC and Clang define a __uint128_t type.
+ * This is usually the best way as it usually uses a native long 64-bit
+ * multiply, such as MULQ on x86_64 or MUL + UMULH on aarch64.
+ *
+ * Usually.
+ *
+ * Despite being a 32-bit platform, Clang (and emscripten) define this
+ * type despite not having the arithmetic for it. This results in a laggy
+ * compiler builtin call which calculates a full 128-bit multiply.
+ * In that case it is best to use the portable one.
+ * https://github.com/Cyan4973/xxHash/issues/211#issuecomment-515575677
+ */
+ #if defined(__GNUC__) && !defined(__wasm__) && \
+ defined(__SIZEOF_INT128__) || \
+ (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128)
+
+ __uint128_t const product = (__uint128_t)lhs * (__uint128_t)rhs;
+ XXH128_hash_t r128;
+ r128.low64 = (xxh_u64)(product);
+ r128.high64 = (xxh_u64)(product >> 64);
+ return r128;
+
+ /*
+ * MSVC for x64's _umul128 method.
+ *
+ * xxh_u64 _umul128(xxh_u64 Multiplier, xxh_u64 Multiplicand, xxh_u64
+ * *HighProduct);
+ *
+ * This compiles to single operand MUL on x64.
+ */
+ #elif defined(_M_X64) || defined(_M_IA64)
+
+ #ifndef _MSC_VER
+ #pragma intrinsic(_umul128)
+ #endif
+ xxh_u64 product_high;
+ xxh_u64 const product_low = _umul128(lhs, rhs, &product_high);
+ XXH128_hash_t r128;
+ r128.low64 = product_low;
+ r128.high64 = product_high;
+ return r128;
+
+ #else
+ /*
+ * Portable scalar method. Optimized for 32-bit and 64-bit ALUs.
+ *
+ * This is a fast and simple grade school multiply, which is shown below
+ * with base 10 arithmetic instead of base 0x100000000.
+ *
+ * 9 3 // D2 lhs = 93
+ * x 7 5 // D2 rhs = 75
+ * ----------
+ * 1 5 // D2 lo_lo = (93 % 10) * (75 % 10) = 15
+ * 4 5 | // D2 hi_lo = (93 / 10) * (75 % 10) = 45
+ * 2 1 | // D2 lo_hi = (93 % 10) * (75 / 10) = 21
+ * + 6 3 | | // D2 hi_hi = (93 / 10) * (75 / 10) = 63
+ * ---------
+ * 2 7 | // D2 cross = (15 / 10) + (45 % 10) + 21 = 27
+ * + 6 7 | | // D2 upper = (27 / 10) + (45 / 10) + 63 = 67
+ * ---------
+ * 6 9 7 5 // D4 res = (27 * 10) + (15 % 10) + (67 * 100) = 6975
+ *
+ * The reasons for adding the products like this are:
+ * 1. It avoids manual carry tracking. Just like how
+ * (9 * 9) + 9 + 9 = 99, the same applies with this for UINT64_MAX.
+ * This avoids a lot of complexity.
+ *
+ * 2. It hints for, and on Clang, compiles to, the powerful UMAAL
+ * instruction available in ARM's Digital Signal Processing extension
+ * in 32-bit ARMv6 and later, which is shown below:
+ *
+ * void UMAAL(xxh_u32 *RdLo, xxh_u32 *RdHi, xxh_u32 Rn, xxh_u32 Rm)
+ * {
+
+ * xxh_u64 product = (xxh_u64)*RdLo * (xxh_u64)*RdHi + Rn + Rm;
+ * *RdLo = (xxh_u32)(product & 0xFFFFFFFF);
+ * *RdHi = (xxh_u32)(product >> 32);
+ * }
+ *
+ * This instruction was designed for efficient long multiplication, and
+ * allows this to be calculated in only 4 instructions at speeds
+ * comparable to some 64-bit ALUs.
+ *
+ * 3. It isn't terrible on other platforms. Usually this will be a couple
+ * of 32-bit ADD/ADCs.
+ */
+
+ /* First calculate all of the cross products. */
+ xxh_u64 const lo_lo = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs & 0xFFFFFFFF);
+ xxh_u64 const hi_lo = XXH_mult32to64(lhs >> 32, rhs & 0xFFFFFFFF);
+ xxh_u64 const lo_hi = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs >> 32);
+ xxh_u64 const hi_hi = XXH_mult32to64(lhs >> 32, rhs >> 32);
+
+ /* Now add the products together. These will never overflow. */
+ xxh_u64 const cross = (lo_lo >> 32) + (hi_lo & 0xFFFFFFFF) + lo_hi;
+ xxh_u64 const upper = (hi_lo >> 32) + (cross >> 32) + hi_hi;
+ xxh_u64 const lower = (cross << 32) | (lo_lo & 0xFFFFFFFF);
+
+ XXH128_hash_t r128;
+ r128.low64 = lower;
+ r128.high64 = upper;
+ return r128;
+ #endif
+
+}
+
+/*!
+ * @brief Calculates a 64-bit to 128-bit multiply, then XOR folds it.
+ *
+ * The reason for the separate function is to prevent passing too many structs
+ * around by value. This will hopefully inline the multiply, but we don't force
+ * it.
+ *
+ * @param lhs, rhs The 64-bit integers to multiply
+ * @return The low 64 bits of the product XOR'd by the high 64 bits.
+ * @see XXH_mult64to128()
+ */
+static xxh_u64 XXH3_mul128_fold64(xxh_u64 lhs, xxh_u64 rhs) {
+
+ XXH128_hash_t product = XXH_mult64to128(lhs, rhs);
+ return product.low64 ^ product.high64;
+
+}
+
+/*! Seems to produce slightly better code on GCC for some reason. */
+XXH_FORCE_INLINE xxh_u64 XXH_xorshift64(xxh_u64 v64, int shift) {
+
+ XXH_ASSERT(0 <= shift && shift < 64);
+ return v64 ^ (v64 >> shift);
+
+}
+
+/*
+ * This is a fast avalanche stage,
+ * suitable when input bits are already partially mixed
+ */
+static XXH64_hash_t XXH3_avalanche(xxh_u64 h64) {
+
+ h64 = XXH_xorshift64(h64, 37);
+ h64 *= 0x165667919E3779F9ULL;
+ h64 = XXH_xorshift64(h64, 32);
+ return h64;
+
+}
+
+/*
+ * This is a stronger avalanche,
+ * inspired by Pelle Evensen's rrmxmx
+ * preferable when input has not been previously mixed
+ */
+static XXH64_hash_t XXH3_rrmxmx(xxh_u64 h64, xxh_u64 len) {
+
+ /* this mix is inspired by Pelle Evensen's rrmxmx */
+ h64 ^= XXH_rotl64(h64, 49) ^ XXH_rotl64(h64, 24);
+ h64 *= 0x9FB21C651E98DF25ULL;
+ h64 ^= (h64 >> 35) + len;
+ h64 *= 0x9FB21C651E98DF25ULL;
+ return XXH_xorshift64(h64, 28);
+
+}
+
+/* ==========================================
+ * Short keys
+ * ==========================================
+ * One of the shortcomings of XXH32 and XXH64 was that their performance was
+ * sub-optimal on short lengths. It used an iterative algorithm which strongly
+ * favored lengths that were a multiple of 4 or 8.
+ *
+ * Instead of iterating over individual inputs, we use a set of single shot
+ * functions which piece together a range of lengths and operate in constant
+ * time.
+ *
+ * Additionally, the number of multiplies has been significantly reduced. This
+ * reduces latency, especially when emulating 64-bit multiplies on 32-bit.
+ *
+ * Depending on the platform, this may or may not be faster than XXH32, but it
+ * is almost guaranteed to be faster than XXH64.
+ */
+
+/*
+ * At very short lengths, there isn't enough input to fully hide secrets, or use
+ * the entire secret.
+ *
+ * There is also only a limited amount of mixing we can do before significantly
+ * impacting performance.
+ *
+ * Therefore, we use different sections of the secret and always mix two secret
+ * samples with an XOR. This should have no effect on performance on the
+ * seedless or withSeed variants because everything _should_ be constant folded
+ * by modern compilers.
+ *
+ * The XOR mixing hides individual parts of the secret and increases entropy.
+ *
+ * This adds an extra layer of strength for custom secrets.
+ */
+XXH_FORCE_INLINE XXH64_hash_t XXH3_len_1to3_64b(const xxh_u8 *input, size_t len,
+ const xxh_u8 *secret,
+ XXH64_hash_t seed) {
+
+ XXH_ASSERT(input != NULL);
+ XXH_ASSERT(1 <= len && len <= 3);
+ XXH_ASSERT(secret != NULL);
+ /*
+ * len = 1: combined = { input[0], 0x01, input[0], input[0] }
+ * len = 2: combined = { input[1], 0x02, input[0], input[1] }
+ * len = 3: combined = { input[2], 0x03, input[0], input[1] }
+ */
+ {
+
+ xxh_u8 const c1 = input[0];
+ xxh_u8 const c2 = input[len >> 1];
+ xxh_u8 const c3 = input[len - 1];
+ xxh_u32 const combined = ((xxh_u32)c1 << 16) | ((xxh_u32)c2 << 24) |
+ ((xxh_u32)c3 << 0) | ((xxh_u32)len << 8);
+ xxh_u64 const bitflip =
+ (XXH_readLE32(secret) ^ XXH_readLE32(secret + 4)) + seed;
+ xxh_u64 const keyed = (xxh_u64)combined ^ bitflip;
+ return XXH64_avalanche(keyed);
+
+ }
+
+}
+
+XXH_FORCE_INLINE XXH64_hash_t XXH3_len_4to8_64b(const xxh_u8 *input, size_t len,
+ const xxh_u8 *secret,
+ XXH64_hash_t seed) {
+
+ XXH_ASSERT(input != NULL);
+ XXH_ASSERT(secret != NULL);
+ XXH_ASSERT(4 <= len && len <= 8);
+ seed ^= (xxh_u64)XXH_swap32((xxh_u32)seed) << 32;
+ {
+
+ xxh_u32 const input1 = XXH_readLE32(input);
+ xxh_u32 const input2 = XXH_readLE32(input + len - 4);
+ xxh_u64 const bitflip =
+ (XXH_readLE64(secret + 8) ^ XXH_readLE64(secret + 16)) - seed;
+ xxh_u64 const input64 = input2 + (((xxh_u64)input1) << 32);
+ xxh_u64 const keyed = input64 ^ bitflip;
+ return XXH3_rrmxmx(keyed, len);
+
+ }
+
+}
+
+XXH_FORCE_INLINE XXH64_hash_t XXH3_len_9to16_64b(const xxh_u8 *input,
+ size_t len,
+ const xxh_u8 *secret,
+ XXH64_hash_t seed) {
+
+ XXH_ASSERT(input != NULL);
+ XXH_ASSERT(secret != NULL);
+ XXH_ASSERT(9 <= len && len <= 16);
+ {
+
+ xxh_u64 const bitflip1 =
+ (XXH_readLE64(secret + 24) ^ XXH_readLE64(secret + 32)) + seed;
+ xxh_u64 const bitflip2 =
+ (XXH_readLE64(secret + 40) ^ XXH_readLE64(secret + 48)) - seed;
+ xxh_u64 const input_lo = XXH_readLE64(input) ^ bitflip1;
+ xxh_u64 const input_hi = XXH_readLE64(input + len - 8) ^ bitflip2;
+ xxh_u64 const acc = len + XXH_swap64(input_lo) + input_hi +
+ XXH3_mul128_fold64(input_lo, input_hi);
+ return XXH3_avalanche(acc);
+
+ }
+
+}
+
+XXH_FORCE_INLINE XXH64_hash_t XXH3_len_0to16_64b(const xxh_u8 *input,
+ size_t len,
+ const xxh_u8 *secret,
+ XXH64_hash_t seed) {
+
+ XXH_ASSERT(len <= 16);
+ {
+
+ if (XXH_likely(len > 8))
+ return XXH3_len_9to16_64b(input, len, secret, seed);
+ if (XXH_likely(len >= 4))
+ return XXH3_len_4to8_64b(input, len, secret, seed);
+ if (len) return XXH3_len_1to3_64b(input, len, secret, seed);
+ return XXH64_avalanche(
+ seed ^ (XXH_readLE64(secret + 56) ^ XXH_readLE64(secret + 64)));
+
+ }
+
+}
+
+/*
+ * DISCLAIMER: There are known *seed-dependent* multicollisions here due to
+ * multiplication by zero, affecting hashes of lengths 17 to 240.
+ *
+ * However, they are very unlikely.
+ *
+ * Keep this in mind when using the unseeded XXH3_64bits() variant: As with all
+ * unseeded non-cryptographic hashes, it does not attempt to defend itself
+ * against specially crafted inputs, only random inputs.
+ *
+ * Compared to classic UMAC where a 1 in 2^31 chance of 4 consecutive bytes
+ * cancelling out the secret is taken an arbitrary number of times (addressed
+ * in XXH3_accumulate_512), this collision is very unlikely with random inputs
+ * and/or proper seeding:
+ *
+ * This only has a 1 in 2^63 chance of 8 consecutive bytes cancelling out, in a
+ * function that is only called up to 16 times per hash with up to 240 bytes of
+ * input.
+ *
+ * This is not too bad for a non-cryptographic hash function, especially with
+ * only 64 bit outputs.
+ *
+ * The 128-bit variant (which trades some speed for strength) is NOT affected
+ * by this, although it is always a good idea to use a proper seed if you care
+ * about strength.
+ */
+XXH_FORCE_INLINE xxh_u64 XXH3_mix16B(const xxh_u8 *XXH_RESTRICT input,
+ const xxh_u8 *XXH_RESTRICT secret,
+ xxh_u64 seed64) {
+
+ #if defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \
+ && defined(__i386__) && defined(__SSE2__) /* x86 + SSE2 */ \
+ && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable like \
+ XXH32 hack */
+ /*
+ * UGLY HACK:
+ * GCC for x86 tends to autovectorize the 128-bit multiply, resulting in
+ * slower code.
+ *
+ * By forcing seed64 into a register, we disrupt the cost model and
+ * cause it to scalarize. See `XXH32_round()`
+ *
+ * FIXME: Clang's output is still _much_ faster -- On an AMD Ryzen 3600,
+ * XXH3_64bits @ len=240 runs at 4.6 GB/s with Clang 9, but 3.3 GB/s on
+ * GCC 9.2, despite both emitting scalar code.
+ *
+ * GCC generates much better scalar code than Clang for the rest of XXH3,
+ * which is why finding a more optimal codepath is an interest.
+ */
+ XXH_COMPILER_GUARD(seed64);
+ #endif
+ {
+
+ xxh_u64 const input_lo = XXH_readLE64(input);
+ xxh_u64 const input_hi = XXH_readLE64(input + 8);
+ return XXH3_mul128_fold64(input_lo ^ (XXH_readLE64(secret) + seed64),
+ input_hi ^ (XXH_readLE64(secret + 8) - seed64));
+
+ }
+
+}
+
+/* For mid range keys, XXH3 uses a Mum-hash variant. */
+XXH_FORCE_INLINE XXH64_hash_t XXH3_len_17to128_64b(
+ const xxh_u8 *XXH_RESTRICT input, size_t len,
+ const xxh_u8 *XXH_RESTRICT secret, size_t secretSize, XXH64_hash_t seed) {
+
+ XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN);
+ (void)secretSize;
+ XXH_ASSERT(16 < len && len <= 128);
+
+ {
+
+ xxh_u64 acc = len * XXH_PRIME64_1;
+ if (len > 32) {
+
+ if (len > 64) {
+
+ if (len > 96) {
+
+ acc += XXH3_mix16B(input + 48, secret + 96, seed);
+ acc += XXH3_mix16B(input + len - 64, secret + 112, seed);
+
+ }
+
+ acc += XXH3_mix16B(input + 32, secret + 64, seed);
+ acc += XXH3_mix16B(input + len - 48, secret + 80, seed);
+
+ }
+
+ acc += XXH3_mix16B(input + 16, secret + 32, seed);
+ acc += XXH3_mix16B(input + len - 32, secret + 48, seed);
+
+ }
+
+ acc += XXH3_mix16B(input + 0, secret + 0, seed);
+ acc += XXH3_mix16B(input + len - 16, secret + 16, seed);
+
+ return XXH3_avalanche(acc);
+
+ }
+
+}
+
+ #define XXH3_MIDSIZE_MAX 240
+
+XXH_NO_INLINE XXH64_hash_t XXH3_len_129to240_64b(
+ const xxh_u8 *XXH_RESTRICT input, size_t len,
+ const xxh_u8 *XXH_RESTRICT secret, size_t secretSize, XXH64_hash_t seed) {
+
+ XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN);
+ (void)secretSize;
+ XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX);
+
+ #define XXH3_MIDSIZE_STARTOFFSET 3
+ #define XXH3_MIDSIZE_LASTOFFSET 17
+
+ {
+
+ xxh_u64 acc = len * XXH_PRIME64_1;
+ int const nbRounds = (int)len / 16;
+ int i;
+ for (i = 0; i < 8; i++) {
+
+ acc += XXH3_mix16B(input + (16 * i), secret + (16 * i), seed);
+
+ }
+
+ acc = XXH3_avalanche(acc);
+ XXH_ASSERT(nbRounds >= 8);
+ #if defined(__clang__) /* Clang */ \
+ && (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \
+ && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable */
+ /*
+ * UGLY HACK:
+ * Clang for ARMv7-A tries to vectorize this loop, similar to GCC x86.
+ * In everywhere else, it uses scalar code.
+ *
+ * For 64->128-bit multiplies, even if the NEON was 100% optimal, it
+ * would still be slower than UMAAL (see XXH_mult64to128).
+ *
+ * Unfortunately, Clang doesn't handle the long multiplies properly and
+ * converts them to the nonexistent "vmulq_u64" intrinsic, which is then
+ * scalarized into an ugly mess of VMOV.32 instructions.
+ *
+ * This mess is difficult to avoid without turning autovectorization
+ * off completely, but they are usually relatively minor and/or not
+ * worth it to fix.
+ *
+ * This loop is the easiest to fix, as unlike XXH32, this pragma
+ * _actually works_ because it is a loop vectorization instead of an
+ * SLP vectorization.
+ */
+ #pragma clang loop vectorize(disable)
+ #endif
+ for (i = 8; i < nbRounds; i++) {
+
+ acc +=
+ XXH3_mix16B(input + (16 * i),
+ secret + (16 * (i - 8)) + XXH3_MIDSIZE_STARTOFFSET, seed);
+
+ }
+
+ /* last bytes */
+ acc += XXH3_mix16B(input + len - 16,
+ secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET,
+ seed);
+ return XXH3_avalanche(acc);
+
+ }
+
+}
+
+ /* ======= Long Keys ======= */
+
+ #define XXH_STRIPE_LEN 64
+ #define XXH_SECRET_CONSUME_RATE \
+ 8 /* nb of secret bytes consumed at each accumulation */
+ #define XXH_ACC_NB (XXH_STRIPE_LEN / sizeof(xxh_u64))
+
+ #ifdef XXH_OLD_NAMES
+ #define STRIPE_LEN XXH_STRIPE_LEN
+ #define ACC_NB XXH_ACC_NB
+ #endif
+
+XXH_FORCE_INLINE void XXH_writeLE64(void *dst, xxh_u64 v64) {
+
+ if (!XXH_CPU_LITTLE_ENDIAN) v64 = XXH_swap64(v64);
+ memcpy(dst, &v64, sizeof(v64));
+
+}
+
+ /* Several intrinsic functions below are supposed to accept __int64 as
+ * argument, as documented in
+ * https://software.intel.com/sites/landingpage/IntrinsicsGuide/ .
+ * However, several environments do not define __int64 type,
+ * requiring a workaround.
+ */
+ #if !defined(__VMS) && \
+ (defined(__cplusplus) || (defined(__STDC_VERSION__) && \
+ (__STDC_VERSION__ >= 199901L) /* C99 */))
+typedef int64_t xxh_i64;
+ #else
+/* the following type must have a width of 64-bit */
+typedef long long xxh_i64;
+ #endif
+
+ /*
+ * XXH3_accumulate_512 is the tightest loop for long inputs, and it is the
+ * most optimized.
+ *
+ * It is a hardened version of UMAC, based off of FARSH's implementation.
+ *
+ * This was chosen because it adapts quite well to 32-bit, 64-bit, and SIMD
+ * implementations, and it is ridiculously fast.
+ *
+ * We harden it by mixing the original input to the accumulators as well as
+ * the product.
+ *
+ * This means that in the (relatively likely) case of a multiply by zero,
+ * the original input is preserved.
+ *
+ * On 128-bit inputs, we swap 64-bit pairs when we add the input to improve
+ * cross-pollination, as otherwise the upper and lower halves would be
+ * essentially independent.
+ *
+ * This doesn't matter on 64-bit hashes since they all get merged together
+ * in the end, so we skip the extra step.
+ *
+ * Both XXH3_64bits and XXH3_128bits use this subroutine.
+ */
+
+ #if (XXH_VECTOR == XXH_AVX512) || \
+ (defined(XXH_DISPATCH_AVX512) && XXH_DISPATCH_AVX512 != 0)
+
+ #ifndef XXH_TARGET_AVX512
+ #define XXH_TARGET_AVX512 /* disable attribute target */
+ #endif
+
+XXH_FORCE_INLINE XXH_TARGET_AVX512 void XXH3_accumulate_512_avx512(
+ void *XXH_RESTRICT acc, const void *XXH_RESTRICT input,
+ const void *XXH_RESTRICT secret) {
+
+ __m512i *const xacc = (__m512i *)acc;
+ XXH_ASSERT((((size_t)acc) & 63) == 0);
+ XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i));
+
+ {
+
+ /* data_vec = input[0]; */
+ __m512i const data_vec = _mm512_loadu_si512(input);
+ /* key_vec = secret[0]; */
+ __m512i const key_vec = _mm512_loadu_si512(secret);
+ /* data_key = data_vec ^ key_vec; */
+ __m512i const data_key = _mm512_xor_si512(data_vec, key_vec);
+ /* data_key_lo = data_key >> 32; */
+ __m512i const data_key_lo =
+ _mm512_shuffle_epi32(data_key, (_MM_PERM_ENUM)_MM_SHUFFLE(0, 3, 0, 1));
+ /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */
+ __m512i const product = _mm512_mul_epu32(data_key, data_key_lo);
+ /* xacc[0] += swap(data_vec); */
+ __m512i const data_swap =
+ _mm512_shuffle_epi32(data_vec, (_MM_PERM_ENUM)_MM_SHUFFLE(1, 0, 3, 2));
+ __m512i const sum = _mm512_add_epi64(*xacc, data_swap);
+ /* xacc[0] += product; */
+ *xacc = _mm512_add_epi64(product, sum);
+
+ }
+
+}
+
+/*
+ * XXH3_scrambleAcc: Scrambles the accumulators to improve mixing.
+ *
+ * Multiplication isn't perfect, as explained by Google in HighwayHash:
+ *
+ * // Multiplication mixes/scrambles bytes 0-7 of the 64-bit result to
+ * // varying degrees. In descending order of goodness, bytes
+ * // 3 4 2 5 1 6 0 7 have quality 228 224 164 160 100 96 36 32.
+ * // As expected, the upper and lower bytes are much worse.
+ *
+ * Source:
+ * https://github.com/google/highwayhash/blob/0aaf66b/highwayhash/hh_avx2.h#L291
+ *
+ * Since our algorithm uses a pseudorandom secret to add some variance into the
+ * mix, we don't need to (or want to) mix as often or as much as HighwayHash
+ * does.
+ *
+ * This isn't as tight as XXH3_accumulate, but still written in SIMD to avoid
+ * extraction.
+ *
+ * Both XXH3_64bits and XXH3_128bits use this subroutine.
+ */
+
+XXH_FORCE_INLINE XXH_TARGET_AVX512 void XXH3_scrambleAcc_avx512(
+ void *XXH_RESTRICT acc, const void *XXH_RESTRICT secret) {
+
+ XXH_ASSERT((((size_t)acc) & 63) == 0);
+ XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i));
+ {
+
+ __m512i *const xacc = (__m512i *)acc;
+ const __m512i prime32 = _mm512_set1_epi32((int)XXH_PRIME32_1);
+
+ /* xacc[0] ^= (xacc[0] >> 47) */
+ __m512i const acc_vec = *xacc;
+ __m512i const shifted = _mm512_srli_epi64(acc_vec, 47);
+ __m512i const data_vec = _mm512_xor_si512(acc_vec, shifted);
+ /* xacc[0] ^= secret; */
+ __m512i const key_vec = _mm512_loadu_si512(secret);
+ __m512i const data_key = _mm512_xor_si512(data_vec, key_vec);
+
+ /* xacc[0] *= XXH_PRIME32_1; */
+ __m512i const data_key_hi =
+ _mm512_shuffle_epi32(data_key, (_MM_PERM_ENUM)_MM_SHUFFLE(0, 3, 0, 1));
+ __m512i const prod_lo = _mm512_mul_epu32(data_key, prime32);
+ __m512i const prod_hi = _mm512_mul_epu32(data_key_hi, prime32);
+ *xacc = _mm512_add_epi64(prod_lo, _mm512_slli_epi64(prod_hi, 32));
+
+ }
+
+}
+
+XXH_FORCE_INLINE XXH_TARGET_AVX512 void XXH3_initCustomSecret_avx512(
+ void *XXH_RESTRICT customSecret, xxh_u64 seed64) {
+
+ XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 63) == 0);
+ XXH_STATIC_ASSERT(XXH_SEC_ALIGN == 64);
+ XXH_ASSERT(((size_t)customSecret & 63) == 0);
+ (void)(&XXH_writeLE64);
+ {
+
+ int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m512i);
+ __m512i const seed = _mm512_mask_set1_epi64(
+ _mm512_set1_epi64((xxh_i64)seed64), 0xAA, (xxh_i64)(0U - seed64));
+
+ const __m512i *const src = (const __m512i *)((const void *)XXH3_kSecret);
+ __m512i *const dest = (__m512i *)customSecret;
+ int i;
+ XXH_ASSERT(((size_t)src & 63) == 0); /* control alignment */
+ XXH_ASSERT(((size_t)dest & 63) == 0);
+ for (i = 0; i < nbRounds; ++i) {
+
+ /* GCC has a bug, _mm512_stream_load_si512 accepts 'void*', not 'void
+ * const*', this will warn "discards 'const' qualifier". */
+ union {
+
+ const __m512i *cp;
+ void * p;
+
+ } remote_const_void;
+
+ remote_const_void.cp = src + i;
+ dest[i] =
+ _mm512_add_epi64(_mm512_stream_load_si512(remote_const_void.p), seed);
+
+ }
+
+ }
+
+}
+
+ #endif
+
+ #if (XXH_VECTOR == XXH_AVX2) || \
+ (defined(XXH_DISPATCH_AVX2) && XXH_DISPATCH_AVX2 != 0)
+
+ #ifndef XXH_TARGET_AVX2
+ #define XXH_TARGET_AVX2 /* disable attribute target */
+ #endif
+
+XXH_FORCE_INLINE XXH_TARGET_AVX2 void XXH3_accumulate_512_avx2(
+ void *XXH_RESTRICT acc, const void *XXH_RESTRICT input,
+ const void *XXH_RESTRICT secret) {
+
+ XXH_ASSERT((((size_t)acc) & 31) == 0);
+ {
+
+ __m256i *const xacc = (__m256i *)acc;
+ /* Unaligned. This is mainly for pointer arithmetic, and because
+ * _mm256_loadu_si256 requires a const __m256i * pointer for some reason.
+ */
+ const __m256i *const xinput = (const __m256i *)input;
+ /* Unaligned. This is mainly for pointer arithmetic, and because
+ * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */
+ const __m256i *const xsecret = (const __m256i *)secret;
+
+ size_t i;
+ for (i = 0; i < XXH_STRIPE_LEN / sizeof(__m256i); i++) {
+
+ /* data_vec = xinput[i]; */
+ __m256i const data_vec = _mm256_loadu_si256(xinput + i);
+ /* key_vec = xsecret[i]; */
+ __m256i const key_vec = _mm256_loadu_si256(xsecret + i);
+ /* data_key = data_vec ^ key_vec; */
+ __m256i const data_key = _mm256_xor_si256(data_vec, key_vec);
+ /* data_key_lo = data_key >> 32; */
+ __m256i const data_key_lo =
+ _mm256_shuffle_epi32(data_key, _MM_SHUFFLE(0, 3, 0, 1));
+ /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */
+ __m256i const product = _mm256_mul_epu32(data_key, data_key_lo);
+ /* xacc[i] += swap(data_vec); */
+ __m256i const data_swap =
+ _mm256_shuffle_epi32(data_vec, _MM_SHUFFLE(1, 0, 3, 2));
+ __m256i const sum = _mm256_add_epi64(xacc[i], data_swap);
+ /* xacc[i] += product; */
+ xacc[i] = _mm256_add_epi64(product, sum);
+
+ }
+
+ }
+
+}
+
+XXH_FORCE_INLINE XXH_TARGET_AVX2 void XXH3_scrambleAcc_avx2(
+ void *XXH_RESTRICT acc, const void *XXH_RESTRICT secret) {
+
+ XXH_ASSERT((((size_t)acc) & 31) == 0);
+ {
+
+ __m256i *const xacc = (__m256i *)acc;
+ /* Unaligned. This is mainly for pointer arithmetic, and because
+ * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */
+ const __m256i *const xsecret = (const __m256i *)secret;
+ const __m256i prime32 = _mm256_set1_epi32((int)XXH_PRIME32_1);
+
+ size_t i;
+ for (i = 0; i < XXH_STRIPE_LEN / sizeof(__m256i); i++) {
+
+ /* xacc[i] ^= (xacc[i] >> 47) */
+ __m256i const acc_vec = xacc[i];
+ __m256i const shifted = _mm256_srli_epi64(acc_vec, 47);
+ __m256i const data_vec = _mm256_xor_si256(acc_vec, shifted);
+ /* xacc[i] ^= xsecret; */
+ __m256i const key_vec = _mm256_loadu_si256(xsecret + i);
+ __m256i const data_key = _mm256_xor_si256(data_vec, key_vec);
+
+ /* xacc[i] *= XXH_PRIME32_1; */
+ __m256i const data_key_hi =
+ _mm256_shuffle_epi32(data_key, _MM_SHUFFLE(0, 3, 0, 1));
+ __m256i const prod_lo = _mm256_mul_epu32(data_key, prime32);
+ __m256i const prod_hi = _mm256_mul_epu32(data_key_hi, prime32);
+ xacc[i] = _mm256_add_epi64(prod_lo, _mm256_slli_epi64(prod_hi, 32));
+
+ }
+
+ }
+
+}
+
+XXH_FORCE_INLINE XXH_TARGET_AVX2 void XXH3_initCustomSecret_avx2(
+ void *XXH_RESTRICT customSecret, xxh_u64 seed64) {
+
+ XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 31) == 0);
+ XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE / sizeof(__m256i)) == 6);
+ XXH_STATIC_ASSERT(XXH_SEC_ALIGN <= 64);
+ (void)(&XXH_writeLE64);
+ XXH_PREFETCH(customSecret);
+ {
+
+ __m256i const seed =
+ _mm256_set_epi64x((xxh_i64)(0U - seed64), (xxh_i64)seed64,
+ (xxh_i64)(0U - seed64), (xxh_i64)seed64);
+
+ const __m256i *const src = (const __m256i *)((const void *)XXH3_kSecret);
+ __m256i * dest = (__m256i *)customSecret;
+
+ #if defined(__GNUC__) || defined(__clang__)
+ /*
+ * On GCC & Clang, marking 'dest' as modified will cause the compiler:
+ * - do not extract the secret from sse registers in the internal loop
+ * - use less common registers, and avoid pushing these reg into stack
+ */
+ XXH_COMPILER_GUARD(dest);
+ #endif
+ XXH_ASSERT(((size_t)src & 31) == 0); /* control alignment */
+ XXH_ASSERT(((size_t)dest & 31) == 0);
+
+ /* GCC -O2 need unroll loop manually */
+ dest[0] = _mm256_add_epi64(_mm256_stream_load_si256(src + 0), seed);
+ dest[1] = _mm256_add_epi64(_mm256_stream_load_si256(src + 1), seed);
+ dest[2] = _mm256_add_epi64(_mm256_stream_load_si256(src + 2), seed);
+ dest[3] = _mm256_add_epi64(_mm256_stream_load_si256(src + 3), seed);
+ dest[4] = _mm256_add_epi64(_mm256_stream_load_si256(src + 4), seed);
+ dest[5] = _mm256_add_epi64(_mm256_stream_load_si256(src + 5), seed);
+
+ }
+
+}
+
+ #endif
+
+ /* x86dispatch always generates SSE2 */
+ #if (XXH_VECTOR == XXH_SSE2) || defined(XXH_X86DISPATCH)
+
+ #ifndef XXH_TARGET_SSE2
+ #define XXH_TARGET_SSE2 /* disable attribute target */
+ #endif
+
+XXH_FORCE_INLINE XXH_TARGET_SSE2 void XXH3_accumulate_512_sse2(
+ void *XXH_RESTRICT acc, const void *XXH_RESTRICT input,
+ const void *XXH_RESTRICT secret) {
+
+ /* SSE2 is just a half-scale version of the AVX2 version. */
+ XXH_ASSERT((((size_t)acc) & 15) == 0);
+ {
+
+ __m128i *const xacc = (__m128i *)acc;
+ /* Unaligned. This is mainly for pointer arithmetic, and because
+ * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */
+ const __m128i *const xinput = (const __m128i *)input;
+ /* Unaligned. This is mainly for pointer arithmetic, and because
+ * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */
+ const __m128i *const xsecret = (const __m128i *)secret;
+
+ size_t i;
+ for (i = 0; i < XXH_STRIPE_LEN / sizeof(__m128i); i++) {
+
+ /* data_vec = xinput[i]; */
+ __m128i const data_vec = _mm_loadu_si128(xinput + i);
+ /* key_vec = xsecret[i]; */
+ __m128i const key_vec = _mm_loadu_si128(xsecret + i);
+ /* data_key = data_vec ^ key_vec; */
+ __m128i const data_key = _mm_xor_si128(data_vec, key_vec);
+ /* data_key_lo = data_key >> 32; */
+ __m128i const data_key_lo =
+ _mm_shuffle_epi32(data_key, _MM_SHUFFLE(0, 3, 0, 1));
+ /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */
+ __m128i const product = _mm_mul_epu32(data_key, data_key_lo);
+ /* xacc[i] += swap(data_vec); */
+ __m128i const data_swap =
+ _mm_shuffle_epi32(data_vec, _MM_SHUFFLE(1, 0, 3, 2));
+ __m128i const sum = _mm_add_epi64(xacc[i], data_swap);
+ /* xacc[i] += product; */
+ xacc[i] = _mm_add_epi64(product, sum);
+
+ }
+
+ }
+
+}
+
+XXH_FORCE_INLINE XXH_TARGET_SSE2 void XXH3_scrambleAcc_sse2(
+ void *XXH_RESTRICT acc, const void *XXH_RESTRICT secret) {
+
+ XXH_ASSERT((((size_t)acc) & 15) == 0);
+ {
+
+ __m128i *const xacc = (__m128i *)acc;
+ /* Unaligned. This is mainly for pointer arithmetic, and because
+ * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */
+ const __m128i *const xsecret = (const __m128i *)secret;
+ const __m128i prime32 = _mm_set1_epi32((int)XXH_PRIME32_1);
+
+ size_t i;
+ for (i = 0; i < XXH_STRIPE_LEN / sizeof(__m128i); i++) {
+
+ /* xacc[i] ^= (xacc[i] >> 47) */
+ __m128i const acc_vec = xacc[i];
+ __m128i const shifted = _mm_srli_epi64(acc_vec, 47);
+ __m128i const data_vec = _mm_xor_si128(acc_vec, shifted);
+ /* xacc[i] ^= xsecret[i]; */
+ __m128i const key_vec = _mm_loadu_si128(xsecret + i);
+ __m128i const data_key = _mm_xor_si128(data_vec, key_vec);
+
+ /* xacc[i] *= XXH_PRIME32_1; */
+ __m128i const data_key_hi =
+ _mm_shuffle_epi32(data_key, _MM_SHUFFLE(0, 3, 0, 1));
+ __m128i const prod_lo = _mm_mul_epu32(data_key, prime32);
+ __m128i const prod_hi = _mm_mul_epu32(data_key_hi, prime32);
+ xacc[i] = _mm_add_epi64(prod_lo, _mm_slli_epi64(prod_hi, 32));
+
+ }
+
+ }
+
+}
+
+XXH_FORCE_INLINE XXH_TARGET_SSE2 void XXH3_initCustomSecret_sse2(
+ void *XXH_RESTRICT customSecret, xxh_u64 seed64) {
+
+ XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0);
+ (void)(&XXH_writeLE64);
+ {
+
+ int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m128i);
+
+ #if defined(_MSC_VER) && defined(_M_IX86) && _MSC_VER < 1900
+ /* MSVC 32bit mode does not support _mm_set_epi64x before 2015 */
+ XXH_ALIGN(16)
+ const xxh_i64 seed64x2[2] = {(xxh_i64)seed64, (xxh_i64)(0U - seed64)};
+ __m128i const seed = _mm_load_si128((__m128i const *)seed64x2);
+ #else
+ __m128i const seed =
+ _mm_set_epi64x((xxh_i64)(0U - seed64), (xxh_i64)seed64);
+ #endif
+ int i;
+
+ const void *const src16 = XXH3_kSecret;
+ __m128i * dst16 = (__m128i *)customSecret;
+ #if defined(__GNUC__) || defined(__clang__)
+ /*
+ * On GCC & Clang, marking 'dest' as modified will cause the compiler:
+ * - do not extract the secret from sse registers in the internal loop
+ * - use less common registers, and avoid pushing these reg into stack
+ */
+ XXH_COMPILER_GUARD(dst16);
+ #endif
+ XXH_ASSERT(((size_t)src16 & 15) == 0); /* control alignment */
+ XXH_ASSERT(((size_t)dst16 & 15) == 0);
+
+ for (i = 0; i < nbRounds; ++i) {
+
+ dst16[i] =
+ _mm_add_epi64(_mm_load_si128((const __m128i *)src16 + i), seed);
+
+ }
+
+ }
+
+}
+
+ #endif
+
+ #if (XXH_VECTOR == XXH_NEON)
+
+XXH_FORCE_INLINE void XXH3_accumulate_512_neon(
+ void *XXH_RESTRICT acc, const void *XXH_RESTRICT input,
+ const void *XXH_RESTRICT secret) {
+
+ XXH_ASSERT((((size_t)acc) & 15) == 0);
+ {
+
+ uint64x2_t *const xacc = (uint64x2_t *)acc;
+ /* We don't use a uint32x4_t pointer because it causes bus errors on ARMv7.
+ */
+ uint8_t const *const xinput = (const uint8_t *)input;
+ uint8_t const *const xsecret = (const uint8_t *)secret;
+
+ size_t i;
+ for (i = 0; i < XXH_STRIPE_LEN / sizeof(uint64x2_t); i++) {
+
+ /* data_vec = xinput[i]; */
+ uint8x16_t data_vec = vld1q_u8(xinput + (i * 16));
+ /* key_vec = xsecret[i]; */
+ uint8x16_t key_vec = vld1q_u8(xsecret + (i * 16));
+ uint64x2_t data_key;
+ uint32x2_t data_key_lo, data_key_hi;
+ /* xacc[i] += swap(data_vec); */
+ uint64x2_t const data64 = vreinterpretq_u64_u8(data_vec);
+ uint64x2_t const swapped = vextq_u64(data64, data64, 1);
+ xacc[i] = vaddq_u64(xacc[i], swapped);
+ /* data_key = data_vec ^ key_vec; */
+ data_key = vreinterpretq_u64_u8(veorq_u8(data_vec, key_vec));
+ /* data_key_lo = (uint32x2_t) (data_key & 0xFFFFFFFF);
+ * data_key_hi = (uint32x2_t) (data_key >> 32);
+ * data_key = UNDEFINED; */
+ XXH_SPLIT_IN_PLACE(data_key, data_key_lo, data_key_hi);
+ /* xacc[i] += (uint64x2_t) data_key_lo * (uint64x2_t) data_key_hi; */
+ xacc[i] = vmlal_u32(xacc[i], data_key_lo, data_key_hi);
+
+ }
+
+ }
+
+}
+
+XXH_FORCE_INLINE void XXH3_scrambleAcc_neon(void *XXH_RESTRICT acc,
+ const void *XXH_RESTRICT secret) {
+
+ XXH_ASSERT((((size_t)acc) & 15) == 0);
+
+ {
+
+ uint64x2_t * xacc = (uint64x2_t *)acc;
+ uint8_t const *xsecret = (uint8_t const *)secret;
+ uint32x2_t prime = vdup_n_u32(XXH_PRIME32_1);
+
+ size_t i;
+ for (i = 0; i < XXH_STRIPE_LEN / sizeof(uint64x2_t); i++) {
+
+ /* xacc[i] ^= (xacc[i] >> 47); */
+ uint64x2_t acc_vec = xacc[i];
+ uint64x2_t shifted = vshrq_n_u64(acc_vec, 47);
+ uint64x2_t data_vec = veorq_u64(acc_vec, shifted);
+
+ /* xacc[i] ^= xsecret[i]; */
+ uint8x16_t key_vec = vld1q_u8(xsecret + (i * 16));
+ uint64x2_t data_key = veorq_u64(data_vec, vreinterpretq_u64_u8(key_vec));
+
+ /* xacc[i] *= XXH_PRIME32_1 */
+ uint32x2_t data_key_lo, data_key_hi;
+ /* data_key_lo = (uint32x2_t) (xacc[i] & 0xFFFFFFFF);
+ * data_key_hi = (uint32x2_t) (xacc[i] >> 32);
+ * xacc[i] = UNDEFINED; */
+ XXH_SPLIT_IN_PLACE(data_key, data_key_lo, data_key_hi);
+ { /*
+ * prod_hi = (data_key >> 32) * XXH_PRIME32_1;
+ *
+ * Avoid vmul_u32 + vshll_n_u32 since Clang 6 and 7 will
+ * incorrectly "optimize" this:
+ * tmp = vmul_u32(vmovn_u64(a), vmovn_u64(b));
+ * shifted = vshll_n_u32(tmp, 32);
+ * to this:
+ * tmp = "vmulq_u64"(a, b); // no such thing!
+ * shifted = vshlq_n_u64(tmp, 32);
+ *
+ * However, unlike SSE, Clang lacks a 64-bit multiply routine
+ * for NEON, and it scalarizes two 64-bit multiplies instead.
+ *
+ * vmull_u32 has the same timing as vmul_u32, and it avoids
+ * this bug completely.
+ * See https://bugs.llvm.org/show_bug.cgi?id=39967
+ */
+ uint64x2_t prod_hi = vmull_u32(data_key_hi, prime);
+ /* xacc[i] = prod_hi << 32; */
+ xacc[i] = vshlq_n_u64(prod_hi, 32);
+ /* xacc[i] += (prod_hi & 0xFFFFFFFF) * XXH_PRIME32_1; */
+ xacc[i] = vmlal_u32(xacc[i], data_key_lo, prime);
+
+ }
+
+ }
+
+ }
+
+}
+
+ #endif
+
+ #if (XXH_VECTOR == XXH_VSX)
+
+XXH_FORCE_INLINE void XXH3_accumulate_512_vsx(void *XXH_RESTRICT acc,
+ const void *XXH_RESTRICT input,
+ const void *XXH_RESTRICT secret) {
+
+ xxh_u64x2 *const xacc = (xxh_u64x2 *)acc; /* presumed aligned */
+ xxh_u64x2 const *const xinput =
+ (xxh_u64x2 const *)input; /* no alignment restriction */
+ xxh_u64x2 const *const xsecret =
+ (xxh_u64x2 const *)secret; /* no alignment restriction */
+ xxh_u64x2 const v32 = {32, 32};
+ size_t i;
+ for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) {
+
+ /* data_vec = xinput[i]; */
+ xxh_u64x2 const data_vec = XXH_vec_loadu(xinput + i);
+ /* key_vec = xsecret[i]; */
+ xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + i);
+ xxh_u64x2 const data_key = data_vec ^ key_vec;
+ /* shuffled = (data_key << 32) | (data_key >> 32); */
+ xxh_u32x4 const shuffled = (xxh_u32x4)vec_rl(data_key, v32);
+ /* product = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)shuffled &
+ * 0xFFFFFFFF); */
+ xxh_u64x2 const product = XXH_vec_mulo((xxh_u32x4)data_key, shuffled);
+ xacc[i] += product;
+
+ /* swap high and low halves */
+ #ifdef __s390x__
+ xacc[i] += vec_permi(data_vec, data_vec, 2);
+ #else
+ xacc[i] += vec_xxpermdi(data_vec, data_vec, 2);
+ #endif
+
+ }
+
+}
+
+XXH_FORCE_INLINE void XXH3_scrambleAcc_vsx(void *XXH_RESTRICT acc,
+ const void *XXH_RESTRICT secret) {
+
+ XXH_ASSERT((((size_t)acc) & 15) == 0);
+
+ {
+
+ xxh_u64x2 *const xacc = (xxh_u64x2 *)acc;
+ const xxh_u64x2 *const xsecret = (const xxh_u64x2 *)secret;
+ /* constants */
+ xxh_u64x2 const v32 = {32, 32};
+ xxh_u64x2 const v47 = {47, 47};
+ xxh_u32x4 const prime = {XXH_PRIME32_1, XXH_PRIME32_1, XXH_PRIME32_1,
+ XXH_PRIME32_1};
+ size_t i;
+ for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) {
+
+ /* xacc[i] ^= (xacc[i] >> 47); */
+ xxh_u64x2 const acc_vec = xacc[i];
+ xxh_u64x2 const data_vec = acc_vec ^ (acc_vec >> v47);
+
+ /* xacc[i] ^= xsecret[i]; */
+ xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + i);
+ xxh_u64x2 const data_key = data_vec ^ key_vec;
+
+ /* xacc[i] *= XXH_PRIME32_1 */
+ /* prod_lo = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)prime &
+ * 0xFFFFFFFF); */
+ xxh_u64x2 const prod_even = XXH_vec_mule((xxh_u32x4)data_key, prime);
+ /* prod_hi = ((xxh_u64x2)data_key >> 32) * ((xxh_u64x2)prime >> 32); */
+ xxh_u64x2 const prod_odd = XXH_vec_mulo((xxh_u32x4)data_key, prime);
+ xacc[i] = prod_odd + (prod_even << v32);
+
+ }
+
+ }
+
+}
+
+ #endif
+
+/* scalar variants - universal */
+
+XXH_FORCE_INLINE void XXH3_accumulate_512_scalar(
+ void *XXH_RESTRICT acc, const void *XXH_RESTRICT input,
+ const void *XXH_RESTRICT secret) {
+
+ xxh_u64 *const xacc = (xxh_u64 *)acc; /* presumed aligned */
+ const xxh_u8 *const xinput =
+ (const xxh_u8 *)input; /* no alignment restriction */
+ const xxh_u8 *const xsecret =
+ (const xxh_u8 *)secret; /* no alignment restriction */
+ size_t i;
+ XXH_ASSERT(((size_t)acc & (XXH_ACC_ALIGN - 1)) == 0);
+ for (i = 0; i < XXH_ACC_NB; i++) {
+
+ xxh_u64 const data_val = XXH_readLE64(xinput + 8 * i);
+ xxh_u64 const data_key = data_val ^ XXH_readLE64(xsecret + i * 8);
+ xacc[i ^ 1] += data_val; /* swap adjacent lanes */
+ xacc[i] += XXH_mult32to64(data_key & 0xFFFFFFFF, data_key >> 32);
+
+ }
+
+}
+
+XXH_FORCE_INLINE void XXH3_scrambleAcc_scalar(void *XXH_RESTRICT acc,
+ const void *XXH_RESTRICT secret) {
+
+ xxh_u64 *const xacc = (xxh_u64 *)acc; /* presumed aligned */
+ const xxh_u8 *const xsecret =
+ (const xxh_u8 *)secret; /* no alignment restriction */
+ size_t i;
+ XXH_ASSERT((((size_t)acc) & (XXH_ACC_ALIGN - 1)) == 0);
+ for (i = 0; i < XXH_ACC_NB; i++) {
+
+ xxh_u64 const key64 = XXH_readLE64(xsecret + 8 * i);
+ xxh_u64 acc64 = xacc[i];
+ acc64 = XXH_xorshift64(acc64, 47);
+ acc64 ^= key64;
+ acc64 *= XXH_PRIME32_1;
+ xacc[i] = acc64;
+
+ }
+
+}
+
+XXH_FORCE_INLINE void XXH3_initCustomSecret_scalar(
+ void *XXH_RESTRICT customSecret, xxh_u64 seed64) {
+
+ /*
+ * We need a separate pointer for the hack below,
+ * which requires a non-const pointer.
+ * Any decent compiler will optimize this out otherwise.
+ */
+ const xxh_u8 *kSecretPtr = XXH3_kSecret;
+ XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0);
+
+ #if defined(__clang__) && defined(__aarch64__)
+ /*
+ * UGLY HACK:
+ * Clang generates a bunch of MOV/MOVK pairs for aarch64, and they are
+ * placed sequentially, in order, at the top of the unrolled loop.
+ *
+ * While MOVK is great for generating constants (2 cycles for a 64-bit
+ * constant compared to 4 cycles for LDR), long MOVK chains stall the
+ * integer pipelines:
+ * I L S
+ * MOVK
+ * MOVK
+ * MOVK
+ * MOVK
+ * ADD
+ * SUB STR
+ * STR
+ * By forcing loads from memory (as the asm line causes Clang to assume
+ * that XXH3_kSecretPtr has been changed), the pipelines are used more
+ * efficiently:
+ * I L S
+ * LDR
+ * ADD LDR
+ * SUB STR
+ * STR
+ * XXH3_64bits_withSeed, len == 256, Snapdragon 835
+ * without hack: 2654.4 MB/s
+ * with hack: 3202.9 MB/s
+ */
+ XXH_COMPILER_GUARD(kSecretPtr);
+ #endif
+ /*
+ * Note: in debug mode, this overrides the asm optimization
+ * and Clang will emit MOVK chains again.
+ */
+ XXH_ASSERT(kSecretPtr == XXH3_kSecret);
+
+ {
+
+ int const nbRounds = XXH_SECRET_DEFAULT_SIZE / 16;
+ int i;
+ for (i = 0; i < nbRounds; i++) {
+
+ /*
+ * The asm hack causes Clang to assume that kSecretPtr aliases with
+ * customSecret, and on aarch64, this prevented LDP from merging two
+ * loads together for free. Putting the loads together before the stores
+ * properly generates LDP.
+ */
+ xxh_u64 lo = XXH_readLE64(kSecretPtr + 16 * i) + seed64;
+ xxh_u64 hi = XXH_readLE64(kSecretPtr + 16 * i + 8) - seed64;
+ XXH_writeLE64((xxh_u8 *)customSecret + 16 * i, lo);
+ XXH_writeLE64((xxh_u8 *)customSecret + 16 * i + 8, hi);
+
+ }
+
+ }
+
+}
+
+typedef void (*XXH3_f_accumulate_512)(void *XXH_RESTRICT, const void *,
+ const void *);
+typedef void (*XXH3_f_scrambleAcc)(void *XXH_RESTRICT, const void *);
+typedef void (*XXH3_f_initCustomSecret)(void *XXH_RESTRICT, xxh_u64);
+
+ #if (XXH_VECTOR == XXH_AVX512)
+
+ #define XXH3_accumulate_512 XXH3_accumulate_512_avx512
+ #define XXH3_scrambleAcc XXH3_scrambleAcc_avx512
+ #define XXH3_initCustomSecret XXH3_initCustomSecret_avx512
+
+ #elif (XXH_VECTOR == XXH_AVX2)
+
+ #define XXH3_accumulate_512 XXH3_accumulate_512_avx2
+ #define XXH3_scrambleAcc XXH3_scrambleAcc_avx2
+ #define XXH3_initCustomSecret XXH3_initCustomSecret_avx2
+
+ #elif (XXH_VECTOR == XXH_SSE2)
+
+ #define XXH3_accumulate_512 XXH3_accumulate_512_sse2
+ #define XXH3_scrambleAcc XXH3_scrambleAcc_sse2
+ #define XXH3_initCustomSecret XXH3_initCustomSecret_sse2
+
+ #elif (XXH_VECTOR == XXH_NEON)
+
+ #define XXH3_accumulate_512 XXH3_accumulate_512_neon
+ #define XXH3_scrambleAcc XXH3_scrambleAcc_neon
+ #define XXH3_initCustomSecret XXH3_initCustomSecret_scalar
+
+ #elif (XXH_VECTOR == XXH_VSX)
+
+ #define XXH3_accumulate_512 XXH3_accumulate_512_vsx
+ #define XXH3_scrambleAcc XXH3_scrambleAcc_vsx
+ #define XXH3_initCustomSecret XXH3_initCustomSecret_scalar
+
+ #else /* scalar */
+
+ #define XXH3_accumulate_512 XXH3_accumulate_512_scalar
+ #define XXH3_scrambleAcc XXH3_scrambleAcc_scalar
+ #define XXH3_initCustomSecret XXH3_initCustomSecret_scalar
+
+ #endif
+
+ #ifndef XXH_PREFETCH_DIST
+ #ifdef __clang__
+ #define XXH_PREFETCH_DIST 320
+ #else
+ #if (XXH_VECTOR == XXH_AVX512)
+ #define XXH_PREFETCH_DIST 512
+ #else
+ #define XXH_PREFETCH_DIST 384
+ #endif
+ #endif /* __clang__ */
+ #endif /* XXH_PREFETCH_DIST */
+
+/*
+ * XXH3_accumulate()
+ * Loops over XXH3_accumulate_512().
+ * Assumption: nbStripes will not overflow the secret size
+ */
+XXH_FORCE_INLINE void XXH3_accumulate(xxh_u64 *XXH_RESTRICT acc,
+ const xxh_u8 *XXH_RESTRICT input,
+ const xxh_u8 *XXH_RESTRICT secret,
+ size_t nbStripes,
+ XXH3_f_accumulate_512 f_acc512) {
+
+ size_t n;
+ for (n = 0; n < nbStripes; n++) {
+
+ const xxh_u8 *const in = input + n * XXH_STRIPE_LEN;
+ XXH_PREFETCH(in + XXH_PREFETCH_DIST);
+ f_acc512(acc, in, secret + n * XXH_SECRET_CONSUME_RATE);
+
+ }
+
+}
+
+XXH_FORCE_INLINE void XXH3_hashLong_internal_loop(
+ xxh_u64 *XXH_RESTRICT acc, const xxh_u8 *XXH_RESTRICT input, size_t len,
+ const xxh_u8 *XXH_RESTRICT secret, size_t secretSize,
+ XXH3_f_accumulate_512 f_acc512, XXH3_f_scrambleAcc f_scramble) {
+
+ size_t const nbStripesPerBlock =
+ (secretSize - XXH_STRIPE_LEN) / XXH_SECRET_CONSUME_RATE;
+ size_t const block_len = XXH_STRIPE_LEN * nbStripesPerBlock;
+ size_t const nb_blocks = (len - 1) / block_len;
+
+ size_t n;
+
+ XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN);
+
+ for (n = 0; n < nb_blocks; n++) {
+
+ XXH3_accumulate(acc, input + n * block_len, secret, nbStripesPerBlock,
+ f_acc512);
+ f_scramble(acc, secret + secretSize - XXH_STRIPE_LEN);
+
+ }
+
+ /* last partial block */
+ XXH_ASSERT(len > XXH_STRIPE_LEN);
+ {
+
+ size_t const nbStripes =
+ ((len - 1) - (block_len * nb_blocks)) / XXH_STRIPE_LEN;
+ XXH_ASSERT(nbStripes <= (secretSize / XXH_SECRET_CONSUME_RATE));
+ XXH3_accumulate(acc, input + nb_blocks * block_len, secret, nbStripes,
+ f_acc512);
+
+ /* last stripe */
+ {
+
+ const xxh_u8 *const p = input + len - XXH_STRIPE_LEN;
+ #define XXH_SECRET_LASTACC_START \
+ 7 /* not aligned on 8, last secret is different from acc & scrambler \
+ */
+ f_acc512(acc, p,
+ secret + secretSize - XXH_STRIPE_LEN - XXH_SECRET_LASTACC_START);
+
+ }
+
+ }
+
+}
+
+XXH_FORCE_INLINE xxh_u64 XXH3_mix2Accs(const xxh_u64 *XXH_RESTRICT acc,
+ const xxh_u8 *XXH_RESTRICT secret) {
+
+ return XXH3_mul128_fold64(acc[0] ^ XXH_readLE64(secret),
+ acc[1] ^ XXH_readLE64(secret + 8));
+
+}
+
+static XXH64_hash_t XXH3_mergeAccs(const xxh_u64 *XXH_RESTRICT acc,
+ const xxh_u8 *XXH_RESTRICT secret,
+ xxh_u64 start) {
+
+ xxh_u64 result64 = start;
+ size_t i = 0;
+
+ for (i = 0; i < 4; i++) {
+
+ result64 += XXH3_mix2Accs(acc + 2 * i, secret + 16 * i);
+ #if defined(__clang__) /* Clang */ \
+ && (defined(__arm__) || defined(__thumb__)) /* ARMv7 */ \
+ && (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \
+ && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable */
+ /*
+ * UGLY HACK:
+ * Prevent autovectorization on Clang ARMv7-a. Exact same problem as
+ * the one in XXH3_len_129to240_64b. Speeds up shorter keys > 240b.
+ * XXH3_64bits, len == 256, Snapdragon 835:
+ * without hack: 2063.7 MB/s
+ * with hack: 2560.7 MB/s
+ */
+ XXH_COMPILER_GUARD(result64);
+ #endif
+
+ }
+
+ return XXH3_avalanche(result64);
+
+}
+
+ #define XXH3_INIT_ACC \
+ { \
+ \
+ XXH_PRIME32_3, XXH_PRIME64_1, XXH_PRIME64_2, XXH_PRIME64_3, \
+ XXH_PRIME64_4, XXH_PRIME32_2, XXH_PRIME64_5, XXH_PRIME32_1 \
+ \
+ }
+
+XXH_FORCE_INLINE XXH64_hash_t XXH3_hashLong_64b_internal(
+ const void *XXH_RESTRICT input, size_t len, const void *XXH_RESTRICT secret,
+ size_t secretSize, XXH3_f_accumulate_512 f_acc512,
+ XXH3_f_scrambleAcc f_scramble) {
+
+ XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC;
+
+ XXH3_hashLong_internal_loop(acc, (const xxh_u8 *)input, len,
+ (const xxh_u8 *)secret, secretSize, f_acc512,
+ f_scramble);
+
+ /* converge into final hash */
+ XXH_STATIC_ASSERT(sizeof(acc) == 64);
+ /* do not align on 8, so that the secret is different from the accumulator
+ */
+ #define XXH_SECRET_MERGEACCS_START 11
+ XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START);
+ return XXH3_mergeAccs(acc,
+ (const xxh_u8 *)secret + XXH_SECRET_MERGEACCS_START,
+ (xxh_u64)len * XXH_PRIME64_1);
+
+}
+
+/*
+ * It's important for performance that XXH3_hashLong is not inlined.
+ */
+XXH_NO_INLINE XXH64_hash_t XXH3_hashLong_64b_withSecret(
+ const void *XXH_RESTRICT input, size_t len, XXH64_hash_t seed64,
+ const xxh_u8 *XXH_RESTRICT secret, size_t secretLen) {
+
+ (void)seed64;
+ return XXH3_hashLong_64b_internal(input, len, secret, secretLen,
+ XXH3_accumulate_512, XXH3_scrambleAcc);
+
+}
+
+/*
+ * It's important for performance that XXH3_hashLong is not inlined.
+ * Since the function is not inlined, the compiler may not be able to understand
+ * that, in some scenarios, its `secret` argument is actually a compile time
+ * constant. This variant enforces that the compiler can detect that, and uses
+ * this opportunity to streamline the generated code for better performance.
+ */
+XXH_NO_INLINE XXH64_hash_t XXH3_hashLong_64b_default(
+ const void *XXH_RESTRICT input, size_t len, XXH64_hash_t seed64,
+ const xxh_u8 *XXH_RESTRICT secret, size_t secretLen) {
+
+ (void)seed64;
+ (void)secret;
+ (void)secretLen;
+ return XXH3_hashLong_64b_internal(input, len, XXH3_kSecret,
+ sizeof(XXH3_kSecret), XXH3_accumulate_512,
+ XXH3_scrambleAcc);
+
+}
+
+/*
+ * XXH3_hashLong_64b_withSeed():
+ * Generate a custom key based on alteration of default XXH3_kSecret with the
+ * seed, and then use this key for long mode hashing.
+ *
+ * This operation is decently fast but nonetheless costs a little bit of time.
+ * Try to avoid it whenever possible (typically when seed==0).
+ *
+ * It's important for performance that XXH3_hashLong is not inlined. Not sure
+ * why (uop cache maybe?), but the difference is large and easily measurable.
+ */
+XXH_FORCE_INLINE XXH64_hash_t XXH3_hashLong_64b_withSeed_internal(
+ const void *input, size_t len, XXH64_hash_t seed,
+ XXH3_f_accumulate_512 f_acc512, XXH3_f_scrambleAcc f_scramble,
+ XXH3_f_initCustomSecret f_initSec) {
+
+ if (seed == 0)
+ return XXH3_hashLong_64b_internal(
+ input, len, XXH3_kSecret, sizeof(XXH3_kSecret), f_acc512, f_scramble);
+ {
+
+ XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE];
+ f_initSec(secret, seed);
+ return XXH3_hashLong_64b_internal(input, len, secret, sizeof(secret),
+ f_acc512, f_scramble);
+
+ }
+
+}
+
+/*
+ * It's important for performance that XXH3_hashLong is not inlined.
+ */
+XXH_NO_INLINE XXH64_hash_t XXH3_hashLong_64b_withSeed(const void * input,
+ size_t len,
+ XXH64_hash_t seed,
+ const xxh_u8 *secret,
+ size_t secretLen) {
+
+ (void)secret;
+ (void)secretLen;
+ return XXH3_hashLong_64b_withSeed_internal(
+ input, len, seed, XXH3_accumulate_512, XXH3_scrambleAcc,
+ XXH3_initCustomSecret);
+
+}
+
+typedef XXH64_hash_t (*XXH3_hashLong64_f)(const void *XXH_RESTRICT, size_t,
+ XXH64_hash_t,
+ const xxh_u8 *XXH_RESTRICT, size_t);
+
+XXH_FORCE_INLINE XXH64_hash_t
+XXH3_64bits_internal(const void *XXH_RESTRICT input, size_t len,
+ XXH64_hash_t seed64, const void *XXH_RESTRICT secret,
+ size_t secretLen, XXH3_hashLong64_f f_hashLong) {
+
+ XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN);
+ /*
+ * If an action is to be taken if `secretLen` condition is not respected,
+ * it should be done here.
+ * For now, it's a contract pre-condition.
+ * Adding a check and a branch here would cost performance at every hash.
+ * Also, note that function signature doesn't offer room to return an error.
+ */
+ if (len <= 16)
+ return XXH3_len_0to16_64b((const xxh_u8 *)input, len,
+ (const xxh_u8 *)secret, seed64);
+ if (len <= 128)
+ return XXH3_len_17to128_64b((const xxh_u8 *)input, len,
+ (const xxh_u8 *)secret, secretLen, seed64);
+ if (len <= XXH3_MIDSIZE_MAX)
+ return XXH3_len_129to240_64b((const xxh_u8 *)input, len,
+ (const xxh_u8 *)secret, secretLen, seed64);
+ return f_hashLong(input, len, seed64, (const xxh_u8 *)secret, secretLen);
+
+}
+
+/* === Public entry point === */
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH64_hash_t XXH3_64bits(const void *input, size_t len) {
+
+ return XXH3_64bits_internal(input, len, 0, XXH3_kSecret, sizeof(XXH3_kSecret),
+ XXH3_hashLong_64b_default);
+
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSecret(const void *input,
+ size_t len,
+ const void *secret,
+ size_t secretSize) {
+
+ return XXH3_64bits_internal(input, len, 0, secret, secretSize,
+ XXH3_hashLong_64b_withSecret);
+
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSeed(const void *input, size_t len,
+ XXH64_hash_t seed) {
+
+ return XXH3_64bits_internal(input, len, seed, XXH3_kSecret,
+ sizeof(XXH3_kSecret), XXH3_hashLong_64b_withSeed);
+
+}
+
+/* === XXH3 streaming === */
+
+/*
+ * Malloc's a pointer that is always aligned to align.
+ *
+ * This must be freed with `XXH_alignedFree()`.
+ *
+ * malloc typically guarantees 16 byte alignment on 64-bit systems and 8 byte
+ * alignment on 32-bit. This isn't enough for the 32 byte aligned loads in AVX2
+ * or on 32-bit, the 16 byte aligned loads in SSE2 and NEON.
+ *
+ * This underalignment previously caused a rather obvious crash which went
+ * completely unnoticed due to XXH3_createState() not actually being tested.
+ * Credit to RedSpah for noticing this bug.
+ *
+ * The alignment is done manually: Functions like posix_memalign or _mm_malloc
+ * are avoided: To maintain portability, we would have to write a fallback
+ * like this anyways, and besides, testing for the existence of library
+ * functions without relying on external build tools is impossible.
+ *
+ * The method is simple: Overallocate, manually align, and store the offset
+ * to the original behind the returned pointer.
+ *
+ * Align must be a power of 2 and 8 <= align <= 128.
+ */
+static void *XXH_alignedMalloc(size_t s, size_t align) {
+
+ XXH_ASSERT(align <= 128 && align >= 8); /* range check */
+ XXH_ASSERT((align & (align - 1)) == 0); /* power of 2 */
+ XXH_ASSERT(s != 0 && s < (s + align)); /* empty/overflow */
+ { /* Overallocate to make room for manual realignment and an offset byte */
+ xxh_u8 *base = (xxh_u8 *)XXH_malloc(s + align);
+ if (base != NULL) {
+
+ /*
+ * Get the offset needed to align this pointer.
+ *
+ * Even if the returned pointer is aligned, there will always be
+ * at least one byte to store the offset to the original pointer.
+ */
+ size_t offset = align - ((size_t)base & (align - 1)); /* base % align */
+ /* Add the offset for the now-aligned pointer */
+ xxh_u8 *ptr = base + offset;
+
+ XXH_ASSERT((size_t)ptr % align == 0);
+
+ /* Store the offset immediately before the returned pointer. */
+ ptr[-1] = (xxh_u8)offset;
+ return ptr;
+
+ }
+
+ return NULL;
+
+ }
+
+}
+
+/*
+ * Frees an aligned pointer allocated by XXH_alignedMalloc(). Don't pass
+ * normal malloc'd pointers, XXH_alignedMalloc has a specific data layout.
+ */
+static void XXH_alignedFree(void *p) {
+
+ if (p != NULL) {
+
+ xxh_u8 *ptr = (xxh_u8 *)p;
+ /* Get the offset byte we added in XXH_malloc. */
+ xxh_u8 offset = ptr[-1];
+ /* Free the original malloc'd pointer */
+ xxh_u8 *base = ptr - offset;
+ XXH_free(base);
+
+ }
+
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH3_state_t *XXH3_createState(void) {
+
+ XXH3_state_t *const state =
+ (XXH3_state_t *)XXH_alignedMalloc(sizeof(XXH3_state_t), 64);
+ if (state == NULL) return NULL;
+ XXH3_INITSTATE(state);
+ return state;
+
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t *statePtr) {
+
+ XXH_alignedFree(statePtr);
+ return XXH_OK;
+
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API void XXH3_copyState(XXH3_state_t * dst_state,
+ const XXH3_state_t *src_state) {
+
+ memcpy(dst_state, src_state, sizeof(*dst_state));
+
+}
+
+static void XXH3_reset_internal(XXH3_state_t *statePtr, XXH64_hash_t seed,
+ const void *secret, size_t secretSize) {
+
+ size_t const initStart = offsetof(XXH3_state_t, bufferedSize);
+ size_t const initLength =
+ offsetof(XXH3_state_t, nbStripesPerBlock) - initStart;
+ XXH_ASSERT(offsetof(XXH3_state_t, nbStripesPerBlock) > initStart);
+ XXH_ASSERT(statePtr != NULL);
+ /* set members from bufferedSize to nbStripesPerBlock (excluded) to 0 */
+ memset((char *)statePtr + initStart, 0, initLength);
+ statePtr->acc[0] = XXH_PRIME32_3;
+ statePtr->acc[1] = XXH_PRIME64_1;
+ statePtr->acc[2] = XXH_PRIME64_2;
+ statePtr->acc[3] = XXH_PRIME64_3;
+ statePtr->acc[4] = XXH_PRIME64_4;
+ statePtr->acc[5] = XXH_PRIME32_2;
+ statePtr->acc[6] = XXH_PRIME64_5;
+ statePtr->acc[7] = XXH_PRIME32_1;
+ statePtr->seed = seed;
+ statePtr->extSecret = (const unsigned char *)secret;
+ XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN);
+ statePtr->secretLimit = secretSize - XXH_STRIPE_LEN;
+ statePtr->nbStripesPerBlock = statePtr->secretLimit / XXH_SECRET_CONSUME_RATE;
+
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset(XXH3_state_t *statePtr) {
+
+ if (statePtr == NULL) return XXH_ERROR;
+ XXH3_reset_internal(statePtr, 0, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE);
+ return XXH_OK;
+
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSecret(
+ XXH3_state_t *statePtr, const void *secret, size_t secretSize) {
+
+ if (statePtr == NULL) return XXH_ERROR;
+ XXH3_reset_internal(statePtr, 0, secret, secretSize);
+ if (secret == NULL) return XXH_ERROR;
+ if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR;
+ return XXH_OK;
+
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSeed(XXH3_state_t *statePtr,
+ XXH64_hash_t seed) {
+
+ if (statePtr == NULL) return XXH_ERROR;
+ if (seed == 0) return XXH3_64bits_reset(statePtr);
+ if (seed != statePtr->seed)
+ XXH3_initCustomSecret(statePtr->customSecret, seed);
+ XXH3_reset_internal(statePtr, seed, NULL, XXH_SECRET_DEFAULT_SIZE);
+ return XXH_OK;
+
+}
+
+/* Note : when XXH3_consumeStripes() is invoked,
+ * there must be a guarantee that at least one more byte must be consumed from
+ * input
+ * so that the function can blindly consume all stripes using the "normal"
+ * secret segment */
+XXH_FORCE_INLINE void XXH3_consumeStripes(
+ xxh_u64 *XXH_RESTRICT acc, size_t *XXH_RESTRICT nbStripesSoFarPtr,
+ size_t nbStripesPerBlock, const xxh_u8 *XXH_RESTRICT input,
+ size_t nbStripes, const xxh_u8 *XXH_RESTRICT secret, size_t secretLimit,
+ XXH3_f_accumulate_512 f_acc512, XXH3_f_scrambleAcc f_scramble) {
+
+ XXH_ASSERT(nbStripes <=
+ nbStripesPerBlock); /* can handle max 1 scramble per invocation */
+ XXH_ASSERT(*nbStripesSoFarPtr < nbStripesPerBlock);
+ if (nbStripesPerBlock - *nbStripesSoFarPtr <= nbStripes) {
+
+ /* need a scrambling operation */
+ size_t const nbStripesToEndofBlock = nbStripesPerBlock - *nbStripesSoFarPtr;
+ size_t const nbStripesAfterBlock = nbStripes - nbStripesToEndofBlock;
+ XXH3_accumulate(acc, input,
+ secret + nbStripesSoFarPtr[0] * XXH_SECRET_CONSUME_RATE,
+ nbStripesToEndofBlock, f_acc512);
+ f_scramble(acc, secret + secretLimit);
+ XXH3_accumulate(acc, input + nbStripesToEndofBlock * XXH_STRIPE_LEN, secret,
+ nbStripesAfterBlock, f_acc512);
+ *nbStripesSoFarPtr = nbStripesAfterBlock;
+
+ } else {
+
+ XXH3_accumulate(acc, input,
+ secret + nbStripesSoFarPtr[0] * XXH_SECRET_CONSUME_RATE,
+ nbStripes, f_acc512);
+ *nbStripesSoFarPtr += nbStripes;
+
+ }
+
+}
+
+/*
+ * Both XXH3_64bits_update and XXH3_128bits_update use this routine.
+ */
+XXH_FORCE_INLINE XXH_errorcode XXH3_update(XXH3_state_t *state,
+ const xxh_u8 *input, size_t len,
+ XXH3_f_accumulate_512 f_acc512,
+ XXH3_f_scrambleAcc f_scramble) {
+
+ if (input == NULL)
+ #if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && \
+ (XXH_ACCEPT_NULL_INPUT_POINTER >= 1)
+ return XXH_OK;
+ #else
+ return XXH_ERROR;
+ #endif
+
+ {
+
+ const xxh_u8 *const bEnd = input + len;
+ const unsigned char *const secret =
+ (state->extSecret == NULL) ? state->customSecret : state->extSecret;
+
+ state->totalLen += len;
+ XXH_ASSERT(state->bufferedSize <= XXH3_INTERNALBUFFER_SIZE);
+
+ if (state->bufferedSize + len <=
+ XXH3_INTERNALBUFFER_SIZE) { /* fill in tmp buffer */
+ XXH_memcpy(state->buffer + state->bufferedSize, input, len);
+ state->bufferedSize += (XXH32_hash_t)len;
+ return XXH_OK;
+
+ }
+
+ /* total input is now > XXH3_INTERNALBUFFER_SIZE */
+
+ #define XXH3_INTERNALBUFFER_STRIPES \
+ (XXH3_INTERNALBUFFER_SIZE / XXH_STRIPE_LEN)
+ XXH_STATIC_ASSERT(XXH3_INTERNALBUFFER_SIZE % XXH_STRIPE_LEN ==
+ 0); /* clean multiple */
+
+ /*
+ * Internal buffer is partially filled (always, except at beginning)
+ * Complete it, then consume it.
+ */
+ if (state->bufferedSize) {
+
+ size_t const loadSize = XXH3_INTERNALBUFFER_SIZE - state->bufferedSize;
+ XXH_memcpy(state->buffer + state->bufferedSize, input, loadSize);
+ input += loadSize;
+ XXH3_consumeStripes(state->acc, &state->nbStripesSoFar,
+ state->nbStripesPerBlock, state->buffer,
+ XXH3_INTERNALBUFFER_STRIPES, secret,
+ state->secretLimit, f_acc512, f_scramble);
+ state->bufferedSize = 0;
+
+ }
+
+ XXH_ASSERT(input < bEnd);
+
+ /* Consume input by a multiple of internal buffer size */
+ if (bEnd - input > XXH3_INTERNALBUFFER_SIZE) {
+
+ const xxh_u8 *const limit = bEnd - XXH3_INTERNALBUFFER_SIZE;
+ do {
+
+ XXH3_consumeStripes(state->acc, &state->nbStripesSoFar,
+ state->nbStripesPerBlock, input,
+ XXH3_INTERNALBUFFER_STRIPES, secret,
+ state->secretLimit, f_acc512, f_scramble);
+ input += XXH3_INTERNALBUFFER_SIZE;
+
+ } while (input < limit);
+
+ /* for last partial stripe */
+ memcpy(state->buffer + sizeof(state->buffer) - XXH_STRIPE_LEN,
+ input - XXH_STRIPE_LEN, XXH_STRIPE_LEN);
+
+ }
+
+ XXH_ASSERT(input < bEnd);
+
+ /* Some remaining input (always) : buffer it */
+ XXH_memcpy(state->buffer, input, (size_t)(bEnd - input));
+ state->bufferedSize = (XXH32_hash_t)(bEnd - input);
+
+ }
+
+ return XXH_OK;
+
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH_errorcode XXH3_64bits_update(XXH3_state_t *state,
+ const void *input, size_t len) {
+
+ return XXH3_update(state, (const xxh_u8 *)input, len, XXH3_accumulate_512,
+ XXH3_scrambleAcc);
+
+}
+
+XXH_FORCE_INLINE void XXH3_digest_long(XXH64_hash_t * acc,
+ const XXH3_state_t * state,
+ const unsigned char *secret) {
+
+ /*
+ * Digest on a local copy. This way, the state remains unaltered, and it can
+ * continue ingesting more input afterwards.
+ */
+ memcpy(acc, state->acc, sizeof(state->acc));
+ if (state->bufferedSize >= XXH_STRIPE_LEN) {
+
+ size_t const nbStripes = (state->bufferedSize - 1) / XXH_STRIPE_LEN;
+ size_t nbStripesSoFar = state->nbStripesSoFar;
+ XXH3_consumeStripes(acc, &nbStripesSoFar, state->nbStripesPerBlock,
+ state->buffer, nbStripes, secret, state->secretLimit,
+ XXH3_accumulate_512, XXH3_scrambleAcc);
+ /* last stripe */
+ XXH3_accumulate_512(acc,
+ state->buffer + state->bufferedSize - XXH_STRIPE_LEN,
+ secret + state->secretLimit - XXH_SECRET_LASTACC_START);
+
+ } else { /* bufferedSize < XXH_STRIPE_LEN */
+
+ xxh_u8 lastStripe[XXH_STRIPE_LEN];
+ size_t const catchupSize = XXH_STRIPE_LEN - state->bufferedSize;
+ XXH_ASSERT(state->bufferedSize >
+ 0); /* there is always some input buffered */
+ memcpy(lastStripe, state->buffer + sizeof(state->buffer) - catchupSize,
+ catchupSize);
+ memcpy(lastStripe + catchupSize, state->buffer, state->bufferedSize);
+ XXH3_accumulate_512(acc, lastStripe,
+ secret + state->secretLimit - XXH_SECRET_LASTACC_START);
+
+ }
+
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest(const XXH3_state_t *state) {
+
+ const unsigned char *const secret =
+ (state->extSecret == NULL) ? state->customSecret : state->extSecret;
+ if (state->totalLen > XXH3_MIDSIZE_MAX) {
+
+ XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB];
+ XXH3_digest_long(acc, state, secret);
+ return XXH3_mergeAccs(acc, secret + XXH_SECRET_MERGEACCS_START,
+ (xxh_u64)state->totalLen * XXH_PRIME64_1);
+
+ }
+
+ /* totalLen <= XXH3_MIDSIZE_MAX: digesting a short input */
+ if (state->seed)
+ return XXH3_64bits_withSeed(state->buffer, (size_t)state->totalLen,
+ state->seed);
+ return XXH3_64bits_withSecret(state->buffer, (size_t)(state->totalLen),
+ secret, state->secretLimit + XXH_STRIPE_LEN);
+
+}
+
+ #define XXH_MIN(x, y) (((x) > (y)) ? (y) : (x))
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API void XXH3_generateSecret(void * secretBuffer,
+ const void *customSeed,
+ size_t customSeedSize) {
+
+ XXH_ASSERT(secretBuffer != NULL);
+ if (customSeedSize == 0) {
+
+ memcpy(secretBuffer, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE);
+ return;
+
+ }
+
+ XXH_ASSERT(customSeed != NULL);
+
+ {
+
+ size_t const segmentSize = sizeof(XXH128_hash_t);
+ size_t const nbSegments = XXH_SECRET_DEFAULT_SIZE / segmentSize;
+ XXH128_canonical_t scrambler;
+ XXH64_hash_t seeds[12];
+ size_t segnb;
+ XXH_ASSERT(nbSegments == 12);
+ XXH_ASSERT(segmentSize * nbSegments ==
+ XXH_SECRET_DEFAULT_SIZE); /* exact multiple */
+ XXH128_canonicalFromHash(&scrambler, XXH128(customSeed, customSeedSize, 0));
+
+ /*
+ * Copy customSeed to seeds[], truncating or repeating as necessary.
+ */
+ {
+
+ size_t toFill = XXH_MIN(customSeedSize, sizeof(seeds));
+ size_t filled = toFill;
+ memcpy(seeds, customSeed, toFill);
+ while (filled < sizeof(seeds)) {
+
+ toFill = XXH_MIN(filled, sizeof(seeds) - filled);
+ memcpy((char *)seeds + filled, seeds, toFill);
+ filled += toFill;
+
+ }
+
+ }
+
+ /* generate secret */
+ memcpy(secretBuffer, &scrambler, sizeof(scrambler));
+ for (segnb = 1; segnb < nbSegments; segnb++) {
+
+ size_t const segmentStart = segnb * segmentSize;
+ XXH128_canonical_t segment;
+ XXH128_canonicalFromHash(&segment,
+ XXH128(&scrambler, sizeof(scrambler),
+ XXH_readLE64(seeds + segnb) + segnb));
+ memcpy((char *)secretBuffer + segmentStart, &segment, sizeof(segment));
+
+ }
+
+ }
+
+}
+
+/* ==========================================
+ * XXH3 128 bits (a.k.a XXH128)
+ * ==========================================
+ * XXH3's 128-bit variant has better mixing and strength than the 64-bit
+ * variant, even without counting the significantly larger output size.
+ *
+ * For example, extra steps are taken to avoid the seed-dependent collisions
+ * in 17-240 byte inputs (See XXH3_mix16B and XXH128_mix32B).
+ *
+ * This strength naturally comes at the cost of some speed, especially on short
+ * lengths. Note that longer hashes are about as fast as the 64-bit version
+ * due to it using only a slight modification of the 64-bit loop.
+ *
+ * XXH128 is also more oriented towards 64-bit machines. It is still extremely
+ * fast for a _128-bit_ hash on 32-bit (it usually clears XXH64).
+ */
+
+XXH_FORCE_INLINE XXH128_hash_t XXH3_len_1to3_128b(const xxh_u8 *input,
+ size_t len,
+ const xxh_u8 *secret,
+ XXH64_hash_t seed) {
+
+ /* A doubled version of 1to3_64b with different constants. */
+ XXH_ASSERT(input != NULL);
+ XXH_ASSERT(1 <= len && len <= 3);
+ XXH_ASSERT(secret != NULL);
+ /*
+ * len = 1: combinedl = { input[0], 0x01, input[0], input[0] }
+ * len = 2: combinedl = { input[1], 0x02, input[0], input[1] }
+ * len = 3: combinedl = { input[2], 0x03, input[0], input[1] }
+ */
+ {
+
+ xxh_u8 const c1 = input[0];
+ xxh_u8 const c2 = input[len >> 1];
+ xxh_u8 const c3 = input[len - 1];
+ xxh_u32 const combinedl = ((xxh_u32)c1 << 16) | ((xxh_u32)c2 << 24) |
+ ((xxh_u32)c3 << 0) | ((xxh_u32)len << 8);
+ xxh_u32 const combinedh = XXH_rotl32(XXH_swap32(combinedl), 13);
+ xxh_u64 const bitflipl =
+ (XXH_readLE32(secret) ^ XXH_readLE32(secret + 4)) + seed;
+ xxh_u64 const bitfliph =
+ (XXH_readLE32(secret + 8) ^ XXH_readLE32(secret + 12)) - seed;
+ xxh_u64 const keyed_lo = (xxh_u64)combinedl ^ bitflipl;
+ xxh_u64 const keyed_hi = (xxh_u64)combinedh ^ bitfliph;
+ XXH128_hash_t h128;
+ h128.low64 = XXH64_avalanche(keyed_lo);
+ h128.high64 = XXH64_avalanche(keyed_hi);
+ return h128;
+
+ }
+
+}
+
+XXH_FORCE_INLINE XXH128_hash_t XXH3_len_4to8_128b(const xxh_u8 *input,
+ size_t len,
+ const xxh_u8 *secret,
+ XXH64_hash_t seed) {
+
+ XXH_ASSERT(input != NULL);
+ XXH_ASSERT(secret != NULL);
+ XXH_ASSERT(4 <= len && len <= 8);
+ seed ^= (xxh_u64)XXH_swap32((xxh_u32)seed) << 32;
+ {
+
+ xxh_u32 const input_lo = XXH_readLE32(input);
+ xxh_u32 const input_hi = XXH_readLE32(input + len - 4);
+ xxh_u64 const input_64 = input_lo + ((xxh_u64)input_hi << 32);
+ xxh_u64 const bitflip =
+ (XXH_readLE64(secret + 16) ^ XXH_readLE64(secret + 24)) + seed;
+ xxh_u64 const keyed = input_64 ^ bitflip;
+
+ /* Shift len to the left to ensure it is even, this avoids even multiplies.
+ */
+ XXH128_hash_t m128 = XXH_mult64to128(keyed, XXH_PRIME64_1 + (len << 2));
+
+ m128.high64 += (m128.low64 << 1);
+ m128.low64 ^= (m128.high64 >> 3);
+
+ m128.low64 = XXH_xorshift64(m128.low64, 35);
+ m128.low64 *= 0x9FB21C651E98DF25ULL;
+ m128.low64 = XXH_xorshift64(m128.low64, 28);
+ m128.high64 = XXH3_avalanche(m128.high64);
+ return m128;
+
+ }
+
+}
+
+XXH_FORCE_INLINE XXH128_hash_t XXH3_len_9to16_128b(const xxh_u8 *input,
+ size_t len,
+ const xxh_u8 *secret,
+ XXH64_hash_t seed) {
+
+ XXH_ASSERT(input != NULL);
+ XXH_ASSERT(secret != NULL);
+ XXH_ASSERT(9 <= len && len <= 16);
+ {
+
+ xxh_u64 const bitflipl =
+ (XXH_readLE64(secret + 32) ^ XXH_readLE64(secret + 40)) - seed;
+ xxh_u64 const bitfliph =
+ (XXH_readLE64(secret + 48) ^ XXH_readLE64(secret + 56)) + seed;
+ xxh_u64 const input_lo = XXH_readLE64(input);
+ xxh_u64 input_hi = XXH_readLE64(input + len - 8);
+ XXH128_hash_t m128 =
+ XXH_mult64to128(input_lo ^ input_hi ^ bitflipl, XXH_PRIME64_1);
+ /*
+ * Put len in the middle of m128 to ensure that the length gets mixed to
+ * both the low and high bits in the 128x64 multiply below.
+ */
+ m128.low64 += (xxh_u64)(len - 1) << 54;
+ input_hi ^= bitfliph;
+ /*
+ * Add the high 32 bits of input_hi to the high 32 bits of m128, then
+ * add the long product of the low 32 bits of input_hi and XXH_PRIME32_2 to
+ * the high 64 bits of m128.
+ *
+ * The best approach to this operation is different on 32-bit and 64-bit.
+ */
+ if (sizeof(void *) < sizeof(xxh_u64)) { /* 32-bit */
+ /*
+ * 32-bit optimized version, which is more readable.
+ *
+ * On 32-bit, it removes an ADC and delays a dependency between the two
+ * halves of m128.high64, but it generates an extra mask on 64-bit.
+ */
+ m128.high64 += (input_hi & 0xFFFFFFFF00000000ULL) +
+ XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2);
+
+ } else {
+
+ /*
+ * 64-bit optimized (albeit more confusing) version.
+ *
+ * Uses some properties of addition and multiplication to remove the mask:
+ *
+ * Let:
+ * a = input_hi.lo = (input_hi & 0x00000000FFFFFFFF)
+ * b = input_hi.hi = (input_hi & 0xFFFFFFFF00000000)
+ * c = XXH_PRIME32_2
+ *
+ * a + (b * c)
+ * Inverse Property: x + y - x == y
+ * a + (b * (1 + c - 1))
+ * Distributive Property: x * (y + z) == (x * y) + (x * z)
+ * a + (b * 1) + (b * (c - 1))
+ * Identity Property: x * 1 == x
+ * a + b + (b * (c - 1))
+ *
+ * Substitute a, b, and c:
+ * input_hi.hi + input_hi.lo + ((xxh_u64)input_hi.lo * (XXH_PRIME32_2 -
+ * 1))
+ *
+ * Since input_hi.hi + input_hi.lo == input_hi, we get this:
+ * input_hi + ((xxh_u64)input_hi.lo * (XXH_PRIME32_2 - 1))
+ */
+ m128.high64 +=
+ input_hi + XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2 - 1);
+
+ }
+
+ /* m128 ^= XXH_swap64(m128 >> 64); */
+ m128.low64 ^= XXH_swap64(m128.high64);
+
+ { /* 128x64 multiply: h128 = m128 * XXH_PRIME64_2; */
+ XXH128_hash_t h128 = XXH_mult64to128(m128.low64, XXH_PRIME64_2);
+ h128.high64 += m128.high64 * XXH_PRIME64_2;
+
+ h128.low64 = XXH3_avalanche(h128.low64);
+ h128.high64 = XXH3_avalanche(h128.high64);
+ return h128;
+
+ }
+
+ }
+
+}
+
+/*
+ * Assumption: `secret` size is >= XXH3_SECRET_SIZE_MIN
+ */
+XXH_FORCE_INLINE XXH128_hash_t XXH3_len_0to16_128b(const xxh_u8 *input,
+ size_t len,
+ const xxh_u8 *secret,
+ XXH64_hash_t seed) {
+
+ XXH_ASSERT(len <= 16);
+ {
+
+ if (len > 8) return XXH3_len_9to16_128b(input, len, secret, seed);
+ if (len >= 4) return XXH3_len_4to8_128b(input, len, secret, seed);
+ if (len) return XXH3_len_1to3_128b(input, len, secret, seed);
+ {
+
+ XXH128_hash_t h128;
+ xxh_u64 const bitflipl =
+ XXH_readLE64(secret + 64) ^ XXH_readLE64(secret + 72);
+ xxh_u64 const bitfliph =
+ XXH_readLE64(secret + 80) ^ XXH_readLE64(secret + 88);
+ h128.low64 = XXH64_avalanche(seed ^ bitflipl);
+ h128.high64 = XXH64_avalanche(seed ^ bitfliph);
+ return h128;
+
+ }
+
+ }
+
+}
+
+/*
+ * A bit slower than XXH3_mix16B, but handles multiply by zero better.
+ */
+XXH_FORCE_INLINE XXH128_hash_t XXH128_mix32B(XXH128_hash_t acc,
+ const xxh_u8 *input_1,
+ const xxh_u8 *input_2,
+ const xxh_u8 *secret,
+ XXH64_hash_t seed) {
+
+ acc.low64 += XXH3_mix16B(input_1, secret + 0, seed);
+ acc.low64 ^= XXH_readLE64(input_2) + XXH_readLE64(input_2 + 8);
+ acc.high64 += XXH3_mix16B(input_2, secret + 16, seed);
+ acc.high64 ^= XXH_readLE64(input_1) + XXH_readLE64(input_1 + 8);
+ return acc;
+
+}
+
+XXH_FORCE_INLINE XXH128_hash_t XXH3_len_17to128_128b(
+ const xxh_u8 *XXH_RESTRICT input, size_t len,
+ const xxh_u8 *XXH_RESTRICT secret, size_t secretSize, XXH64_hash_t seed) {
+
+ XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN);
+ (void)secretSize;
+ XXH_ASSERT(16 < len && len <= 128);
+
+ {
+
+ XXH128_hash_t acc;
+ acc.low64 = len * XXH_PRIME64_1;
+ acc.high64 = 0;
+ if (len > 32) {
+
+ if (len > 64) {
+
+ if (len > 96) {
+
+ acc = XXH128_mix32B(acc, input + 48, input + len - 64, secret + 96,
+ seed);
+
+ }
+
+ acc =
+ XXH128_mix32B(acc, input + 32, input + len - 48, secret + 64, seed);
+
+ }
+
+ acc = XXH128_mix32B(acc, input + 16, input + len - 32, secret + 32, seed);
+
+ }
+
+ acc = XXH128_mix32B(acc, input, input + len - 16, secret, seed);
+ {
+
+ XXH128_hash_t h128;
+ h128.low64 = acc.low64 + acc.high64;
+ h128.high64 = (acc.low64 * XXH_PRIME64_1) + (acc.high64 * XXH_PRIME64_4) +
+ ((len - seed) * XXH_PRIME64_2);
+ h128.low64 = XXH3_avalanche(h128.low64);
+ h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64);
+ return h128;
+
+ }
+
+ }
+
+}
+
+XXH_NO_INLINE XXH128_hash_t XXH3_len_129to240_128b(
+ const xxh_u8 *XXH_RESTRICT input, size_t len,
+ const xxh_u8 *XXH_RESTRICT secret, size_t secretSize, XXH64_hash_t seed) {
+
+ XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN);
+ (void)secretSize;
+ XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX);
+
+ {
+
+ XXH128_hash_t acc;
+ int const nbRounds = (int)len / 32;
+ int i;
+ acc.low64 = len * XXH_PRIME64_1;
+ acc.high64 = 0;
+ for (i = 0; i < 4; i++) {
+
+ acc = XXH128_mix32B(acc, input + (32 * i), input + (32 * i) + 16,
+ secret + (32 * i), seed);
+
+ }
+
+ acc.low64 = XXH3_avalanche(acc.low64);
+ acc.high64 = XXH3_avalanche(acc.high64);
+ XXH_ASSERT(nbRounds >= 4);
+ for (i = 4; i < nbRounds; i++) {
+
+ acc = XXH128_mix32B(acc, input + (32 * i), input + (32 * i) + 16,
+ secret + XXH3_MIDSIZE_STARTOFFSET + (32 * (i - 4)),
+ seed);
+
+ }
+
+ /* last bytes */
+ acc = XXH128_mix32B(
+ acc, input + len - 16, input + len - 32,
+ secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET - 16,
+ 0ULL - seed);
+
+ {
+
+ XXH128_hash_t h128;
+ h128.low64 = acc.low64 + acc.high64;
+ h128.high64 = (acc.low64 * XXH_PRIME64_1) + (acc.high64 * XXH_PRIME64_4) +
+ ((len - seed) * XXH_PRIME64_2);
+ h128.low64 = XXH3_avalanche(h128.low64);
+ h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64);
+ return h128;
+
+ }
+
+ }
+
+}
+
+XXH_FORCE_INLINE XXH128_hash_t XXH3_hashLong_128b_internal(
+ const void *XXH_RESTRICT input, size_t len,
+ const xxh_u8 *XXH_RESTRICT secret, size_t secretSize,
+ XXH3_f_accumulate_512 f_acc512, XXH3_f_scrambleAcc f_scramble) {
+
+ XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC;
+
+ XXH3_hashLong_internal_loop(acc, (const xxh_u8 *)input, len, secret,
+ secretSize, f_acc512, f_scramble);
+
+ /* converge into final hash */
+ XXH_STATIC_ASSERT(sizeof(acc) == 64);
+ XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START);
+ {
+
+ XXH128_hash_t h128;
+ h128.low64 = XXH3_mergeAccs(acc, secret + XXH_SECRET_MERGEACCS_START,
+ (xxh_u64)len * XXH_PRIME64_1);
+ h128.high64 = XXH3_mergeAccs(
+ acc, secret + secretSize - sizeof(acc) - XXH_SECRET_MERGEACCS_START,
+ ~((xxh_u64)len * XXH_PRIME64_2));
+ return h128;
+
+ }
+
+}
+
+/*
+ * It's important for performance that XXH3_hashLong is not inlined.
+ */
+XXH_NO_INLINE XXH128_hash_t XXH3_hashLong_128b_default(
+ const void *XXH_RESTRICT input, size_t len, XXH64_hash_t seed64,
+ const void *XXH_RESTRICT secret, size_t secretLen) {
+
+ (void)seed64;
+ (void)secret;
+ (void)secretLen;
+ return XXH3_hashLong_128b_internal(input, len, XXH3_kSecret,
+ sizeof(XXH3_kSecret), XXH3_accumulate_512,
+ XXH3_scrambleAcc);
+
+}
+
+/*
+ * It's important for performance that XXH3_hashLong is not inlined.
+ */
+XXH_NO_INLINE XXH128_hash_t XXH3_hashLong_128b_withSecret(
+ const void *XXH_RESTRICT input, size_t len, XXH64_hash_t seed64,
+ const void *XXH_RESTRICT secret, size_t secretLen) {
+
+ (void)seed64;
+ return XXH3_hashLong_128b_internal(input, len, (const xxh_u8 *)secret,
+ secretLen, XXH3_accumulate_512,
+ XXH3_scrambleAcc);
+
+}
+
+XXH_FORCE_INLINE XXH128_hash_t XXH3_hashLong_128b_withSeed_internal(
+ const void *XXH_RESTRICT input, size_t len, XXH64_hash_t seed64,
+ XXH3_f_accumulate_512 f_acc512, XXH3_f_scrambleAcc f_scramble,
+ XXH3_f_initCustomSecret f_initSec) {
+
+ if (seed64 == 0)
+ return XXH3_hashLong_128b_internal(
+ input, len, XXH3_kSecret, sizeof(XXH3_kSecret), f_acc512, f_scramble);
+ {
+
+ XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE];
+ f_initSec(secret, seed64);
+ return XXH3_hashLong_128b_internal(input, len, (const xxh_u8 *)secret,
+ sizeof(secret), f_acc512, f_scramble);
+
+ }
+
+}
+
+/*
+ * It's important for performance that XXH3_hashLong is not inlined.
+ */
+XXH_NO_INLINE XXH128_hash_t
+XXH3_hashLong_128b_withSeed(const void *input, size_t len, XXH64_hash_t seed64,
+ const void *XXH_RESTRICT secret, size_t secretLen) {
+
+ (void)secret;
+ (void)secretLen;
+ return XXH3_hashLong_128b_withSeed_internal(
+ input, len, seed64, XXH3_accumulate_512, XXH3_scrambleAcc,
+ XXH3_initCustomSecret);
+
+}
+
+typedef XXH128_hash_t (*XXH3_hashLong128_f)(const void *XXH_RESTRICT, size_t,
+ XXH64_hash_t,
+ const void *XXH_RESTRICT, size_t);
+
+XXH_FORCE_INLINE XXH128_hash_t
+XXH3_128bits_internal(const void *input, size_t len, XXH64_hash_t seed64,
+ const void *XXH_RESTRICT secret, size_t secretLen,
+ XXH3_hashLong128_f f_hl128) {
+
+ XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN);
+ /*
+ * If an action is to be taken if `secret` conditions are not respected,
+ * it should be done here.
+ * For now, it's a contract pre-condition.
+ * Adding a check and a branch here would cost performance at every hash.
+ */
+ if (len <= 16)
+ return XXH3_len_0to16_128b((const xxh_u8 *)input, len,
+ (const xxh_u8 *)secret, seed64);
+ if (len <= 128)
+ return XXH3_len_17to128_128b((const xxh_u8 *)input, len,
+ (const xxh_u8 *)secret, secretLen, seed64);
+ if (len <= XXH3_MIDSIZE_MAX)
+ return XXH3_len_129to240_128b((const xxh_u8 *)input, len,
+ (const xxh_u8 *)secret, secretLen, seed64);
+ return f_hl128(input, len, seed64, secret, secretLen);
+
+}
+
+/* === Public XXH128 API === */
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH128_hash_t XXH3_128bits(const void *input, size_t len) {
+
+ return XXH3_128bits_internal(input, len, 0, XXH3_kSecret,
+ sizeof(XXH3_kSecret),
+ XXH3_hashLong_128b_default);
+
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSecret(const void *input,
+ size_t len,
+ const void *secret,
+ size_t secretSize) {
+
+ return XXH3_128bits_internal(input, len, 0, (const xxh_u8 *)secret,
+ secretSize, XXH3_hashLong_128b_withSecret);
+
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSeed(const void * input,
+ size_t len,
+ XXH64_hash_t seed) {
+
+ return XXH3_128bits_internal(input, len, seed, XXH3_kSecret,
+ sizeof(XXH3_kSecret),
+ XXH3_hashLong_128b_withSeed);
+
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH128_hash_t XXH128(const void *input, size_t len,
+ XXH64_hash_t seed) {
+
+ return XXH3_128bits_withSeed(input, len, seed);
+
+}
+
+/* === XXH3 128-bit streaming === */
+
+/*
+ * All the functions are actually the same as for 64-bit streaming variant.
+ * The only difference is the finalization routine.
+ */
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset(XXH3_state_t *statePtr) {
+
+ if (statePtr == NULL) return XXH_ERROR;
+ XXH3_reset_internal(statePtr, 0, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE);
+ return XXH_OK;
+
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecret(
+ XXH3_state_t *statePtr, const void *secret, size_t secretSize) {
+
+ if (statePtr == NULL) return XXH_ERROR;
+ XXH3_reset_internal(statePtr, 0, secret, secretSize);
+ if (secret == NULL) return XXH_ERROR;
+ if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR;
+ return XXH_OK;
+
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSeed(XXH3_state_t *statePtr,
+ XXH64_hash_t seed) {
+
+ if (statePtr == NULL) return XXH_ERROR;
+ if (seed == 0) return XXH3_128bits_reset(statePtr);
+ if (seed != statePtr->seed)
+ XXH3_initCustomSecret(statePtr->customSecret, seed);
+ XXH3_reset_internal(statePtr, seed, NULL, XXH_SECRET_DEFAULT_SIZE);
+ return XXH_OK;
+
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH_errorcode XXH3_128bits_update(XXH3_state_t *state,
+ const void * input,
+ size_t len) {
+
+ return XXH3_update(state, (const xxh_u8 *)input, len, XXH3_accumulate_512,
+ XXH3_scrambleAcc);
+
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest(const XXH3_state_t *state) {
+
+ const unsigned char *const secret =
+ (state->extSecret == NULL) ? state->customSecret : state->extSecret;
+ if (state->totalLen > XXH3_MIDSIZE_MAX) {
+
+ XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB];
+ XXH3_digest_long(acc, state, secret);
+ XXH_ASSERT(state->secretLimit + XXH_STRIPE_LEN >=
+ sizeof(acc) + XXH_SECRET_MERGEACCS_START);
+ {
+
+ XXH128_hash_t h128;
+ h128.low64 = XXH3_mergeAccs(acc, secret + XXH_SECRET_MERGEACCS_START,
+ (xxh_u64)state->totalLen * XXH_PRIME64_1);
+ h128.high64 =
+ XXH3_mergeAccs(acc,
+ secret + state->secretLimit + XXH_STRIPE_LEN -
+ sizeof(acc) - XXH_SECRET_MERGEACCS_START,
+ ~((xxh_u64)state->totalLen * XXH_PRIME64_2));
+ return h128;
+
+ }
+
+ }
+
+ /* len <= XXH3_MIDSIZE_MAX : short code */
+ if (state->seed)
+ return XXH3_128bits_withSeed(state->buffer, (size_t)state->totalLen,
+ state->seed);
+ return XXH3_128bits_withSecret(state->buffer, (size_t)(state->totalLen),
+ secret, state->secretLimit + XXH_STRIPE_LEN);
+
+}
+
+ /* 128-bit utility functions */
+
+ #include <string.h> /* memcmp, memcpy */
+
+/* return : 1 is equal, 0 if different */
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2) {
+
+ /* note : XXH128_hash_t is compact, it has no padding byte */
+ return !(memcmp(&h1, &h2, sizeof(h1)));
+
+}
+
+/* This prototype is compatible with stdlib's qsort().
+ * return : >0 if *h128_1 > *h128_2
+ * <0 if *h128_1 < *h128_2
+ * =0 if *h128_1 == *h128_2 */
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API int XXH128_cmp(const void *h128_1, const void *h128_2) {
+
+ XXH128_hash_t const h1 = *(const XXH128_hash_t *)h128_1;
+ XXH128_hash_t const h2 = *(const XXH128_hash_t *)h128_2;
+ int const hcmp = (h1.high64 > h2.high64) - (h2.high64 > h1.high64);
+ /* note : bets that, in most cases, hash values are different */
+ if (hcmp) return hcmp;
+ return (h1.low64 > h2.low64) - (h2.low64 > h1.low64);
+
+}
+
+/*====== Canonical representation ======*/
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API void XXH128_canonicalFromHash(XXH128_canonical_t *dst,
+ XXH128_hash_t hash) {
+
+ XXH_STATIC_ASSERT(sizeof(XXH128_canonical_t) == sizeof(XXH128_hash_t));
+ if (XXH_CPU_LITTLE_ENDIAN) {
+
+ hash.high64 = XXH_swap64(hash.high64);
+ hash.low64 = XXH_swap64(hash.low64);
+
+ }
+
+ memcpy(dst, &hash.high64, sizeof(hash.high64));
+ memcpy((char *)dst + sizeof(hash.high64), &hash.low64, sizeof(hash.low64));
+
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH128_hash_t
+XXH128_hashFromCanonical(const XXH128_canonical_t *src) {
+
+ XXH128_hash_t h;
+ h.high64 = XXH_readBE64(src);
+ h.low64 = XXH_readBE64(src->digest + 8);
+ return h;
+
+}
+
+ /* Pop our optimization override from above */
+ #if XXH_VECTOR == XXH_AVX2 /* AVX2 */ \
+ && defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \
+ && defined(__OPTIMIZE__) && \
+ !defined(__OPTIMIZE_SIZE__) /* respect -O0 and -Os */
+ #pragma GCC pop_options
+ #endif
+
+ #endif /* XXH_NO_LONG_LONG */
+
+ #endif /* XXH_NO_XXH3 */
+
+/*!
+ * @}
+ */
+#endif /* XXH_IMPLEMENTATION */
+
+#if defined(__cplusplus)
+
+}
+
+#endif
+
diff --git a/instrumentation/Makefile b/instrumentation/Makefile
new file mode 100644
index 00000000..6cdd1a07
--- /dev/null
+++ b/instrumentation/Makefile
@@ -0,0 +1,2 @@
+all:
+ @echo "no need to do make in the instrumentation/ directory :) - it is all done in the main one"
diff --git a/instrumentation/README.cmplog.md b/instrumentation/README.cmplog.md
new file mode 100644
index 00000000..8a9fd372
--- /dev/null
+++ b/instrumentation/README.cmplog.md
@@ -0,0 +1,44 @@
+# CmpLog instrumentation
+
+The CmpLog instrumentation enables logging of comparison operands in a shared
+memory.
+
+These values can be used by various mutators built on top of it. At the moment,
+we support the Redqueen mutator (input-2-state instructions only), for details
+see [the Redqueen paper](https://github.com/RUB-SysSec/redqueen).
+
+## Build
+
+To use CmpLog, you have to build two versions of the instrumented target
+program:
+
+* The first version is built using the regular AFL++ instrumentation.
+* The second one, the CmpLog binary, is built with setting `AFL_LLVM_CMPLOG`
+ during the compilation.
+
+For example:
+
+```
+./configure --cc=~/path/to/afl-clang-fast
+make
+cp ./program ./program.afl
+make clean
+export AFL_LLVM_CMPLOG=1
+./configure --cc=~/path/to/afl-clang-fast
+make
+cp ./program ./program.cmplog
+unset AFL_LLVM_CMPLOG
+```
+
+## Use
+
+AFL++ has the new `-c` option that needs to be used to specify the CmpLog binary
+(the second build).
+
+For example:
+
+```
+afl-fuzz -i input -o output -c ./program.cmplog -m none -- ./program.afl @@
+```
+
+Be careful with the usage of `-m` because CmpLog can map a lot of pages.
diff --git a/instrumentation/README.gcc_plugin.md b/instrumentation/README.gcc_plugin.md
new file mode 100644
index 00000000..ed39af9d
--- /dev/null
+++ b/instrumentation/README.gcc_plugin.md
@@ -0,0 +1,102 @@
+# GCC-based instrumentation for afl-fuzz
+
+For the general instruction manual, see [docs/README.md](../docs/README.md).
+
+For the LLVM-based instrumentation, see [README.llvm.md](README.llvm.md).
+
+This document describes how to build and use `afl-gcc-fast` and `afl-g++-fast`,
+which instrument the target with the help of gcc plugins.
+
+TL;DR:
+* Check the version of your gcc compiler: `gcc --version`
+* `apt-get install gcc-VERSION-plugin-dev` or similar to install headers for gcc
+ plugins.
+* `gcc` and `g++` must match the gcc-VERSION you installed headers for. You can
+ set `AFL_CC`/`AFL_CXX` to point to these!
+* `make`
+* Just use `afl-gcc-fast`/`afl-g++-fast` normally like you would do with
+ `afl-clang-fast`.
+
+## 1) Introduction
+
+The code in this directory allows to instrument programs for AFL++ using true
+compiler-level instrumentation, instead of the more crude assembly-level
+rewriting approach taken by afl-gcc and afl-clang. This has several interesting
+properties:
+
+- The compiler can make many optimizations that are hard to pull off when
+ manually inserting assembly. As a result, some slow, CPU-bound programs will
+ run up to around faster.
+
+ The gains are less pronounced for fast binaries, where the speed is limited
+ chiefly by the cost of creating new processes. In such cases, the gain will
+ probably stay within 10%.
+
+- The instrumentation is CPU-independent. At least in principle, you should be
+ able to rely on it to fuzz programs on non-x86 architectures (after building
+ `afl-fuzz` with `AFL_NOX86=1`).
+
+- Because the feature relies on the internals of GCC, it is gcc-specific and
+ will *not* work with LLVM (see [README.llvm.md](README.llvm.md) for an
+ alternative).
+
+Once this implementation is shown to be sufficiently robust and portable, it
+will probably replace afl-gcc. For now, it can be built separately and co-exists
+with the original code.
+
+The idea and much of the implementation comes from Laszlo Szekeres.
+
+## 2) How to use
+
+In order to leverage this mechanism, you need to have modern enough GCC (>=
+version 4.5.0) and the plugin development headers installed on your system. That
+should be all you need. On Debian machines, these headers can be acquired by
+installing the `gcc-VERSION-plugin-dev` packages.
+
+To build the instrumentation itself, type `make`. This will generate binaries
+called `afl-gcc-fast` and `afl-g++-fast` in the parent directory.
+
+The gcc and g++ compiler links have to point to gcc-VERSION - or set these by
+pointing the environment variables `AFL_CC`/`AFL_CXX` to them. If the `CC`/`CXX`
+environment variables have been set, those compilers will be preferred over
+those from the `AFL_CC`/`AFL_CXX` settings.
+
+Once this is done, you can instrument third-party code in a way similar to the
+standard operating mode of AFL++, e.g.:
+
+```
+ CC=/path/to/afl/afl-gcc-fast
+ CXX=/path/to/afl/afl-g++-fast
+ export CC CXX
+ ./configure [...options...]
+ make
+```
+
+Note: We also used `CXX` to set the C++ compiler to `afl-g++-fast` for C++ code.
+
+The tool honors roughly the same environmental variables as `afl-gcc` (see
+[docs/env_variables.md](../docs/env_variables.md). This includes
+`AFL_INST_RATIO`, `AFL_USE_ASAN`, `AFL_HARDEN`, and `AFL_DONT_OPTIMIZE`.
+
+Note: if you want the GCC plugin to be installed on your system for all users,
+you need to build it before issuing 'make install' in the parent directory.
+
+## 3) Gotchas, feedback, bugs
+
+This is an early-stage mechanism, so field reports are welcome. You can send bug
+reports to afl@aflplus.plus.
+
+## 4) Bonus feature #1: deferred initialization
+
+See
+[README.persistent_mode.md#3) Deferred initialization](README.persistent_mode.md#3-deferred-initialization).
+
+## 5) Bonus feature #2: persistent mode
+
+See
+[README.persistent_mode.md#4) Persistent mode](README.persistent_mode.md#4-persistent-mode).
+
+## 6) Bonus feature #3: selective instrumentation
+
+It can be more effective to fuzzing to only instrument parts of the code. For
+details, see [README.instrument_list.md](README.instrument_list.md). \ No newline at end of file
diff --git a/instrumentation/README.instrument_list.md b/instrumentation/README.instrument_list.md
new file mode 100644
index 00000000..3ed64807
--- /dev/null
+++ b/instrumentation/README.instrument_list.md
@@ -0,0 +1,131 @@
+# Using AFL++ with partial instrumentation
+
+This file describes two different mechanisms to selectively instrument only
+specific parts in the target.
+
+Both mechanisms work for LLVM and GCC_PLUGIN, but not for afl-clang/afl-gcc.
+
+## 1) Description and purpose
+
+When building and testing complex programs where only a part of the program is
+the fuzzing target, it often helps to only instrument the necessary parts of the
+program, leaving the rest uninstrumented. This helps to focus the fuzzer on the
+important parts of the program, avoiding undesired noise and disturbance by
+uninteresting code being exercised.
+
+For this purpose, "partial instrumentation" support is provided by AFL++ that
+allows to specify what should be instrumented and what not.
+
+Both mechanisms for partial instrumentation can be used together.
+
+## 2) Selective instrumentation with __AFL_COVERAGE_... directives
+
+In this mechanism, the selective instrumentation is done in the source code.
+
+After the includes, a special define has to be made, e.g.:
+
+```
+#include <stdio.h>
+#include <stdint.h>
+// ...
+
+__AFL_COVERAGE(); // <- required for this feature to work
+```
+
+If you want to disable the coverage at startup until you specify coverage should
+be started, then add `__AFL_COVERAGE_START_OFF();` at that position.
+
+From here on out, you have the following macros available that you can use in
+any function where you want:
+
+* `__AFL_COVERAGE_ON();` - Enable coverage from this point onwards.
+* `__AFL_COVERAGE_OFF();` - Disable coverage from this point onwards.
+* `__AFL_COVERAGE_DISCARD();` - Reset all coverage gathered until this point.
+* `__AFL_COVERAGE_SKIP();` - Mark this test case as unimportant. Whatever
+ happens, afl-fuzz will ignore it.
+
+A special function is `__afl_coverage_interesting`. To use this, you must define
+`void __afl_coverage_interesting(u8 val, u32 id);`. Then you can use this
+function globally, where the `val` parameter can be set by you, the `id`
+parameter is for afl-fuzz and will be overwritten. Note that useful parameters
+for `val` are: 1, 2, 3, 4, 8, 16, 32, 64, 128. A value of, e.g., 33 will be seen
+as 32 for coverage purposes.
+
+## 3) Selective instrumentation with AFL_LLVM_ALLOWLIST/AFL_LLVM_DENYLIST
+
+This feature is equivalent to llvm 12 sancov feature and allows to specify on a
+filename and/or function name level to instrument these or skip them.
+
+### 3a) How to use the partial instrumentation mode
+
+In order to build with partial instrumentation, you need to build with
+afl-clang-fast/afl-clang-fast++ or afl-clang-lto/afl-clang-lto++. 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 should contain the file names or functions that are to be instrumented
+(`AFL_LLVM_ALLOWLIST`) or are specifically NOT to be instrumented
+(`AFL_LLVM_DENYLIST`).
+
+GCC_PLUGIN: you can use either `AFL_LLVM_ALLOWLIST` or `AFL_GCC_ALLOWLIST` (or
+the same for `_DENYLIST`), both work.
+
+For matching to succeed, the function/file name that is being compiled must end
+in the function/file name entry contained in this instrument file list. That is
+to avoid breaking the match when absolute paths are used during compilation.
+
+**NOTE:** In builds with optimization enabled, functions might be inlined and
+would not match!
+
+For example, if your source tree looks like this:
+
+```
+project/
+project/feature_a/a1.cpp
+project/feature_a/a2.cpp
+project/feature_b/b1.cpp
+project/feature_b/b2.cpp
+```
+
+And you only want to test feature_a, then create an "instrument file list" file
+containing:
+
+```
+feature_a/a1.cpp
+feature_a/a2.cpp
+```
+
+However, if the "instrument file list" file contains only this, it works as
+well:
+
+```
+a1.cpp
+a2.cpp
+```
+
+But it might lead to files being unwantedly instrumented if the same filename
+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! `nm` can print these names.
+
+AFL++ is able to identify whether 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:
+
+```
+src: *malloc.c
+```
+
+And function entries like this:
+
+```
+fun: MallocFoo
+```
+
+Note that whitespace is ignored and comments (`# foo`) are supported.
+
+### 3b) UNIX-style pattern matching
+
+You can add UNIX-style pattern matching in the "instrument file list" entries.
+See `man fnmatch` for the syntax. Do not set any of the `fnmatch` flags. \ No newline at end of file
diff --git a/instrumentation/README.laf-intel.md b/instrumentation/README.laf-intel.md
new file mode 100644
index 00000000..414be060
--- /dev/null
+++ b/instrumentation/README.laf-intel.md
@@ -0,0 +1,49 @@
+# laf-intel instrumentation
+
+## Introduction
+
+This originally is the work of an individual nicknamed laf-intel. His blog
+[Circumventing Fuzzing Roadblocks with Compiler Transformations](https://lafintel.wordpress.com/)
+and GitLab repo [laf-llvm-pass](https://gitlab.com/laf-intel/laf-llvm-pass/)
+describe some code transformations that help AFL++ to enter conditional blocks,
+where conditions consist of comparisons of large values.
+
+## Usage
+
+By default, these passes will not run when you compile programs using
+afl-clang-fast. Hence, you can use AFL++ as usual. To enable the passes, you
+must set environment variables before you compile the target project.
+
+The following options exist:
+
+`export AFL_LLVM_LAF_SPLIT_SWITCHES=1`
+
+Enables the split-switches pass.
+
+`export AFL_LLVM_LAF_TRANSFORM_COMPARES=1`
+
+Enables the transform-compares pass (strcmp, memcmp, strncmp, strcasecmp,
+strncasecmp).
+
+`export AFL_LLVM_LAF_SPLIT_COMPARES=1`
+
+Enables the split-compares pass. By default, it will
+1. simplify operators >= (and <=) into chains of > (<) and == comparisons
+2. change signed integer comparisons to a chain of sign-only comparison and
+ unsigned integer comparisons
+3. split all unsigned integer comparisons with bit widths of 64, 32, or 16 bits
+ to chains of 8 bits comparisons.
+
+You can change the behavior of the last step by setting `export
+AFL_LLVM_LAF_SPLIT_COMPARES_BITW=<bit_width>`, where bit_width may be 64, 32, or
+16. For example, a bit_width of 16 would split larger comparisons down to 16 bit
+comparisons.
+
+A new unique feature is splitting floating point comparisons into a series
+of sign, exponent and mantissa comparisons followed by splitting each of them
+into 8 bit comparisons when necessary. It is activated with the
+`AFL_LLVM_LAF_SPLIT_FLOATS` setting.
+
+Note that setting this automatically activates `AFL_LLVM_LAF_SPLIT_COMPARES`.
+
+You can also set `AFL_LLVM_LAF_ALL` and have all of the above enabled. :-)
diff --git a/instrumentation/README.llvm.md b/instrumentation/README.llvm.md
new file mode 100644
index 00000000..7855a987
--- /dev/null
+++ b/instrumentation/README.llvm.md
@@ -0,0 +1,278 @@
+# Fast LLVM-based instrumentation for afl-fuzz
+
+For the general instruction manual, see [docs/README.md](../docs/README.md).
+
+For the GCC-based instrumentation, see
+[README.gcc_plugin.md](README.gcc_plugin.md).
+
+## 1) Introduction
+
+! llvm_mode works with llvm versions 3.8 up to 13 !
+
+The code in this directory allows you to instrument programs for AFL++ using
+true compiler-level instrumentation, instead of the more crude assembly-level
+rewriting approach taken by afl-gcc and afl-clang. This has several interesting
+properties:
+
+- The compiler can make many optimizations that are hard to pull off when
+ manually inserting assembly. As a result, some slow, CPU-bound programs will
+ run up to around 2x faster.
+
+ The gains are less pronounced for fast binaries, where the speed is limited
+ chiefly by the cost of creating new processes. In such cases, the gain will
+ probably stay within 10%.
+
+- The instrumentation is CPU-independent. At least in principle, you should be
+ able to rely on it to fuzz programs on non-x86 architectures (after building
+ afl-fuzz with AFL_NO_X86=1).
+
+- The instrumentation can cope a bit better with multi-threaded targets.
+
+- Because the feature relies on the internals of LLVM, it is clang-specific and
+ will *not* work with GCC (see ../gcc_plugin/ for an alternative once it is
+ available).
+
+Once this implementation is shown to be sufficiently robust and portable, it
+will probably replace afl-clang. For now, it can be built separately and
+co-exists with the original code.
+
+The idea and much of the initial implementation came from Laszlo Szekeres.
+
+## 2a) How to use this - short
+
+Set the `LLVM_CONFIG` variable to the clang version you want to use, e.g.:
+
+```
+LLVM_CONFIG=llvm-config-9 make
+```
+
+In case you have your own compiled llvm version specify the full path:
+
+```
+LLVM_CONFIG=~/llvm-project/build/bin/llvm-config make
+```
+
+If you try to use a new llvm version on an old Linux this can fail because of
+old c++ libraries. In this case usually switching to gcc/g++ to compile
+llvm_mode will work:
+
+```
+LLVM_CONFIG=llvm-config-7 REAL_CC=gcc REAL_CXX=g++ make
+```
+
+It is highly recommended to use the newest clang version you can put your hands
+on :)
+
+Then look at [README.persistent_mode.md](README.persistent_mode.md).
+
+## 2b) How to use this - long
+
+In order to leverage this mechanism, you need to have clang installed on your
+system. You should also make sure that the llvm-config tool is in your path (or
+pointed to via LLVM_CONFIG in the environment).
+
+Note that if you have several LLVM versions installed, pointing LLVM_CONFIG to
+the version you want to use will switch compiling to this specific version - if
+you installation is set up correctly :-)
+
+Unfortunately, some systems that do have clang come without llvm-config or the
+LLVM development headers; one example of this is FreeBSD. FreeBSD users will
+also run into problems with clang being built statically and not being able to
+load modules (you'll see "Service unavailable" when loading afl-llvm-pass.so).
+
+To solve all your problems, you can grab pre-built binaries for your OS from:
+
+[https://llvm.org/releases/download.html](https://llvm.org/releases/download.html)
+
+...and then put the bin/ directory from the tarball at the beginning of your
+$PATH when compiling the feature and building packages later on. You don't need
+to be root for that.
+
+To build the instrumentation itself, type `make`. This will generate binaries
+called afl-clang-fast and afl-clang-fast++ in the parent directory. Once this is
+done, you can instrument third-party code in a way similar to the standard
+operating mode of AFL, e.g.:
+
+```
+ CC=/path/to/afl/afl-clang-fast ./configure [...options...]
+ make
+```
+
+Be sure to also include CXX set to afl-clang-fast++ for C++ code.
+
+Note that afl-clang-fast/afl-clang-fast++ are just pointers to afl-cc. You can
+also use afl-cc/afl-c++ and instead direct it to use LLVM instrumentation by
+either setting `AFL_CC_COMPILER=LLVM` or pass the parameter `--afl-llvm` via
+CFLAGS/CXXFLAGS/CPPFLAGS.
+
+The tool honors roughly the same environmental variables as afl-gcc (see
+[docs/env_variables.md](../docs/env_variables.md)). This includes
+`AFL_USE_ASAN`, `AFL_HARDEN`, and `AFL_DONT_OPTIMIZE`. However, `AFL_INST_RATIO`
+is not honored as it does not serve a good purpose with the more effective
+PCGUARD analysis.
+
+## 3) Options
+
+Several options are present to make llvm_mode faster or help it rearrange the
+code to make afl-fuzz path discovery easier.
+
+If you need just to instrument specific parts of the code, you can the
+instrument file list which C/C++ files to actually instrument. See
+[README.instrument_list.md](README.instrument_list.md)
+
+For splitting memcmp, strncmp, etc., see
+[README.laf-intel.md](README.laf-intel.md).
+
+Then there are different ways of instrumenting the target:
+
+1. A better instrumentation strategy uses LTO and link time instrumentation.
+ Note that not all targets can compile in this mode, however, if it works it
+ is the best option you can use. To go with this option, use
+ afl-clang-lto/afl-clang-lto++. See [README.lto.md](README.lto.md).
+
+2. Alternatively you can choose a completely different coverage method:
+
+2a. N-GRAM coverage - which combines the previous visited edges with the current
+ one. This explodes the map but on the other hand has proven to be effective
+ for fuzzing. See
+ [7) AFL++ N-Gram Branch Coverage](#7-afl-n-gram-branch-coverage).
+
+2b. Context sensitive coverage - which combines the visited edges with an
+ individual caller ID (the function that called the current one). See
+ [6) AFL++ Context Sensitive Branch Coverage](#6-afl-context-sensitive-branch-coverage).
+
+Then - additionally to one of the instrumentation options above - there is a
+very effective new instrumentation option called CmpLog as an alternative to
+laf-intel that allow AFL++ to apply mutations similar to Redqueen. See
+[README.cmplog.md](README.cmplog.md).
+
+Finally, if your llvm version is 8 or lower, you can activate a mode that
+prevents that a counter overflow result in a 0 value. This is good for path
+discovery, but the llvm implementation for x86 for this functionality is not
+optimal and was only fixed in llvm 9. You can set this with AFL_LLVM_NOT_ZERO=1.
+
+Support for thread safe counters has been added for all modes. Activate it with
+`AFL_LLVM_THREADSAFE_INST=1`. The tradeoff is better precision in multi threaded
+apps for a slightly higher instrumentation overhead. This also disables the
+nozero counter default for performance reasons.
+
+## 4) deferred initialization, persistent mode, shared memory fuzzing
+
+This is the most powerful and effective fuzzing you can do. For a full
+explanation, see [README.persistent_mode.md](README.persistent_mode.md).
+
+## 5) Bonus feature: 'dict2file' pass
+
+Just specify `AFL_LLVM_DICT2FILE=/absolute/path/file.txt` and during compilation
+all constant string compare parameters will be written to this file to be used
+with afl-fuzz' `-x` option.
+
+## 6) AFL++ Context Sensitive Branch Coverage
+
+### What is this?
+
+This is an LLVM-based implementation of the context sensitive branch coverage.
+
+Basically every function gets its own ID and, every time when an edge is logged,
+all the IDs in the callstack are hashed and combined with the edge transition
+hash to augment the classic edge coverage with the information about the calling
+context.
+
+So if both function A and function B call a function C, the coverage collected
+in C will be different.
+
+In math the coverage is collected as follows: `map[current_location_ID ^
+previous_location_ID >> 1 ^ hash_callstack_IDs] += 1`
+
+The callstack hash is produced XOR-ing the function IDs to avoid explosion with
+recursive functions.
+
+### Usage
+
+Set the `AFL_LLVM_INSTRUMENT=CTX` or `AFL_LLVM_CTX=1` environment variable.
+
+It is highly recommended to increase the MAP_SIZE_POW2 definition in config.h to
+at least 18 and maybe up to 20 for this as otherwise too many map collisions
+occur.
+
+### Caller Branch Coverage
+
+If the context sensitive coverage introduces too may collisions and becoming
+detrimental, the user can choose to augment edge coverage with just the called
+function ID, instead of the entire callstack hash.
+
+In math the coverage is collected as follows: `map[current_location_ID ^
+previous_location_ID >> 1 ^ previous_callee_ID] += 1`
+
+Set the `AFL_LLVM_INSTRUMENT=CALLER` or `AFL_LLVM_CALLER=1` environment
+variable.
+
+## 7) AFL++ N-Gram Branch Coverage
+
+### Source
+
+This is an LLVM-based implementation of the n-gram branch coverage proposed in
+the paper
+["Be Sensitive and Collaborative: Analyzing Impact of Coverage Metrics in Greybox Fuzzing"](https://www.usenix.org/system/files/raid2019-wang-jinghan.pdf)
+by Jinghan Wang, et. al.
+
+Note that the original implementation (available
+[here](https://github.com/bitsecurerlab/afl-sensitive)) is built on top of AFL's
+QEMU mode. This is essentially a port that uses LLVM vectorized instructions
+(available from llvm versions 4.0.1 and higher) to achieve the same results when
+compiling source code.
+
+In math the branch coverage is performed as follows: `map[current_location ^
+prev_location[0] >> 1 ^ prev_location[1] >> 1 ^ ... up to n-1`] += 1`
+
+### Usage
+
+The size of `n` (i.e., the number of branches to remember) is an option that is
+specified either in the `AFL_LLVM_INSTRUMENT=NGRAM-{value}` or the
+`AFL_LLVM_NGRAM_SIZE` environment variable. Good values are 2, 4, or 8, valid
+are 2-16.
+
+It is highly recommended to increase the MAP_SIZE_POW2 definition in config.h to
+at least 18 and maybe up to 20 for this as otherwise too many map collisions
+occur.
+
+## 8) NeverZero counters
+
+In larger, complex, or reiterative programs, the byte sized counters that
+collect the edge coverage can easily fill up and wrap around. This is not that
+much of an issue - unless, by chance, it wraps just to a value of zero when the
+program execution ends. In this case, afl-fuzz is not able to see that the edge
+has been accessed and will ignore it.
+
+NeverZero prevents this behavior. If a counter wraps, it jumps over the value 0
+directly to a 1. This improves path discovery (by a very small amount) at a very
+low cost (one instruction per edge).
+
+(The alternative of saturated counters has been tested also and proved to be
+inferior in terms of path discovery.)
+
+This is implemented in afl-gcc and afl-gcc-fast, however, for llvm_mode this is
+optional if multithread safe counters are selected or the llvm version is below
+9 - as there are severe performance costs in these cases.
+
+If you want to enable this for llvm versions below 9 or thread safe counters,
+then set
+
+```
+export AFL_LLVM_NOT_ZERO=1
+```
+
+In case you are on llvm 9 or greater and you do not want this behavior, then you
+can set:
+
+```
+AFL_LLVM_SKIP_NEVERZERO=1
+```
+
+If the target does not have extensive loops or functions that are called a lot,
+then this can give a small performance boost.
+
+Please note that the default counter implementations are not thread safe!
+
+Support for thread safe counters in mode LLVM CLASSIC can be activated with
+setting `AFL_LLVM_THREADSAFE_INST=1`. \ No newline at end of file
diff --git a/instrumentation/README.lto.md b/instrumentation/README.lto.md
new file mode 100644
index 00000000..a20175b1
--- /dev/null
+++ b/instrumentation/README.lto.md
@@ -0,0 +1,364 @@
+# afl-clang-lto - collision free instrumentation at link time
+
+## TL;DR:
+
+This version requires a current llvm 11+ compiled from the GitHub master.
+
+1. Use afl-clang-lto/afl-clang-lto++ because it is faster and gives better
+ coverage than anything else that is out there in the AFL world.
+
+2. You can use it together with llvm_mode: laf-intel and the instrument file
+ listing features and can be combined with cmplog/Redqueen.
+
+3. It only works with llvm 11+.
+
+4. AUTODICTIONARY feature (see below)!
+
+5. If any problems arise, be sure to set `AR=llvm-ar RANLIB=llvm-ranlib`. Some
+ targets might need `LD=afl-clang-lto` and others `LD=afl-ld-lto`.
+
+## Introduction and problem description
+
+A big issue with how AFL++ works is that the basic block IDs that are set during
+compilation are random - and hence naturally the larger the number of
+instrumented locations, the higher the number of edge collisions are in the map.
+This can result in not discovering new paths and therefore degrade the
+efficiency of the fuzzing process.
+
+*This issue is underestimated in the fuzzing community!* With a 2^16 = 64kb
+standard map at already 256 instrumented blocks, there is on average one
+collision. On average, a target has 10.000 to 50.000 instrumented blocks, hence
+the real collisions are between 750-18.000!
+
+To reach a solution that prevents any collisions took several approaches and
+many dead ends until we got to this:
+
+* We instrument at link time when we have all files pre-compiled.
+* To instrument at link time, we compile in LTO (link time optimization) mode.
+* Our compiler (afl-clang-lto/afl-clang-lto++) takes care of setting the correct
+ LTO options and runs our own afl-ld linker instead of the system linker.
+* The LLVM linker collects all LTO files to link and instruments them so that we
+ have non-colliding edge overage.
+* We use a new (for afl) edge coverage - which is the same as in llvm
+ -fsanitize=coverage edge coverage mode. :)
+
+The result:
+
+* 10-25% speed gain compared to llvm_mode
+* guaranteed non-colliding edge coverage :-)
+* The compile time, especially for binaries to an instrumented library, can be
+ much longer.
+
+Example build output from a libtiff build:
+
+```
+libtool: link: afl-clang-lto -g -O2 -Wall -W -o thumbnail thumbnail.o ../libtiff/.libs/libtiff.a ../port/.libs/libport.a -llzma -ljbig -ljpeg -lz -lm
+afl-clang-lto++2.63d by Marc "vanHauser" Heuse <mh@mh-sec.de> in mode LTO
+afl-llvm-lto++2.63d by Marc "vanHauser" Heuse <mh@mh-sec.de>
+AUTODICTIONARY: 11 strings found
+[+] Instrumented 12071 locations with no collisions (on average 1046 collisions would be in afl-gcc/afl-clang-fast) (non-hardened mode).
+```
+
+## Getting llvm 11+
+
+### Installing llvm version 11 or 12
+
+llvm 11 or even 12 should be available in all current Linux repositories. If you
+use an outdated Linux distribution, read the next section.
+
+### Installing llvm from the llvm repository (version 12+)
+
+Installing the llvm snapshot builds is easy and mostly painless:
+
+In the following line, change `NAME` for your Debian or Ubuntu release name
+(e.g., buster, focal, eon, etc.):
+
+```
+echo deb http://apt.llvm.org/NAME/ llvm-toolchain-NAME NAME >> /etc/apt/sources.list
+```
+
+Then add the pgp key of llvm and install the packages:
+
+```
+wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
+apt-get update && apt-get upgrade -y
+apt-get install -y clang-12 clang-tools-12 libc++1-12 libc++-12-dev \
+ libc++abi1-12 libc++abi-12-dev libclang1-12 libclang-12-dev \
+ libclang-common-12-dev libclang-cpp12 libclang-cpp12-dev liblld-12 \
+ liblld-12-dev liblldb-12 liblldb-12-dev libllvm12 libomp-12-dev \
+ libomp5-12 lld-12 lldb-12 llvm-12 llvm-12-dev llvm-12-runtime llvm-12-tools
+```
+
+### Building llvm yourself (version 12+)
+
+Building llvm from GitHub takes quite some time and is not painless:
+
+```sh
+sudo apt install binutils-dev # this is *essential*!
+git clone --depth=1 https://github.com/llvm/llvm-project
+cd llvm-project
+mkdir build
+cd build
+
+# Add -G Ninja if ninja-build installed
+# "Building with ninja significantly improves your build time, especially with
+# incremental builds, and improves your memory usage."
+cmake \
+ -DCLANG_INCLUDE_DOCS="OFF" \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DLLVM_BINUTILS_INCDIR=/usr/include/ \
+ -DLLVM_BUILD_LLVM_DYLIB="ON" \
+ -DLLVM_ENABLE_BINDINGS="OFF" \
+ -DLLVM_ENABLE_PROJECTS='clang;compiler-rt;libcxx;libcxxabi;libunwind;lld' \
+ -DLLVM_ENABLE_WARNINGS="OFF" \
+ -DLLVM_INCLUDE_BENCHMARKS="OFF" \
+ -DLLVM_INCLUDE_DOCS="OFF" \
+ -DLLVM_INCLUDE_EXAMPLES="OFF" \
+ -DLLVM_INCLUDE_TESTS="OFF" \
+ -DLLVM_LINK_LLVM_DYLIB="ON" \
+ -DLLVM_TARGETS_TO_BUILD="host" \
+ ../llvm/
+cmake --build . -j4
+export PATH="$(pwd)/bin:$PATH"
+export LLVM_CONFIG="$(pwd)/bin/llvm-config"
+export LD_LIBRARY_PATH="$(llvm-config --libdir)${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
+cd /path/to/AFLplusplus/
+make
+sudo make install
+```
+
+## How to use afl-clang-lto
+
+Just use afl-clang-lto like you did with afl-clang-fast or afl-gcc.
+
+Also, the instrument file listing (AFL_LLVM_ALLOWLIST/AFL_LLVM_DENYLIST ->
+[README.instrument_list.md](README.instrument_list.md)) and laf-intel/compcov
+(AFL_LLVM_LAF_* -> [README.laf-intel.md](README.laf-intel.md)) work.
+
+Example:
+
+```
+CC=afl-clang-lto CXX=afl-clang-lto++ RANLIB=llvm-ranlib AR=llvm-ar ./configure
+make
+```
+
+NOTE: some targets also need to set the linker, try both `afl-clang-lto` and
+`afl-ld-lto` for `LD=` before `configure`.
+
+## Instrumenting shared libraries
+
+Note: this is highly discouraged! Try to compile to static libraries with
+afl-clang-lto instead of shared libraries!
+
+To make instrumented shared libraries work with afl-clang-lto, you have to do
+quite some extra steps.
+
+Every shared library you want to instrument has to be individually compiled. The
+environment variable `AFL_LLVM_LTO_DONTWRITEID=1` has to be set during
+compilation. Additionally, the environment variable `AFL_LLVM_LTO_STARTID` has
+to be set to the added edge count values of all previous compiled instrumented
+shared libraries for that target. E.g., for the first shared library this would
+be `AFL_LLVM_LTO_STARTID=0` and afl-clang-lto will then report how many edges
+have been instrumented (let's say it reported 1000 instrumented edges). The
+second shared library then has to be set to that value
+(`AFL_LLVM_LTO_STARTID=1000` in our example), for the third to all previous
+counts added, etc.
+
+The final program compilation step then may *not* have
+`AFL_LLVM_LTO_DONTWRITEID` set, and `AFL_LLVM_LTO_STARTID` must be set to all
+edge counts added of all shared libraries it will be linked to.
+
+This is quite some hands-on work, so better stay away from instrumenting shared
+libraries. :-)
+
+## AUTODICTIONARY feature
+
+While compiling, a dictionary based on string comparisons is automatically
+generated and put into the target binary. This dictionary is transferred to
+afl-fuzz on start. This improves coverage statistically by 5-10%. :)
+
+Note that if for any reason you do not want to use the autodictionary feature,
+then just set the environment variable `AFL_NO_AUTODICT` when starting afl-fuzz.
+
+## Fixed memory map
+
+To speed up fuzzing a little bit more, it is possible to set a fixed shared
+memory map. Recommended is the value 0x10000.
+
+In most cases, this will work without any problems. However, if a target uses
+early constructors, ifuncs, or a deferred forkserver, this can crash the target.
+
+Also, on unusual operating systems/processors/kernels or weird libraries the
+recommended 0x10000 address might not work, so then change the fixed address.
+
+To enable this feature, set `AFL_LLVM_MAP_ADDR` with the address.
+
+## Document edge IDs
+
+Setting `export AFL_LLVM_DOCUMENT_IDS=file` will document in a file which edge
+ID was given to which function. This helps to identify functions with variable
+bytes or which functions were touched by an input.
+
+## Solving difficult targets
+
+Some targets are difficult because the configure script does unusual stuff that
+is unexpected for afl. See the next section `Potential issues` for how to solve
+these.
+
+### Example: ffmpeg
+
+An example of a hard to solve target is ffmpeg. Here is how to successfully
+instrument it:
+
+1. Get and extract the current ffmpeg and change to its directory.
+
+2. Running configure with --cc=clang fails and various other items will fail
+ when compiling, so we have to trick configure:
+
+ ```
+ ./configure --enable-lto --disable-shared --disable-inline-asm
+ ```
+
+3. Now the configuration is done - and we edit the settings in
+ `./ffbuild/config.mak` (-: the original line, +: what to change it into):
+
+ ```
+ -CC=gcc
+ +CC=afl-clang-lto
+ -CXX=g++
+ +CXX=afl-clang-lto++
+ -AS=gcc
+ +AS=llvm-as
+ -LD=gcc
+ +LD=afl-clang-lto++
+ -DEPCC=gcc
+ +DEPCC=afl-clang-lto
+ -DEPAS=gcc
+ +DEPAS=afl-clang-lto++
+ -AR=ar
+ +AR=llvm-ar
+ -AR_CMD=ar
+ +AR_CMD=llvm-ar
+ -NM_CMD=nm -g
+ +NM_CMD=llvm-nm -g
+ -RANLIB=ranlib -D
+ +RANLIB=llvm-ranlib -D
+ ```
+
+4. Then type make, wait for a long time, and you are done. :)
+
+### Example: WebKit jsc
+
+Building jsc is difficult as the build script has bugs.
+
+1. Checkout Webkit:
+
+ ```
+ svn checkout https://svn.webkit.org/repository/webkit/trunk WebKit
+ cd WebKit
+ ```
+
+2. Fix the build environment:
+
+ ```
+ mkdir -p WebKitBuild/Release
+ cd WebKitBuild/Release
+ ln -s ../../../../../usr/bin/llvm-ar-12 llvm-ar-12
+ ln -s ../../../../../usr/bin/llvm-ranlib-12 llvm-ranlib-12
+ cd ../..
+ ```
+
+3. Build. :)
+
+ ```
+ Tools/Scripts/build-jsc --jsc-only --cli --cmakeargs="-DCMAKE_AR='llvm-ar-12' -DCMAKE_RANLIB='llvm-ranlib-12' -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DCMAKE_CC_FLAGS='-O3 -lrt' -DCMAKE_CXX_FLAGS='-O3 -lrt' -DIMPORTED_LOCATION='/lib/x86_64-linux-gnu/' -DCMAKE_CC=afl-clang-lto -DCMAKE_CXX=afl-clang-lto++ -DENABLE_STATIC_JSC=ON"
+ ```
+
+## Potential issues
+
+### Compiling libraries fails
+
+If you see this message:
+
+```
+/bin/ld: libfoo.a: error adding symbols: archive has no index; run ranlib to add one
+```
+
+This is because usually gnu gcc ranlib is being called which cannot deal with
+clang LTO files. The solution is simple: when you `./configure`, you also have
+to set `RANLIB=llvm-ranlib` and `AR=llvm-ar`.
+
+Solution:
+
+```
+AR=llvm-ar RANLIB=llvm-ranlib CC=afl-clang-lto CXX=afl-clang-lto++ ./configure --disable-shared
+```
+
+And on some targets you have to set `AR=/RANLIB=` even for `make` as the
+configure script does not save it. Other targets ignore environment variables
+and need the parameters set via `./configure --cc=... --cxx= --ranlib= ...` etc.
+(I am looking at you ffmpeg!)
+
+If you see this message:
+
+```
+assembler command failed ...
+```
+
+Then try setting `llvm-as` for configure:
+
+```
+AS=llvm-as ...
+```
+
+### Compiling programs still fail
+
+afl-clang-lto is still work in progress.
+
+Known issues:
+* Anything that llvm 11+ cannot compile, afl-clang-lto cannot compile either -
+ obviously.
+* Anything that does not compile with LTO, afl-clang-lto cannot compile either -
+ obviously.
+
+Hence, if building a target with afl-clang-lto fails, try to build it with
+llvm12 and LTO enabled (`CC=clang-12`, `CXX=clang++-12`, `CFLAGS=-flto=full`,
+and `CXXFLAGS=-flto=full`).
+
+If this succeeds, then there is an issue with afl-clang-lto. Please report at
+[https://github.com/AFLplusplus/AFLplusplus/issues/226](https://github.com/AFLplusplus/AFLplusplus/issues/226).
+
+Even some targets where clang-12 fails can be built if the fail is just in
+`./configure`, see `Solving difficult targets` above.
+
+## History
+
+This was originally envisioned by hexcoder- in Summer 2019. However, we saw no
+way to create a pass that is run at link time - although there is a option for
+this in the PassManager: EP_FullLinkTimeOptimizationLast. ("Fun" info - nobody
+knows what this is doing. And the developer who implemented this didn't respond
+to emails.)
+
+In December then came the idea to implement this as a pass that is run via the
+llvm "opt" program, which is performed via an own linker that afterwards calls
+the real linker. This was first implemented in January and work ... kinda. The
+LTO time instrumentation worked, however, "how" the basic blocks were
+instrumented was a problem, as reducing duplicates turned out to be very, very
+difficult with a program that has so many paths and therefore so many
+dependencies. A lot of strategies were implemented - and failed. And then sat
+solvers were tried, but with over 10.000 variables that turned out to be a
+dead-end too.
+
+The final idea to solve this came from domenukk who proposed to insert a block
+into an edge and then just use incremental counters ... and this worked! After
+some trials and errors to implement this vanhauser-thc found out that there is
+actually an llvm function for this: SplitEdge() :-)
+
+Still more problems came up though as this only works without bugs from llvm 9
+onwards, and with high optimization the link optimization ruins the instrumented
+control flow graph.
+
+This is all now fixed with llvm 11+. The llvm's own linker is now able to load
+passes and this bypasses all problems we had.
+
+Happy end :) \ No newline at end of file
diff --git a/instrumentation/README.persistent_mode.md b/instrumentation/README.persistent_mode.md
new file mode 100644
index 00000000..14e59f4a
--- /dev/null
+++ b/instrumentation/README.persistent_mode.md
@@ -0,0 +1,198 @@
+# llvm_mode persistent mode
+
+## 1) Introduction
+
+In persistent mode, AFL++ fuzzes a target multiple times in a single forked
+process, instead of forking a new process for each fuzz execution. This is the
+most effective way to fuzz, as the speed can easily be x10 or x20 times faster
+without any disadvantages. *All professional fuzzing uses this mode.*
+
+Persistent mode requires that the target can be called in one or more functions,
+and that it's state can be completely reset so that multiple calls can be
+performed without resource leaks, and that earlier runs will have no impact on
+future runs. An indicator for this is the `stability` value in the `afl-fuzz`
+UI. If this decreases to lower values in persistent mode compared to
+non-persistent mode, then the fuzz target keeps state.
+
+Examples can be found in [utils/persistent_mode](../utils/persistent_mode).
+
+## 2) TL;DR:
+
+Example `fuzz_target.c`:
+
+```c
+#include "what_you_need_for_your_target.h"
+
+__AFL_FUZZ_INIT();
+
+main() {
+
+ // anything else here, e.g. command line arguments, initialization, etc.
+
+#ifdef __AFL_HAVE_MANUAL_CONTROL
+ __AFL_INIT();
+#endif
+
+ unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF; // must be after __AFL_INIT
+ // and before __AFL_LOOP!
+
+ while (__AFL_LOOP(10000)) {
+
+ int len = __AFL_FUZZ_TESTCASE_LEN; // don't use the macro directly in a
+ // call!
+
+ if (len < 8) continue; // check for a required/useful minimum input length
+
+ /* Setup function call, e.g. struct target *tmp = libtarget_init() */
+ /* Call function to be fuzzed, e.g.: */
+ target_function(buf, len);
+ /* Reset state. e.g. libtarget_free(tmp) */
+
+ }
+
+ return 0;
+
+}
+```
+
+And then compile:
+
+```
+afl-clang-fast -o fuzz_target fuzz_target.c -lwhat_you_need_for_your_target
+```
+
+And that is it! The speed increase is usually x10 to x20.
+
+If you want to be able to compile the target without afl-clang-fast/lto, then
+add this just after the includes:
+
+```c
+#ifndef __AFL_FUZZ_TESTCASE_LEN
+ ssize_t fuzz_len;
+ #define __AFL_FUZZ_TESTCASE_LEN fuzz_len
+ unsigned char fuzz_buf[1024000];
+ #define __AFL_FUZZ_TESTCASE_BUF fuzz_buf
+ #define __AFL_FUZZ_INIT() void sync(void);
+ #define __AFL_LOOP(x) ((fuzz_len = read(0, fuzz_buf, sizeof(fuzz_buf))) > 0 ? 1 : 0)
+ #define __AFL_INIT() sync()
+#endif
+```
+
+## 3) Deferred initialization
+
+AFL++ tries to optimize performance by executing the targeted binary just once,
+stopping it just before `main()`, and then cloning this "main" process to get a
+steady supply of targets to fuzz.
+
+Although this approach eliminates much of the OS-, linker- and libc-level costs
+of executing the program, it does not always help with binaries that perform
+other time-consuming initialization steps - say, parsing a large config file
+before getting to the fuzzed data.
+
+In such cases, it's beneficial to initialize the forkserver a bit later, once
+most of the initialization work is already done, but before the binary attempts
+to read the fuzzed input and parse it; in some cases, this can offer a 10x+
+performance gain. You can implement delayed initialization in LLVM mode in a
+fairly simple way.
+
+First, find a suitable location in the code where the delayed cloning can take
+place. This needs to be done with *extreme* care to avoid breaking the binary.
+In particular, the program will probably malfunction if you select a location
+after:
+
+- The creation of any vital threads or child processes - since the forkserver
+ can't clone them easily.
+
+- The initialization of timers via `setitimer()` or equivalent calls.
+
+- The creation of temporary files, network sockets, offset-sensitive file
+ descriptors, and similar shared-state resources - but only provided that their
+ state meaningfully influences the behavior of the program later on.
+
+- Any access to the fuzzed input, including reading the metadata about its size.
+
+With the location selected, add this code in the appropriate spot:
+
+```c
+#ifdef __AFL_HAVE_MANUAL_CONTROL
+ __AFL_INIT();
+#endif
+```
+
+You don't need the #ifdef guards, but including them ensures that the program
+will keep working normally when compiled with a tool other than afl-clang-fast/
+afl-clang-lto/afl-gcc-fast.
+
+Finally, recompile the program with afl-clang-fast/afl-clang-lto/afl-gcc-fast
+(afl-gcc or afl-clang will *not* generate a deferred-initialization binary) -
+and you should be all set!
+
+## 4) Persistent mode
+
+Some libraries provide APIs that are stateless, or whose state can be reset in
+between processing different input files. When such a reset is performed, a
+single long-lived process can be reused to try out multiple test cases,
+eliminating the need for repeated `fork()` calls and the associated OS overhead.
+
+The basic structure of the program that does this would be:
+
+```c
+ while (__AFL_LOOP(1000)) {
+
+ /* Read input data. */
+ /* Call library code to be fuzzed. */
+ /* Reset state. */
+
+ }
+
+ /* Exit normally. */
+```
+
+The numerical value specified within the loop controls the maximum number of
+iterations before AFL++ will restart the process from scratch. This minimizes
+the impact of memory leaks and similar glitches; 1000 is a good starting point,
+and going much higher increases the likelihood of hiccups without giving you any
+real performance benefits.
+
+A more detailed template is shown in
+[utils/persistent_mode](../utils/persistent_mode). Similarly to the deferred
+initialization, the feature works only with afl-clang-fast; `#ifdef` guards can
+be used to suppress it when using other compilers.
+
+Note that as with the deferred initialization, the feature is easy to misuse; if
+you do not fully reset the critical state, you may end up with false positives
+or waste a whole lot of CPU power doing nothing useful at all. Be particularly
+wary of memory leaks and of the state of file descriptors.
+
+When running in this mode, the execution paths will inherently vary a bit
+depending on whether the input loop is being entered for the first time or
+executed again.
+
+## 5) Shared memory fuzzing
+
+You can speed up the fuzzing process even more by receiving the fuzzing data via
+shared memory instead of stdin or files. This is a further speed multiplier of
+about 2x.
+
+Setting this up is very easy:
+
+After the includes set the following macro:
+
+```c
+__AFL_FUZZ_INIT();
+```
+
+Directly at the start of main - or if you are using the deferred forkserver with
+`__AFL_INIT()`, then *after* `__AFL_INIT()`:
+
+```c
+ unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF;
+```
+
+Then as first line after the `__AFL_LOOP` while loop:
+
+```c
+ int len = __AFL_FUZZ_TESTCASE_LEN;
+```
+
+And that is all! \ No newline at end of file
diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc
new file mode 100644
index 00000000..9a48ae6d
--- /dev/null
+++ b/instrumentation/SanitizerCoverageLTO.so.cc
@@ -0,0 +1,1791 @@
+/* SanitizeCoverage.cpp ported to afl++ LTO :-) */
+
+#define AFL_LLVM_PASS
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <list>
+#include <string>
+#include <fstream>
+#include <set>
+#include <iostream>
+
+#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Analysis/EHPersonalities.h"
+#include "llvm/Analysis/PostDominators.h"
+#include "llvm/Analysis/ValueTracking.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/CFG.h"
+#include "llvm/IR/Constant.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DebugInfo.h"
+#include "llvm/IR/Dominators.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/InlineAsm.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/MDBuilder.h"
+#include "llvm/IR/Mangler.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Type.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/SpecialCaseList.h"
+#include "llvm/Support/VirtualFileSystem.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Transforms/Instrumentation.h"
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
+#include "llvm/Passes/PassPlugin.h"
+#include "llvm/Passes/PassBuilder.h"
+#include "llvm/IR/PassManager.h"
+
+#include "config.h"
+#include "debug.h"
+#include "afl-llvm-common.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "sancov"
+
+const char SanCovTracePCIndirName[] = "__sanitizer_cov_trace_pc_indir";
+const char SanCovTracePCName[] = "__sanitizer_cov_trace_pc";
+// const char SanCovTracePCGuardName =
+// "__sanitizer_cov_trace_pc_guard";
+const char SanCovGuardsSectionName[] = "sancov_guards";
+const char SanCovCountersSectionName[] = "sancov_cntrs";
+const char SanCovBoolFlagSectionName[] = "sancov_bools";
+const char SanCovPCsSectionName[] = "sancov_pcs";
+
+static cl::opt<int> ClCoverageLevel(
+ "lto-coverage-level",
+ cl::desc("Sanitizer Coverage. 0: none, 1: entry block, 2: all blocks, "
+ "3: all blocks and critical edges"),
+ cl::Hidden, cl::init(3));
+
+static cl::opt<bool> ClTracePC("lto-coverage-trace-pc",
+ cl::desc("Experimental pc tracing"), cl::Hidden,
+ cl::init(false));
+
+static cl::opt<bool> ClTracePCGuard("lto-coverage-trace-pc-guard",
+ cl::desc("pc tracing with a guard"),
+ cl::Hidden, cl::init(false));
+
+// If true, we create a global variable that contains PCs of all instrumented
+// BBs, put this global into a named section, and pass this section's bounds
+// to __sanitizer_cov_pcs_init.
+// This way the coverage instrumentation does not need to acquire the PCs
+// at run-time. Works with trace-pc-guard, inline-8bit-counters, and
+// inline-bool-flag.
+static cl::opt<bool> ClCreatePCTable("lto-coverage-pc-table",
+ cl::desc("create a static PC table"),
+ cl::Hidden, cl::init(false));
+
+static cl::opt<bool> ClInline8bitCounters(
+ "lto-coverage-inline-8bit-counters",
+ cl::desc("increments 8-bit counter for every edge"), cl::Hidden,
+ cl::init(false));
+
+static cl::opt<bool> ClInlineBoolFlag(
+ "lto-coverage-inline-bool-flag",
+ cl::desc("sets a boolean flag for every edge"), cl::Hidden,
+ cl::init(false));
+
+static cl::opt<bool> ClPruneBlocks(
+ "lto-coverage-prune-blocks",
+ cl::desc("Reduce the number of instrumented blocks"), cl::Hidden,
+ cl::init(true));
+
+namespace {
+
+SanitizerCoverageOptions getOptions(int LegacyCoverageLevel) {
+
+ SanitizerCoverageOptions Res;
+ switch (LegacyCoverageLevel) {
+
+ case 0:
+ Res.CoverageType = SanitizerCoverageOptions::SCK_None;
+ break;
+ case 1:
+ Res.CoverageType = SanitizerCoverageOptions::SCK_Function;
+ break;
+ case 2:
+ Res.CoverageType = SanitizerCoverageOptions::SCK_BB;
+ break;
+ case 3:
+ Res.CoverageType = SanitizerCoverageOptions::SCK_Edge;
+ break;
+ case 4:
+ Res.CoverageType = SanitizerCoverageOptions::SCK_Edge;
+ Res.IndirectCalls = true;
+ break;
+
+ }
+
+ return Res;
+
+}
+
+SanitizerCoverageOptions OverrideFromCL(SanitizerCoverageOptions Options) {
+
+ // Sets CoverageType and IndirectCalls.
+ SanitizerCoverageOptions CLOpts = getOptions(ClCoverageLevel);
+ Options.CoverageType = std::max(Options.CoverageType, CLOpts.CoverageType);
+ Options.IndirectCalls |= CLOpts.IndirectCalls;
+ Options.TracePC |= ClTracePC;
+ Options.TracePCGuard |= ClTracePCGuard;
+ Options.Inline8bitCounters |= ClInline8bitCounters;
+ Options.InlineBoolFlag |= ClInlineBoolFlag;
+ Options.PCTable |= ClCreatePCTable;
+ Options.NoPrune |= !ClPruneBlocks;
+ if (!Options.TracePCGuard && !Options.TracePC &&
+ !Options.Inline8bitCounters && !Options.InlineBoolFlag)
+ Options.TracePCGuard = true; // TracePCGuard is default.
+ return Options;
+
+}
+
+using DomTreeCallback = function_ref<const DominatorTree *(Function &F)>;
+using PostDomTreeCallback =
+ function_ref<const PostDominatorTree *(Function &F)>;
+
+class ModuleSanitizerCoverageLTO
+ : public PassInfoMixin<ModuleSanitizerCoverageLTO> {
+
+ public:
+ ModuleSanitizerCoverageLTO(
+ const SanitizerCoverageOptions &Options = SanitizerCoverageOptions())
+ : Options(OverrideFromCL(Options)) {
+
+ }
+
+ bool instrumentModule(Module &M, DomTreeCallback DTCallback,
+ PostDomTreeCallback PDTCallback);
+
+ PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
+
+ private:
+ void instrumentFunction(Function &F, DomTreeCallback DTCallback,
+ PostDomTreeCallback PDTCallback);
+ void InjectCoverageForIndirectCalls(Function & F,
+ ArrayRef<Instruction *> IndirCalls);
+ bool InjectCoverage(Function &F, ArrayRef<BasicBlock *> AllBlocks,
+ bool IsLeafFunc = true);
+ GlobalVariable *CreateFunctionLocalArrayInSection(size_t NumElements,
+ Function &F, Type *Ty,
+ const char *Section);
+ GlobalVariable *CreatePCArray(Function &F, ArrayRef<BasicBlock *> AllBlocks);
+ void CreateFunctionLocalArrays(Function &F, ArrayRef<BasicBlock *> AllBlocks);
+ void InjectCoverageAtBlock(Function &F, BasicBlock &BB, size_t Idx,
+ bool IsLeafFunc = true);
+ // std::pair<Value *, Value *> CreateSecStartEnd(Module &M, const char
+ // *Section,
+ // Type *Ty);
+
+ void SetNoSanitizeMetadata(Instruction *I) {
+
+ I->setMetadata(I->getModule()->getMDKindID("nosanitize"),
+ MDNode::get(*C, None));
+
+ }
+
+ std::string getSectionName(const std::string &Section) const;
+ // std::string getSectionStart(const std::string &Section) const;
+ // std::string getSectionEnd(const std::string &Section) const;
+ FunctionCallee SanCovTracePCIndir;
+ FunctionCallee SanCovTracePC /*, SanCovTracePCGuard*/;
+ Type *IntptrTy, *IntptrPtrTy, *Int64Ty, *Int64PtrTy, *Int32Ty, *Int32PtrTy,
+ *Int16Ty, *Int8Ty, *Int8PtrTy, *Int1Ty, *Int1PtrTy;
+ Module * CurModule;
+ std::string CurModuleUniqueId;
+ Triple TargetTriple;
+ LLVMContext * C;
+ const DataLayout *DL;
+
+ GlobalVariable *FunctionGuardArray; // for trace-pc-guard.
+ GlobalVariable *Function8bitCounterArray; // for inline-8bit-counters.
+ GlobalVariable *FunctionBoolArray; // for inline-bool-flag.
+ GlobalVariable *FunctionPCsArray; // for pc-table.
+ SmallVector<GlobalValue *, 20> GlobalsToAppendToUsed;
+ SmallVector<GlobalValue *, 20> GlobalsToAppendToCompilerUsed;
+
+ SanitizerCoverageOptions Options;
+
+ // afl++ START
+ // const SpecialCaseList * Allowlist;
+ // const SpecialCaseList * Blocklist;
+ uint32_t autodictionary = 1;
+ uint32_t inst = 0;
+ uint32_t afl_global_id = 0;
+ uint32_t unhandled = 0;
+ uint32_t select_cnt = 0;
+ uint64_t map_addr = 0;
+ const char * skip_nozero = NULL;
+ const char * use_threadsafe_counters = nullptr;
+ std::vector<BasicBlock *> BlockList;
+ DenseMap<Value *, std::string *> valueMap;
+ std::vector<std::string> dictionary;
+ IntegerType * Int8Tyi = NULL;
+ IntegerType * Int32Tyi = NULL;
+ IntegerType * Int64Tyi = NULL;
+ ConstantInt * Zero = NULL;
+ ConstantInt * One = NULL;
+ LLVMContext * Ct = NULL;
+ Module * Mo = NULL;
+ GlobalVariable * AFLMapPtr = NULL;
+ Value * MapPtrFixed = NULL;
+ std::ofstream dFile;
+ size_t found = 0;
+ // afl++ END
+
+};
+
+class ModuleSanitizerCoverageLegacyPass : public ModulePass {
+
+ public:
+ static char ID;
+ StringRef getPassName() const override {
+
+ return "sancov";
+
+ }
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+
+ AU.addRequired<DominatorTreeWrapperPass>();
+ AU.addRequired<PostDominatorTreeWrapperPass>();
+
+ }
+
+ ModuleSanitizerCoverageLegacyPass(
+ const SanitizerCoverageOptions &Options = SanitizerCoverageOptions())
+ : ModulePass(ID), Options(Options) {
+
+ initializeModuleSanitizerCoverageLegacyPassPass(
+ *PassRegistry::getPassRegistry());
+
+ }
+
+ bool runOnModule(Module &M) override {
+
+ ModuleSanitizerCoverageLTO ModuleSancov(Options);
+ auto DTCallback = [this](Function &F) -> const DominatorTree * {
+
+ return &this->getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();
+
+ };
+
+ auto PDTCallback = [this](Function &F) -> const PostDominatorTree * {
+
+ return &this->getAnalysis<PostDominatorTreeWrapperPass>(F)
+ .getPostDomTree();
+
+ };
+
+ return ModuleSancov.instrumentModule(M, DTCallback, PDTCallback);
+
+ }
+
+ private:
+ SanitizerCoverageOptions Options;
+
+};
+
+} // namespace
+
+extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
+llvmGetPassPluginInfo() {
+
+ return {LLVM_PLUGIN_API_VERSION, "SanitizerCoverageLTO", "v0.1",
+ /* lambda to insert our pass into the pass pipeline. */
+ [](PassBuilder &PB) {
+
+#if LLVM_VERSION_MAJOR <= 13
+ using OptimizationLevel = typename PassBuilder::OptimizationLevel;
+#endif
+ // PB.registerFullLinkTimeOptimizationLastEPCallback(
+ PB.registerOptimizerLastEPCallback(
+ [](ModulePassManager &MPM, OptimizationLevel OL) {
+
+ MPM.addPass(ModuleSanitizerCoverageLTO());
+
+ });
+
+ }};
+
+}
+
+PreservedAnalyses ModuleSanitizerCoverageLTO::run(Module & M,
+ ModuleAnalysisManager &MAM) {
+
+ ModuleSanitizerCoverageLTO ModuleSancov(Options);
+ auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
+ auto DTCallback = [&FAM](Function &F) -> const DominatorTree * {
+
+ return &FAM.getResult<DominatorTreeAnalysis>(F);
+
+ };
+
+ auto PDTCallback = [&FAM](Function &F) -> const PostDominatorTree * {
+
+ return &FAM.getResult<PostDominatorTreeAnalysis>(F);
+
+ };
+
+ if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
+ return PreservedAnalyses::none();
+
+ return PreservedAnalyses::all();
+
+}
+
+bool ModuleSanitizerCoverageLTO::instrumentModule(
+ Module &M, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) {
+
+ if (Options.CoverageType == SanitizerCoverageOptions::SCK_None) return false;
+ /*
+ if (Allowlist &&
+ !Allowlist->inSection("coverage", "src", MNAME))
+ return false;
+ if (Blocklist &&
+ Blocklist->inSection("coverage", "src", MNAME))
+ return false;
+ */
+ BlockList.clear();
+ valueMap.clear();
+ dictionary.clear();
+ C = &(M.getContext());
+ DL = &M.getDataLayout();
+ CurModule = &M;
+ CurModuleUniqueId = getUniqueModuleId(CurModule);
+ TargetTriple = Triple(M.getTargetTriple());
+ FunctionGuardArray = nullptr;
+ Function8bitCounterArray = nullptr;
+ FunctionBoolArray = nullptr;
+ FunctionPCsArray = nullptr;
+ IntptrTy = Type::getIntNTy(*C, DL->getPointerSizeInBits());
+ IntptrPtrTy = PointerType::getUnqual(IntptrTy);
+ Type * VoidTy = Type::getVoidTy(*C);
+ IRBuilder<> IRB(*C);
+ Int64PtrTy = PointerType::getUnqual(IRB.getInt64Ty());
+ Int32PtrTy = PointerType::getUnqual(IRB.getInt32Ty());
+ Int8PtrTy = PointerType::getUnqual(IRB.getInt8Ty());
+ Int1PtrTy = PointerType::getUnqual(IRB.getInt1Ty());
+ Int64Ty = IRB.getInt64Ty();
+ Int32Ty = IRB.getInt32Ty();
+ Int16Ty = IRB.getInt16Ty();
+ Int8Ty = IRB.getInt8Ty();
+ Int1Ty = IRB.getInt1Ty();
+
+ /* afl++ START */
+ char * ptr;
+ LLVMContext &Ctx = M.getContext();
+ Ct = &Ctx;
+ Int8Tyi = IntegerType::getInt8Ty(Ctx);
+ Int32Tyi = IntegerType::getInt32Ty(Ctx);
+ Int64Tyi = IntegerType::getInt64Ty(Ctx);
+
+ /* Show a banner */
+ setvbuf(stdout, NULL, _IONBF, 0);
+ if (getenv("AFL_DEBUG")) debug = 1;
+
+ if ((isatty(2) && !getenv("AFL_QUIET")) || debug) {
+
+ SAYF(cCYA "afl-llvm-lto" VERSION cRST
+ " by Marc \"vanHauser\" Heuse <mh@mh-sec.de>\n");
+
+ } else
+
+ be_quiet = 1;
+
+ skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
+ use_threadsafe_counters = getenv("AFL_LLVM_THREADSAFE_INST");
+
+ if ((ptr = getenv("AFL_LLVM_LTO_STARTID")) != NULL)
+ if ((afl_global_id = atoi(ptr)) < 0)
+ FATAL("AFL_LLVM_LTO_STARTID value of \"%s\" is negative\n", ptr);
+
+ if ((ptr = getenv("AFL_LLVM_DOCUMENT_IDS")) != NULL) {
+
+ dFile.open(ptr, std::ofstream::out | std::ofstream::app);
+ if (dFile.is_open()) WARNF("Cannot access document file %s", ptr);
+
+ }
+
+ // we make this the default as the fixed map has problems with
+ // defered forkserver, early constructors, ifuncs and maybe more
+ /*if (getenv("AFL_LLVM_MAP_DYNAMIC"))*/
+ map_addr = 0;
+
+ if ((ptr = getenv("AFL_LLVM_MAP_ADDR"))) {
+
+ uint64_t val;
+ if (!*ptr || !strcmp(ptr, "0") || !strcmp(ptr, "0x0")) {
+
+ map_addr = 0;
+
+ } else if (getenv("AFL_LLVM_MAP_DYNAMIC")) {
+
+ FATAL(
+ "AFL_LLVM_MAP_ADDR and AFL_LLVM_MAP_DYNAMIC cannot be used together");
+
+ } else if (strncmp(ptr, "0x", 2) != 0) {
+
+ map_addr = 0x10000; // the default
+
+ } else {
+
+ val = strtoull(ptr, NULL, 16);
+ if (val < 0x100 || val > 0xffffffff00000000) {
+
+ FATAL(
+ "AFL_LLVM_MAP_ADDR must be a value between 0x100 and "
+ "0xffffffff00000000");
+
+ }
+
+ map_addr = val;
+
+ }
+
+ }
+
+ /* Get/set the globals for the SHM region. */
+
+ if (!map_addr) {
+
+ AFLMapPtr =
+ new GlobalVariable(M, PointerType::get(Int8Tyi, 0), false,
+ GlobalValue::ExternalLinkage, 0, "__afl_area_ptr");
+
+ } else {
+
+ ConstantInt *MapAddr = ConstantInt::get(Int64Tyi, map_addr);
+ MapPtrFixed =
+ ConstantExpr::getIntToPtr(MapAddr, PointerType::getUnqual(Int8Tyi));
+
+ }
+
+ Zero = ConstantInt::get(Int8Tyi, 0);
+ One = ConstantInt::get(Int8Tyi, 1);
+
+ initInstrumentList();
+ scanForDangerousFunctions(&M);
+ Mo = &M;
+
+ if (autodictionary) {
+
+ for (auto &F : M) {
+
+ if (!isInInstrumentList(&F, MNAME) || !F.size()) { continue; }
+
+ for (auto &BB : F) {
+
+ for (auto &IN : BB) {
+
+ CallInst *callInst = nullptr;
+ CmpInst * cmpInst = nullptr;
+
+ if ((cmpInst = dyn_cast<CmpInst>(&IN))) {
+
+ Value * op = cmpInst->getOperand(1);
+ ConstantInt *ilen = dyn_cast<ConstantInt>(op);
+
+ if (ilen && ilen->uge(0xffffffffffffffff) == false) {
+
+ u64 val2 = 0, val = ilen->getZExtValue();
+ u32 len = 0;
+ if (val > 0x10000 && val < 0xffffffff) len = 4;
+ if (val > 0x100000001 && val < 0xffffffffffffffff) len = 8;
+
+ if (len) {
+
+ auto c = cmpInst->getPredicate();
+
+ switch (c) {
+
+ case CmpInst::FCMP_OGT: // fall through
+ case CmpInst::FCMP_OLE: // fall through
+ case CmpInst::ICMP_SLE: // fall through
+ case CmpInst::ICMP_SGT:
+
+ // signed comparison and it is a negative constant
+ if ((len == 4 && (val & 80000000)) ||
+ (len == 8 && (val & 8000000000000000))) {
+
+ if ((val & 0xffff) != 1) val2 = val - 1;
+ break;
+
+ }
+
+ // fall through
+
+ case CmpInst::FCMP_UGT: // fall through
+ case CmpInst::FCMP_ULE: // fall through
+ case CmpInst::ICMP_UGT: // fall through
+ case CmpInst::ICMP_ULE:
+ if ((val & 0xffff) != 0xfffe) val2 = val + 1;
+ break;
+
+ case CmpInst::FCMP_OLT: // fall through
+ case CmpInst::FCMP_OGE: // fall through
+ case CmpInst::ICMP_SLT: // fall through
+ case CmpInst::ICMP_SGE:
+
+ // signed comparison and it is a negative constant
+ if ((len == 4 && (val & 80000000)) ||
+ (len == 8 && (val & 8000000000000000))) {
+
+ if ((val & 0xffff) != 1) val2 = val - 1;
+ break;
+
+ }
+
+ // fall through
+
+ case CmpInst::FCMP_ULT: // fall through
+ case CmpInst::FCMP_UGE: // fall through
+ case CmpInst::ICMP_ULT: // fall through
+ case CmpInst::ICMP_UGE:
+ if ((val & 0xffff) != 1) val2 = val - 1;
+ break;
+
+ default:
+ val2 = 0;
+
+ }
+
+ dictionary.push_back(std::string((char *)&val, len));
+ found++;
+
+ if (val2) {
+
+ dictionary.push_back(std::string((char *)&val2, len));
+ found++;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ 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 isStdString = true;
+ size_t optLen = 0;
+
+ Function *Callee = callInst->getCalledFunction();
+ if (!Callee) continue;
+ if (callInst->getCallingConv() != llvm::CallingConv::C) continue;
+ std::string FuncName = Callee->getName().str();
+
+ isStrcmp &= (!FuncName.compare("strcmp") ||
+ !FuncName.compare("xmlStrcmp") ||
+ !FuncName.compare("xmlStrEqual") ||
+ !FuncName.compare("g_strcmp0") ||
+ !FuncName.compare("curl_strequal") ||
+ !FuncName.compare("strcsequal"));
+ isMemcmp &=
+ (!FuncName.compare("memcmp") || !FuncName.compare("bcmp") ||
+ !FuncName.compare("CRYPTO_memcmp") ||
+ !FuncName.compare("OPENSSL_memcmp") ||
+ !FuncName.compare("memcmp_const_time") ||
+ !FuncName.compare("memcmpct"));
+ isStrncmp &= (!FuncName.compare("strncmp") ||
+ !FuncName.compare("xmlStrncmp") ||
+ !FuncName.compare("curl_strnequal"));
+ isStrcasecmp &= (!FuncName.compare("strcasecmp") ||
+ !FuncName.compare("stricmp") ||
+ !FuncName.compare("ap_cstr_casecmp") ||
+ !FuncName.compare("OPENSSL_strcasecmp") ||
+ !FuncName.compare("xmlStrcasecmp") ||
+ !FuncName.compare("g_strcasecmp") ||
+ !FuncName.compare("g_ascii_strcasecmp") ||
+ !FuncName.compare("Curl_strcasecompare") ||
+ !FuncName.compare("Curl_safe_strcasecompare") ||
+ !FuncName.compare("cmsstrcasecmp"));
+ isStrncasecmp &= (!FuncName.compare("strncasecmp") ||
+ !FuncName.compare("strnicmp") ||
+ !FuncName.compare("ap_cstr_casecmpn") ||
+ !FuncName.compare("OPENSSL_strncasecmp") ||
+ !FuncName.compare("xmlStrncasecmp") ||
+ !FuncName.compare("g_ascii_strncasecmp") ||
+ !FuncName.compare("Curl_strncasecompare") ||
+ !FuncName.compare("g_strncasecmp"));
+
+ isIntMemcpy &= !FuncName.compare("llvm.memcpy.p0i8.p0i8.i64");
+ isStdString &=
+ ((FuncName.find("basic_string") != std::string::npos &&
+ FuncName.find("compare") != std::string::npos) ||
+ (FuncName.find("basic_string") != std::string::npos &&
+ FuncName.find("find") != std::string::npos));
+
+ /* 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 && !isStdString)
+ continue;
+
+ /* Verify the strcmp/memcmp/strncmp/strcasecmp/strncasecmp function
+ * prototype */
+ FunctionType *FT = Callee->getFunctionType();
+
+ isStrcmp &= FT->getNumParams() == 2 &&
+ FT->getReturnType()->isIntegerTy(32) &&
+ FT->getParamType(0) == FT->getParamType(1) &&
+ FT->getParamType(0) ==
+ IntegerType::getInt8PtrTy(M.getContext());
+ isStrcasecmp &= FT->getNumParams() == 2 &&
+ FT->getReturnType()->isIntegerTy(32) &&
+ FT->getParamType(0) == FT->getParamType(1) &&
+ FT->getParamType(0) ==
+ IntegerType::getInt8PtrTy(M.getContext());
+ isMemcmp &= FT->getNumParams() == 3 &&
+ FT->getReturnType()->isIntegerTy(32) &&
+ FT->getParamType(0)->isPointerTy() &&
+ FT->getParamType(1)->isPointerTy() &&
+ FT->getParamType(2)->isIntegerTy();
+ isStrncmp &= FT->getNumParams() == 3 &&
+ FT->getReturnType()->isIntegerTy(32) &&
+ FT->getParamType(0) == FT->getParamType(1) &&
+ FT->getParamType(0) ==
+ IntegerType::getInt8PtrTy(M.getContext()) &&
+ FT->getParamType(2)->isIntegerTy();
+ isStrncasecmp &= FT->getNumParams() == 3 &&
+ FT->getReturnType()->isIntegerTy(32) &&
+ FT->getParamType(0) == FT->getParamType(1) &&
+ FT->getParamType(0) ==
+ IntegerType::getInt8PtrTy(M.getContext()) &&
+ FT->getParamType(2)->isIntegerTy();
+ isStdString &= FT->getNumParams() >= 2 &&
+ FT->getParamType(0)->isPointerTy() &&
+ FT->getParamType(1)->isPointerTy();
+
+ if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
+ !isStrncasecmp && !isIntMemcpy && !isStdString)
+ continue;
+
+ /* is a str{n,}{case,}cmp/memcmp, check if we have
+ * str{case,}cmp(x, "const") or str{case,}cmp("const", x)
+ * strn{case,}cmp(x, "const", ..) or strn{case,}cmp("const", x, ..)
+ * memcmp(x, "const", ..) or memcmp("const", x, ..) */
+ Value *Str1P = callInst->getArgOperand(0),
+ *Str2P = callInst->getArgOperand(1);
+ std::string Str1, Str2;
+ StringRef TmpStr;
+ bool HasStr1 = getConstantStringInfo(Str1P, TmpStr);
+ if (TmpStr.empty())
+ HasStr1 = false;
+ else
+ Str1 = TmpStr.str();
+ bool HasStr2 = getConstantStringInfo(Str2P, TmpStr);
+ if (TmpStr.empty())
+ HasStr2 = false;
+ else
+ Str2 = TmpStr.str();
+
+ if (debug)
+ fprintf(stderr, "F:%s %p(%s)->\"%s\"(%s) %p(%s)->\"%s\"(%s)\n",
+ FuncName.c_str(), Str1P, Str1P->getName().str().c_str(),
+ Str1.c_str(), HasStr1 == true ? "true" : "false", Str2P,
+ Str2P->getName().str().c_str(), Str2.c_str(),
+ HasStr2 == true ? "true" : "false");
+
+ // we handle the 2nd parameter first because of llvm memcpy
+ if (!HasStr2) {
+
+ auto *Ptr = dyn_cast<ConstantExpr>(Str2P);
+ if (Ptr && Ptr->getOpcode() == Instruction::GetElementPtr) {
+
+ if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
+
+ if (Var->hasInitializer()) {
+
+ if (auto *Array = dyn_cast<ConstantDataArray>(
+ Var->getInitializer())) {
+
+ HasStr2 = true;
+ Str2 = Array->getRawDataValues().str();
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ // for the internal memcpy routine we only care for the second
+ // parameter and are not reporting anything.
+ if (isIntMemcpy == true) {
+
+ if (HasStr2 == true) {
+
+ Value * op2 = callInst->getArgOperand(2);
+ ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
+ if (ilen) {
+
+ uint64_t literalLength = Str2.size();
+ uint64_t optLength = ilen->getZExtValue();
+ if (optLength > literalLength + 1) {
+
+ optLength = Str2.length() + 1;
+
+ }
+
+ if (literalLength + 1 == optLength) {
+
+ Str2.append("\0", 1); // add null byte
+
+ }
+
+ }
+
+ valueMap[Str1P] = new std::string(Str2);
+
+ if (debug)
+ fprintf(stderr, "Saved: %s for %p\n", Str2.c_str(), Str1P);
+ continue;
+
+ }
+
+ continue;
+
+ }
+
+ // Neither a literal nor a global variable?
+ // maybe it is a local variable that we saved
+ if (!HasStr2) {
+
+ std::string *strng = valueMap[Str2P];
+ if (strng && !strng->empty()) {
+
+ Str2 = *strng;
+ HasStr2 = true;
+ if (debug)
+ fprintf(stderr, "Filled2: %s for %p\n", strng->c_str(),
+ Str2P);
+
+ }
+
+ }
+
+ if (!HasStr1) {
+
+ auto Ptr = dyn_cast<ConstantExpr>(Str1P);
+
+ if (Ptr && Ptr->getOpcode() == Instruction::GetElementPtr) {
+
+ if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
+
+ if (Var->hasInitializer()) {
+
+ if (auto *Array = dyn_cast<ConstantDataArray>(
+ Var->getInitializer())) {
+
+ HasStr1 = true;
+ Str1 = Array->getRawDataValues().str();
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ // Neither a literal nor a global variable?
+ // maybe it is a local variable that we saved
+ if (!HasStr1) {
+
+ std::string *strng = valueMap[Str1P];
+ if (strng && !strng->empty()) {
+
+ Str1 = *strng;
+ HasStr1 = true;
+ if (debug)
+ fprintf(stderr, "Filled1: %s for %p\n", strng->c_str(),
+ Str1P);
+
+ }
+
+ }
+
+ /* handle cases of one string is const, one string is variable */
+ if (!(HasStr1 ^ HasStr2)) continue;
+
+ std::string thestring;
+
+ if (HasStr1)
+ thestring = Str1;
+ else
+ thestring = Str2;
+
+ optLen = thestring.length();
+ if (optLen < 2 || (optLen == 2 && !thestring[1])) { continue; }
+
+ if (isMemcmp || isStrncmp || isStrncasecmp) {
+
+ Value * op2 = callInst->getArgOperand(2);
+ ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
+
+ if (ilen) {
+
+ uint64_t literalLength = optLen;
+ optLen = ilen->getZExtValue();
+ if (optLen > thestring.length() + 1) {
+
+ optLen = thestring.length() + 1;
+
+ }
+
+ if (optLen < 2) { continue; }
+ if (literalLength + 1 == optLen) { // add null byte
+
+ thestring.append("\0", 1);
+
+ }
+
+ }
+
+ }
+
+ // add null byte if this is a string compare function and a null
+ // was not already added
+ if (!isMemcmp) {
+
+ /*
+ if (addedNull == false && thestring[optLen - 1] !=
+ '\0') {
+
+ thestring.append("\0", 1); // add null byte
+ optLen++;
+
+ }
+
+ */
+ if (!isStdString &&
+ thestring.find('\0', 0) != std::string::npos) {
+
+ // 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 %zu/%zu \"", FuncName.c_str(), optLen,
+ thestring.length());
+ for (uint8_t i = 0; i < thestring.length(); i++) {
+
+ uint8_t c = thestring[i];
+ if (c <= 32 || c >= 127)
+ fprintf(stderr, "\\x%02x", c);
+ else
+ fprintf(stderr, "%c", c);
+
+ }
+
+ fprintf(stderr, "\"\n");
+
+ }
+
+ // we take the longer string, even if the compare was to a
+ // shorter part. Note that depending on the optimizer of the
+ // compiler this can be wrong, but it is more likely that this
+ // is helping the fuzzer
+ if (optLen != thestring.length()) optLen = thestring.length();
+ if (optLen > MAX_AUTO_EXTRA) optLen = MAX_AUTO_EXTRA;
+ if (optLen < MIN_AUTO_EXTRA) // too short? skip
+ continue;
+
+ dictionary.push_back(thestring.substr(0, optLen));
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ // afl++ END
+
+ SanCovTracePCIndir =
+ M.getOrInsertFunction(SanCovTracePCIndirName, VoidTy, IntptrTy);
+ // Make sure smaller parameters are zero-extended to i64 as required by the
+ // x86_64 ABI.
+ AttributeList SanCovTraceCmpZeroExtAL;
+ if (TargetTriple.getArch() == Triple::x86_64) {
+
+ SanCovTraceCmpZeroExtAL =
+ SanCovTraceCmpZeroExtAL.addParamAttribute(*C, 0, Attribute::ZExt);
+ SanCovTraceCmpZeroExtAL =
+ SanCovTraceCmpZeroExtAL.addParamAttribute(*C, 1, Attribute::ZExt);
+
+ }
+
+ SanCovTracePC = M.getOrInsertFunction(SanCovTracePCName, VoidTy);
+
+ // SanCovTracePCGuard =
+ // M.getOrInsertFunction(SanCovTracePCGuardName, VoidTy, Int32PtrTy);
+
+ for (auto &F : M)
+ instrumentFunction(F, DTCallback, PDTCallback);
+
+ // afl++ START
+ if (dFile.is_open()) dFile.close();
+
+ if (!getenv("AFL_LLVM_LTO_DONTWRITEID") || dictionary.size() || map_addr) {
+
+ // yes we could create our own function, insert it into ctors ...
+ // but this would be a pain in the butt ... so we use afl-llvm-rt-lto.o
+
+ Function *f = M.getFunction("__afl_auto_init_globals");
+
+ if (!f) {
+
+ fprintf(stderr,
+ "Error: init function could not be found (this should not "
+ "happen)\n");
+ exit(-1);
+
+ }
+
+ BasicBlock *bb = &f->getEntryBlock();
+ if (!bb) {
+
+ fprintf(stderr,
+ "Error: init function does not have an EntryBlock (this should "
+ "not happen)\n");
+ exit(-1);
+
+ }
+
+ BasicBlock::iterator IP = bb->getFirstInsertionPt();
+ IRBuilder<> IRB(&(*IP));
+
+ if (map_addr) {
+
+ GlobalVariable *AFLMapAddrFixed = new GlobalVariable(
+ M, Int64Tyi, true, GlobalValue::ExternalLinkage, 0, "__afl_map_addr");
+ ConstantInt *MapAddr = ConstantInt::get(Int64Tyi, map_addr);
+ StoreInst * StoreMapAddr = IRB.CreateStore(MapAddr, AFLMapAddrFixed);
+ ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(StoreMapAddr);
+
+ }
+
+ if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL) {
+
+ uint32_t write_loc = afl_global_id;
+
+ write_loc = (((afl_global_id + 8) >> 3) << 3);
+
+ GlobalVariable *AFLFinalLoc =
+ new GlobalVariable(M, Int32Tyi, true, GlobalValue::ExternalLinkage, 0,
+ "__afl_final_loc");
+ ConstantInt *const_loc = ConstantInt::get(Int32Tyi, write_loc);
+ StoreInst * StoreFinalLoc = IRB.CreateStore(const_loc, AFLFinalLoc);
+ ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(StoreFinalLoc);
+
+ }
+
+ if (dictionary.size()) {
+
+ size_t memlen = 0, count = 0, offset = 0;
+
+ // sort and unique the dictionary
+ std::sort(dictionary.begin(), dictionary.end());
+ auto last = std::unique(dictionary.begin(), dictionary.end());
+ dictionary.erase(last, dictionary.end());
+
+ for (auto token : dictionary) {
+
+ memlen += token.length();
+ count++;
+
+ }
+
+ if (!be_quiet)
+ printf("AUTODICTIONARY: %lu string%s found\n", count,
+ count == 1 ? "" : "s");
+
+ if (count) {
+
+ auto ptrhld = std::unique_ptr<char[]>(new char[memlen + count]);
+
+ count = 0;
+
+ for (auto token : dictionary) {
+
+ if (offset + token.length() < 0xfffff0 && count < MAX_AUTO_EXTRAS) {
+
+ ptrhld.get()[offset++] = (uint8_t)token.length();
+ memcpy(ptrhld.get() + offset, token.c_str(), token.length());
+ offset += token.length();
+ count++;
+
+ }
+
+ }
+
+ GlobalVariable *AFLDictionaryLen =
+ new GlobalVariable(M, Int32Tyi, false, GlobalValue::ExternalLinkage,
+ 0, "__afl_dictionary_len");
+ ConstantInt *const_len = ConstantInt::get(Int32Tyi, offset);
+ StoreInst *StoreDictLen = IRB.CreateStore(const_len, AFLDictionaryLen);
+ ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(StoreDictLen);
+
+ ArrayType *ArrayTy = ArrayType::get(IntegerType::get(Ctx, 8), offset);
+ GlobalVariable *AFLInternalDictionary = new GlobalVariable(
+ M, ArrayTy, true, GlobalValue::ExternalLinkage,
+ ConstantDataArray::get(Ctx,
+ *(new ArrayRef<char>(ptrhld.get(), offset))),
+ "__afl_internal_dictionary");
+ AFLInternalDictionary->setInitializer(ConstantDataArray::get(
+ Ctx, *(new ArrayRef<char>(ptrhld.get(), offset))));
+ AFLInternalDictionary->setConstant(true);
+
+ GlobalVariable *AFLDictionary = new GlobalVariable(
+ M, PointerType::get(Int8Tyi, 0), false,
+ GlobalValue::ExternalLinkage, 0, "__afl_dictionary");
+
+ Value *AFLDictOff = IRB.CreateGEP(Int8Ty, AFLInternalDictionary, Zero);
+ Value *AFLDictPtr =
+ IRB.CreatePointerCast(AFLDictOff, PointerType::get(Int8Tyi, 0));
+ StoreInst *StoreDict = IRB.CreateStore(AFLDictPtr, AFLDictionary);
+ ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(StoreDict);
+
+ }
+
+ }
+
+ }
+
+ /* Say something nice. */
+
+ if (!be_quiet) {
+
+ if (!inst)
+ WARNF("No instrumentation targets found.");
+ else {
+
+ char modeline[100];
+ snprintf(modeline, sizeof(modeline), "%s%s%s%s%s%s",
+ getenv("AFL_HARDEN") ? "hardened" : "non-hardened",
+ getenv("AFL_USE_ASAN") ? ", ASAN" : "",
+ getenv("AFL_USE_MSAN") ? ", MSAN" : "",
+ getenv("AFL_USE_TSAN") ? ", TSAN" : "",
+ getenv("AFL_USE_CFISAN") ? ", CFISAN" : "",
+ getenv("AFL_USE_UBSAN") ? ", UBSAN" : "");
+ OKF("Instrumented %u locations (%u selects) without collisions (%llu "
+ "collisions have been avoided) (%s mode).",
+ inst, select_cnt, calculateCollisions(inst), modeline);
+
+ }
+
+ }
+
+ // afl++ END
+
+ // We don't reference these arrays directly in any of our runtime functions,
+ // so we need to prevent them from being dead stripped.
+ if (TargetTriple.isOSBinFormatMachO()) appendToUsed(M, GlobalsToAppendToUsed);
+ appendToCompilerUsed(M, GlobalsToAppendToCompilerUsed);
+ return true;
+
+}
+
+// True if block has successors and it dominates all of them.
+static bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) {
+
+ if (succ_begin(BB) == succ_end(BB)) return false;
+
+ for (const BasicBlock *SUCC : make_range(succ_begin(BB), succ_end(BB))) {
+
+ if (!DT->dominates(BB, SUCC)) return false;
+
+ }
+
+ return true;
+
+}
+
+// True if block has predecessors and it postdominates all of them.
+static bool isFullPostDominator(const BasicBlock * BB,
+ const PostDominatorTree *PDT) {
+
+ if (pred_begin(BB) == pred_end(BB)) return false;
+
+ for (const BasicBlock *PRED : make_range(pred_begin(BB), pred_end(BB))) {
+
+ if (!PDT->dominates(BB, PRED)) return false;
+
+ }
+
+ return true;
+
+}
+
+static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB,
+ const DominatorTree * DT,
+ const PostDominatorTree * PDT,
+ const SanitizerCoverageOptions &Options) {
+
+ // Don't insert coverage for blocks containing nothing but unreachable: we
+ // will never call __sanitizer_cov() for them, so counting them in
+ // NumberOfInstrumentedBlocks() might complicate calculation of code coverage
+ // percentage. Also, unreachable instructions frequently have no debug
+ // locations.
+ if (isa<UnreachableInst>(BB->getFirstNonPHIOrDbgOrLifetime())) return false;
+
+ // Don't insert coverage into blocks without a valid insertion point
+ // (catchswitch blocks).
+ if (BB->getFirstInsertionPt() == BB->end()) return false;
+
+ // afl++ START
+ if (!Options.NoPrune && &F.getEntryBlock() == BB && F.size() > 1)
+ return false;
+ // afl++ END
+
+ if (Options.NoPrune || &F.getEntryBlock() == BB) return true;
+
+ if (Options.CoverageType == SanitizerCoverageOptions::SCK_Function &&
+ &F.getEntryBlock() != BB)
+ return false;
+
+ // Do not instrument full dominators, or full post-dominators with multiple
+ // predecessors.
+ return !isFullDominator(BB, DT) &&
+ !(isFullPostDominator(BB, PDT) && !BB->getSinglePredecessor());
+
+}
+
+void ModuleSanitizerCoverageLTO::instrumentFunction(
+ Function &F, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) {
+
+ if (F.empty()) return;
+ if (F.getName().find(".module_ctor") != std::string::npos)
+ return; // Should not instrument sanitizer init functions.
+ if (F.getName().startswith("__sanitizer_"))
+ return; // Don't instrument __sanitizer_* callbacks.
+ // Don't touch available_externally functions, their actual body is elsewhere.
+ if (F.getLinkage() == GlobalValue::AvailableExternallyLinkage) return;
+ // Don't instrument MSVC CRT configuration helpers. They may run before normal
+ // initialization.
+ if (F.getName() == "__local_stdio_printf_options" ||
+ F.getName() == "__local_stdio_scanf_options")
+ return;
+ if (isa<UnreachableInst>(F.getEntryBlock().getTerminator())) return;
+ // Don't instrument functions using SEH for now. Splitting basic blocks like
+ // we do for coverage breaks WinEHPrepare.
+ // FIXME: Remove this when SEH no longer uses landingpad pattern matching.
+ if (F.hasPersonalityFn() &&
+ isAsynchronousEHPersonality(classifyEHPersonality(F.getPersonalityFn())))
+ return;
+ // if (Allowlist && !Allowlist->inSection("coverage", "fun", F.getName()))
+ // return;
+ // if (Blocklist && Blocklist->inSection("coverage", "fun", F.getName()))
+ // return;
+
+ // afl++ START
+ if (!F.size()) return;
+ if (!isInInstrumentList(&F, FMNAME)) return;
+ // afl++ END
+
+ if (Options.CoverageType >= SanitizerCoverageOptions::SCK_Edge)
+ SplitAllCriticalEdges(
+ F, CriticalEdgeSplittingOptions().setIgnoreUnreachableDests());
+ SmallVector<Instruction *, 8> IndirCalls;
+ SmallVector<BasicBlock *, 16> BlocksToInstrument;
+
+ const DominatorTree * DT = DTCallback(F);
+ const PostDominatorTree *PDT = PDTCallback(F);
+ bool IsLeafFunc = true;
+ uint32_t skip_next = 0;
+
+ for (auto &BB : F) {
+
+ for (auto &IN : BB) {
+
+ CallInst *callInst = nullptr;
+
+ if ((callInst = dyn_cast<CallInst>(&IN))) {
+
+ Function *Callee = callInst->getCalledFunction();
+ if (!Callee) continue;
+ if (callInst->getCallingConv() != llvm::CallingConv::C) continue;
+ StringRef FuncName = Callee->getName();
+ if (!FuncName.compare(StringRef("dlopen")) ||
+ !FuncName.compare(StringRef("_dlopen"))) {
+
+ fprintf(stderr,
+ "WARNING: dlopen() detected. To have coverage for a library "
+ "that your target dlopen()'s this must either happen before "
+ "__AFL_INIT() or you must use AFL_PRELOAD to preload all "
+ "dlopen()'ed libraries!\n");
+ continue;
+
+ }
+
+ if (FuncName.compare(StringRef("__afl_coverage_interesting"))) continue;
+
+ Value *val = ConstantInt::get(Int32Ty, ++afl_global_id);
+ callInst->setOperand(1, val);
+ ++inst;
+
+ }
+
+ SelectInst *selectInst = nullptr;
+
+ /*
+ std::string errMsg;
+ raw_string_ostream os(errMsg);
+ IN.print(os);
+ fprintf(stderr, "X(%u): %s\n", skip_next, os.str().c_str());
+ */
+ if (!skip_next && (selectInst = dyn_cast<SelectInst>(&IN))) {
+
+ uint32_t vector_cnt = 0;
+ Value * condition = selectInst->getCondition();
+ Value * result;
+ auto t = condition->getType();
+ IRBuilder<> IRB(selectInst->getNextNode());
+
+ ++select_cnt;
+
+ if (t->getTypeID() == llvm::Type::IntegerTyID) {
+
+ Value *val1 = ConstantInt::get(Int32Ty, ++afl_global_id);
+ Value *val2 = ConstantInt::get(Int32Ty, ++afl_global_id);
+ result = IRB.CreateSelect(condition, val1, val2);
+ skip_next = 1;
+ inst += 2;
+
+ } else
+
+#if LLVM_VERSION_MAJOR >= 14
+ if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
+
+ FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
+ if (tt) {
+
+ uint32_t elements = tt->getElementCount().getFixedValue();
+ vector_cnt = elements;
+ inst += vector_cnt * 2;
+ if (elements) {
+
+ FixedVectorType *GuardPtr1 =
+ FixedVectorType::get(Int32Ty, elements);
+ FixedVectorType *GuardPtr2 =
+ FixedVectorType::get(Int32Ty, elements);
+ Value *x, *y;
+
+ Value *val1 = ConstantInt::get(Int32Ty, ++afl_global_id);
+ Value *val2 = ConstantInt::get(Int32Ty, ++afl_global_id);
+ x = IRB.CreateInsertElement(GuardPtr1, val1, (uint64_t)0);
+ y = IRB.CreateInsertElement(GuardPtr2, val2, (uint64_t)0);
+
+ for (uint64_t i = 1; i < elements; i++) {
+
+ val1 = ConstantInt::get(Int32Ty, ++afl_global_id);
+ val2 = ConstantInt::get(Int32Ty, ++afl_global_id);
+ x = IRB.CreateInsertElement(GuardPtr1, val1, i);
+ y = IRB.CreateInsertElement(GuardPtr2, val2, i);
+
+ }
+
+ result = IRB.CreateSelect(condition, x, y);
+ skip_next = 1;
+
+ }
+
+ }
+
+ } else
+
+#endif
+ {
+
+ unhandled++;
+ continue;
+
+ }
+
+ uint32_t vector_cur = 0;
+ /* Load SHM pointer */
+ LoadInst *MapPtr =
+ IRB.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr);
+ ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(MapPtr);
+
+ while (1) {
+
+ /* Get CurLoc */
+ Value *MapPtrIdx = nullptr;
+
+ /* Load counter for CurLoc */
+ if (!vector_cnt) {
+
+ MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtr, result);
+
+ } else {
+
+ auto element = IRB.CreateExtractElement(result, vector_cur++);
+ MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtr, element);
+
+ }
+
+ if (use_threadsafe_counters) {
+
+ IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One,
+#if LLVM_VERSION_MAJOR >= 13
+ llvm::MaybeAlign(1),
+#endif
+ llvm::AtomicOrdering::Monotonic);
+
+ } else {
+
+ LoadInst *Counter = IRB.CreateLoad(IRB.getInt8Ty(), MapPtrIdx);
+ ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(Counter);
+
+ /* Update bitmap */
+
+ Value *Incr = IRB.CreateAdd(Counter, One);
+
+ if (skip_nozero == NULL) {
+
+ auto cf = IRB.CreateICmpEQ(Incr, Zero);
+ auto carry = IRB.CreateZExt(cf, Int8Ty);
+ Incr = IRB.CreateAdd(Incr, carry);
+
+ }
+
+ auto nosan = IRB.CreateStore(Incr, MapPtrIdx);
+ ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(nosan);
+
+ }
+
+ if (!vector_cnt || vector_cnt == vector_cur) { break; }
+
+ }
+
+ skip_next = 1;
+
+ } else {
+
+ skip_next = 0;
+
+ }
+
+ }
+
+ if (shouldInstrumentBlock(F, &BB, DT, PDT, Options))
+ BlocksToInstrument.push_back(&BB);
+ for (auto &Inst : BB) {
+
+ if (Options.IndirectCalls) {
+
+ CallBase *CB = dyn_cast<CallBase>(&Inst);
+ if (CB && !CB->getCalledFunction()) IndirCalls.push_back(&Inst);
+
+ }
+
+ }
+
+ }
+
+ InjectCoverage(F, BlocksToInstrument, IsLeafFunc);
+ InjectCoverageForIndirectCalls(F, IndirCalls);
+
+}
+
+GlobalVariable *ModuleSanitizerCoverageLTO::CreateFunctionLocalArrayInSection(
+ size_t NumElements, Function &F, Type *Ty, const char *Section) {
+
+ ArrayType *ArrayTy = ArrayType::get(Ty, NumElements);
+ auto Array = new GlobalVariable(
+ *CurModule, ArrayTy, false, GlobalVariable::PrivateLinkage,
+ Constant::getNullValue(ArrayTy), "__sancov_gen_");
+
+#if LLVM_VERSION_MAJOR >= 13
+ if (TargetTriple.supportsCOMDAT() &&
+ (TargetTriple.isOSBinFormatELF() || !F.isInterposable()))
+ if (auto Comdat = getOrCreateFunctionComdat(F, TargetTriple))
+ Array->setComdat(Comdat);
+#else
+ if (TargetTriple.supportsCOMDAT() && !F.isInterposable())
+ if (auto Comdat =
+ GetOrCreateFunctionComdat(F, TargetTriple, CurModuleUniqueId))
+ Array->setComdat(Comdat);
+#endif
+ Array->setSection(getSectionName(Section));
+ Array->setAlignment(Align(DL->getTypeStoreSize(Ty).getFixedSize()));
+ GlobalsToAppendToUsed.push_back(Array);
+ GlobalsToAppendToCompilerUsed.push_back(Array);
+ MDNode *MD = MDNode::get(F.getContext(), ValueAsMetadata::get(&F));
+ Array->addMetadata(LLVMContext::MD_associated, *MD);
+
+ return Array;
+
+}
+
+GlobalVariable *ModuleSanitizerCoverageLTO::CreatePCArray(
+ Function &F, ArrayRef<BasicBlock *> AllBlocks) {
+
+ size_t N = AllBlocks.size();
+ assert(N);
+ SmallVector<Constant *, 32> PCs;
+ IRBuilder<> IRB(&*F.getEntryBlock().getFirstInsertionPt());
+ for (size_t i = 0; i < N; i++) {
+
+ if (&F.getEntryBlock() == AllBlocks[i]) {
+
+ PCs.push_back((Constant *)IRB.CreatePointerCast(&F, IntptrPtrTy));
+ PCs.push_back((Constant *)IRB.CreateIntToPtr(
+ ConstantInt::get(IntptrTy, 1), IntptrPtrTy));
+
+ } else {
+
+ PCs.push_back((Constant *)IRB.CreatePointerCast(
+ BlockAddress::get(AllBlocks[i]), IntptrPtrTy));
+ PCs.push_back((Constant *)IRB.CreateIntToPtr(
+ ConstantInt::get(IntptrTy, 0), IntptrPtrTy));
+
+ }
+
+ }
+
+ auto *PCArray = CreateFunctionLocalArrayInSection(N * 2, F, IntptrPtrTy,
+ SanCovPCsSectionName);
+ PCArray->setInitializer(
+ ConstantArray::get(ArrayType::get(IntptrPtrTy, N * 2), PCs));
+ PCArray->setConstant(true);
+
+ return PCArray;
+
+}
+
+void ModuleSanitizerCoverageLTO::CreateFunctionLocalArrays(
+ Function &F, ArrayRef<BasicBlock *> AllBlocks) {
+
+ if (Options.TracePCGuard)
+ FunctionGuardArray = CreateFunctionLocalArrayInSection(
+ AllBlocks.size(), F, Int32Ty, SanCovGuardsSectionName);
+ if (Options.Inline8bitCounters)
+ Function8bitCounterArray = CreateFunctionLocalArrayInSection(
+ AllBlocks.size(), F, Int8Ty, SanCovCountersSectionName);
+ if (Options.InlineBoolFlag)
+ FunctionBoolArray = CreateFunctionLocalArrayInSection(
+ AllBlocks.size(), F, Int1Ty, SanCovBoolFlagSectionName);
+ if (Options.PCTable) FunctionPCsArray = CreatePCArray(F, AllBlocks);
+
+}
+
+bool ModuleSanitizerCoverageLTO::InjectCoverage(
+ Function &F, ArrayRef<BasicBlock *> AllBlocks, bool IsLeafFunc) {
+
+ if (AllBlocks.empty()) return false;
+ CreateFunctionLocalArrays(F, AllBlocks);
+
+ for (size_t i = 0, N = AllBlocks.size(); i < N; i++) {
+
+ // afl++ START
+ if (BlockList.size()) {
+
+ int skip = 0;
+ for (uint32_t k = 0; k < BlockList.size(); k++) {
+
+ if (AllBlocks[i] == 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;
+
+ }
+
+ // afl++ END
+
+ InjectCoverageAtBlock(F, *AllBlocks[i], i, IsLeafFunc);
+
+ }
+
+ return true;
+
+}
+
+// On every indirect call we call a run-time function
+// __sanitizer_cov_indir_call* with two parameters:
+// - callee address,
+// - global cache array that contains CacheSize pointers (zero-initialized).
+// The cache is used to speed up recording the caller-callee pairs.
+// The address of the caller is passed implicitly via caller PC.
+// CacheSize is encoded in the name of the run-time function.
+void ModuleSanitizerCoverageLTO::InjectCoverageForIndirectCalls(
+ Function &F, ArrayRef<Instruction *> IndirCalls) {
+
+ if (IndirCalls.empty()) return;
+ assert(Options.TracePC || Options.TracePCGuard ||
+ Options.Inline8bitCounters || Options.InlineBoolFlag);
+ for (auto I : IndirCalls) {
+
+ IRBuilder<> IRB(I);
+ CallBase & CB = cast<CallBase>(*I);
+ Value * Callee = CB.getCalledOperand();
+ if (isa<InlineAsm>(Callee)) continue;
+ IRB.CreateCall(SanCovTracePCIndir, IRB.CreatePointerCast(Callee, IntptrTy));
+
+ }
+
+}
+
+void ModuleSanitizerCoverageLTO::InjectCoverageAtBlock(Function & F,
+ BasicBlock &BB,
+ size_t Idx,
+ bool IsLeafFunc) {
+
+ BasicBlock::iterator IP = BB.getFirstInsertionPt();
+ bool IsEntryBB = &BB == &F.getEntryBlock();
+
+ if (IsEntryBB) {
+
+ // Keep static allocas and llvm.localescape calls in the entry block. Even
+ // if we aren't splitting the block, it's nice for allocas to be before
+ // calls.
+ IP = PrepareToSplitEntryBlock(BB, IP);
+
+ }
+
+ IRBuilder<> IRB(&*IP);
+ if (Options.TracePC) {
+
+ IRB.CreateCall(SanCovTracePC)
+#if LLVM_VERSION_MAJOR >= 12
+ ->setCannotMerge(); // gets the PC using GET_CALLER_PC.
+#else
+ ->cannotMerge(); // gets the PC using GET_CALLER_PC.
+#endif
+
+ }
+
+ if (Options.TracePCGuard) {
+
+ // afl++ START
+ ++afl_global_id;
+
+ if (dFile.is_open()) {
+
+ unsigned long long int moduleID =
+ (((unsigned long long int)(rand() & 0xffffffff)) << 32) | getpid();
+ dFile << "ModuleID=" << moduleID << " Function=" << F.getName().str()
+ << " edgeID=" << afl_global_id << "\n";
+
+ }
+
+ /* Set the ID of the inserted basic block */
+
+ ConstantInt *CurLoc = ConstantInt::get(Int32Tyi, afl_global_id);
+
+ /* Load SHM pointer */
+
+ Value *MapPtrIdx;
+
+ if (map_addr) {
+
+ MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtrFixed, CurLoc);
+
+ } else {
+
+ LoadInst *MapPtr = IRB.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr);
+ ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(MapPtr);
+ MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtr, CurLoc);
+
+ }
+
+ /* Update bitmap */
+ if (use_threadsafe_counters) { /* Atomic */
+
+ IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One,
+#if LLVM_VERSION_MAJOR >= 13
+ llvm::MaybeAlign(1),
+#endif
+ llvm::AtomicOrdering::Monotonic);
+
+ } else {
+
+ LoadInst *Counter = IRB.CreateLoad(IRB.getInt8Ty(), MapPtrIdx);
+ ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(Counter);
+
+ Value *Incr = IRB.CreateAdd(Counter, One);
+
+ if (skip_nozero == NULL) {
+
+ auto cf = IRB.CreateICmpEQ(Incr, Zero);
+ auto carry = IRB.CreateZExt(cf, Int8Tyi);
+ Incr = IRB.CreateAdd(Incr, carry);
+
+ }
+
+ auto nosan = IRB.CreateStore(Incr, MapPtrIdx);
+ ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(nosan);
+
+ }
+
+ // done :)
+
+ inst++;
+ // afl++ END
+
+ /*
+ XXXXXXXXXXXXXXXXXXX
+
+ auto GuardPtr = IRB.CreateIntToPtr(
+ IRB.CreateAdd(IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
+ ConstantInt::get(IntptrTy, Idx * 4)),
+ Int32PtrTy);
+
+ IRB.CreateCall(SanCovTracePCGuard, GuardPtr)->setCannotMerge();
+ */
+
+ }
+
+ if (Options.Inline8bitCounters) {
+
+ auto CounterPtr = IRB.CreateGEP(
+ Function8bitCounterArray->getValueType(), Function8bitCounterArray,
+ {ConstantInt::get(IntptrTy, 0), ConstantInt::get(IntptrTy, Idx)});
+ auto Load = IRB.CreateLoad(Int8Ty, CounterPtr);
+ auto Inc = IRB.CreateAdd(Load, ConstantInt::get(Int8Ty, 1));
+ auto Store = IRB.CreateStore(Inc, CounterPtr);
+ SetNoSanitizeMetadata(Load);
+ SetNoSanitizeMetadata(Store);
+
+ }
+
+ if (Options.InlineBoolFlag) {
+
+ auto FlagPtr = IRB.CreateGEP(
+ FunctionBoolArray->getValueType(), FunctionBoolArray,
+ {ConstantInt::get(IntptrTy, 0), ConstantInt::get(IntptrTy, Idx)});
+ auto Load = IRB.CreateLoad(Int1Ty, FlagPtr);
+ auto ThenTerm =
+ SplitBlockAndInsertIfThen(IRB.CreateIsNull(Load), &*IP, false);
+ IRBuilder<> ThenIRB(ThenTerm);
+ auto Store = ThenIRB.CreateStore(ConstantInt::getTrue(Int1Ty), FlagPtr);
+ SetNoSanitizeMetadata(Load);
+ SetNoSanitizeMetadata(Store);
+
+ }
+
+}
+
+std::string ModuleSanitizerCoverageLTO::getSectionName(
+ const std::string &Section) const {
+
+ if (TargetTriple.isOSBinFormatCOFF()) {
+
+ if (Section == SanCovCountersSectionName) return ".SCOV$CM";
+ if (Section == SanCovBoolFlagSectionName) return ".SCOV$BM";
+ if (Section == SanCovPCsSectionName) return ".SCOVP$M";
+ return ".SCOV$GM"; // For SanCovGuardsSectionName.
+
+ }
+
+ if (TargetTriple.isOSBinFormatMachO()) return "__DATA,__" + Section;
+ return "__" + Section;
+
+}
+
+char ModuleSanitizerCoverageLegacyPass::ID = 0;
+
+INITIALIZE_PASS_BEGIN(ModuleSanitizerCoverageLegacyPass, "sancov",
+ "Pass for instrumenting coverage on functions", false,
+ false)
+INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(PostDominatorTreeWrapperPass)
+INITIALIZE_PASS_END(ModuleSanitizerCoverageLegacyPass, "sancov",
+ "Pass for instrumenting coverage on functions", false,
+ false)
+
+ModulePass *llvm::createModuleSanitizerCoverageLegacyPassPass(
+ const SanitizerCoverageOptions &Options,
+ const std::vector<std::string> &AllowlistFiles,
+ const std::vector<std::string> &BlocklistFiles) {
+
+ return new ModuleSanitizerCoverageLegacyPass(Options);
+
+}
+
+static void registerLTOPass(const PassManagerBuilder &,
+ legacy::PassManagerBase &PM) {
+
+ auto p = new ModuleSanitizerCoverageLegacyPass();
+ PM.add(p);
+
+}
+
+static RegisterStandardPasses RegisterCompTransPass(
+ PassManagerBuilder::EP_OptimizerLast, registerLTOPass);
+
+static RegisterStandardPasses RegisterCompTransPass0(
+ PassManagerBuilder::EP_EnabledOnOptLevel0, registerLTOPass);
+
+#if LLVM_VERSION_MAJOR >= 11
+static RegisterStandardPasses RegisterCompTransPassLTO(
+ PassManagerBuilder::EP_FullLinkTimeOptimizationLast, registerLTOPass);
+#endif
+
diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc
new file mode 100644
index 00000000..408353b3
--- /dev/null
+++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc
@@ -0,0 +1,1551 @@
+//===-- SanitizerCoverage.cpp - coverage instrumentation for sanitizers ---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Coverage instrumentation done on LLVM IR level, works with Sanitizers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Analysis/EHPersonalities.h"
+#include "llvm/Analysis/PostDominators.h"
+#include "llvm/IR/CFG.h"
+#include "llvm/IR/Constant.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DebugInfo.h"
+#include "llvm/IR/Dominators.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/InlineAsm.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/MDBuilder.h"
+#include "llvm/IR/Mangler.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/PassManager.h"
+#include "llvm/IR/Type.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/SpecialCaseList.h"
+#include "llvm/Support/VirtualFileSystem.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Transforms/Instrumentation.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
+#include "llvm/Passes/PassPlugin.h"
+#include "llvm/Passes/PassBuilder.h"
+#include "llvm/IR/PassManager.h"
+
+#include "config.h"
+#include "debug.h"
+#include "afl-llvm-common.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "sancov"
+
+const char SanCovTracePCIndirName[] = "__sanitizer_cov_trace_pc_indir";
+const char SanCovTracePCName[] = "__sanitizer_cov_trace_pc";
+const char SanCovTraceCmp1[] = "__sanitizer_cov_trace_cmp1";
+const char SanCovTraceCmp2[] = "__sanitizer_cov_trace_cmp2";
+const char SanCovTraceCmp4[] = "__sanitizer_cov_trace_cmp4";
+const char SanCovTraceCmp8[] = "__sanitizer_cov_trace_cmp8";
+const char SanCovTraceConstCmp1[] = "__sanitizer_cov_trace_const_cmp1";
+const char SanCovTraceConstCmp2[] = "__sanitizer_cov_trace_const_cmp2";
+const char SanCovTraceConstCmp4[] = "__sanitizer_cov_trace_const_cmp4";
+const char SanCovTraceConstCmp8[] = "__sanitizer_cov_trace_const_cmp8";
+const char SanCovTraceDiv4[] = "__sanitizer_cov_trace_div4";
+const char SanCovTraceDiv8[] = "__sanitizer_cov_trace_div8";
+const char SanCovTraceGep[] = "__sanitizer_cov_trace_gep";
+const char SanCovTraceSwitchName[] = "__sanitizer_cov_trace_switch";
+const char SanCovModuleCtorTracePcGuardName[] =
+ "sancov.module_ctor_trace_pc_guard";
+const char SanCovModuleCtor8bitCountersName[] =
+ "sancov.module_ctor_8bit_counters";
+const char SanCovModuleCtorBoolFlagName[] = "sancov.module_ctor_bool_flag";
+static const uint64_t SanCtorAndDtorPriority = 2;
+
+const char SanCovTracePCGuardName[] = "__sanitizer_cov_trace_pc_guard";
+const char SanCovTracePCGuardInitName[] = "__sanitizer_cov_trace_pc_guard_init";
+const char SanCov8bitCountersInitName[] = "__sanitizer_cov_8bit_counters_init";
+const char SanCovBoolFlagInitName[] = "__sanitizer_cov_bool_flag_init";
+const char SanCovPCsInitName[] = "__sanitizer_cov_pcs_init";
+
+const char SanCovGuardsSectionName[] = "sancov_guards";
+const char SanCovCountersSectionName[] = "sancov_cntrs";
+const char SanCovBoolFlagSectionName[] = "sancov_bools";
+const char SanCovPCsSectionName[] = "sancov_pcs";
+
+const char SanCovLowestStackName[] = "__sancov_lowest_stack";
+
+static const char *skip_nozero;
+static const char *use_threadsafe_counters;
+
+namespace {
+
+SanitizerCoverageOptions OverrideFromCL(SanitizerCoverageOptions Options) {
+
+ // Sets CoverageType and IndirectCalls.
+ // SanitizerCoverageOptions CLOpts = getOptions(ClCoverageLevel);
+ Options.CoverageType =
+ SanitizerCoverageOptions::SCK_Edge; // std::max(Options.CoverageType,
+ // CLOpts.CoverageType);
+ Options.IndirectCalls = false; // CLOpts.IndirectCalls;
+ Options.TraceCmp = false; //|= ClCMPTracing;
+ Options.TraceDiv = false; //|= ClDIVTracing;
+ Options.TraceGep = false; //|= ClGEPTracing;
+ Options.TracePC = false; //|= ClTracePC;
+ Options.TracePCGuard = true; // |= ClTracePCGuard;
+ Options.Inline8bitCounters = 0; //|= ClInline8bitCounters;
+ // Options.InlineBoolFlag = 0; //|= ClInlineBoolFlag;
+ Options.PCTable = false; //|= ClCreatePCTable;
+ Options.NoPrune = false; //|= !ClPruneBlocks;
+ Options.StackDepth = false; //|= ClStackDepth;
+ if (!Options.TracePCGuard && !Options.TracePC &&
+ !Options.Inline8bitCounters && !Options.StackDepth /*&&
+ !Options.InlineBoolFlag*/)
+ Options.TracePCGuard = true; // TracePCGuard is default.
+
+ return Options;
+
+}
+
+using DomTreeCallback = function_ref<const DominatorTree *(Function &F)>;
+using PostDomTreeCallback =
+ function_ref<const PostDominatorTree *(Function &F)>;
+
+class ModuleSanitizerCoverageAFL
+ : public PassInfoMixin<ModuleSanitizerCoverageAFL> {
+
+ public:
+ ModuleSanitizerCoverageAFL(
+ const SanitizerCoverageOptions &Options = SanitizerCoverageOptions())
+ : Options(OverrideFromCL(Options)) {
+
+ }
+
+ PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
+
+ bool instrumentModule(Module &M, DomTreeCallback DTCallback,
+ PostDomTreeCallback PDTCallback);
+
+ private:
+ void instrumentFunction(Function &F, DomTreeCallback DTCallback,
+ PostDomTreeCallback PDTCallback);
+ void InjectCoverageForIndirectCalls(Function & F,
+ ArrayRef<Instruction *> IndirCalls);
+ void InjectTraceForCmp(Function &F, ArrayRef<Instruction *> CmpTraceTargets);
+ void InjectTraceForDiv(Function & F,
+ ArrayRef<BinaryOperator *> DivTraceTargets);
+ void InjectTraceForGep(Function & F,
+ ArrayRef<GetElementPtrInst *> GepTraceTargets);
+ void InjectTraceForSwitch(Function & F,
+ ArrayRef<Instruction *> SwitchTraceTargets);
+ bool InjectCoverage(Function &F, ArrayRef<BasicBlock *> AllBlocks,
+ bool IsLeafFunc = true);
+ GlobalVariable *CreateFunctionLocalArrayInSection(size_t NumElements,
+ Function &F, Type *Ty,
+ const char *Section);
+ GlobalVariable *CreatePCArray(Function &F, ArrayRef<BasicBlock *> AllBlocks);
+ void CreateFunctionLocalArrays(Function &F, ArrayRef<BasicBlock *> AllBlocks,
+ uint32_t special);
+ void InjectCoverageAtBlock(Function &F, BasicBlock &BB, size_t Idx,
+ bool IsLeafFunc = true);
+ Function *CreateInitCallsForSections(Module &M, const char *CtorName,
+ const char *InitFunctionName, Type *Ty,
+ const char *Section);
+ std::pair<Value *, Value *> CreateSecStartEnd(Module &M, const char *Section,
+ Type *Ty);
+
+ void SetNoSanitizeMetadata(Instruction *I) {
+
+ I->setMetadata(I->getModule()->getMDKindID("nosanitize"),
+ MDNode::get(*C, None));
+
+ }
+
+ std::string getSectionName(const std::string &Section) const;
+ std::string getSectionStart(const std::string &Section) const;
+ std::string getSectionEnd(const std::string &Section) const;
+ FunctionCallee SanCovTracePCIndir;
+ FunctionCallee SanCovTracePC, SanCovTracePCGuard;
+ FunctionCallee SanCovTraceCmpFunction[4];
+ FunctionCallee SanCovTraceConstCmpFunction[4];
+ FunctionCallee SanCovTraceDivFunction[2];
+ FunctionCallee SanCovTraceGepFunction;
+ FunctionCallee SanCovTraceSwitchFunction;
+ GlobalVariable *SanCovLowestStack;
+ Type *IntptrTy, *IntptrPtrTy, *Int64Ty, *Int64PtrTy, *Int32Ty, *Int32PtrTy,
+ *Int16Ty, *Int8Ty, *Int8PtrTy, *Int1Ty, *Int1PtrTy;
+ Module * CurModule;
+ std::string CurModuleUniqueId;
+ Triple TargetTriple;
+ LLVMContext * C;
+ const DataLayout *DL;
+
+ GlobalVariable *FunctionGuardArray; // for trace-pc-guard.
+ GlobalVariable *Function8bitCounterArray; // for inline-8bit-counters.
+ GlobalVariable *FunctionBoolArray; // for inline-bool-flag.
+ GlobalVariable *FunctionPCsArray; // for pc-table.
+ SmallVector<GlobalValue *, 20> GlobalsToAppendToUsed;
+ SmallVector<GlobalValue *, 20> GlobalsToAppendToCompilerUsed;
+
+ SanitizerCoverageOptions Options;
+
+ uint32_t instr = 0, selects = 0, unhandled = 0;
+ GlobalVariable *AFLMapPtr = NULL;
+ ConstantInt * One = NULL;
+ ConstantInt * Zero = NULL;
+
+};
+
+class ModuleSanitizerCoverageLegacyPass : public ModulePass {
+
+ public:
+ ModuleSanitizerCoverageLegacyPass(
+ const SanitizerCoverageOptions &Options = SanitizerCoverageOptions())
+ : ModulePass(ID), Options(Options) {
+
+ initializeModuleSanitizerCoverageLegacyPassPass(
+ *PassRegistry::getPassRegistry());
+
+ }
+
+ bool runOnModule(Module &M) override {
+
+ ModuleSanitizerCoverageAFL ModuleSancov(Options);
+ auto DTCallback = [this](Function &F) -> const DominatorTree * {
+
+ return &this->getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();
+
+ };
+
+ auto PDTCallback = [this](Function &F) -> const PostDominatorTree * {
+
+ return &this->getAnalysis<PostDominatorTreeWrapperPass>(F)
+ .getPostDomTree();
+
+ };
+
+ return ModuleSancov.instrumentModule(M, DTCallback, PDTCallback);
+
+ }
+
+ /*static*/ char ID; // Pass identification, replacement for typeid
+ StringRef getPassName() const override {
+
+ return "ModuleSanitizerCoverage";
+
+ }
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+
+ AU.addRequired<DominatorTreeWrapperPass>();
+ AU.addRequired<PostDominatorTreeWrapperPass>();
+
+ }
+
+ private:
+ SanitizerCoverageOptions Options;
+
+};
+
+} // namespace
+
+#if 1
+
+extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
+llvmGetPassPluginInfo() {
+
+ return {LLVM_PLUGIN_API_VERSION, "SanitizerCoveragePCGUARD", "v0.1",
+ /* lambda to insert our pass into the pass pipeline. */
+ [](PassBuilder &PB) {
+
+ #if LLVM_VERSION_MAJOR <= 13
+ using OptimizationLevel = typename PassBuilder::OptimizationLevel;
+ #endif
+ PB.registerOptimizerLastEPCallback(
+ [](ModulePassManager &MPM, OptimizationLevel OL) {
+
+ MPM.addPass(ModuleSanitizerCoverageAFL());
+
+ });
+
+ }};
+
+}
+
+#endif
+
+PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module & M,
+ ModuleAnalysisManager &MAM) {
+
+ ModuleSanitizerCoverageAFL ModuleSancov(Options);
+ auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
+ auto DTCallback = [&FAM](Function &F) -> const DominatorTree * {
+
+ return &FAM.getResult<DominatorTreeAnalysis>(F);
+
+ };
+
+ auto PDTCallback = [&FAM](Function &F) -> const PostDominatorTree * {
+
+ return &FAM.getResult<PostDominatorTreeAnalysis>(F);
+
+ };
+
+ if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
+ return PreservedAnalyses::none();
+ return PreservedAnalyses::all();
+
+}
+
+std::pair<Value *, Value *> ModuleSanitizerCoverageAFL::CreateSecStartEnd(
+ Module &M, const char *Section, Type *Ty) {
+
+ GlobalVariable *SecStart =
+ new GlobalVariable(M,
+#if LLVM_VERSION_MAJOR >= 15
+ Ty,
+#else
+ Ty->getPointerElementType(),
+#endif
+ false, GlobalVariable::ExternalWeakLinkage, nullptr,
+ getSectionStart(Section));
+ SecStart->setVisibility(GlobalValue::HiddenVisibility);
+ GlobalVariable *SecEnd =
+ new GlobalVariable(M,
+#if LLVM_VERSION_MAJOR >= 15
+ Ty,
+#else
+ Ty->getPointerElementType(),
+#endif
+ false, GlobalVariable::ExternalWeakLinkage, nullptr,
+ getSectionEnd(Section));
+ SecEnd->setVisibility(GlobalValue::HiddenVisibility);
+ IRBuilder<> IRB(M.getContext());
+ if (!TargetTriple.isOSBinFormatCOFF())
+ return std::make_pair(SecStart, SecEnd);
+
+ // Account for the fact that on windows-msvc __start_* symbols actually
+ // point to a uint64_t before the start of the array.
+ auto SecStartI8Ptr = IRB.CreatePointerCast(SecStart, Int8PtrTy);
+ auto GEP = IRB.CreateGEP(Int8Ty, SecStartI8Ptr,
+ ConstantInt::get(IntptrTy, sizeof(uint64_t)));
+ return std::make_pair(IRB.CreatePointerCast(GEP, Ty), SecEnd);
+
+}
+
+Function *ModuleSanitizerCoverageAFL::CreateInitCallsForSections(
+ Module &M, const char *CtorName, const char *InitFunctionName, Type *Ty,
+ const char *Section) {
+
+ auto SecStartEnd = CreateSecStartEnd(M, Section, Ty);
+ auto SecStart = SecStartEnd.first;
+ auto SecEnd = SecStartEnd.second;
+ Function *CtorFunc;
+ std::tie(CtorFunc, std::ignore) = createSanitizerCtorAndInitFunctions(
+ M, CtorName, InitFunctionName, {Ty, Ty}, {SecStart, SecEnd});
+ assert(CtorFunc->getName() == CtorName);
+
+ if (TargetTriple.supportsCOMDAT()) {
+
+ // Use comdat to dedup CtorFunc.
+ CtorFunc->setComdat(M.getOrInsertComdat(CtorName));
+ appendToGlobalCtors(M, CtorFunc, SanCtorAndDtorPriority, CtorFunc);
+
+ } else {
+
+ appendToGlobalCtors(M, CtorFunc, SanCtorAndDtorPriority);
+
+ }
+
+ if (TargetTriple.isOSBinFormatCOFF()) {
+
+ // In COFF files, if the contructors are set as COMDAT (they are because
+ // COFF supports COMDAT) and the linker flag /OPT:REF (strip unreferenced
+ // functions and data) is used, the constructors get stripped. To prevent
+ // this, give the constructors weak ODR linkage and ensure the linker knows
+ // to include the sancov constructor. This way the linker can deduplicate
+ // the constructors but always leave one copy.
+ CtorFunc->setLinkage(GlobalValue::WeakODRLinkage);
+ appendToUsed(M, CtorFunc);
+
+ }
+
+ return CtorFunc;
+
+}
+
+bool ModuleSanitizerCoverageAFL::instrumentModule(
+ Module &M, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) {
+
+ setvbuf(stdout, NULL, _IONBF, 0);
+ if (getenv("AFL_DEBUG")) debug = 1;
+
+ if ((isatty(2) && !getenv("AFL_QUIET")) || debug) {
+
+ SAYF(cCYA "SanitizerCoveragePCGUARD" VERSION cRST "\n");
+
+ } else
+
+ be_quiet = 1;
+
+ skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
+ use_threadsafe_counters = getenv("AFL_LLVM_THREADSAFE_INST");
+
+ initInstrumentList();
+ scanForDangerousFunctions(&M);
+
+ if (debug) {
+
+ fprintf(stderr,
+ "SANCOV: covtype:%u indirect:%d stack:%d noprune:%d "
+ "createtable:%d tracepcguard:%d tracepc:%d\n",
+ Options.CoverageType, Options.IndirectCalls == true ? 1 : 0,
+ Options.StackDepth == true ? 1 : 0, Options.NoPrune == true ? 1 : 0,
+ // Options.InlineBoolFlag == true ? 1 : 0,
+ Options.PCTable == true ? 1 : 0,
+ Options.TracePCGuard == true ? 1 : 0,
+ Options.TracePC == true ? 1 : 0);
+
+ }
+
+ if (Options.CoverageType == SanitizerCoverageOptions::SCK_None) return false;
+ C = &(M.getContext());
+ DL = &M.getDataLayout();
+ CurModule = &M;
+ CurModuleUniqueId = getUniqueModuleId(CurModule);
+ TargetTriple = Triple(M.getTargetTriple());
+ FunctionGuardArray = nullptr;
+ Function8bitCounterArray = nullptr;
+ FunctionBoolArray = nullptr;
+ FunctionPCsArray = nullptr;
+ IntptrTy = Type::getIntNTy(*C, DL->getPointerSizeInBits());
+ IntptrPtrTy = PointerType::getUnqual(IntptrTy);
+ Type * VoidTy = Type::getVoidTy(*C);
+ IRBuilder<> IRB(*C);
+ Int64PtrTy = PointerType::getUnqual(IRB.getInt64Ty());
+ Int32PtrTy = PointerType::getUnqual(IRB.getInt32Ty());
+ Int8PtrTy = PointerType::getUnqual(IRB.getInt8Ty());
+ Int1PtrTy = PointerType::getUnqual(IRB.getInt1Ty());
+ Int64Ty = IRB.getInt64Ty();
+ Int32Ty = IRB.getInt32Ty();
+ Int16Ty = IRB.getInt16Ty();
+ Int8Ty = IRB.getInt8Ty();
+ Int1Ty = IRB.getInt1Ty();
+ LLVMContext &Ctx = M.getContext();
+
+ AFLMapPtr =
+ new GlobalVariable(M, PointerType::get(Int8Ty, 0), false,
+ GlobalValue::ExternalLinkage, 0, "__afl_area_ptr");
+ One = ConstantInt::get(IntegerType::getInt8Ty(Ctx), 1);
+ Zero = ConstantInt::get(IntegerType::getInt8Ty(Ctx), 0);
+
+ SanCovTracePCIndir =
+ M.getOrInsertFunction(SanCovTracePCIndirName, VoidTy, IntptrTy);
+ // Make sure smaller parameters are zero-extended to i64 if required by the
+ // target ABI.
+ AttributeList SanCovTraceCmpZeroExtAL;
+ SanCovTraceCmpZeroExtAL =
+ SanCovTraceCmpZeroExtAL.addParamAttribute(*C, 0, Attribute::ZExt);
+ SanCovTraceCmpZeroExtAL =
+ SanCovTraceCmpZeroExtAL.addParamAttribute(*C, 1, Attribute::ZExt);
+
+ SanCovTraceCmpFunction[0] =
+ M.getOrInsertFunction(SanCovTraceCmp1, SanCovTraceCmpZeroExtAL, VoidTy,
+ IRB.getInt8Ty(), IRB.getInt8Ty());
+ SanCovTraceCmpFunction[1] =
+ M.getOrInsertFunction(SanCovTraceCmp2, SanCovTraceCmpZeroExtAL, VoidTy,
+ IRB.getInt16Ty(), IRB.getInt16Ty());
+ SanCovTraceCmpFunction[2] =
+ M.getOrInsertFunction(SanCovTraceCmp4, SanCovTraceCmpZeroExtAL, VoidTy,
+ IRB.getInt32Ty(), IRB.getInt32Ty());
+ SanCovTraceCmpFunction[3] =
+ M.getOrInsertFunction(SanCovTraceCmp8, VoidTy, Int64Ty, Int64Ty);
+
+ SanCovTraceConstCmpFunction[0] = M.getOrInsertFunction(
+ SanCovTraceConstCmp1, SanCovTraceCmpZeroExtAL, VoidTy, Int8Ty, Int8Ty);
+ SanCovTraceConstCmpFunction[1] = M.getOrInsertFunction(
+ SanCovTraceConstCmp2, SanCovTraceCmpZeroExtAL, VoidTy, Int16Ty, Int16Ty);
+ SanCovTraceConstCmpFunction[2] = M.getOrInsertFunction(
+ SanCovTraceConstCmp4, SanCovTraceCmpZeroExtAL, VoidTy, Int32Ty, Int32Ty);
+ SanCovTraceConstCmpFunction[3] =
+ M.getOrInsertFunction(SanCovTraceConstCmp8, VoidTy, Int64Ty, Int64Ty);
+
+ {
+
+ AttributeList AL;
+ AL = AL.addParamAttribute(*C, 0, Attribute::ZExt);
+ SanCovTraceDivFunction[0] =
+ M.getOrInsertFunction(SanCovTraceDiv4, AL, VoidTy, IRB.getInt32Ty());
+
+ }
+
+ SanCovTraceDivFunction[1] =
+ M.getOrInsertFunction(SanCovTraceDiv8, VoidTy, Int64Ty);
+ SanCovTraceGepFunction =
+ M.getOrInsertFunction(SanCovTraceGep, VoidTy, IntptrTy);
+ SanCovTraceSwitchFunction =
+ M.getOrInsertFunction(SanCovTraceSwitchName, VoidTy, Int64Ty, Int64PtrTy);
+
+ Constant *SanCovLowestStackConstant =
+ M.getOrInsertGlobal(SanCovLowestStackName, IntptrTy);
+ SanCovLowestStack = dyn_cast<GlobalVariable>(SanCovLowestStackConstant);
+ if (!SanCovLowestStack) {
+
+ C->emitError(StringRef("'") + SanCovLowestStackName +
+ "' should not be declared by the user");
+ return true;
+
+ }
+
+ SanCovLowestStack->setThreadLocalMode(
+ GlobalValue::ThreadLocalMode::InitialExecTLSModel);
+ if (Options.StackDepth && !SanCovLowestStack->isDeclaration())
+ SanCovLowestStack->setInitializer(Constant::getAllOnesValue(IntptrTy));
+
+ SanCovTracePC = M.getOrInsertFunction(SanCovTracePCName, VoidTy);
+ SanCovTracePCGuard =
+ M.getOrInsertFunction(SanCovTracePCGuardName, VoidTy, Int32PtrTy);
+
+ for (auto &F : M)
+ instrumentFunction(F, DTCallback, PDTCallback);
+
+ Function *Ctor = nullptr;
+
+ if (FunctionGuardArray)
+ Ctor = CreateInitCallsForSections(M, SanCovModuleCtorTracePcGuardName,
+ SanCovTracePCGuardInitName, Int32PtrTy,
+ SanCovGuardsSectionName);
+ if (Function8bitCounterArray)
+ Ctor = CreateInitCallsForSections(M, SanCovModuleCtor8bitCountersName,
+ SanCov8bitCountersInitName, Int8PtrTy,
+ SanCovCountersSectionName);
+ if (FunctionBoolArray) {
+
+ Ctor = CreateInitCallsForSections(M, SanCovModuleCtorBoolFlagName,
+ SanCovBoolFlagInitName, Int1PtrTy,
+ SanCovBoolFlagSectionName);
+
+ }
+
+ if (Ctor && Options.PCTable) {
+
+ auto SecStartEnd = CreateSecStartEnd(M, SanCovPCsSectionName, IntptrPtrTy);
+ FunctionCallee InitFunction = declareSanitizerInitFunction(
+ M, SanCovPCsInitName, {IntptrPtrTy, IntptrPtrTy});
+ IRBuilder<> IRBCtor(Ctor->getEntryBlock().getTerminator());
+ IRBCtor.CreateCall(InitFunction, {SecStartEnd.first, SecStartEnd.second});
+
+ }
+
+ // We don't reference these arrays directly in any of our runtime functions,
+ // so we need to prevent them from being dead stripped.
+ if (TargetTriple.isOSBinFormatMachO()) appendToUsed(M, GlobalsToAppendToUsed);
+ appendToCompilerUsed(M, GlobalsToAppendToCompilerUsed);
+
+ if (!be_quiet) {
+
+ if (!instr)
+ WARNF("No instrumentation targets found.");
+ else {
+
+ char modeline[100];
+ snprintf(modeline, sizeof(modeline), "%s%s%s%s%s%s",
+ getenv("AFL_HARDEN") ? "hardened" : "non-hardened",
+ getenv("AFL_USE_ASAN") ? ", ASAN" : "",
+ getenv("AFL_USE_MSAN") ? ", MSAN" : "",
+ getenv("AFL_USE_TSAN") ? ", TSAN" : "",
+ getenv("AFL_USE_CFISAN") ? ", CFISAN" : "",
+ getenv("AFL_USE_UBSAN") ? ", UBSAN" : "");
+ OKF("Instrumented %u locations with no collisions (%s mode) of which are "
+ "%u handled and %u unhandled selects.",
+ instr, modeline, selects, unhandled);
+
+ }
+
+ }
+
+ return true;
+
+}
+
+// True if block has successors and it dominates all of them.
+bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) {
+
+ if (succ_begin(BB) == succ_end(BB)) return false;
+
+ for (const BasicBlock *SUCC : make_range(succ_begin(BB), succ_end(BB))) {
+
+ if (!DT->dominates(BB, SUCC)) return false;
+
+ }
+
+ return true;
+
+}
+
+// True if block has predecessors and it postdominates all of them.
+bool isFullPostDominator(const BasicBlock *BB, const PostDominatorTree *PDT) {
+
+ if (pred_begin(BB) == pred_end(BB)) return false;
+
+ for (const BasicBlock *PRED : make_range(pred_begin(BB), pred_end(BB))) {
+
+ if (!PDT->dominates(BB, PRED)) return false;
+
+ }
+
+ return true;
+
+}
+
+bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB,
+ const DominatorTree * DT,
+ const PostDominatorTree * PDT,
+ const SanitizerCoverageOptions &Options) {
+
+ // Don't insert coverage for blocks containing nothing but unreachable: we
+ // will never call __sanitizer_cov() for them, so counting them in
+ // NumberOfInstrumentedBlocks() might complicate calculation of code coverage
+ // percentage. Also, unreachable instructions frequently have no debug
+ // locations.
+ if (isa<UnreachableInst>(BB->getFirstNonPHIOrDbgOrLifetime())) return false;
+
+ // Don't insert coverage into blocks without a valid insertion point
+ // (catchswitch blocks).
+ if (BB->getFirstInsertionPt() == BB->end()) return false;
+
+ if (Options.NoPrune || &F.getEntryBlock() == BB) return true;
+
+ if (Options.CoverageType == SanitizerCoverageOptions::SCK_Function &&
+ &F.getEntryBlock() != BB)
+ return false;
+
+ // Do not instrument full dominators, or full post-dominators with multiple
+ // predecessors.
+ return !isFullDominator(BB, DT) &&
+ !(isFullPostDominator(BB, PDT) && !BB->getSinglePredecessor());
+
+}
+
+// Returns true iff From->To is a backedge.
+// A twist here is that we treat From->To as a backedge if
+// * To dominates From or
+// * To->UniqueSuccessor dominates From
+bool IsBackEdge(BasicBlock *From, BasicBlock *To, const DominatorTree *DT) {
+
+ if (DT->dominates(To, From)) return true;
+ if (auto Next = To->getUniqueSuccessor())
+ if (DT->dominates(Next, From)) return true;
+ return false;
+
+}
+
+// Prunes uninteresting Cmp instrumentation:
+// * CMP instructions that feed into loop backedge branch.
+//
+// Note that Cmp pruning is controlled by the same flag as the
+// BB pruning.
+bool IsInterestingCmp(ICmpInst *CMP, const DominatorTree *DT,
+ const SanitizerCoverageOptions &Options) {
+
+ if (!Options.NoPrune)
+ if (CMP->hasOneUse())
+ if (auto BR = dyn_cast<BranchInst>(CMP->user_back()))
+ for (BasicBlock *B : BR->successors())
+ if (IsBackEdge(BR->getParent(), B, DT)) return false;
+ return true;
+
+}
+
+void ModuleSanitizerCoverageAFL::instrumentFunction(
+ Function &F, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) {
+
+ if (F.empty()) return;
+ if (!isInInstrumentList(&F, FMNAME)) return;
+
+ if (F.getName().find(".module_ctor") != std::string::npos)
+ return; // Should not instrument sanitizer init functions.
+ if (F.getName().startswith("__sanitizer_"))
+ return; // Don't instrument __sanitizer_* callbacks.
+ // Don't touch available_externally functions, their actual body is elewhere.
+ if (F.getLinkage() == GlobalValue::AvailableExternallyLinkage) return;
+ // Don't instrument MSVC CRT configuration helpers. They may run before normal
+ // initialization.
+ if (F.getName() == "__local_stdio_printf_options" ||
+ F.getName() == "__local_stdio_scanf_options")
+ return;
+ if (isa<UnreachableInst>(F.getEntryBlock().getTerminator())) return;
+ // Don't instrument functions using SEH for now. Splitting basic blocks like
+ // we do for coverage breaks WinEHPrepare.
+ // FIXME: Remove this when SEH no longer uses landingpad pattern matching.
+ if (F.hasPersonalityFn() &&
+ isAsynchronousEHPersonality(classifyEHPersonality(F.getPersonalityFn())))
+ return;
+ if (Options.CoverageType >= SanitizerCoverageOptions::SCK_Edge)
+ SplitAllCriticalEdges(
+ F, CriticalEdgeSplittingOptions().setIgnoreUnreachableDests());
+ SmallVector<Instruction *, 8> IndirCalls;
+ SmallVector<BasicBlock *, 16> BlocksToInstrument;
+ SmallVector<Instruction *, 8> CmpTraceTargets;
+ SmallVector<Instruction *, 8> SwitchTraceTargets;
+ SmallVector<BinaryOperator *, 8> DivTraceTargets;
+ SmallVector<GetElementPtrInst *, 8> GepTraceTargets;
+
+ const DominatorTree * DT = DTCallback(F);
+ const PostDominatorTree *PDT = PDTCallback(F);
+ bool IsLeafFunc = true;
+
+ for (auto &BB : F) {
+
+ if (shouldInstrumentBlock(F, &BB, DT, PDT, Options))
+ BlocksToInstrument.push_back(&BB);
+ for (auto &Inst : BB) {
+
+ if (Options.IndirectCalls) {
+
+ CallBase *CB = dyn_cast<CallBase>(&Inst);
+ if (CB && !CB->getCalledFunction()) IndirCalls.push_back(&Inst);
+
+ }
+
+ if (Options.TraceCmp) {
+
+ if (ICmpInst *CMP = dyn_cast<ICmpInst>(&Inst))
+ if (IsInterestingCmp(CMP, DT, Options))
+ CmpTraceTargets.push_back(&Inst);
+ if (isa<SwitchInst>(&Inst)) SwitchTraceTargets.push_back(&Inst);
+
+ }
+
+ if (Options.TraceDiv)
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(&Inst))
+ if (BO->getOpcode() == Instruction::SDiv ||
+ BO->getOpcode() == Instruction::UDiv)
+ DivTraceTargets.push_back(BO);
+ if (Options.TraceGep)
+ if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(&Inst))
+ GepTraceTargets.push_back(GEP);
+ if (Options.StackDepth)
+ if (isa<InvokeInst>(Inst) ||
+ (isa<CallInst>(Inst) && !isa<IntrinsicInst>(Inst)))
+ IsLeafFunc = false;
+
+ }
+
+ }
+
+ InjectCoverage(F, BlocksToInstrument, IsLeafFunc);
+ InjectCoverageForIndirectCalls(F, IndirCalls);
+ InjectTraceForCmp(F, CmpTraceTargets);
+ InjectTraceForSwitch(F, SwitchTraceTargets);
+ InjectTraceForDiv(F, DivTraceTargets);
+ InjectTraceForGep(F, GepTraceTargets);
+
+}
+
+GlobalVariable *ModuleSanitizerCoverageAFL::CreateFunctionLocalArrayInSection(
+ size_t NumElements, Function &F, Type *Ty, const char *Section) {
+
+ ArrayType *ArrayTy = ArrayType::get(Ty, NumElements);
+ auto Array = new GlobalVariable(
+ *CurModule, ArrayTy, false, GlobalVariable::PrivateLinkage,
+ Constant::getNullValue(ArrayTy), "__sancov_gen_");
+
+#if LLVM_VERSION_MAJOR >= 13
+ if (TargetTriple.supportsCOMDAT() &&
+ (TargetTriple.isOSBinFormatELF() || !F.isInterposable()))
+ if (auto Comdat = getOrCreateFunctionComdat(F, TargetTriple))
+ Array->setComdat(Comdat);
+#else
+ if (TargetTriple.supportsCOMDAT() && !F.isInterposable())
+ if (auto Comdat =
+ GetOrCreateFunctionComdat(F, TargetTriple, CurModuleUniqueId))
+ Array->setComdat(Comdat);
+#endif
+
+ Array->setSection(getSectionName(Section));
+#if (LLVM_VERSION_MAJOR >= 11) || \
+ (LLVM_VERSION_MAJOR == 10 && LLVM_VERSION_MINOR >= 1)
+ Array->setAlignment(Align(DL->getTypeStoreSize(Ty).getFixedSize()));
+#else
+ Array->setAlignment(Align(4)); // cheating
+#endif
+ GlobalsToAppendToUsed.push_back(Array);
+ GlobalsToAppendToCompilerUsed.push_back(Array);
+ MDNode *MD = MDNode::get(F.getContext(), ValueAsMetadata::get(&F));
+ Array->addMetadata(LLVMContext::MD_associated, *MD);
+
+ return Array;
+
+}
+
+GlobalVariable *ModuleSanitizerCoverageAFL::CreatePCArray(
+ Function &F, ArrayRef<BasicBlock *> AllBlocks) {
+
+ size_t N = AllBlocks.size();
+ assert(N);
+ SmallVector<Constant *, 32> PCs;
+ IRBuilder<> IRB(&*F.getEntryBlock().getFirstInsertionPt());
+ for (size_t i = 0; i < N; i++) {
+
+ if (&F.getEntryBlock() == AllBlocks[i]) {
+
+ PCs.push_back((Constant *)IRB.CreatePointerCast(&F, IntptrPtrTy));
+ PCs.push_back((Constant *)IRB.CreateIntToPtr(
+ ConstantInt::get(IntptrTy, 1), IntptrPtrTy));
+
+ } else {
+
+ PCs.push_back((Constant *)IRB.CreatePointerCast(
+ BlockAddress::get(AllBlocks[i]), IntptrPtrTy));
+ PCs.push_back((Constant *)IRB.CreateIntToPtr(
+ ConstantInt::get(IntptrTy, 0), IntptrPtrTy));
+
+ }
+
+ }
+
+ auto *PCArray = CreateFunctionLocalArrayInSection(N * 2, F, IntptrPtrTy,
+ SanCovPCsSectionName);
+ PCArray->setInitializer(
+ ConstantArray::get(ArrayType::get(IntptrPtrTy, N * 2), PCs));
+ PCArray->setConstant(true);
+
+ return PCArray;
+
+}
+
+void ModuleSanitizerCoverageAFL::CreateFunctionLocalArrays(
+ Function &F, ArrayRef<BasicBlock *> AllBlocks, uint32_t special) {
+
+ if (Options.TracePCGuard)
+ FunctionGuardArray = CreateFunctionLocalArrayInSection(
+ AllBlocks.size() + special, F, Int32Ty, SanCovGuardsSectionName);
+
+ if (Options.Inline8bitCounters)
+ Function8bitCounterArray = CreateFunctionLocalArrayInSection(
+ AllBlocks.size(), F, Int8Ty, SanCovCountersSectionName);
+ /*
+ if (Options.InlineBoolFlag)
+ FunctionBoolArray = CreateFunctionLocalArrayInSection(
+ AllBlocks.size(), F, Int1Ty, SanCovBoolFlagSectionName);
+ */
+ if (Options.PCTable) FunctionPCsArray = CreatePCArray(F, AllBlocks);
+
+}
+
+bool ModuleSanitizerCoverageAFL::InjectCoverage(
+ Function &F, ArrayRef<BasicBlock *> AllBlocks, bool IsLeafFunc) {
+
+ uint32_t cnt_cov = 0, cnt_sel = 0, cnt_sel_inc = 0;
+
+ for (auto &BB : F) {
+
+ for (auto &IN : BB) {
+
+ CallInst *callInst = nullptr;
+
+ if ((callInst = dyn_cast<CallInst>(&IN))) {
+
+ Function *Callee = callInst->getCalledFunction();
+ if (!Callee) continue;
+ if (callInst->getCallingConv() != llvm::CallingConv::C) continue;
+ StringRef FuncName = Callee->getName();
+ if (!FuncName.compare(StringRef("dlopen")) ||
+ !FuncName.compare(StringRef("_dlopen"))) {
+
+ fprintf(stderr,
+ "WARNING: dlopen() detected. To have coverage for a library "
+ "that your target dlopen()'s this must either happen before "
+ "__AFL_INIT() or you must use AFL_PRELOAD to preload all "
+ "dlopen()'ed libraries!\n");
+ continue;
+
+ }
+
+ if (FuncName.compare(StringRef("__afl_coverage_interesting"))) continue;
+
+ cnt_cov++;
+
+ }
+
+ SelectInst *selectInst = nullptr;
+
+ if ((selectInst = dyn_cast<SelectInst>(&IN))) {
+
+ Value *c = selectInst->getCondition();
+ auto t = c->getType();
+ if (t->getTypeID() == llvm::Type::IntegerTyID) {
+
+ cnt_sel++;
+ cnt_sel_inc += 2;
+
+ }
+
+#if (LLVM_VERSION_MAJOR >= 12)
+ else if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
+
+ FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
+ if (tt) {
+
+ cnt_sel++;
+ cnt_sel_inc += tt->getElementCount().getKnownMinValue();
+
+ }
+
+ }
+
+#endif
+
+ }
+
+ }
+
+ }
+
+ /* Create PCGUARD array */
+ CreateFunctionLocalArrays(F, AllBlocks, cnt_cov + cnt_sel_inc);
+ selects += cnt_sel;
+
+ uint32_t special = 0, local_selects = 0, skip_next = 0;
+
+ for (auto &BB : F) {
+
+ for (auto &IN : BB) {
+
+ CallInst *callInst = nullptr;
+
+ /*
+ std::string errMsg;
+ raw_string_ostream os(errMsg);
+ IN.print(os);
+ fprintf(stderr, "X: %s\n", os.str().c_str());
+ */
+ if ((callInst = dyn_cast<CallInst>(&IN))) {
+
+ Function *Callee = callInst->getCalledFunction();
+ if (!Callee) continue;
+ if (callInst->getCallingConv() != llvm::CallingConv::C) continue;
+ StringRef FuncName = Callee->getName();
+ if (FuncName.compare(StringRef("__afl_coverage_interesting"))) continue;
+
+ IRBuilder<> IRB(callInst);
+
+ if (!FunctionGuardArray) {
+
+ fprintf(stderr,
+ "SANCOV: FunctionGuardArray is NULL, failed to emit "
+ "instrumentation.");
+ continue;
+
+ }
+
+ Value *GuardPtr = IRB.CreateIntToPtr(
+ IRB.CreateAdd(
+ IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
+ ConstantInt::get(IntptrTy, (++special + AllBlocks.size()) * 4)),
+ Int32PtrTy);
+
+ LoadInst *Idx = IRB.CreateLoad(IRB.getInt32Ty(), GuardPtr);
+ ModuleSanitizerCoverageAFL::SetNoSanitizeMetadata(Idx);
+
+ callInst->setOperand(1, Idx);
+
+ }
+
+ SelectInst *selectInst = nullptr;
+
+ if (!skip_next && (selectInst = dyn_cast<SelectInst>(&IN))) {
+
+ uint32_t vector_cnt = 0;
+ Value * condition = selectInst->getCondition();
+ Value * result;
+ auto t = condition->getType();
+ IRBuilder<> IRB(selectInst->getNextNode());
+
+ if (t->getTypeID() == llvm::Type::IntegerTyID) {
+
+ if (!FunctionGuardArray) {
+
+ fprintf(stderr,
+ "SANCOV: FunctionGuardArray is NULL, failed to emit "
+ "instrumentation.");
+ continue;
+
+ }
+
+ auto GuardPtr1 = IRB.CreateIntToPtr(
+ IRB.CreateAdd(
+ IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
+ ConstantInt::get(
+ IntptrTy,
+ (cnt_cov + ++local_selects + AllBlocks.size()) * 4)),
+ Int32PtrTy);
+
+ auto GuardPtr2 = IRB.CreateIntToPtr(
+ IRB.CreateAdd(
+ IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
+ ConstantInt::get(
+ IntptrTy,
+ (cnt_cov + ++local_selects + AllBlocks.size()) * 4)),
+ Int32PtrTy);
+
+ result = IRB.CreateSelect(condition, GuardPtr1, GuardPtr2);
+
+ } else
+
+#if LLVM_VERSION_MAJOR >= 14
+ if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
+
+ FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
+ if (tt) {
+
+ uint32_t elements = tt->getElementCount().getFixedValue();
+ vector_cnt = elements;
+ if (elements) {
+
+ FixedVectorType *GuardPtr1 =
+ FixedVectorType::get(Int32PtrTy, elements);
+ FixedVectorType *GuardPtr2 =
+ FixedVectorType::get(Int32PtrTy, elements);
+ Value *x, *y;
+
+ if (!FunctionGuardArray) {
+
+ fprintf(stderr,
+ "SANCOV: FunctionGuardArray is NULL, failed to emit "
+ "instrumentation.");
+ continue;
+
+ }
+
+ Value *val1 = IRB.CreateIntToPtr(
+ IRB.CreateAdd(
+ IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
+ ConstantInt::get(
+ IntptrTy,
+ (cnt_cov + ++local_selects + AllBlocks.size()) * 4)),
+ Int32PtrTy);
+ x = IRB.CreateInsertElement(GuardPtr1, val1, (uint64_t)0);
+
+ Value *val2 = IRB.CreateIntToPtr(
+ IRB.CreateAdd(
+ IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
+ ConstantInt::get(
+ IntptrTy,
+ (cnt_cov + ++local_selects + AllBlocks.size()) * 4)),
+ Int32PtrTy);
+ y = IRB.CreateInsertElement(GuardPtr2, val2, (uint64_t)0);
+
+ for (uint64_t i = 1; i < elements; i++) {
+
+ val1 = IRB.CreateIntToPtr(
+ IRB.CreateAdd(
+ IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
+ ConstantInt::get(IntptrTy, (cnt_cov + ++local_selects +
+ AllBlocks.size()) *
+ 4)),
+ Int32PtrTy);
+ x = IRB.CreateInsertElement(x, val1, i);
+
+ val2 = IRB.CreateIntToPtr(
+ IRB.CreateAdd(
+ IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
+ ConstantInt::get(IntptrTy, (cnt_cov + ++local_selects +
+ AllBlocks.size()) *
+ 4)),
+ Int32PtrTy);
+ y = IRB.CreateInsertElement(y, val2, i);
+
+ }
+
+ /*
+ std::string errMsg;
+ raw_string_ostream os(errMsg);
+ x->print(os);
+ fprintf(stderr, "X: %s\n", os.str().c_str());
+ */
+ result = IRB.CreateSelect(condition, x, y);
+
+ }
+
+ }
+
+ } else
+
+#endif
+ {
+
+ unhandled++;
+ continue;
+
+ }
+
+ uint32_t vector_cur = 0;
+
+ /* Load SHM pointer */
+
+ LoadInst *MapPtr =
+ IRB.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr);
+ ModuleSanitizerCoverageAFL::SetNoSanitizeMetadata(MapPtr);
+
+ /*
+ std::string errMsg;
+ raw_string_ostream os(errMsg);
+ result->print(os);
+ fprintf(stderr, "X: %s\n", os.str().c_str());
+ */
+
+ while (1) {
+
+ /* Get CurLoc */
+ LoadInst *CurLoc = nullptr;
+ Value * MapPtrIdx = nullptr;
+
+ /* Load counter for CurLoc */
+ if (!vector_cnt) {
+
+ CurLoc = IRB.CreateLoad(IRB.getInt32Ty(), result);
+ ModuleSanitizerCoverageAFL::SetNoSanitizeMetadata(CurLoc);
+ MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtr, CurLoc);
+
+ } else {
+
+ auto element = IRB.CreateExtractElement(result, vector_cur++);
+ auto elementptr = IRB.CreateIntToPtr(element, Int32PtrTy);
+ auto elementld = IRB.CreateLoad(IRB.getInt32Ty(), elementptr);
+ ModuleSanitizerCoverageAFL::SetNoSanitizeMetadata(elementld);
+ MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtr, elementld);
+
+ }
+
+ if (use_threadsafe_counters) {
+
+ IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One,
+#if LLVM_VERSION_MAJOR >= 13
+ llvm::MaybeAlign(1),
+#endif
+ llvm::AtomicOrdering::Monotonic);
+
+ } else {
+
+ LoadInst *Counter = IRB.CreateLoad(IRB.getInt8Ty(), MapPtrIdx);
+ ModuleSanitizerCoverageAFL::SetNoSanitizeMetadata(Counter);
+
+ /* Update bitmap */
+
+ Value *Incr = IRB.CreateAdd(Counter, One);
+
+ if (skip_nozero == NULL) {
+
+ auto cf = IRB.CreateICmpEQ(Incr, Zero);
+ auto carry = IRB.CreateZExt(cf, Int8Ty);
+ Incr = IRB.CreateAdd(Incr, carry);
+
+ }
+
+ StoreInst *StoreCtx = IRB.CreateStore(Incr, MapPtrIdx);
+ ModuleSanitizerCoverageAFL::SetNoSanitizeMetadata(StoreCtx);
+
+ }
+
+ if (!vector_cnt) {
+
+ vector_cnt = 2;
+ break;
+
+ } else if (vector_cnt == vector_cur) {
+
+ break;
+
+ }
+
+ }
+
+ skip_next = 1;
+ instr += vector_cnt;
+
+ } else {
+
+ skip_next = 0;
+
+ }
+
+ }
+
+ }
+
+ if (AllBlocks.empty() && !special && !local_selects) return false;
+
+ if (!AllBlocks.empty())
+ for (size_t i = 0, N = AllBlocks.size(); i < N; i++)
+ InjectCoverageAtBlock(F, *AllBlocks[i], i, IsLeafFunc);
+
+ return true;
+
+}
+
+// On every indirect call we call a run-time function
+// __sanitizer_cov_indir_call* with two parameters:
+// - callee address,
+// - global cache array that contains CacheSize pointers (zero-initialized).
+// The cache is used to speed up recording the caller-callee pairs.
+// The address of the caller is passed implicitly via caller PC.
+// CacheSize is encoded in the name of the run-time function.
+void ModuleSanitizerCoverageAFL::InjectCoverageForIndirectCalls(
+ Function &F, ArrayRef<Instruction *> IndirCalls) {
+
+ if (IndirCalls.empty()) return;
+ for (auto I : IndirCalls) {
+
+ IRBuilder<> IRB(I);
+ CallBase & CB = cast<CallBase>(*I);
+ Value * Callee = CB.getCalledOperand();
+ if (isa<InlineAsm>(Callee)) continue;
+ IRB.CreateCall(SanCovTracePCIndir, IRB.CreatePointerCast(Callee, IntptrTy));
+
+ }
+
+}
+
+// For every switch statement we insert a call:
+// __sanitizer_cov_trace_switch(CondValue,
+// {NumCases, ValueSizeInBits, Case0Value, Case1Value, Case2Value, ... })
+
+void ModuleSanitizerCoverageAFL::InjectTraceForSwitch(
+ Function &, ArrayRef<Instruction *> SwitchTraceTargets) {
+
+ for (auto I : SwitchTraceTargets) {
+
+ if (SwitchInst *SI = dyn_cast<SwitchInst>(I)) {
+
+ IRBuilder<> IRB(I);
+ SmallVector<Constant *, 16> Initializers;
+ Value * Cond = SI->getCondition();
+ if (Cond->getType()->getScalarSizeInBits() >
+ Int64Ty->getScalarSizeInBits())
+ continue;
+ Initializers.push_back(ConstantInt::get(Int64Ty, SI->getNumCases()));
+ Initializers.push_back(
+ ConstantInt::get(Int64Ty, Cond->getType()->getScalarSizeInBits()));
+ if (Cond->getType()->getScalarSizeInBits() <
+ Int64Ty->getScalarSizeInBits())
+ Cond = IRB.CreateIntCast(Cond, Int64Ty, false);
+ for (auto It : SI->cases()) {
+
+ Constant *C = It.getCaseValue();
+ if (C->getType()->getScalarSizeInBits() <
+ Int64Ty->getScalarSizeInBits())
+ C = ConstantExpr::getCast(CastInst::ZExt, It.getCaseValue(), Int64Ty);
+ Initializers.push_back(C);
+
+ }
+
+ llvm::sort(drop_begin(Initializers, 2),
+ [](const Constant *A, const Constant *B) {
+
+ return cast<ConstantInt>(A)->getLimitedValue() <
+ cast<ConstantInt>(B)->getLimitedValue();
+
+ });
+
+ ArrayType *ArrayOfInt64Ty = ArrayType::get(Int64Ty, Initializers.size());
+ GlobalVariable *GV = new GlobalVariable(
+ *CurModule, ArrayOfInt64Ty, false, GlobalVariable::InternalLinkage,
+ ConstantArray::get(ArrayOfInt64Ty, Initializers),
+ "__sancov_gen_cov_switch_values");
+ IRB.CreateCall(SanCovTraceSwitchFunction,
+ {Cond, IRB.CreatePointerCast(GV, Int64PtrTy)});
+
+ }
+
+ }
+
+}
+
+void ModuleSanitizerCoverageAFL::InjectTraceForDiv(
+ Function &, ArrayRef<BinaryOperator *> DivTraceTargets) {
+
+ for (auto BO : DivTraceTargets) {
+
+ IRBuilder<> IRB(BO);
+ Value * A1 = BO->getOperand(1);
+ if (isa<ConstantInt>(A1)) continue;
+ if (!A1->getType()->isIntegerTy()) continue;
+ uint64_t TypeSize = DL->getTypeStoreSizeInBits(A1->getType());
+ int CallbackIdx = TypeSize == 32 ? 0 : TypeSize == 64 ? 1 : -1;
+ if (CallbackIdx < 0) continue;
+ auto Ty = Type::getIntNTy(*C, TypeSize);
+ IRB.CreateCall(SanCovTraceDivFunction[CallbackIdx],
+ {IRB.CreateIntCast(A1, Ty, true)});
+
+ }
+
+}
+
+void ModuleSanitizerCoverageAFL::InjectTraceForGep(
+ Function &, ArrayRef<GetElementPtrInst *> GepTraceTargets) {
+
+ for (auto GEP : GepTraceTargets) {
+
+ IRBuilder<> IRB(GEP);
+ for (Use &Idx : GEP->indices())
+ if (!isa<ConstantInt>(Idx) && Idx->getType()->isIntegerTy())
+ IRB.CreateCall(SanCovTraceGepFunction,
+ {IRB.CreateIntCast(Idx, IntptrTy, true)});
+
+ }
+
+}
+
+void ModuleSanitizerCoverageAFL::InjectTraceForCmp(
+ Function &, ArrayRef<Instruction *> CmpTraceTargets) {
+
+ for (auto I : CmpTraceTargets) {
+
+ if (ICmpInst *ICMP = dyn_cast<ICmpInst>(I)) {
+
+ IRBuilder<> IRB(ICMP);
+ Value * A0 = ICMP->getOperand(0);
+ Value * A1 = ICMP->getOperand(1);
+ if (!A0->getType()->isIntegerTy()) continue;
+ uint64_t TypeSize = DL->getTypeStoreSizeInBits(A0->getType());
+ int CallbackIdx = TypeSize == 8 ? 0
+ : TypeSize == 16 ? 1
+ : TypeSize == 32 ? 2
+ : TypeSize == 64 ? 3
+ : -1;
+ if (CallbackIdx < 0) continue;
+ // __sanitizer_cov_trace_cmp((type_size << 32) | predicate, A0, A1);
+ auto CallbackFunc = SanCovTraceCmpFunction[CallbackIdx];
+ bool FirstIsConst = isa<ConstantInt>(A0);
+ bool SecondIsConst = isa<ConstantInt>(A1);
+ // If both are const, then we don't need such a comparison.
+ if (FirstIsConst && SecondIsConst) continue;
+ // If only one is const, then make it the first callback argument.
+ if (FirstIsConst || SecondIsConst) {
+
+ CallbackFunc = SanCovTraceConstCmpFunction[CallbackIdx];
+ if (SecondIsConst) std::swap(A0, A1);
+
+ }
+
+ auto Ty = Type::getIntNTy(*C, TypeSize);
+ IRB.CreateCall(CallbackFunc, {IRB.CreateIntCast(A0, Ty, true),
+ IRB.CreateIntCast(A1, Ty, true)});
+
+ }
+
+ }
+
+}
+
+void ModuleSanitizerCoverageAFL::InjectCoverageAtBlock(Function & F,
+ BasicBlock &BB,
+ size_t Idx,
+ bool IsLeafFunc) {
+
+ BasicBlock::iterator IP = BB.getFirstInsertionPt();
+ bool IsEntryBB = &BB == &F.getEntryBlock();
+
+ if (IsEntryBB) {
+
+ // Keep allocas and llvm.localescape calls in the entry block. Even
+ // if we aren't splitting the block, it's nice for allocas to be before
+ // calls.
+ IP = PrepareToSplitEntryBlock(BB, IP);
+
+ }
+
+ IRBuilder<> IRB(&*IP);
+
+ if (Options.TracePC) {
+
+ IRB.CreateCall(SanCovTracePC);
+ // ->setCannotMerge(); // gets the PC using GET_CALLER_PC.
+
+ }
+
+ if (Options.TracePCGuard) {
+
+ /* Get CurLoc */
+
+ Value *GuardPtr = IRB.CreateIntToPtr(
+ IRB.CreateAdd(IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
+ ConstantInt::get(IntptrTy, Idx * 4)),
+ Int32PtrTy);
+
+ LoadInst *CurLoc = IRB.CreateLoad(IRB.getInt32Ty(), GuardPtr);
+ ModuleSanitizerCoverageAFL::SetNoSanitizeMetadata(CurLoc);
+
+ /* Load SHM pointer */
+
+ LoadInst *MapPtr = IRB.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr);
+ ModuleSanitizerCoverageAFL::SetNoSanitizeMetadata(MapPtr);
+
+ /* Load counter for CurLoc */
+
+ Value *MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtr, CurLoc);
+
+ if (use_threadsafe_counters) {
+
+ IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One,
+#if LLVM_VERSION_MAJOR >= 13
+ llvm::MaybeAlign(1),
+#endif
+ llvm::AtomicOrdering::Monotonic);
+
+ } else {
+
+ LoadInst *Counter = IRB.CreateLoad(IRB.getInt8Ty(), MapPtrIdx);
+ ModuleSanitizerCoverageAFL::SetNoSanitizeMetadata(Counter);
+
+ /* Update bitmap */
+
+ Value *Incr = IRB.CreateAdd(Counter, One);
+
+ if (skip_nozero == NULL) {
+
+ auto cf = IRB.CreateICmpEQ(Incr, Zero);
+ auto carry = IRB.CreateZExt(cf, Int8Ty);
+ Incr = IRB.CreateAdd(Incr, carry);
+
+ }
+
+ StoreInst *StoreCtx = IRB.CreateStore(Incr, MapPtrIdx);
+ ModuleSanitizerCoverageAFL::SetNoSanitizeMetadata(StoreCtx);
+
+ }
+
+ // done :)
+
+ // IRB.CreateCall(SanCovTracePCGuard, Offset)->setCannotMerge();
+ // IRB.CreateCall(SanCovTracePCGuard, GuardPtr)->setCannotMerge();
+ ++instr;
+
+ }
+
+ if (Options.Inline8bitCounters) {
+
+ auto CounterPtr = IRB.CreateGEP(
+ Function8bitCounterArray->getValueType(), Function8bitCounterArray,
+ {ConstantInt::get(IntptrTy, 0), ConstantInt::get(IntptrTy, Idx)});
+ auto Load = IRB.CreateLoad(Int8Ty, CounterPtr);
+ auto Inc = IRB.CreateAdd(Load, ConstantInt::get(Int8Ty, 1));
+ auto Store = IRB.CreateStore(Inc, CounterPtr);
+ SetNoSanitizeMetadata(Load);
+ SetNoSanitizeMetadata(Store);
+
+ }
+
+ /*
+ if (Options.InlineBoolFlag) {
+
+ auto FlagPtr = IRB.CreateGEP(
+ FunctionBoolArray->getValueType(), FunctionBoolArray,
+ {ConstantInt::get(IntptrTy, 0), ConstantInt::get(IntptrTy, Idx)});
+ auto Load = IRB.CreateLoad(Int1Ty, FlagPtr);
+ auto ThenTerm =
+ SplitBlockAndInsertIfThen(IRB.CreateIsNull(Load), &*IP, false);
+ IRBuilder<> ThenIRB(ThenTerm);
+ auto Store = ThenIRB.CreateStore(ConstantInt::getTrue(Int1Ty), FlagPtr);
+ SetNoSanitizeMetadata(Load);
+ SetNoSanitizeMetadata(Store);
+
+ }
+
+ */
+
+ if (Options.StackDepth && IsEntryBB && !IsLeafFunc) {
+
+ // Check stack depth. If it's the deepest so far, record it.
+ Module * M = F.getParent();
+ Function *GetFrameAddr = Intrinsic::getDeclaration(
+ M, Intrinsic::frameaddress,
+ IRB.getInt8PtrTy(M->getDataLayout().getAllocaAddrSpace()));
+ auto FrameAddrPtr =
+ IRB.CreateCall(GetFrameAddr, {Constant::getNullValue(Int32Ty)});
+ auto FrameAddrInt = IRB.CreatePtrToInt(FrameAddrPtr, IntptrTy);
+ auto LowestStack = IRB.CreateLoad(IntptrTy, SanCovLowestStack);
+ auto IsStackLower = IRB.CreateICmpULT(FrameAddrInt, LowestStack);
+ auto ThenTerm = SplitBlockAndInsertIfThen(IsStackLower, &*IP, false);
+ IRBuilder<> ThenIRB(ThenTerm);
+ auto Store = ThenIRB.CreateStore(FrameAddrInt, SanCovLowestStack);
+ SetNoSanitizeMetadata(LowestStack);
+ SetNoSanitizeMetadata(Store);
+
+ }
+
+}
+
+std::string ModuleSanitizerCoverageAFL::getSectionName(
+ const std::string &Section) const {
+
+ if (TargetTriple.isOSBinFormatCOFF()) {
+
+ if (Section == SanCovCountersSectionName) return ".SCOV$CM";
+ if (Section == SanCovBoolFlagSectionName) return ".SCOV$BM";
+ if (Section == SanCovPCsSectionName) return ".SCOVP$M";
+ return ".SCOV$GM"; // For SanCovGuardsSectionName.
+
+ }
+
+ if (TargetTriple.isOSBinFormatMachO()) return "__DATA,__" + Section;
+ return "__" + Section;
+
+}
+
+std::string ModuleSanitizerCoverageAFL::getSectionStart(
+ const std::string &Section) const {
+
+ if (TargetTriple.isOSBinFormatMachO())
+ return "\1section$start$__DATA$__" + Section;
+ return "__start___" + Section;
+
+}
+
+std::string ModuleSanitizerCoverageAFL::getSectionEnd(
+ const std::string &Section) const {
+
+ if (TargetTriple.isOSBinFormatMachO())
+ return "\1section$end$__DATA$__" + Section;
+ return "__stop___" + Section;
+
+}
+
+#if 0
+
+char ModuleSanitizerCoverageLegacyPass::ID = 0;
+INITIALIZE_PASS_BEGIN(ModuleSanitizerCoverageLegacyPass, "sancov",
+ "Pass for instrumenting coverage on functions", false,
+ false)
+INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(PostDominatorTreeWrapperPass)
+INITIALIZE_PASS_END(ModuleSanitizerCoverageLegacyPass, "sancov",
+ "Pass for instrumenting coverage on functions", false,
+ false)
+ModulePass *llvm::createModuleSanitizerCoverageLegacyPassPass(
+ const SanitizerCoverageOptions &Options,
+ const std::vector<std::string> &AllowlistFiles,
+ const std::vector<std::string> &BlocklistFiles) {
+
+ return new ModuleSanitizerCoverageLegacyPass(Options, AllowlistFiles,
+ BlocklistFiles);
+
+}
+
+#endif
+
diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c
new file mode 100644
index 00000000..db7ac7b0
--- /dev/null
+++ b/instrumentation/afl-compiler-rt.o.c
@@ -0,0 +1,2317 @@
+/*
+ american fuzzy lop++ - instrumentation bootstrap
+ ------------------------------------------------
+
+ Copyright 2015, 2016 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+
+*/
+
+#ifdef __ANDROID__
+ #include "android-ashmem.h"
+#endif
+#include "config.h"
+#include "types.h"
+#include "cmplog.h"
+#include "llvm-alternative-coverage.h"
+
+#define XXH_INLINE_ALL
+#include "xxhash.h"
+#undef XXH_INLINE_ALL
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <limits.h>
+#include <errno.h>
+
+#include <sys/mman.h>
+#ifndef __HAIKU__
+ #include <sys/syscall.h>
+#endif
+#ifndef USEMMAP
+ #include <sys/shm.h>
+#endif
+#include <sys/wait.h>
+#include <sys/types.h>
+
+#if !__GNUC__
+ #include "llvm/Config/llvm-config.h"
+#endif
+
+#ifdef __linux__
+ #include "snapshot-inl.h"
+#endif
+
+/* This is a somewhat ugly hack for the experimental 'trace-pc-guard' mode.
+ Basically, we need to make sure that the forkserver is initialized after
+ the LLVM-generated runtime initialization pass, not before. */
+
+#ifndef MAP_FIXED_NOREPLACE
+ #ifdef MAP_EXCL
+ #define MAP_FIXED_NOREPLACE MAP_EXCL | MAP_FIXED
+ #else
+ #define MAP_FIXED_NOREPLACE MAP_FIXED
+ #endif
+#endif
+
+#define CTOR_PRIO 3
+#define EARLY_FS_PRIO 5
+
+#include <sys/mman.h>
+#include <fcntl.h>
+
+/* Globals needed by the injected instrumentation. The __afl_area_initial region
+ is used for instrumentation output before __afl_map_shm() has a chance to
+ run. It will end up as .comm, so it shouldn't be too wasteful. */
+
+#if MAP_SIZE <= 65536
+ #define MAP_INITIAL_SIZE 2097152
+#else
+ #define MAP_INITIAL_SIZE MAP_SIZE
+#endif
+
+#if defined(__HAIKU__)
+extern ssize_t _kern_write(int fd, off_t pos, const void *buffer,
+ size_t bufferSize);
+#endif // HAIKU
+
+static u8 __afl_area_initial[MAP_INITIAL_SIZE];
+static u8 *__afl_area_ptr_dummy = __afl_area_initial;
+static u8 *__afl_area_ptr_backup = __afl_area_initial;
+
+u8 * __afl_area_ptr = __afl_area_initial;
+u8 * __afl_dictionary;
+u8 * __afl_fuzz_ptr;
+static u32 __afl_fuzz_len_dummy;
+u32 * __afl_fuzz_len = &__afl_fuzz_len_dummy;
+
+u32 __afl_final_loc;
+u32 __afl_map_size = MAP_SIZE;
+u32 __afl_dictionary_len;
+u64 __afl_map_addr;
+
+// for the __AFL_COVERAGE_ON/__AFL_COVERAGE_OFF features to work:
+int __afl_selective_coverage __attribute__((weak));
+int __afl_selective_coverage_start_off __attribute__((weak));
+static int __afl_selective_coverage_temp = 1;
+
+#if defined(__ANDROID__) || defined(__HAIKU__)
+PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX];
+PREV_LOC_T __afl_prev_caller[CTX_MAX_K];
+u32 __afl_prev_ctx;
+#else
+__thread PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX];
+__thread PREV_LOC_T __afl_prev_caller[CTX_MAX_K];
+__thread u32 __afl_prev_ctx;
+#endif
+
+int __afl_sharedmem_fuzzing __attribute__((weak));
+
+struct cmp_map *__afl_cmp_map;
+struct cmp_map *__afl_cmp_map_backup;
+
+/* Child pid? */
+
+static s32 child_pid;
+static void (*old_sigterm_handler)(int) = 0;
+
+/* Running in persistent mode? */
+
+static u8 is_persistent;
+
+/* Are we in sancov mode? */
+
+static u8 _is_sancov;
+
+/* Debug? */
+
+static u32 __afl_debug;
+
+/* Already initialized markers */
+
+u32 __afl_already_initialized_shm;
+u32 __afl_already_initialized_forkserver;
+u32 __afl_already_initialized_first;
+u32 __afl_already_initialized_second;
+u32 __afl_already_initialized_init;
+
+/* Dummy pipe for area_is_valid() */
+
+static int __afl_dummy_fd[2] = {2, 2};
+
+/* ensure we kill the child on termination */
+
+static void at_exit(int signal) {
+
+ if (unlikely(child_pid > 0)) {
+
+ kill(child_pid, SIGKILL);
+ child_pid = -1;
+
+ }
+
+ _exit(0);
+
+}
+
+#define default_hash(a, b) XXH3_64bits(a, b)
+
+/* Uninspired gcc plugin instrumentation */
+
+void __afl_trace(const u32 x) {
+
+ PREV_LOC_T prev = __afl_prev_loc[0];
+ __afl_prev_loc[0] = (x >> 1);
+
+ u8 *p = &__afl_area_ptr[prev ^ x];
+
+#if 1 /* enable for neverZero feature. */
+ #if __GNUC__
+ u8 c = __builtin_add_overflow(*p, 1, p);
+ *p += c;
+ #else
+ *p += 1 + ((u8)(1 + *p) == 0);
+ #endif
+#else
+ ++*p;
+#endif
+
+ return;
+
+}
+
+/* Error reporting to forkserver controller */
+
+static void send_forkserver_error(int error) {
+
+ u32 status;
+ if (!error || error > 0xffff) return;
+ status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error));
+ if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) { return; }
+
+}
+
+/* SHM fuzzing setup. */
+
+static void __afl_map_shm_fuzz() {
+
+ char *id_str = getenv(SHM_FUZZ_ENV_VAR);
+
+ if (__afl_debug) {
+
+ fprintf(stderr, "DEBUG: fuzzcase shmem %s\n", id_str ? id_str : "none");
+
+ }
+
+ if (id_str) {
+
+ u8 *map = NULL;
+
+#ifdef USEMMAP
+ const char *shm_file_path = id_str;
+ int shm_fd = -1;
+
+ /* create the shared memory segment as if it was a file */
+ shm_fd = shm_open(shm_file_path, O_RDWR, DEFAULT_PERMISSION);
+ if (shm_fd == -1) {
+
+ fprintf(stderr, "shm_open() failed for fuzz\n");
+ send_forkserver_error(FS_ERROR_SHM_OPEN);
+ exit(1);
+
+ }
+
+ map =
+ (u8 *)mmap(0, MAX_FILE + sizeof(u32), PROT_READ, MAP_SHARED, shm_fd, 0);
+
+#else
+ u32 shm_id = atoi(id_str);
+ map = (u8 *)shmat(shm_id, NULL, 0);
+
+#endif
+
+ /* Whooooops. */
+
+ if (!map || map == (void *)-1) {
+
+ perror("Could not access fuzzing shared memory");
+ send_forkserver_error(FS_ERROR_SHM_OPEN);
+ exit(1);
+
+ }
+
+ __afl_fuzz_len = (u32 *)map;
+ __afl_fuzz_ptr = map + sizeof(u32);
+
+ if (__afl_debug) {
+
+ fprintf(stderr, "DEBUG: successfully got fuzzing shared memory\n");
+
+ }
+
+ } else {
+
+ fprintf(stderr, "Error: variable for fuzzing shared memory is not set\n");
+ send_forkserver_error(FS_ERROR_SHM_OPEN);
+ exit(1);
+
+ }
+
+}
+
+/* SHM setup. */
+
+static void __afl_map_shm(void) {
+
+ if (__afl_already_initialized_shm) return;
+ __afl_already_initialized_shm = 1;
+
+ // if we are not running in afl ensure the map exists
+ if (!__afl_area_ptr) { __afl_area_ptr = __afl_area_ptr_dummy; }
+
+ char *id_str = getenv(SHM_ENV_VAR);
+
+ if (__afl_final_loc) {
+
+ __afl_map_size = ++__afl_final_loc; // as we count starting 0
+
+ if (__afl_final_loc > MAP_SIZE) {
+
+ char *ptr;
+ u32 val = 0;
+ if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) val = atoi(ptr);
+ if (val < __afl_final_loc) {
+
+ if (__afl_final_loc > FS_OPT_MAX_MAPSIZE) {
+
+ 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);
+ exit(-1);
+
+ }
+
+ } else {
+
+ if (!getenv("AFL_QUIET"))
+ fprintf(stderr,
+ "Warning: AFL++ tools might need to set AFL_MAP_SIZE to %u "
+ "to be able to run this instrumented program if this "
+ "crashes!\n",
+ __afl_final_loc);
+
+ }
+
+ }
+
+ }
+
+ }
+
+ /* If we're running under AFL, attach to the appropriate region, replacing the
+ early-stage __afl_area_initial region that is needed to allow some really
+ hacky .init code to work correctly in projects such as OpenSSL. */
+
+ if (__afl_debug) {
+
+ fprintf(
+ stderr,
+ "DEBUG: (1) id_str %s, __afl_area_ptr %p, __afl_area_initial %p, "
+ "__afl_area_ptr_dummy %p, __afl_map_addr 0x%llx, MAP_SIZE %u, "
+ "__afl_final_loc %u, __afl_map_size %u, max_size_forkserver %u/0x%x\n",
+ id_str == NULL ? "<null>" : id_str, __afl_area_ptr, __afl_area_initial,
+ __afl_area_ptr_dummy, __afl_map_addr, MAP_SIZE, __afl_final_loc,
+ __afl_map_size, FS_OPT_MAX_MAPSIZE, FS_OPT_MAX_MAPSIZE);
+
+ }
+
+ if (id_str) {
+
+ if (__afl_area_ptr && __afl_area_ptr != __afl_area_initial &&
+ __afl_area_ptr != __afl_area_ptr_dummy) {
+
+ if (__afl_map_addr) {
+
+ munmap((void *)__afl_map_addr, __afl_final_loc);
+
+ } else {
+
+ free(__afl_area_ptr);
+
+ }
+
+ __afl_area_ptr = __afl_area_ptr_dummy;
+
+ }
+
+#ifdef USEMMAP
+ const char * shm_file_path = id_str;
+ int shm_fd = -1;
+ unsigned char *shm_base = NULL;
+
+ /* create the shared memory segment as if it was a file */
+ shm_fd = shm_open(shm_file_path, O_RDWR, DEFAULT_PERMISSION);
+ if (shm_fd == -1) {
+
+ fprintf(stderr, "shm_open() failed\n");
+ send_forkserver_error(FS_ERROR_SHM_OPEN);
+ exit(1);
+
+ }
+
+ /* map the shared memory segment to the address space of the process */
+ if (__afl_map_addr) {
+
+ shm_base =
+ mmap((void *)__afl_map_addr, __afl_map_size, PROT_READ | PROT_WRITE,
+ MAP_FIXED_NOREPLACE | MAP_SHARED, shm_fd, 0);
+
+ } else {
+
+ shm_base = mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED,
+ shm_fd, 0);
+
+ }
+
+ close(shm_fd);
+ shm_fd = -1;
+
+ if (shm_base == MAP_FAILED) {
+
+ fprintf(stderr, "mmap() failed\n");
+ perror("mmap for map");
+
+ if (__afl_map_addr)
+ send_forkserver_error(FS_ERROR_MAP_ADDR);
+ else
+ send_forkserver_error(FS_ERROR_MMAP);
+
+ exit(2);
+
+ }
+
+ __afl_area_ptr = shm_base;
+#else
+ u32 shm_id = atoi(id_str);
+
+ if (__afl_map_size && __afl_map_size > MAP_SIZE) {
+
+ u8 *map_env = (u8 *)getenv("AFL_MAP_SIZE");
+ if (!map_env || atoi((char *)map_env) < MAP_SIZE) {
+
+ send_forkserver_error(FS_ERROR_MAP_SIZE);
+ _exit(1);
+
+ }
+
+ }
+
+ __afl_area_ptr = (u8 *)shmat(shm_id, (void *)__afl_map_addr, 0);
+
+ /* Whooooops. */
+
+ if (!__afl_area_ptr || __afl_area_ptr == (void *)-1) {
+
+ if (__afl_map_addr)
+ send_forkserver_error(FS_ERROR_MAP_ADDR);
+ else
+ send_forkserver_error(FS_ERROR_SHMAT);
+
+ perror("shmat for map");
+ _exit(1);
+
+ }
+
+#endif
+
+ /* Write something into the bitmap so that even with low AFL_INST_RATIO,
+ our parent doesn't give up on us. */
+
+ __afl_area_ptr[0] = 1;
+
+ } else if ((!__afl_area_ptr || __afl_area_ptr == __afl_area_initial) &&
+
+ __afl_map_addr) {
+
+ __afl_area_ptr = (u8 *)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 acquire mmap for address %p\n",
+ (void *)__afl_map_addr);
+ send_forkserver_error(FS_ERROR_SHM_OPEN);
+ exit(1);
+
+ }
+
+ } 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 = (u8 *)malloc(__afl_final_loc);
+
+ }
+
+ if (!__afl_area_ptr) { __afl_area_ptr = __afl_area_ptr_dummy; }
+
+ }
+
+ __afl_area_ptr_backup = __afl_area_ptr;
+
+ if (__afl_debug) {
+
+ fprintf(stderr,
+ "DEBUG: (2) id_str %s, __afl_area_ptr %p, __afl_area_initial %p, "
+ "__afl_area_ptr_dummy %p, __afl_map_addr 0x%llx, MAP_SIZE "
+ "%u, __afl_final_loc %u, __afl_map_size %u,"
+ "max_size_forkserver %u/0x%x\n",
+ id_str == NULL ? "<null>" : id_str, __afl_area_ptr,
+ __afl_area_initial, __afl_area_ptr_dummy, __afl_map_addr, MAP_SIZE,
+ __afl_final_loc, __afl_map_size, FS_OPT_MAX_MAPSIZE,
+ FS_OPT_MAX_MAPSIZE);
+
+ }
+
+ if (__afl_selective_coverage) {
+
+ if (__afl_map_size > MAP_INITIAL_SIZE) {
+
+ __afl_area_ptr_dummy = (u8 *)malloc(__afl_map_size);
+
+ if (__afl_area_ptr_dummy) {
+
+ if (__afl_selective_coverage_start_off) {
+
+ __afl_area_ptr = __afl_area_ptr_dummy;
+
+ }
+
+ } else {
+
+ fprintf(stderr, "Error: __afl_selective_coverage failed!\n");
+ __afl_selective_coverage = 0;
+ // continue;
+
+ }
+
+ }
+
+ }
+
+ id_str = getenv(CMPLOG_SHM_ENV_VAR);
+
+ if (__afl_debug) {
+
+ fprintf(stderr, "DEBUG: cmplog id_str %s\n",
+ id_str == NULL ? "<null>" : id_str);
+
+ }
+
+ if (id_str) {
+
+ if ((__afl_dummy_fd[1] = open("/dev/null", O_WRONLY)) < 0) {
+
+ if (pipe(__afl_dummy_fd) < 0) { __afl_dummy_fd[1] = 1; }
+
+ }
+
+#ifdef USEMMAP
+ const char * shm_file_path = id_str;
+ int shm_fd = -1;
+ struct cmp_map *shm_base = NULL;
+
+ /* create the shared memory segment as if it was a file */
+ shm_fd = shm_open(shm_file_path, O_RDWR, DEFAULT_PERMISSION);
+ if (shm_fd == -1) {
+
+ perror("shm_open() failed\n");
+ send_forkserver_error(FS_ERROR_SHM_OPEN);
+ exit(1);
+
+ }
+
+ /* map the shared memory segment to the address space of the process */
+ shm_base = mmap(0, sizeof(struct cmp_map), PROT_READ | PROT_WRITE,
+ MAP_SHARED, shm_fd, 0);
+ if (shm_base == MAP_FAILED) {
+
+ close(shm_fd);
+ shm_fd = -1;
+
+ fprintf(stderr, "mmap() failed\n");
+ send_forkserver_error(FS_ERROR_SHM_OPEN);
+ exit(2);
+
+ }
+
+ __afl_cmp_map = shm_base;
+#else
+ u32 shm_id = atoi(id_str);
+
+ __afl_cmp_map = (struct cmp_map *)shmat(shm_id, NULL, 0);
+#endif
+
+ __afl_cmp_map_backup = __afl_cmp_map;
+
+ if (!__afl_cmp_map || __afl_cmp_map == (void *)-1) {
+
+ perror("shmat for cmplog");
+ send_forkserver_error(FS_ERROR_SHM_OPEN);
+ _exit(1);
+
+ }
+
+ }
+
+}
+
+/* unmap SHM. */
+
+static void __afl_unmap_shm(void) {
+
+ if (!__afl_already_initialized_shm) return;
+
+ char *id_str = getenv(SHM_ENV_VAR);
+
+ if (id_str) {
+
+#ifdef USEMMAP
+
+ munmap((void *)__afl_area_ptr, __afl_map_size);
+
+#else
+
+ shmdt((void *)__afl_area_ptr);
+
+#endif
+
+ } else if ((!__afl_area_ptr || __afl_area_ptr == __afl_area_initial) &&
+
+ __afl_map_addr) {
+
+ munmap((void *)__afl_map_addr, __afl_map_size);
+
+ }
+
+ __afl_area_ptr = __afl_area_ptr_dummy;
+
+ id_str = getenv(CMPLOG_SHM_ENV_VAR);
+
+ if (id_str) {
+
+#ifdef USEMMAP
+
+ munmap((void *)__afl_cmp_map, __afl_map_size);
+
+#else
+
+ shmdt((void *)__afl_cmp_map);
+
+#endif
+
+ __afl_cmp_map = NULL;
+ __afl_cmp_map_backup = NULL;
+
+ }
+
+ __afl_already_initialized_shm = 0;
+
+}
+
+#define write_error(text) write_error_with_location(text, __FILE__, __LINE__)
+
+void write_error_with_location(char *text, char *filename, int linenumber) {
+
+ u8 * o = getenv("__AFL_OUT_DIR");
+ char *e = strerror(errno);
+
+ if (o) {
+
+ char buf[4096];
+ snprintf(buf, sizeof(buf), "%s/error.txt", o);
+ FILE *f = fopen(buf, "a");
+
+ if (f) {
+
+ fprintf(f, "File %s, line %d: Error(%s): %s\n", filename, linenumber,
+ text, e);
+ fclose(f);
+
+ }
+
+ }
+
+ fprintf(stderr, "File %s, line %d: Error(%s): %s\n", filename, linenumber,
+ text, e);
+
+}
+
+#ifdef __linux__
+static void __afl_start_snapshots(void) {
+
+ static u8 tmp[4] = {0, 0, 0, 0};
+ u32 status = 0;
+ u32 already_read_first = 0;
+ u32 was_killed;
+
+ u8 child_stopped = 0;
+
+ void (*old_sigchld_handler)(int) = signal(SIGCHLD, SIG_DFL);
+
+ /* Phone home and tell the parent that we're OK. If parent isn't there,
+ assume we're not running in forkserver mode and just execute program. */
+
+ status |= (FS_OPT_ENABLED | FS_OPT_SNAPSHOT | FS_OPT_NEWCMPLOG);
+ if (__afl_sharedmem_fuzzing != 0) status |= FS_OPT_SHDMEM_FUZZ;
+ if (__afl_map_size <= FS_OPT_MAX_MAPSIZE)
+ status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
+ if (__afl_dictionary_len && __afl_dictionary) status |= FS_OPT_AUTODICT;
+ memcpy(tmp, &status, 4);
+
+ if (write(FORKSRV_FD + 1, tmp, 4) != 4) { return; }
+
+ if (__afl_sharedmem_fuzzing || (__afl_dictionary_len && __afl_dictionary)) {
+
+ if (read(FORKSRV_FD, &was_killed, 4) != 4) {
+
+ write_error("read to afl-fuzz");
+ _exit(1);
+
+ }
+
+ if (__afl_debug) {
+
+ fprintf(stderr, "target forkserver recv: %08x\n", was_killed);
+
+ }
+
+ if ((was_killed & (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) ==
+ (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) {
+
+ __afl_map_shm_fuzz();
+
+ }
+
+ if ((was_killed & (FS_OPT_ENABLED | FS_OPT_AUTODICT)) ==
+ (FS_OPT_ENABLED | FS_OPT_AUTODICT) &&
+ __afl_dictionary_len && __afl_dictionary) {
+
+ // great lets pass the dictionary through the forkserver FD
+ u32 len = __afl_dictionary_len, offset = 0;
+ s32 ret;
+
+ if (write(FORKSRV_FD + 1, &len, 4) != 4) {
+
+ write(2, "Error: could not send dictionary len\n",
+ strlen("Error: could not send dictionary len\n"));
+ _exit(1);
+
+ }
+
+ while (len != 0) {
+
+ ret = write(FORKSRV_FD + 1, __afl_dictionary + offset, len);
+
+ if (ret < 1) {
+
+ write(2, "Error: could not send dictionary\n",
+ strlen("Error: could not send dictionary\n"));
+ _exit(1);
+
+ }
+
+ len -= ret;
+ offset += ret;
+
+ }
+
+ } else {
+
+ // uh this forkserver does not understand extended option passing
+ // or does not want the dictionary
+ if (!__afl_fuzz_ptr) already_read_first = 1;
+
+ }
+
+ }
+
+ while (1) {
+
+ int status;
+
+ if (already_read_first) {
+
+ already_read_first = 0;
+
+ } else {
+
+ /* Wait for parent by reading from the pipe. Abort if read fails. */
+ if (read(FORKSRV_FD, &was_killed, 4) != 4) {
+
+ write_error("reading from afl-fuzz");
+ _exit(1);
+
+ }
+
+ }
+
+ #ifdef _AFL_DOCUMENT_MUTATIONS
+ if (__afl_fuzz_ptr) {
+
+ static uint32_t counter = 0;
+ char fn[32];
+ sprintf(fn, "%09u:forkserver", counter);
+ s32 fd_doc = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
+ if (fd_doc >= 0) {
+
+ if (write(fd_doc, __afl_fuzz_ptr, *__afl_fuzz_len) != *__afl_fuzz_len) {
+
+ fprintf(stderr, "write of mutation file failed: %s\n", fn);
+ unlink(fn);
+
+ }
+
+ close(fd_doc);
+
+ }
+
+ counter++;
+
+ }
+
+ #endif
+
+ /* If we stopped the child in persistent mode, but there was a race
+ condition and afl-fuzz already issued SIGKILL, write off the old
+ process. */
+
+ if (child_stopped && was_killed) {
+
+ child_stopped = 0;
+ if (waitpid(child_pid, &status, 0) < 0) {
+
+ write_error("child_stopped && was_killed");
+ _exit(1); // TODO why exit?
+
+ }
+
+ }
+
+ if (!child_stopped) {
+
+ /* Once woken up, create a clone of our process. */
+
+ child_pid = fork();
+ if (child_pid < 0) {
+
+ write_error("fork");
+ _exit(1);
+
+ }
+
+ /* In child process: close fds, resume execution. */
+
+ if (!child_pid) {
+
+ //(void)nice(-20); // does not seem to improve
+
+ signal(SIGCHLD, old_sigchld_handler);
+ signal(SIGTERM, old_sigterm_handler);
+
+ close(FORKSRV_FD);
+ close(FORKSRV_FD + 1);
+
+ if (!afl_snapshot_take(AFL_SNAPSHOT_MMAP | AFL_SNAPSHOT_FDS |
+ AFL_SNAPSHOT_REGS | AFL_SNAPSHOT_EXIT)) {
+
+ raise(SIGSTOP);
+
+ }
+
+ __afl_area_ptr[0] = 1;
+ memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T));
+
+ return;
+
+ }
+
+ } else {
+
+ /* Special handling for persistent mode: if the child is alive but
+ currently stopped, simply restart it with SIGCONT. */
+
+ kill(child_pid, SIGCONT);
+ child_stopped = 0;
+
+ }
+
+ /* In parent process: write PID to pipe, then wait for child. */
+
+ if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) {
+
+ write_error("write to afl-fuzz");
+ _exit(1);
+
+ }
+
+ if (waitpid(child_pid, &status, WUNTRACED) < 0) {
+
+ write_error("waitpid");
+ _exit(1);
+
+ }
+
+ /* In persistent mode, the child stops itself with SIGSTOP to indicate
+ a successful run. In this case, we want to wake it up without forking
+ again. */
+
+ if (WIFSTOPPED(status)) child_stopped = 1;
+
+ /* Relay wait status to pipe, then loop back. */
+
+ if (write(FORKSRV_FD + 1, &status, 4) != 4) {
+
+ write_error("writing to afl-fuzz");
+ _exit(1);
+
+ }
+
+ }
+
+}
+
+#endif
+
+/* Fork server logic. */
+
+static void __afl_start_forkserver(void) {
+
+ if (__afl_already_initialized_forkserver) return;
+ __afl_already_initialized_forkserver = 1;
+
+ struct sigaction orig_action;
+ sigaction(SIGTERM, NULL, &orig_action);
+ old_sigterm_handler = orig_action.sa_handler;
+ signal(SIGTERM, at_exit);
+
+#ifdef __linux__
+ if (/*!is_persistent &&*/ !__afl_cmp_map && !getenv("AFL_NO_SNAPSHOT") &&
+ afl_snapshot_init() >= 0) {
+
+ __afl_start_snapshots();
+ return;
+
+ }
+
+#endif
+
+ u8 tmp[4] = {0, 0, 0, 0};
+ u32 status_for_fsrv = 0;
+ u32 already_read_first = 0;
+ u32 was_killed;
+
+ u8 child_stopped = 0;
+
+ void (*old_sigchld_handler)(int) = signal(SIGCHLD, SIG_DFL);
+
+ if (__afl_map_size <= FS_OPT_MAX_MAPSIZE) {
+
+ status_for_fsrv |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
+
+ }
+
+ if (__afl_dictionary_len && __afl_dictionary) {
+
+ status_for_fsrv |= FS_OPT_AUTODICT;
+
+ }
+
+ if (__afl_sharedmem_fuzzing != 0) { status_for_fsrv |= FS_OPT_SHDMEM_FUZZ; }
+ if (status_for_fsrv) {
+
+ status_for_fsrv |= (FS_OPT_ENABLED | FS_OPT_NEWCMPLOG);
+
+ }
+
+ memcpy(tmp, &status_for_fsrv, 4);
+
+ /* Phone home and tell the parent that we're OK. If parent isn't there,
+ assume we're not running in forkserver mode and just execute program. */
+
+ if (write(FORKSRV_FD + 1, tmp, 4) != 4) { return; }
+
+ if (__afl_sharedmem_fuzzing || (__afl_dictionary_len && __afl_dictionary)) {
+
+ if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
+
+ if (__afl_debug) {
+
+ fprintf(stderr, "target forkserver recv: %08x\n", was_killed);
+
+ }
+
+ if ((was_killed & (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) ==
+ (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) {
+
+ __afl_map_shm_fuzz();
+
+ }
+
+ if ((was_killed & (FS_OPT_ENABLED | FS_OPT_AUTODICT)) ==
+ (FS_OPT_ENABLED | FS_OPT_AUTODICT) &&
+ __afl_dictionary_len && __afl_dictionary) {
+
+ // great lets pass the dictionary through the forkserver FD
+ u32 len = __afl_dictionary_len, offset = 0;
+
+ if (write(FORKSRV_FD + 1, &len, 4) != 4) {
+
+ write(2, "Error: could not send dictionary len\n",
+ strlen("Error: could not send dictionary len\n"));
+ _exit(1);
+
+ }
+
+ while (len != 0) {
+
+ s32 ret;
+ ret = write(FORKSRV_FD + 1, __afl_dictionary + offset, len);
+
+ if (ret < 1) {
+
+ write(2, "Error: could not send dictionary\n",
+ strlen("Error: could not send dictionary\n"));
+ _exit(1);
+
+ }
+
+ len -= ret;
+ offset += ret;
+
+ }
+
+ } else {
+
+ // uh this forkserver does not understand extended option passing
+ // or does not want the dictionary
+ if (!__afl_fuzz_ptr) already_read_first = 1;
+
+ }
+
+ }
+
+ while (1) {
+
+ int status;
+
+ /* Wait for parent by reading from the pipe. Abort if read fails. */
+
+ if (already_read_first) {
+
+ already_read_first = 0;
+
+ } else {
+
+ if (read(FORKSRV_FD, &was_killed, 4) != 4) {
+
+ // write_error("read from afl-fuzz");
+ _exit(1);
+
+ }
+
+ }
+
+#ifdef _AFL_DOCUMENT_MUTATIONS
+ if (__afl_fuzz_ptr) {
+
+ static uint32_t counter = 0;
+ char fn[32];
+ sprintf(fn, "%09u:forkserver", counter);
+ s32 fd_doc = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
+ if (fd_doc >= 0) {
+
+ if (write(fd_doc, __afl_fuzz_ptr, *__afl_fuzz_len) != *__afl_fuzz_len) {
+
+ fprintf(stderr, "write of mutation file failed: %s\n", fn);
+ unlink(fn);
+
+ }
+
+ close(fd_doc);
+
+ }
+
+ counter++;
+
+ }
+
+#endif
+
+ /* If we stopped the child in persistent mode, but there was a race
+ condition and afl-fuzz already issued SIGKILL, write off the old
+ process. */
+
+ if (child_stopped && was_killed) {
+
+ child_stopped = 0;
+ if (waitpid(child_pid, &status, 0) < 0) {
+
+ write_error("child_stopped && was_killed");
+ _exit(1);
+
+ }
+
+ }
+
+ if (!child_stopped) {
+
+ /* Once woken up, create a clone of our process. */
+
+ child_pid = fork();
+ if (child_pid < 0) {
+
+ write_error("fork");
+ _exit(1);
+
+ }
+
+ /* In child process: close fds, resume execution. */
+
+ if (!child_pid) {
+
+ //(void)nice(-20);
+
+ signal(SIGCHLD, old_sigchld_handler);
+ signal(SIGTERM, old_sigterm_handler);
+
+ close(FORKSRV_FD);
+ close(FORKSRV_FD + 1);
+ return;
+
+ }
+
+ } else {
+
+ /* Special handling for persistent mode: if the child is alive but
+ currently stopped, simply restart it with SIGCONT. */
+
+ kill(child_pid, SIGCONT);
+ child_stopped = 0;
+
+ }
+
+ /* In parent process: write PID to pipe, then wait for child. */
+
+ if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) {
+
+ write_error("write to afl-fuzz");
+ _exit(1);
+
+ }
+
+ if (waitpid(child_pid, &status, is_persistent ? WUNTRACED : 0) < 0) {
+
+ write_error("waitpid");
+ _exit(1);
+
+ }
+
+ /* In persistent mode, the child stops itself with SIGSTOP to indicate
+ a successful run. In this case, we want to wake it up without forking
+ again. */
+
+ if (WIFSTOPPED(status)) child_stopped = 1;
+
+ /* Relay wait status to pipe, then loop back. */
+
+ if (write(FORKSRV_FD + 1, &status, 4) != 4) {
+
+ write_error("writing to afl-fuzz");
+ _exit(1);
+
+ }
+
+ }
+
+}
+
+/* A simplified persistent mode handler, used as explained in
+ * README.llvm.md. */
+
+int __afl_persistent_loop(unsigned int max_cnt) {
+
+ static u8 first_pass = 1;
+ static u32 cycle_cnt;
+
+ if (first_pass) {
+
+ /* Make sure that every iteration of __AFL_LOOP() starts with a clean slate.
+ On subsequent calls, the parent will take care of that, but on the first
+ iteration, it's our job to erase any trace of whatever happened
+ before the loop. */
+
+ if (is_persistent) {
+
+ memset(__afl_area_ptr, 0, __afl_map_size);
+ __afl_area_ptr[0] = 1;
+ memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T));
+
+ }
+
+ cycle_cnt = max_cnt;
+ first_pass = 0;
+ __afl_selective_coverage_temp = 1;
+
+ return 1;
+
+ }
+
+ if (is_persistent) {
+
+ if (--cycle_cnt) {
+
+ raise(SIGSTOP);
+
+ __afl_area_ptr[0] = 1;
+ memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T));
+ __afl_selective_coverage_temp = 1;
+
+ return 1;
+
+ } else {
+
+ /* When exiting __AFL_LOOP(), make sure that the subsequent code that
+ follows the loop is not traced. We do that by pivoting back to the
+ dummy output region. */
+
+ __afl_area_ptr = __afl_area_ptr_dummy;
+
+ }
+
+ }
+
+ return 0;
+
+}
+
+/* This one can be called from user code when deferred forkserver mode
+ is enabled. */
+
+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_ptr_dummy;
+
+ if (__afl_debug) {
+
+ fprintf(stderr,
+ "DEBUG: disabled instrumentation because of "
+ "AFL_DISABLE_LLVM_INSTRUMENTATION\n");
+
+ }
+
+ }
+
+ if (!init_done) {
+
+ __afl_start_forkserver();
+ init_done = 1;
+
+ }
+
+}
+
+/* Initialization of the forkserver - latest possible */
+
+__attribute__((constructor())) void __afl_auto_init(void) {
+
+ if (__afl_already_initialized_init) { return; }
+
+#ifdef __ANDROID__
+ // Disable handlers in linker/debuggerd, check include/debuggerd/handler.h
+ signal(SIGABRT, SIG_DFL);
+ signal(SIGBUS, SIG_DFL);
+ signal(SIGFPE, SIG_DFL);
+ signal(SIGILL, SIG_DFL);
+ signal(SIGSEGV, SIG_DFL);
+ signal(SIGSTKFLT, SIG_DFL);
+ signal(SIGSYS, SIG_DFL);
+ signal(SIGTRAP, SIG_DFL);
+#endif
+
+ __afl_already_initialized_init = 1;
+
+ if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return;
+
+ if (getenv(DEFER_ENV_VAR)) return;
+
+ __afl_manual_init();
+
+}
+
+/* Optionally run an early forkserver */
+
+__attribute__((constructor(EARLY_FS_PRIO))) void __early_forkserver(void) {
+
+ if (getenv("AFL_EARLY_FORKSERVER")) { __afl_auto_init(); }
+
+}
+
+/* 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 (__afl_already_initialized_second) return;
+ __afl_already_initialized_second = 1;
+
+ if (getenv("AFL_DEBUG")) {
+
+ __afl_debug = 1;
+ fprintf(stderr, "DEBUG: debug enabled\n");
+
+ }
+
+ 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;
+ __afl_area_ptr_backup = __afl_area_ptr;
+
+ }
+
+ }
+
+} // ptr memleak report is a false positive
+
+/* preset __afl_area_ptr #1 - at constructor level 0 global variables have
+ not been set */
+
+__attribute__((constructor(0))) void __afl_auto_first(void) {
+
+ if (__afl_already_initialized_first) return;
+ __afl_already_initialized_first = 1;
+
+ if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return;
+ u8 *ptr = (u8 *)malloc(MAP_INITIAL_SIZE);
+
+ if (ptr && (ssize_t)ptr != -1) {
+
+ __afl_area_ptr = ptr;
+ __afl_area_ptr_backup = __afl_area_ptr;
+
+ }
+
+} // ptr memleak report is a false positive
+
+/* 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 README.llvm.md.
+
+ The first function (__sanitizer_cov_trace_pc_guard) is called back on every
+ edge (as opposed to every basic block). */
+
+void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
+
+ // For stability analysis, if you want to know to which function unstable
+ // edge IDs belong - uncomment, recompile+install llvm_mode, recompile
+ // the target. libunwind and libbacktrace are better solutions.
+ // Set AFL_DEBUG_CHILD=1 and run afl-fuzz with 2>file to capture
+ // the backtrace output
+ /*
+ uint32_t unstable[] = { ... unstable edge IDs };
+ uint32_t idx;
+ char bt[1024];
+ for (idx = 0; i < sizeof(unstable)/sizeof(uint32_t); i++) {
+
+ if (unstable[idx] == __afl_area_ptr[*guard]) {
+
+ int bt_size = backtrace(bt, 256);
+ if (bt_size > 0) {
+
+ char **bt_syms = backtrace_symbols(bt, bt_size);
+ if (bt_syms) {
+
+ fprintf(stderr, "DEBUG: edge=%u caller=%s\n", unstable[idx],
+ bt_syms[0]);
+ free(bt_syms);
+
+ }
+
+ }
+
+ }
+
+ }
+
+ */
+
+#if (LLVM_VERSION_MAJOR < 9)
+
+ __afl_area_ptr[*guard]++;
+
+#else
+
+ __afl_area_ptr[*guard] =
+ __afl_area_ptr[*guard] + 1 + (__afl_area_ptr[*guard] == 255 ? 1 : 0);
+
+#endif
+
+}
+
+/* Init callback. Populates instrumentation IDs. Note that we're using
+ ID of 0 as a special value to indicate non-instrumented bits. That may
+ still touch the bitmap, but in a fairly harmless way. */
+
+void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
+
+ u32 inst_ratio = 100;
+ char *x;
+
+ _is_sancov = 1;
+
+ if (__afl_debug) {
+
+ fprintf(stderr,
+ "Running __sanitizer_cov_trace_pc_guard_init: %p-%p (%lu edges) "
+ "after_fs=%u\n",
+ start, stop, (unsigned long)(stop - start),
+ __afl_already_initialized_forkserver);
+
+ }
+
+ if (start == stop || *start) return;
+
+ // If a dlopen of an instrumented library happens after the forkserver then
+ // we have a problem as we cannot increase the coverage map anymore.
+ if (__afl_already_initialized_forkserver) {
+
+ if (!getenv("AFL_IGNORE_PROBLEMS")) {
+
+ fprintf(
+ stderr,
+ "[-] FATAL: forkserver is already up, but an instrumented dlopen() "
+ "library loaded afterwards. You must AFL_PRELOAD such libraries to "
+ "be able to fuzz them or LD_PRELOAD to run outside of afl-fuzz.\n"
+ "To ignore this set AFL_IGNORE_PROBLEMS=1.\n");
+ abort();
+
+ } else {
+
+ static u32 offset = 4;
+
+ while (start < stop) {
+
+ *(start++) = offset;
+ if (unlikely(++offset >= __afl_final_loc)) { offset = 4; }
+
+ }
+
+ }
+
+ }
+
+ x = getenv("AFL_INST_RATIO");
+ if (x) { inst_ratio = (u32)atoi(x); }
+
+ if (!inst_ratio || inst_ratio > 100) {
+
+ fprintf(stderr, "[-] ERROR: Invalid AFL_INST_RATIO (must be 1-100).\n");
+ abort();
+
+ }
+
+ /* instrumented code is loaded *after* our forkserver is up. this is a
+ problem. We cannot prevent collisions then :( */
+ /*
+ if (__afl_already_initialized_forkserver &&
+ __afl_final_loc + 1 + stop - start > __afl_map_size) {
+
+ if (__afl_debug) {
+
+ fprintf(stderr, "Warning: new instrumented code after the forkserver!\n");
+
+ }
+
+ __afl_final_loc = 2;
+
+ if (1 + stop - start > __afl_map_size) {
+
+ *(start++) = ++__afl_final_loc;
+
+ while (start < stop) {
+
+ if (R(100) < inst_ratio)
+ *start = ++__afl_final_loc % __afl_map_size;
+ else
+ *start = 4;
+
+ start++;
+
+ }
+
+ return;
+
+ }
+
+ }
+
+ */
+
+ /* Make sure that the first element in the range is always set - we use that
+ to avoid duplicate calls (which can happen as an artifact of the underlying
+ implementation in LLVM). */
+
+ *(start++) = ++__afl_final_loc;
+
+ while (start < stop) {
+
+ if (R(100) < inst_ratio)
+ *start = ++__afl_final_loc;
+ else
+ *start = 4;
+
+ start++;
+
+ }
+
+ if (__afl_debug) {
+
+ fprintf(stderr,
+ "Done __sanitizer_cov_trace_pc_guard_init: __afl_final_loc = %u\n",
+ __afl_final_loc);
+
+ }
+
+ if (__afl_already_initialized_shm && __afl_final_loc > __afl_map_size) {
+
+ if (__afl_debug) {
+
+ fprintf(stderr, "Reinit shm necessary (+%u)\n",
+ __afl_final_loc - __afl_map_size);
+
+ }
+
+ __afl_unmap_shm();
+ __afl_map_shm();
+
+ }
+
+}
+
+///// CmpLog instrumentation
+
+void __cmplog_ins_hook1(uint8_t arg1, uint8_t arg2, uint8_t attr) {
+
+ // fprintf(stderr, "hook1 arg0=%02x arg1=%02x attr=%u\n",
+ // (u8) arg1, (u8) arg2, attr);
+
+ if (unlikely(!__afl_cmp_map || arg1 == arg2)) return;
+
+ uintptr_t k = (uintptr_t)__builtin_return_address(0);
+ k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1));
+
+ u32 hits;
+
+ if (__afl_cmp_map->headers[k].type != CMP_TYPE_INS) {
+
+ __afl_cmp_map->headers[k].type = CMP_TYPE_INS;
+ hits = 0;
+ __afl_cmp_map->headers[k].hits = 1;
+ __afl_cmp_map->headers[k].shape = 0;
+
+ } else {
+
+ hits = __afl_cmp_map->headers[k].hits++;
+
+ }
+
+ __afl_cmp_map->headers[k].attribute = attr;
+
+ hits &= CMP_MAP_H - 1;
+ __afl_cmp_map->log[k][hits].v0 = arg1;
+ __afl_cmp_map->log[k][hits].v1 = arg2;
+
+}
+
+void __cmplog_ins_hook2(uint16_t arg1, uint16_t arg2, uint8_t attr) {
+
+ if (unlikely(!__afl_cmp_map || arg1 == arg2)) return;
+
+ uintptr_t k = (uintptr_t)__builtin_return_address(0);
+ k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1));
+
+ u32 hits;
+
+ if (__afl_cmp_map->headers[k].type != CMP_TYPE_INS) {
+
+ __afl_cmp_map->headers[k].type = CMP_TYPE_INS;
+ hits = 0;
+ __afl_cmp_map->headers[k].hits = 1;
+ __afl_cmp_map->headers[k].shape = 1;
+
+ } else {
+
+ hits = __afl_cmp_map->headers[k].hits++;
+
+ if (!__afl_cmp_map->headers[k].shape) {
+
+ __afl_cmp_map->headers[k].shape = 1;
+
+ }
+
+ }
+
+ __afl_cmp_map->headers[k].attribute = attr;
+
+ hits &= CMP_MAP_H - 1;
+ __afl_cmp_map->log[k][hits].v0 = arg1;
+ __afl_cmp_map->log[k][hits].v1 = arg2;
+
+}
+
+void __cmplog_ins_hook4(uint32_t arg1, uint32_t arg2, uint8_t attr) {
+
+ // fprintf(stderr, "hook4 arg0=%x arg1=%x attr=%u\n", arg1, arg2, attr);
+
+ if (unlikely(!__afl_cmp_map || arg1 == arg2)) return;
+
+ uintptr_t k = (uintptr_t)__builtin_return_address(0);
+ k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1));
+
+ u32 hits;
+
+ if (__afl_cmp_map->headers[k].type != CMP_TYPE_INS) {
+
+ __afl_cmp_map->headers[k].type = CMP_TYPE_INS;
+ hits = 0;
+ __afl_cmp_map->headers[k].hits = 1;
+ __afl_cmp_map->headers[k].shape = 3;
+
+ } else {
+
+ hits = __afl_cmp_map->headers[k].hits++;
+
+ if (__afl_cmp_map->headers[k].shape < 3) {
+
+ __afl_cmp_map->headers[k].shape = 3;
+
+ }
+
+ }
+
+ __afl_cmp_map->headers[k].attribute = attr;
+
+ hits &= CMP_MAP_H - 1;
+ __afl_cmp_map->log[k][hits].v0 = arg1;
+ __afl_cmp_map->log[k][hits].v1 = arg2;
+
+}
+
+void __cmplog_ins_hook8(uint64_t arg1, uint64_t arg2, uint8_t attr) {
+
+ // fprintf(stderr, "hook8 arg0=%lx arg1=%lx attr=%u\n", arg1, arg2, attr);
+
+ if (unlikely(!__afl_cmp_map || arg1 == arg2)) return;
+
+ uintptr_t k = (uintptr_t)__builtin_return_address(0);
+ k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1));
+
+ u32 hits;
+
+ if (__afl_cmp_map->headers[k].type != CMP_TYPE_INS) {
+
+ __afl_cmp_map->headers[k].type = CMP_TYPE_INS;
+ hits = 0;
+ __afl_cmp_map->headers[k].hits = 1;
+ __afl_cmp_map->headers[k].shape = 7;
+
+ } else {
+
+ hits = __afl_cmp_map->headers[k].hits++;
+
+ if (__afl_cmp_map->headers[k].shape < 7) {
+
+ __afl_cmp_map->headers[k].shape = 7;
+
+ }
+
+ }
+
+ __afl_cmp_map->headers[k].attribute = attr;
+
+ hits &= CMP_MAP_H - 1;
+ __afl_cmp_map->log[k][hits].v0 = arg1;
+ __afl_cmp_map->log[k][hits].v1 = arg2;
+
+}
+
+#ifdef WORD_SIZE_64
+// support for u24 to u120 via llvm _ExitInt(). size is in bytes minus 1
+void __cmplog_ins_hookN(uint128_t arg1, uint128_t arg2, uint8_t attr,
+ uint8_t size) {
+
+ // fprintf(stderr, "hookN arg0=%llx:%llx arg1=%llx:%llx bytes=%u attr=%u\n",
+ // (u64)(arg1 >> 64), (u64)arg1, (u64)(arg2 >> 64), (u64)arg2, size + 1,
+ // attr);
+
+ if (unlikely(!__afl_cmp_map || arg1 == arg2)) return;
+
+ uintptr_t k = (uintptr_t)__builtin_return_address(0);
+ k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1));
+
+ u32 hits;
+
+ if (__afl_cmp_map->headers[k].type != CMP_TYPE_INS) {
+
+ __afl_cmp_map->headers[k].type = CMP_TYPE_INS;
+ hits = 0;
+ __afl_cmp_map->headers[k].hits = 1;
+ __afl_cmp_map->headers[k].shape = size;
+
+ } else {
+
+ hits = __afl_cmp_map->headers[k].hits++;
+
+ if (__afl_cmp_map->headers[k].shape < size) {
+
+ __afl_cmp_map->headers[k].shape = size;
+
+ }
+
+ }
+
+ __afl_cmp_map->headers[k].attribute = attr;
+
+ hits &= CMP_MAP_H - 1;
+ __afl_cmp_map->log[k][hits].v0 = (u64)arg1;
+ __afl_cmp_map->log[k][hits].v1 = (u64)arg2;
+
+ if (size > 7) {
+
+ __afl_cmp_map->log[k][hits].v0_128 = (u64)(arg1 >> 64);
+ __afl_cmp_map->log[k][hits].v1_128 = (u64)(arg2 >> 64);
+
+ }
+
+}
+
+void __cmplog_ins_hook16(uint128_t arg1, uint128_t arg2, uint8_t attr) {
+
+ if (likely(!__afl_cmp_map)) return;
+
+ uintptr_t k = (uintptr_t)__builtin_return_address(0);
+ k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1));
+
+ u32 hits;
+
+ if (__afl_cmp_map->headers[k].type != CMP_TYPE_INS) {
+
+ __afl_cmp_map->headers[k].type = CMP_TYPE_INS;
+ hits = 0;
+ __afl_cmp_map->headers[k].hits = 1;
+ __afl_cmp_map->headers[k].shape = 15;
+
+ } else {
+
+ hits = __afl_cmp_map->headers[k].hits++;
+
+ if (__afl_cmp_map->headers[k].shape < 15) {
+
+ __afl_cmp_map->headers[k].shape = 15;
+
+ }
+
+ }
+
+ __afl_cmp_map->headers[k].attribute = attr;
+
+ hits &= CMP_MAP_H - 1;
+ __afl_cmp_map->log[k][hits].v0 = (u64)arg1;
+ __afl_cmp_map->log[k][hits].v1 = (u64)arg2;
+ __afl_cmp_map->log[k][hits].v0_128 = (u64)(arg1 >> 64);
+ __afl_cmp_map->log[k][hits].v1_128 = (u64)(arg2 >> 64);
+
+}
+
+#endif
+
+void __sanitizer_cov_trace_cmp1(uint8_t arg1, uint8_t arg2) {
+
+ __cmplog_ins_hook1(arg1, arg2, 0);
+
+}
+
+void __sanitizer_cov_trace_const_cmp1(uint8_t arg1, uint8_t arg2) {
+
+ __cmplog_ins_hook1(arg1, arg2, 0);
+
+}
+
+void __sanitizer_cov_trace_cmp2(uint16_t arg1, uint16_t arg2) {
+
+ __cmplog_ins_hook2(arg1, arg2, 0);
+
+}
+
+void __sanitizer_cov_trace_const_cmp2(uint16_t arg1, uint16_t arg2) {
+
+ __cmplog_ins_hook2(arg1, arg2, 0);
+
+}
+
+void __sanitizer_cov_trace_cmp4(uint32_t arg1, uint32_t arg2) {
+
+ __cmplog_ins_hook4(arg1, arg2, 0);
+
+}
+
+void __sanitizer_cov_trace_const_cmp4(uint32_t arg1, uint32_t arg2) {
+
+ __cmplog_ins_hook4(arg1, arg2, 0);
+
+}
+
+void __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2) {
+
+ __cmplog_ins_hook8(arg1, arg2, 0);
+
+}
+
+void __sanitizer_cov_trace_const_cmp8(uint64_t arg1, uint64_t arg2) {
+
+ __cmplog_ins_hook8(arg1, arg2, 0);
+
+}
+
+#ifdef WORD_SIZE_64
+void __sanitizer_cov_trace_cmp16(uint128_t arg1, uint128_t arg2) {
+
+ __cmplog_ins_hook16(arg1, arg2, 0);
+
+}
+
+void __sanitizer_cov_trace_const_cmp16(uint128_t arg1, uint128_t arg2) {
+
+ __cmplog_ins_hook16(arg1, arg2, 0);
+
+}
+
+#endif
+
+void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) {
+
+ if (likely(!__afl_cmp_map)) return;
+
+ for (uint64_t i = 0; i < cases[0]; i++) {
+
+ uintptr_t k = (uintptr_t)__builtin_return_address(0) + i;
+ k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) &
+ (CMP_MAP_W - 1));
+
+ u32 hits;
+
+ if (__afl_cmp_map->headers[k].type != CMP_TYPE_INS) {
+
+ __afl_cmp_map->headers[k].type = CMP_TYPE_INS;
+ hits = 0;
+ __afl_cmp_map->headers[k].hits = 1;
+ __afl_cmp_map->headers[k].shape = 7;
+
+ } else {
+
+ hits = __afl_cmp_map->headers[k].hits++;
+
+ if (__afl_cmp_map->headers[k].shape < 7) {
+
+ __afl_cmp_map->headers[k].shape = 7;
+
+ }
+
+ }
+
+ __afl_cmp_map->headers[k].attribute = 1;
+
+ hits &= CMP_MAP_H - 1;
+ __afl_cmp_map->log[k][hits].v0 = val;
+ __afl_cmp_map->log[k][hits].v1 = cases[i + 2];
+
+ }
+
+}
+
+__attribute__((weak)) void *__asan_region_is_poisoned(void *beg, size_t size) {
+
+ return NULL;
+
+}
+
+// POSIX shenanigan to see if an area is mapped.
+// If it is mapped as X-only, we have a problem, so maybe we should add a check
+// to avoid to call it on .text addresses
+static int area_is_valid(void *ptr, size_t len) {
+
+ if (unlikely(!ptr || __asan_region_is_poisoned(ptr, len))) { return 0; }
+
+#ifndef __HAIKU__
+ long r = syscall(SYS_write, __afl_dummy_fd[1], ptr, len);
+#else
+ long r = _kern_write(__afl_dummy_fd[1], -1, ptr, len);
+#endif // HAIKU
+
+ if (r <= 0 || r > len) return 0;
+
+ // even if the write succeed this can be a false positive if we cross
+ // a page boundary. who knows why.
+
+ char *p = (char *)ptr;
+ long page_size = sysconf(_SC_PAGE_SIZE);
+ char *page = (char *)((uintptr_t)p & ~(page_size - 1)) + page_size;
+
+ if (page > p + len) {
+
+ // no, not crossing a page boundary
+ return (int)r;
+
+ } else {
+
+ // yes it crosses a boundary, hence we can only return the length of
+ // rest of the first page, we cannot detect if the next page is valid
+ // or not, neither by SYS_write nor msync() :-(
+ return (int)(page - p);
+
+ }
+
+}
+
+/* hook for string with length functions, eg. strncmp, strncasecmp etc.
+ Note that we ignore the len parameter and take longer strings if present. */
+void __cmplog_rtn_hook_strn(u8 *ptr1, u8 *ptr2, u64 len) {
+
+ // fprintf(stderr, "RTN1 %p %p %u\n", ptr1, ptr2, len);
+ if (likely(!__afl_cmp_map)) return;
+ if (unlikely(!len)) return;
+ int len0 = MIN(len, 31);
+ int len1 = strnlen(ptr1, len0);
+ if (len1 < 31) len1 = area_is_valid(ptr1, len1 + 1);
+ int len2 = strnlen(ptr2, len0);
+ if (len2 < 31) len2 = area_is_valid(ptr1, len2 + 1);
+ int l = MAX(len1, len2);
+ if (l < 2) return;
+
+ uintptr_t k = (uintptr_t)__builtin_return_address(0);
+ k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1));
+
+ u32 hits;
+
+ if (__afl_cmp_map->headers[k].type != CMP_TYPE_RTN) {
+
+ __afl_cmp_map->headers[k].type = CMP_TYPE_RTN;
+ __afl_cmp_map->headers[k].hits = 1;
+ __afl_cmp_map->headers[k].shape = l - 1;
+ hits = 0;
+
+ } else {
+
+ hits = __afl_cmp_map->headers[k].hits++;
+
+ if (__afl_cmp_map->headers[k].shape < l) {
+
+ __afl_cmp_map->headers[k].shape = l - 1;
+
+ }
+
+ }
+
+ struct cmpfn_operands *cmpfn = (struct cmpfn_operands *)__afl_cmp_map->log[k];
+ hits &= CMP_MAP_RTN_H - 1;
+
+ cmpfn[hits].v0_len = 0x80 + l;
+ cmpfn[hits].v1_len = 0x80 + l;
+ __builtin_memcpy(cmpfn[hits].v0, ptr1, len1);
+ __builtin_memcpy(cmpfn[hits].v1, ptr2, len2);
+ // fprintf(stderr, "RTN3\n");
+
+}
+
+/* hook for string functions, eg. strcmp, strcasecmp etc. */
+void __cmplog_rtn_hook_str(u8 *ptr1, u8 *ptr2) {
+
+ // fprintf(stderr, "RTN1 %p %p\n", ptr1, ptr2);
+ if (likely(!__afl_cmp_map)) return;
+ if (unlikely(!ptr1 || !ptr2)) return;
+ int len1 = strnlen(ptr1, 30) + 1;
+ int len2 = strnlen(ptr2, 30) + 1;
+ int l = MAX(len1, len2);
+ if (l < 3) return;
+
+ uintptr_t k = (uintptr_t)__builtin_return_address(0);
+ k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1));
+
+ u32 hits;
+
+ if (__afl_cmp_map->headers[k].type != CMP_TYPE_RTN) {
+
+ __afl_cmp_map->headers[k].type = CMP_TYPE_RTN;
+ __afl_cmp_map->headers[k].hits = 1;
+ __afl_cmp_map->headers[k].shape = l - 1;
+ hits = 0;
+
+ } else {
+
+ hits = __afl_cmp_map->headers[k].hits++;
+
+ if (__afl_cmp_map->headers[k].shape < l) {
+
+ __afl_cmp_map->headers[k].shape = l - 1;
+
+ }
+
+ }
+
+ struct cmpfn_operands *cmpfn = (struct cmpfn_operands *)__afl_cmp_map->log[k];
+ hits &= CMP_MAP_RTN_H - 1;
+
+ cmpfn[hits].v0_len = 0x80 + len1;
+ cmpfn[hits].v1_len = 0x80 + len2;
+ __builtin_memcpy(cmpfn[hits].v0, ptr1, len1);
+ __builtin_memcpy(cmpfn[hits].v1, ptr2, len2);
+ // fprintf(stderr, "RTN3\n");
+
+}
+
+/* hook function for all other func(ptr, ptr, ...) variants */
+void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) {
+
+ /*
+ u32 i;
+ if (area_is_valid(ptr1, 31) <= 0 || area_is_valid(ptr2, 31) <= 0) return;
+ fprintf(stderr, "rtn arg0=");
+ for (i = 0; i < 32; i++)
+ fprintf(stderr, "%02x", ptr1[i]);
+ fprintf(stderr, " arg1=");
+ for (i = 0; i < 32; i++)
+ fprintf(stderr, "%02x", ptr2[i]);
+ fprintf(stderr, "\n");
+ */
+
+ // fprintf(stderr, "RTN1 %p %p\n", ptr1, ptr2);
+ if (likely(!__afl_cmp_map)) return;
+ int l1, l2;
+ if ((l1 = area_is_valid(ptr1, 31)) <= 0 ||
+ (l2 = area_is_valid(ptr2, 31)) <= 0)
+ return;
+ int len = MIN(31, MIN(l1, l2));
+
+ // fprintf(stderr, "RTN2 %u\n", len);
+ uintptr_t k = (uintptr_t)__builtin_return_address(0);
+ k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1));
+
+ u32 hits;
+
+ if (__afl_cmp_map->headers[k].type != CMP_TYPE_RTN) {
+
+ __afl_cmp_map->headers[k].type = CMP_TYPE_RTN;
+ __afl_cmp_map->headers[k].hits = 1;
+ __afl_cmp_map->headers[k].shape = len - 1;
+ hits = 0;
+
+ } else {
+
+ hits = __afl_cmp_map->headers[k].hits++;
+
+ if (__afl_cmp_map->headers[k].shape < len) {
+
+ __afl_cmp_map->headers[k].shape = len - 1;
+
+ }
+
+ }
+
+ struct cmpfn_operands *cmpfn = (struct cmpfn_operands *)__afl_cmp_map->log[k];
+ hits &= CMP_MAP_RTN_H - 1;
+
+ cmpfn[hits].v0_len = len;
+ cmpfn[hits].v1_len = len;
+ __builtin_memcpy(cmpfn[hits].v0, ptr1, len);
+ __builtin_memcpy(cmpfn[hits].v1, ptr2, len);
+ // fprintf(stderr, "RTN3\n");
+
+}
+
+/* hook for func(ptr, ptr, len, ...) looking functions.
+ Note that for the time being we ignore len as this could be wrong
+ information and pass it on to the standard binary rtn hook */
+void __cmplog_rtn_hook_n(u8 *ptr1, u8 *ptr2, u64 len) {
+
+ (void)(len);
+ __cmplog_rtn_hook(ptr1, ptr2);
+
+#if 0
+ /*
+ u32 i;
+ if (area_is_valid(ptr1, 31) <= 0 || area_is_valid(ptr2, 31) <= 0) return;
+ fprintf(stderr, "rtn_n len=%u arg0=", len);
+ for (i = 0; i < len; i++)
+ fprintf(stderr, "%02x", ptr1[i]);
+ fprintf(stderr, " arg1=");
+ for (i = 0; i < len; i++)
+ fprintf(stderr, "%02x", ptr2[i]);
+ fprintf(stderr, "\n");
+ */
+
+ // fprintf(stderr, "RTN1 %p %p %u\n", ptr1, ptr2, len);
+ if (likely(!__afl_cmp_map)) return;
+ if (unlikely(!len)) return;
+ int l = MIN(31, len);
+
+ if ((l = area_is_valid(ptr1, l)) <= 0 || (l = area_is_valid(ptr2, l)) <= 0)
+ return;
+
+ // fprintf(stderr, "RTN2 %u\n", l);
+ uintptr_t k = (uintptr_t)__builtin_return_address(0);
+ k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1));
+
+ u32 hits;
+
+ if (__afl_cmp_map->headers[k].type != CMP_TYPE_RTN) {
+
+ __afl_cmp_map->headers[k].type = CMP_TYPE_RTN;
+ __afl_cmp_map->headers[k].hits = 1;
+ __afl_cmp_map->headers[k].shape = l - 1;
+ hits = 0;
+
+ } else {
+
+ hits = __afl_cmp_map->headers[k].hits++;
+
+ if (__afl_cmp_map->headers[k].shape < l) {
+
+ __afl_cmp_map->headers[k].shape = l - 1;
+
+ }
+
+ }
+
+ struct cmpfn_operands *cmpfn = (struct cmpfn_operands *)__afl_cmp_map->log[k];
+ hits &= CMP_MAP_RTN_H - 1;
+
+ cmpfn[hits].v0_len = l;
+ cmpfn[hits].v1_len = l;
+ __builtin_memcpy(cmpfn[hits].v0, ptr1, l);
+ __builtin_memcpy(cmpfn[hits].v1, ptr2, l);
+ // fprintf(stderr, "RTN3\n");
+#endif
+
+}
+
+// gcc libstdc++
+// _ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE7compareEPKc
+static u8 *get_gcc_stdstring(u8 *string) {
+
+ u32 *len = (u32 *)(string + 8);
+
+ if (*len < 16) { // in structure
+
+ return (string + 16);
+
+ } else { // in memory
+
+ u8 **ptr = (u8 **)string;
+ return (*ptr);
+
+ }
+
+}
+
+// llvm libc++ _ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocator
+// IcEEE7compareEmmPKcm
+static u8 *get_llvm_stdstring(u8 *string) {
+
+ // length is in: if ((string[0] & 1) == 0) u8 len = (string[0] >> 1);
+ // or: if (string[0] & 1) u32 *len = (u32 *) (string + 8);
+
+ if (string[0] & 1) { // in memory
+
+ u8 **ptr = (u8 **)(string + 16);
+ return (*ptr);
+
+ } else { // in structure
+
+ return (string + 1);
+
+ }
+
+}
+
+void __cmplog_rtn_gcc_stdstring_cstring(u8 *stdstring, u8 *cstring) {
+
+ if (likely(!__afl_cmp_map)) return;
+ if (area_is_valid(stdstring, 32) <= 0 || area_is_valid(cstring, 32) <= 0)
+ return;
+
+ __cmplog_rtn_hook(get_gcc_stdstring(stdstring), cstring);
+
+}
+
+void __cmplog_rtn_gcc_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) {
+
+ if (likely(!__afl_cmp_map)) return;
+ if (area_is_valid(stdstring1, 32) <= 0 || area_is_valid(stdstring2, 32) <= 0)
+ return;
+
+ __cmplog_rtn_hook(get_gcc_stdstring(stdstring1),
+ get_gcc_stdstring(stdstring2));
+
+}
+
+void __cmplog_rtn_llvm_stdstring_cstring(u8 *stdstring, u8 *cstring) {
+
+ if (likely(!__afl_cmp_map)) return;
+ if (area_is_valid(stdstring, 32) <= 0 || area_is_valid(cstring, 32) <= 0)
+ return;
+
+ __cmplog_rtn_hook(get_llvm_stdstring(stdstring), cstring);
+
+}
+
+void __cmplog_rtn_llvm_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) {
+
+ if (likely(!__afl_cmp_map)) return;
+ if (area_is_valid(stdstring1, 32) <= 0 || area_is_valid(stdstring2, 32) <= 0)
+ return;
+
+ __cmplog_rtn_hook(get_llvm_stdstring(stdstring1),
+ get_llvm_stdstring(stdstring2));
+
+}
+
+/* COVERAGE manipulation features */
+
+// this variable is then used in the shm setup to create an additional map
+// if __afl_map_size > MAP_SIZE or cmplog is used.
+// Especially with cmplog this would result in a ~260MB mem increase per
+// target run.
+
+// disable coverage from this point onwards until turned on again
+void __afl_coverage_off() {
+
+ if (likely(__afl_selective_coverage)) {
+
+ __afl_area_ptr = __afl_area_ptr_dummy;
+ __afl_cmp_map = NULL;
+
+ }
+
+}
+
+// enable coverage
+void __afl_coverage_on() {
+
+ if (likely(__afl_selective_coverage && __afl_selective_coverage_temp)) {
+
+ __afl_area_ptr = __afl_area_ptr_backup;
+ if (__afl_cmp_map_backup) { __afl_cmp_map = __afl_cmp_map_backup; }
+
+ }
+
+}
+
+// discard all coverage up to this point
+void __afl_coverage_discard() {
+
+ memset(__afl_area_ptr_backup, 0, __afl_map_size);
+ __afl_area_ptr_backup[0] = 1;
+
+ if (__afl_cmp_map) { memset(__afl_cmp_map, 0, sizeof(struct cmp_map)); }
+
+}
+
+// discard the testcase
+void __afl_coverage_skip() {
+
+ __afl_coverage_discard();
+
+ if (likely(is_persistent && __afl_selective_coverage)) {
+
+ __afl_coverage_off();
+ __afl_selective_coverage_temp = 0;
+
+ } else {
+
+ exit(0);
+
+ }
+
+}
+
+// mark this area as especially interesting
+void __afl_coverage_interesting(u8 val, u32 id) {
+
+ __afl_area_ptr[id] = val;
+
+}
+
+void __afl_set_persistent_mode(u8 mode) {
+
+ is_persistent = mode;
+
+}
+
+#undef write_error
+
diff --git a/instrumentation/afl-llvm-common.cc b/instrumentation/afl-llvm-common.cc
new file mode 100644
index 00000000..9483da83
--- /dev/null
+++ b/instrumentation/afl-llvm-common.cc
@@ -0,0 +1,600 @@
+#define AFL_LLVM_PASS
+
+#include "config.h"
+#include "debug.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <fnmatch.h>
+
+#include <list>
+#include <string>
+#include <fstream>
+
+#include <llvm/Support/raw_ostream.h>
+
+#define IS_EXTERN extern
+#include "afl-llvm-common.h"
+
+using namespace llvm;
+
+static std::list<std::string> allowListFiles;
+static std::list<std::string> allowListFunctions;
+static std::list<std::string> denyListFiles;
+static std::list<std::string> denyListFunctions;
+
+char *getBBName(const llvm::BasicBlock *BB) {
+
+ static char *name;
+
+ if (!BB->getName().empty()) {
+
+ name = strdup(BB->getName().str().c_str());
+ return name;
+
+ }
+
+ std::string Str;
+ raw_string_ostream OS(Str);
+
+#if LLVM_VERSION_MAJOR >= 4 || \
+ (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7)
+ BB->printAsOperand(OS, false);
+#endif
+ name = strdup(OS.str().c_str());
+ return name;
+
+}
+
+/* Function that we never instrument or analyze */
+/* Note: this ignore check is also called in isInInstrumentList() */
+bool isIgnoreFunction(const llvm::Function *F) {
+
+ // Starting from "LLVMFuzzer" these are functions used in libfuzzer based
+ // fuzzing campaign installations, e.g. oss-fuzz
+
+ static constexpr const char *ignoreList[] = {
+
+ "asan.",
+ "llvm.",
+ "sancov.",
+ "__ubsan",
+ "ign.",
+ "__afl",
+ "_fini",
+ "__libc_",
+ "__asan",
+ "__msan",
+ "__cmplog",
+ "__sancov",
+ "__san",
+ "__cxx_",
+ "__decide_deferred",
+ "_GLOBAL",
+ "_ZZN6__asan",
+ "_ZZN6__lsan",
+ "msan.",
+ "LLVMFuzzerM",
+ "LLVMFuzzerC",
+ "LLVMFuzzerI",
+ "maybe_duplicate_stderr",
+ "discard_output",
+ "close_stdout",
+ "dup_and_close_stderr",
+ "maybe_close_fd_mask",
+ "ExecuteFilesOnyByOne"
+
+ };
+
+ for (auto const &ignoreListFunc : ignoreList) {
+
+ if (F->getName().startswith(ignoreListFunc)) { return true; }
+
+ }
+
+ static constexpr const char *ignoreSubstringList[] = {
+
+ "__asan", "__msan", "__ubsan", "__lsan", "__san", "__sanitize",
+ "__cxx", "DebugCounter", "DwarfDebug", "DebugLoc"
+
+ };
+
+ for (auto const &ignoreListFunc : ignoreSubstringList) {
+
+ // hexcoder: F->getName().contains() not avaiilable in llvm 3.8.0
+ if (StringRef::npos != F->getName().find(ignoreListFunc)) { return true; }
+
+ }
+
+ return false;
+
+}
+
+void initInstrumentList() {
+
+ char *allowlist = getenv("AFL_LLVM_ALLOWLIST");
+ if (!allowlist) allowlist = getenv("AFL_LLVM_INSTRUMENT_FILE");
+ if (!allowlist) allowlist = getenv("AFL_LLVM_WHITELIST");
+ char *denylist = getenv("AFL_LLVM_DENYLIST");
+ if (!denylist) denylist = getenv("AFL_LLVM_BLOCKLIST");
+
+ if (allowlist && denylist)
+ FATAL(
+ "You can only specify either AFL_LLVM_ALLOWLIST or AFL_LLVM_DENYLIST "
+ "but not both!");
+
+ if (allowlist) {
+
+ std::string line;
+ std::ifstream fileStream;
+ fileStream.open(allowlist);
+ if (!fileStream) report_fatal_error("Unable to open AFL_LLVM_ALLOWLIST");
+ getline(fileStream, line);
+
+ while (fileStream) {
+
+ int is_file = -1;
+ std::size_t npos;
+ std::string original_line = line;
+
+ line.erase(std::remove_if(line.begin(), line.end(), ::isspace),
+ line.end());
+
+ // remove # and following
+ if ((npos = line.find("#")) != std::string::npos)
+ line = line.substr(0, npos);
+
+ if (line.compare(0, 4, "fun:") == 0) {
+
+ is_file = 0;
+ line = line.substr(4);
+
+ } else if (line.compare(0, 9, "function:") == 0) {
+
+ is_file = 0;
+ line = line.substr(9);
+
+ } else if (line.compare(0, 4, "src:") == 0) {
+
+ is_file = 1;
+ line = line.substr(4);
+
+ } else if (line.compare(0, 7, "source:") == 0) {
+
+ is_file = 1;
+ line = line.substr(7);
+
+ }
+
+ if (line.find(":") != std::string::npos) {
+
+ FATAL("invalid line in AFL_LLVM_ALLOWLIST: %s", original_line.c_str());
+
+ }
+
+ if (line.length() > 0) {
+
+ // if the entry contains / or . it must be a file
+ if (is_file == -1)
+ if (line.find("/") != std::string::npos ||
+ line.find(".") != std::string::npos)
+ is_file = 1;
+ // otherwise it is a function
+
+ if (is_file == 1)
+ allowListFiles.push_back(line);
+ else
+ allowListFunctions.push_back(line);
+
+ }
+
+ getline(fileStream, line);
+
+ }
+
+ if (debug)
+ DEBUGF("loaded allowlist with %zu file and %zu function entries\n",
+ allowListFiles.size(), allowListFunctions.size());
+
+ }
+
+ if (denylist) {
+
+ std::string line;
+ std::ifstream fileStream;
+ fileStream.open(denylist);
+ if (!fileStream) report_fatal_error("Unable to open AFL_LLVM_DENYLIST");
+ getline(fileStream, line);
+
+ while (fileStream) {
+
+ int is_file = -1;
+ std::size_t npos;
+ std::string original_line = line;
+
+ line.erase(std::remove_if(line.begin(), line.end(), ::isspace),
+ line.end());
+
+ // remove # and following
+ if ((npos = line.find("#")) != std::string::npos)
+ line = line.substr(0, npos);
+
+ if (line.compare(0, 4, "fun:") == 0) {
+
+ is_file = 0;
+ line = line.substr(4);
+
+ } else if (line.compare(0, 9, "function:") == 0) {
+
+ is_file = 0;
+ line = line.substr(9);
+
+ } else if (line.compare(0, 4, "src:") == 0) {
+
+ is_file = 1;
+ line = line.substr(4);
+
+ } else if (line.compare(0, 7, "source:") == 0) {
+
+ is_file = 1;
+ line = line.substr(7);
+
+ }
+
+ if (line.find(":") != std::string::npos) {
+
+ FATAL("invalid line in AFL_LLVM_DENYLIST: %s", original_line.c_str());
+
+ }
+
+ if (line.length() > 0) {
+
+ // if the entry contains / or . it must be a file
+ if (is_file == -1)
+ if (line.find("/") != std::string::npos ||
+ line.find(".") != std::string::npos)
+ is_file = 1;
+ // otherwise it is a function
+
+ if (is_file == 1)
+ denyListFiles.push_back(line);
+ else
+ denyListFunctions.push_back(line);
+
+ }
+
+ getline(fileStream, line);
+
+ }
+
+ if (debug)
+ DEBUGF("loaded denylist with %zu file and %zu function entries\n",
+ denyListFiles.size(), denyListFunctions.size());
+
+ }
+
+}
+
+void scanForDangerousFunctions(llvm::Module *M) {
+
+ if (!M) return;
+
+#if LLVM_VERSION_MAJOR >= 4 || \
+ (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 9)
+
+ 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,
+ "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());
+
+ }
+
+ 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) {
+
+ 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());
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+#endif
+
+}
+
+static std::string getSourceName(llvm::Function *F) {
+
+ // 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();
+
+#if LLVM_VERSION_MAJOR >= 4 || \
+ (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7)
+ if (Loc) {
+
+ StringRef instFilename;
+ DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode());
+
+ if (cDILoc) { instFilename = cDILoc->getFilename(); }
+
+ if (instFilename.str().empty() && cDILoc) {
+
+ /* 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
+
+ return std::string("");
+
+}
+
+bool isInInstrumentList(llvm::Function *F, std::string Filename) {
+
+ 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()) {
+
+ if (!denyListFunctions.empty()) {
+
+ std::string instFunction = F->getName().str();
+
+ for (std::list<std::string>::iterator it = denyListFunctions.begin();
+ it != denyListFunctions.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)
+ DEBUGF(
+ "Function %s is in the deny function list, not instrumenting "
+ "... \n",
+ instFunction.c_str());
+ return false;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ if (!denyListFiles.empty()) {
+
+ std::string source_file = getSourceName(F);
+
+ if (source_file.empty()) { source_file = Filename; }
+
+ if (!source_file.empty()) {
+
+ for (std::list<std::string>::iterator it = denyListFiles.begin();
+ it != denyListFiles.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 (source_file.length() >= it->length()) {
+
+ if (fnmatch(("*" + *it).c_str(), source_file.c_str(), 0) == 0) {
+
+ return false;
+
+ }
+
+ }
+
+ }
+
+ } 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 be "
+ "instrumented (recompile with -g -O[1-3] and use a modern llvm).",
+ F->getName().str().c_str());
+
+ }
+
+ }
+
+ }
+
+ // 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)
+ DEBUGF(
+ "Function %s is in the allow function list, instrumenting "
+ "... \n",
+ instFunction.c_str());
+ return true;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ if (!allowListFiles.empty()) {
+
+ std::string source_file = getSourceName(F);
+
+ if (source_file.empty()) { source_file = Filename; }
+
+ if (!source_file.empty()) {
+
+ for (std::list<std::string>::iterator it = allowListFiles.begin();
+ it != allowListFiles.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 (source_file.length() >= it->length()) {
+
+ if (fnmatch(("*" + *it).c_str(), source_file.c_str(), 0) == 0) {
+
+ if (debug)
+ DEBUGF(
+ "Function %s is in the allowlist (%s), instrumenting ... "
+ "\n",
+ F->getName().str().c_str(), source_file.c_str());
+ return true;
+
+ }
+
+ }
+
+ }
+
+ } 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] and use a modern llvm).",
+ F->getName().str().c_str());
+ return false;
+
+ }
+
+ }
+
+ }
+
+ return return_default;
+
+}
+
+// Calculate the number of average collisions that would occur if all
+// location IDs would be assigned randomly (like normal afl/afl++).
+// This uses the "balls in bins" algorithm.
+unsigned long long int calculateCollisions(uint32_t edges) {
+
+ double bins = MAP_SIZE;
+ double balls = edges;
+ double step1 = 1 - (1 / bins);
+ double step2 = pow(step1, balls);
+ double step3 = bins * step2;
+ double step4 = round(step3);
+ unsigned long long int empty = step4;
+ unsigned long long int collisions = edges - (MAP_SIZE - empty);
+ return collisions;
+
+}
+
diff --git a/instrumentation/afl-llvm-common.h b/instrumentation/afl-llvm-common.h
new file mode 100644
index 00000000..dee5f9fc
--- /dev/null
+++ b/instrumentation/afl-llvm-common.h
@@ -0,0 +1,60 @@
+#ifndef __AFLLLVMCOMMON_H
+#define __AFLLLVMCOMMON_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <list>
+#include <string>
+#include <fstream>
+#include <sys/time.h>
+
+#include "llvm/Config/llvm-config.h"
+#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 5
+typedef long double max_align_t;
+#endif
+
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+
+#if LLVM_VERSION_MAJOR > 3 || \
+ (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
+ #include "llvm/IR/DebugInfo.h"
+ #include "llvm/IR/CFG.h"
+#else
+ #include "llvm/DebugInfo.h"
+ #include "llvm/Support/CFG.h"
+#endif
+
+#if LLVM_VERSION_MAJOR >= 11
+ #define MNAME M.getSourceFileName()
+ #define FMNAME F.getParent()->getSourceFileName()
+#else
+ #define MNAME std::string("")
+ #define FMNAME std::string("")
+#endif
+
+char *getBBName(const llvm::BasicBlock *BB);
+bool isIgnoreFunction(const llvm::Function *F);
+void initInstrumentList();
+bool isInInstrumentList(llvm::Function *F, std::string Filename);
+unsigned long long int calculateCollisions(uint32_t edges);
+void scanForDangerousFunctions(llvm::Module *M);
+
+#ifndef IS_EXTERN
+ #define IS_EXTERN
+#endif
+
+IS_EXTERN int debug;
+IS_EXTERN int be_quiet;
+
+#undef IS_EXTERN
+
+#endif
+
diff --git a/instrumentation/afl-llvm-dict2file.so.cc b/instrumentation/afl-llvm-dict2file.so.cc
new file mode 100644
index 00000000..31aaab07
--- /dev/null
+++ b/instrumentation/afl-llvm-dict2file.so.cc
@@ -0,0 +1,746 @@
+/*
+ american fuzzy lop++ - LLVM LTO instrumentation pass
+ ----------------------------------------------------
+
+ Written by Marc Heuse <mh@mh-sec.de>
+
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ This library is plugged into LLVM when invoking clang through afl-clang-lto.
+
+ */
+
+#define AFL_LLVM_PASS
+
+#include "config.h"
+#include "debug.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <ctype.h>
+
+#include <list>
+#include <string>
+#include <fstream>
+#include <set>
+
+#include "llvm/Config/llvm-config.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/IR/IRBuilder.h"
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+ #include "llvm/Passes/PassPlugin.h"
+ #include "llvm/Passes/PassBuilder.h"
+ #include "llvm/IR/PassManager.h"
+#else
+ #include "llvm/IR/LegacyPassManager.h"
+#endif
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/DebugInfo.h"
+#include "llvm/IR/CFG.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/ValueTracking.h"
+#include "llvm/Pass.h"
+#include "llvm/IR/Constants.h"
+
+#include "afl-llvm-common.h"
+
+#ifndef O_DSYNC
+ #define O_DSYNC O_SYNC
+#endif
+
+using namespace llvm;
+
+namespace {
+
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+class AFLdict2filePass : public PassInfoMixin<AFLdict2filePass> {
+
+ std::ofstream of;
+ void dict2file(u8 *, u32);
+
+ public:
+ AFLdict2filePass() {
+
+#else
+
+class AFLdict2filePass : public ModulePass {
+
+ std::ofstream of;
+ void dict2file(u8 *, u32);
+
+ public:
+ static char ID;
+
+ AFLdict2filePass() : ModulePass(ID) {
+
+#endif
+
+ if (getenv("AFL_DEBUG")) debug = 1;
+
+ }
+
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+ PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
+#else
+ bool runOnModule(Module &M) override;
+#endif
+
+};
+
+} // namespace
+
+#if LLVM_MAJOR >= 11
+extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
+llvmGetPassPluginInfo() {
+
+ return {LLVM_PLUGIN_API_VERSION, "AFLdict2filePass", "v0.1",
+ /* lambda to insert our pass into the pass pipeline. */
+ [](PassBuilder &PB) {
+
+ #if LLVM_VERSION_MAJOR <= 13
+ using OptimizationLevel = typename PassBuilder::OptimizationLevel;
+ #endif
+ PB.registerOptimizerLastEPCallback(
+ [](ModulePassManager &MPM, OptimizationLevel OL) {
+
+ MPM.addPass(AFLdict2filePass());
+
+ });
+
+ }};
+
+}
+
+#else
+char AFLdict2filePass::ID = 0;
+#endif
+
+void AFLdict2filePass::dict2file(u8 *mem, u32 len) {
+
+ u32 i, j, binary = 0;
+ char line[MAX_AUTO_EXTRA * 8], tmp[8];
+
+ strcpy(line, "\"");
+ j = 1;
+ for (i = 0; i < len; i++) {
+
+ if (isprint(mem[i]) && mem[i] != '\\' && mem[i] != '"') {
+
+ line[j++] = mem[i];
+
+ } else {
+
+ if (i + 1 != len || mem[i] != 0 || binary || len == 4 || len == 8) {
+
+ line[j] = 0;
+ sprintf(tmp, "\\x%02x", (u8)mem[i]);
+ strcat(line, tmp);
+ j = strlen(line);
+
+ }
+
+ binary = 1;
+
+ }
+
+ }
+
+ line[j] = 0;
+ strcat(line, "\"\n");
+ of << line;
+ of.flush();
+
+ if (!be_quiet) fprintf(stderr, "Found dictionary token: %s", line);
+
+}
+
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+PreservedAnalyses AFLdict2filePass::run(Module &M, ModuleAnalysisManager &MAM) {
+
+#else
+bool AFLdict2filePass::runOnModule(Module &M) {
+
+#endif
+
+ DenseMap<Value *, std::string *> valueMap;
+ char * ptr;
+ int found = 0;
+
+ /* Show a banner */
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ if ((isatty(2) && !getenv("AFL_QUIET")) || debug) {
+
+ SAYF(cCYA "afl-llvm-dict2file" VERSION cRST
+ " by Marc \"vanHauser\" Heuse <mh@mh-sec.de>\n");
+
+ } else
+
+ be_quiet = 1;
+
+ scanForDangerousFunctions(&M);
+
+ ptr = getenv("AFL_LLVM_DICT2FILE");
+
+ if (!ptr || *ptr != '/')
+ FATAL("AFL_LLVM_DICT2FILE is not set to an absolute path: %s", ptr);
+
+ of.open(ptr, std::ofstream::out | std::ofstream::app);
+ if (!of.is_open()) PFATAL("Could not open/create %s.", ptr);
+
+ /* Instrument all the things! */
+
+ for (auto &F : M) {
+
+ if (isIgnoreFunction(&F)) continue;
+ if (!isInInstrumentList(&F, MNAME) || !F.size()) { continue; }
+
+ /* Some implementation notes.
+ *
+ * We try to handle 3 cases:
+ * - memcmp("foo", arg, 3) <- literal string
+ * - static char globalvar[] = "foo";
+ * memcmp(globalvar, arg, 3) <- global variable
+ * - char localvar[] = "foo";
+ * memcmp(locallvar, arg, 3) <- local variable
+ *
+ * The local variable case is the hardest. We can only detect that
+ * case if there is no reassignment or change in the variable.
+ * And it might not work across llvm version.
+ * What we do is hooking the initializer function for local variables
+ * (llvm.memcpy.p0i8.p0i8.i64) and note the string and the assigned
+ * variable. And if that variable is then used in a compare function
+ * we use that noted string.
+ * This seems not to work for tokens that have a size <= 4 :-(
+ *
+ * - if the compared length is smaller than the string length we
+ * save the full string. This is likely better for fuzzing but
+ * might be wrong in a few cases depending on optimizers
+ *
+ * - not using StringRef because there is a bug in the llvm 11
+ * checkout I am using which sometimes points to wrong strings
+ *
+ * Over and out. Took me a full day. damn. mh/vh
+ */
+
+ for (auto &BB : F) {
+
+ for (auto &IN : BB) {
+
+ CallInst *callInst = nullptr;
+ CmpInst * cmpInst = nullptr;
+
+ if ((cmpInst = dyn_cast<CmpInst>(&IN))) {
+
+ Value * op = cmpInst->getOperand(1);
+ ConstantInt *ilen = dyn_cast<ConstantInt>(op);
+
+ /* We skip > 64 bit integers. why? first because their value is
+ difficult to obtain, and second because clang does not support
+ literals > 64 bit (as of llvm 12) */
+
+ if (ilen && ilen->uge(0xffffffffffffffff) == false) {
+
+ u64 val2 = 0, val = ilen->getZExtValue();
+ u32 len = 0;
+ if (val > 0x10000 && val < 0xffffffff) len = 4;
+ if (val > 0x100000001 && val < 0xffffffffffffffff) len = 8;
+
+ if (len) {
+
+ auto c = cmpInst->getPredicate();
+
+ switch (c) {
+
+ case CmpInst::FCMP_OGT: // fall through
+ case CmpInst::FCMP_OLE: // fall through
+ case CmpInst::ICMP_SLE: // fall through
+ case CmpInst::ICMP_SGT:
+
+ // signed comparison and it is a negative constant
+ if ((len == 4 && (val & 80000000)) ||
+ (len == 8 && (val & 8000000000000000))) {
+
+ if ((val & 0xffff) != 1) val2 = val - 1;
+ break;
+
+ }
+
+ // fall through
+
+ case CmpInst::FCMP_UGT: // fall through
+ case CmpInst::FCMP_ULE: // fall through
+ case CmpInst::ICMP_UGT: // fall through
+ case CmpInst::ICMP_ULE:
+ if ((val & 0xffff) != 0xfffe) val2 = val + 1;
+ break;
+
+ case CmpInst::FCMP_OLT: // fall through
+ case CmpInst::FCMP_OGE: // fall through
+ case CmpInst::ICMP_SLT: // fall through
+ case CmpInst::ICMP_SGE:
+
+ // signed comparison and it is a negative constant
+ if ((len == 4 && (val & 80000000)) ||
+ (len == 8 && (val & 8000000000000000))) {
+
+ if ((val & 0xffff) != 1) val2 = val - 1;
+ break;
+
+ }
+
+ // fall through
+
+ case CmpInst::FCMP_ULT: // fall through
+ case CmpInst::FCMP_UGE: // fall through
+ case CmpInst::ICMP_ULT: // fall through
+ case CmpInst::ICMP_UGE:
+ if ((val & 0xffff) != 1) val2 = val - 1;
+ break;
+
+ default:
+ val2 = 0;
+
+ }
+
+ dict2file((u8 *)&val, len);
+ found++;
+ if (val2) {
+
+ dict2file((u8 *)&val2, len);
+ found++;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ 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 isStdString = true;
+ bool isStrstr = true;
+ size_t optLen = 0;
+
+ Function *Callee = callInst->getCalledFunction();
+ if (!Callee) continue;
+ if (callInst->getCallingConv() != llvm::CallingConv::C) continue;
+ std::string FuncName = Callee->getName().str();
+ isStrcmp &=
+ (!FuncName.compare("strcmp") || !FuncName.compare("xmlStrcmp") ||
+ !FuncName.compare("xmlStrEqual") ||
+ !FuncName.compare("g_strcmp0") ||
+ !FuncName.compare("curl_strequal") ||
+ !FuncName.compare("strcsequal"));
+ isMemcmp &=
+ (!FuncName.compare("memcmp") || !FuncName.compare("bcmp") ||
+ !FuncName.compare("CRYPTO_memcmp") ||
+ !FuncName.compare("OPENSSL_memcmp") ||
+ !FuncName.compare("memcmp_const_time") ||
+ !FuncName.compare("memcmpct"));
+ isStrncmp &= (!FuncName.compare("strncmp") ||
+ !FuncName.compare("xmlStrncmp") ||
+ !FuncName.compare("curl_strnequal"));
+ isStrcasecmp &= (!FuncName.compare("strcasecmp") ||
+ !FuncName.compare("stricmp") ||
+ !FuncName.compare("ap_cstr_casecmp") ||
+ !FuncName.compare("OPENSSL_strcasecmp") ||
+ !FuncName.compare("xmlStrcasecmp") ||
+ !FuncName.compare("g_strcasecmp") ||
+ !FuncName.compare("g_ascii_strcasecmp") ||
+ !FuncName.compare("Curl_strcasecompare") ||
+ !FuncName.compare("Curl_safe_strcasecompare") ||
+ !FuncName.compare("cmsstrcasecmp"));
+ isStrncasecmp &= (!FuncName.compare("strncasecmp") ||
+ !FuncName.compare("strnicmp") ||
+ !FuncName.compare("ap_cstr_casecmpn") ||
+ !FuncName.compare("OPENSSL_strncasecmp") ||
+ !FuncName.compare("xmlStrncasecmp") ||
+ !FuncName.compare("g_ascii_strncasecmp") ||
+ !FuncName.compare("Curl_strncasecompare") ||
+ !FuncName.compare("g_strncasecmp"));
+ isStrstr &= (!FuncName.compare("strstr") ||
+ !FuncName.compare("g_strstr_len") ||
+ !FuncName.compare("ap_strcasestr") ||
+ !FuncName.compare("xmlStrstr") ||
+ !FuncName.compare("xmlStrcasestr") ||
+ !FuncName.compare("g_str_has_prefix") ||
+ !FuncName.compare("g_str_has_suffix"));
+ isIntMemcpy &= !FuncName.compare("llvm.memcpy.p0i8.p0i8.i64");
+ isStdString &= ((FuncName.find("basic_string") != std::string::npos &&
+ FuncName.find("compare") != std::string::npos) ||
+ (FuncName.find("basic_string") != std::string::npos &&
+ FuncName.find("find") != std::string::npos));
+
+ if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
+ !isStrncasecmp && !isIntMemcpy && !isStdString && !isStrstr)
+ continue;
+
+ /* Verify the strcmp/memcmp/strncmp/strcasecmp/strncasecmp function
+ * prototype */
+ FunctionType *FT = Callee->getFunctionType();
+
+ isStrstr &=
+ FT->getNumParams() == 2 &&
+ FT->getParamType(0) == FT->getParamType(1) &&
+ FT->getParamType(0) == IntegerType::getInt8PtrTy(M.getContext());
+ isStrcmp &=
+ FT->getNumParams() == 2 && FT->getReturnType()->isIntegerTy(32) &&
+ FT->getParamType(0) == FT->getParamType(1) &&
+ FT->getParamType(0) == IntegerType::getInt8PtrTy(M.getContext());
+ isStrcasecmp &=
+ FT->getNumParams() == 2 && FT->getReturnType()->isIntegerTy(32) &&
+ FT->getParamType(0) == FT->getParamType(1) &&
+ FT->getParamType(0) == IntegerType::getInt8PtrTy(M.getContext());
+ isMemcmp &= FT->getNumParams() == 3 &&
+ FT->getReturnType()->isIntegerTy(32) &&
+ FT->getParamType(0)->isPointerTy() &&
+ FT->getParamType(1)->isPointerTy() &&
+ FT->getParamType(2)->isIntegerTy();
+ isStrncmp &= FT->getNumParams() == 3 &&
+ FT->getReturnType()->isIntegerTy(32) &&
+ FT->getParamType(0) == FT->getParamType(1) &&
+ FT->getParamType(0) ==
+ IntegerType::getInt8PtrTy(M.getContext()) &&
+ FT->getParamType(2)->isIntegerTy();
+ isStrncasecmp &= FT->getNumParams() == 3 &&
+ FT->getReturnType()->isIntegerTy(32) &&
+ FT->getParamType(0) == FT->getParamType(1) &&
+ FT->getParamType(0) ==
+ IntegerType::getInt8PtrTy(M.getContext()) &&
+ FT->getParamType(2)->isIntegerTy();
+ isStdString &= FT->getNumParams() >= 2 &&
+ FT->getParamType(0)->isPointerTy() &&
+ FT->getParamType(1)->isPointerTy();
+
+ if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
+ !isStrncasecmp && !isIntMemcpy && !isStdString && !isStrstr)
+ continue;
+
+ /* is a str{n,}{case,}cmp/memcmp, check if we have
+ * str{case,}cmp(x, "const") or str{case,}cmp("const", x)
+ * strn{case,}cmp(x, "const", ..) or strn{case,}cmp("const", x, ..)
+ * memcmp(x, "const", ..) or memcmp("const", x, ..) */
+ Value *Str1P = callInst->getArgOperand(0),
+ *Str2P = callInst->getArgOperand(1);
+ std::string Str1, Str2;
+ StringRef TmpStr;
+ bool HasStr1;
+ getConstantStringInfo(Str1P, TmpStr);
+
+ if (isStrstr || TmpStr.empty()) {
+
+ HasStr1 = false;
+
+ } else {
+
+ HasStr1 = true;
+ Str1 = TmpStr.str();
+
+ }
+
+ bool HasStr2;
+ getConstantStringInfo(Str2P, TmpStr);
+ if (TmpStr.empty()) {
+
+ HasStr2 = false;
+
+ } else {
+
+ HasStr2 = true;
+ Str2 = TmpStr.str();
+
+ }
+
+ if (debug)
+ fprintf(stderr, "F:%s %p(%s)->\"%s\"(%s) %p(%s)->\"%s\"(%s)\n",
+ FuncName.c_str(), (void *)Str1P,
+ Str1P->getName().str().c_str(), Str1.c_str(),
+ HasStr1 == true ? "true" : "false", (void *)Str2P,
+ Str2P->getName().str().c_str(), Str2.c_str(),
+ HasStr2 == true ? "true" : "false");
+
+ // we handle the 2nd parameter first because of llvm memcpy
+ if (!HasStr2) {
+
+ auto *Ptr = dyn_cast<ConstantExpr>(Str2P);
+ if (Ptr && Ptr->getOpcode() == Instruction::GetElementPtr) {
+
+ if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
+
+ if (Var->hasInitializer()) {
+
+ if (auto *Array =
+ dyn_cast<ConstantDataArray>(Var->getInitializer())) {
+
+ HasStr2 = true;
+ Str2 = Array->getRawDataValues().str();
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ // for the internal memcpy routine we only care for the second
+ // parameter and are not reporting anything.
+ if (isIntMemcpy == true) {
+
+ if (HasStr2 == true) {
+
+ Value * op2 = callInst->getArgOperand(2);
+ ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
+ if (ilen) {
+
+ uint64_t literalLength = Str2.length();
+ uint64_t optLength = ilen->getZExtValue();
+ if (optLength > literalLength + 1) {
+
+ optLength = Str2.length() + 1;
+
+ }
+
+ if (literalLength + 1 == optLength) {
+
+ Str2.append("\0", 1); // add null byte
+
+ }
+
+ }
+
+ valueMap[Str1P] = new std::string(Str2);
+
+ if (debug) {
+
+ fprintf(stderr, "Saved: %s for %p\n", Str2.c_str(),
+ (void *)Str1P);
+
+ }
+
+ continue;
+
+ }
+
+ continue;
+
+ }
+
+ // Neither a literal nor a global variable?
+ // maybe it is a local variable that we saved
+ if (!HasStr2) {
+
+ std::string *strng = valueMap[Str2P];
+ if (strng && !strng->empty()) {
+
+ Str2 = *strng;
+ HasStr2 = true;
+ if (debug)
+ fprintf(stderr, "Filled2: %s for %p\n", strng->c_str(),
+ (void *)Str2P);
+
+ }
+
+ }
+
+ if (!HasStr1) {
+
+ auto Ptr = dyn_cast<ConstantExpr>(Str1P);
+
+ if (Ptr && Ptr->getOpcode() == Instruction::GetElementPtr) {
+
+ if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
+
+ if (Var->hasInitializer()) {
+
+ if (auto *Array =
+ dyn_cast<ConstantDataArray>(Var->getInitializer())) {
+
+ HasStr1 = true;
+ Str1 = Array->getRawDataValues().str();
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ // Neither a literal nor a global variable?
+ // maybe it is a local variable that we saved
+ if (!HasStr1) {
+
+ std::string *strng = valueMap[Str1P];
+ if (strng && !strng->empty()) {
+
+ Str1 = *strng;
+ HasStr1 = true;
+ if (debug)
+ fprintf(stderr, "Filled1: %s for %p\n", strng->c_str(),
+ (void *)Str1P);
+
+ }
+
+ }
+
+ /* handle cases of one string is const, one string is variable */
+ if (!(HasStr1 ^ HasStr2)) continue;
+
+ std::string thestring;
+
+ if (HasStr1)
+ thestring = Str1;
+ else
+ thestring = Str2;
+
+ optLen = thestring.length();
+
+ if (optLen < 2 || (optLen == 2 && !thestring[1])) { continue; }
+
+ if (isMemcmp || isStrncmp || isStrncasecmp) {
+
+ Value * op2 = callInst->getArgOperand(2);
+ ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
+
+ if (ilen) {
+
+ uint64_t literalLength = optLen;
+ optLen = ilen->getZExtValue();
+ if (optLen > thestring.length() + 1) {
+
+ optLen = thestring.length() + 1;
+
+ }
+
+ if (optLen < 2) { continue; }
+ if (literalLength + 1 == optLen) { // add null byte
+
+ thestring.append("\0", 1);
+
+ }
+
+ }
+
+ }
+
+ // add null byte if this is a string compare function and a null
+ // was not already added
+ if (!isMemcmp) {
+
+ /*
+ if (addedNull == false && thestring[optLen - 1] != '\0')
+ {
+
+ thestring.append("\0", 1); // add null byte
+ optLen++;
+
+ }
+
+ */
+ if (!isStdString && thestring.find('\0', 0) != std::string::npos) {
+
+ // 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);
+
+ }
+
+ }
+
+ // we take the longer string, even if the compare was to a
+ // shorter part. Note that depending on the optimizer of the
+ // compiler this can be wrong, but it is more likely that this
+ // is helping the fuzzer
+ if (optLen != thestring.length()) optLen = thestring.length();
+ if (optLen > MAX_AUTO_EXTRA) optLen = MAX_AUTO_EXTRA;
+ if (optLen < 3) // too short? skip
+ continue;
+
+ ptr = (char *)thestring.c_str();
+
+ dict2file((u8 *)ptr, optLen);
+ found++;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ of.close();
+
+ /* Say something nice. */
+
+ if (!be_quiet) {
+
+ if (!found)
+ OKF("No entries for a dictionary found.");
+ else
+ OKF("Wrote %d entries to the dictionary file.\n", found);
+
+ }
+
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+ auto PA = PreservedAnalyses::all();
+ return PA;
+#else
+ return true;
+#endif
+
+}
+
+#if LLVM_VERSION_MAJOR < 11 /* use old pass manager */
+static void registerAFLdict2filePass(const PassManagerBuilder &,
+ legacy::PassManagerBase &PM) {
+
+ PM.add(new AFLdict2filePass());
+
+}
+
+static RegisterPass<AFLdict2filePass> X("afl-dict2file",
+ "afl++ dict2file instrumentation pass",
+ false, false);
+
+static RegisterStandardPasses RegisterAFLdict2filePass(
+ PassManagerBuilder::EP_OptimizerLast, registerAFLdict2filePass);
+
+static RegisterStandardPasses RegisterAFLdict2filePass0(
+ PassManagerBuilder::EP_EnabledOnOptLevel0, registerAFLdict2filePass);
+
+#endif
+
diff --git a/instrumentation/afl-llvm-lto-instrumentlist.so.cc b/instrumentation/afl-llvm-lto-instrumentlist.so.cc
new file mode 100644
index 00000000..70c6b10d
--- /dev/null
+++ b/instrumentation/afl-llvm-lto-instrumentlist.so.cc
@@ -0,0 +1,175 @@
+/*
+ american fuzzy lop++ - LLVM-mode instrumentation pass
+ ---------------------------------------------------
+
+ Written by Laszlo Szekeres <lszekeres@google.com> and
+ Michal Zalewski
+
+ LLVM integration design comes from Laszlo Szekeres. C bits copied-and-pasted
+ from afl-as.c are Michal's fault.
+
+ Copyright 2015, 2016 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ This library is plugged into LLVM when invoking clang through afl-clang-fast.
+ It tells the compiler to add code roughly equivalent to the bits discussed
+ in ../afl-as.h.
+
+ */
+
+#define AFL_LLVM_PASS
+
+#include "config.h"
+#include "debug.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <list>
+#include <string>
+#include <fstream>
+#include <sys/time.h>
+#include <fnmatch.h>
+
+#include "llvm/IR/DebugInfo.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/Debug.h"
+//#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/Passes/PassPlugin.h"
+#include "llvm/Passes/PassBuilder.h"
+#include "llvm/IR/PassManager.h"
+#include "llvm/IR/CFG.h"
+#if LLVM_VERSION_MAJOR >= 14 /* how about stable interfaces? */
+ #include "llvm/Passes/OptimizationLevel.h"
+#endif
+
+#include "afl-llvm-common.h"
+
+using namespace llvm;
+
+namespace {
+
+class AFLcheckIfInstrument : public PassInfoMixin<AFLcheckIfInstrument> {
+
+ public:
+ AFLcheckIfInstrument() {
+
+ if (getenv("AFL_DEBUG")) debug = 1;
+
+ initInstrumentList();
+
+ }
+
+ PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
+
+ protected:
+ std::list<std::string> myInstrumentList;
+
+};
+
+} // namespace
+
+extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
+llvmGetPassPluginInfo() {
+
+ return {LLVM_PLUGIN_API_VERSION, "AFLcheckIfInstrument", "v0.1",
+ /* lambda to insert our pass into the pass pipeline. */
+ [](PassBuilder &PB) {
+
+#if LLVM_VERSION_MAJOR <= 13
+ using OptimizationLevel = typename PassBuilder::OptimizationLevel;
+#endif
+ PB.registerOptimizerLastEPCallback(
+ [](ModulePassManager &MPM, OptimizationLevel OL) {
+
+ MPM.addPass(AFLcheckIfInstrument());
+
+ });
+
+ }};
+
+}
+
+PreservedAnalyses AFLcheckIfInstrument::run(Module & M,
+ ModuleAnalysisManager &MAM) {
+
+ /* Show a banner */
+
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
+
+ SAYF(cCYA "afl-llvm-lto-instrumentlist" VERSION cRST
+ " by Marc \"vanHauser\" Heuse <mh@mh-sec.de>\n");
+
+ } else if (getenv("AFL_QUIET"))
+
+ be_quiet = 1;
+
+ for (auto &F : M) {
+
+ if (F.size() < 1) continue;
+
+ // fprintf(stderr, "F:%s\n", F.getName().str().c_str());
+
+ if (isInInstrumentList(&F, MNAME)) {
+
+ if (debug)
+ DEBUGF("function %s is in the instrument file list\n",
+ F.getName().str().c_str());
+
+ } else {
+
+ if (debug)
+ DEBUGF("function %s is NOT in the instrument file list\n",
+ F.getName().str().c_str());
+
+ auto & Ctx = F.getContext();
+ AttributeList Attrs = F.getAttributes();
+#if LLVM_VERSION_MAJOR >= 14
+ AttributeList NewAttrs = Attrs.addFnAttribute(Ctx, "skipinstrument");
+ F.setAttributes(NewAttrs);
+#else
+ AttrBuilder NewAttrs;
+ NewAttrs.addAttribute("skipinstrument");
+ F.setAttributes(
+ Attrs.addAttributes(Ctx, AttributeList::FunctionIndex, NewAttrs));
+#endif
+
+ }
+
+ }
+
+ auto PA = PreservedAnalyses::all();
+ return PA;
+
+}
+
+#if 0
+static void registerAFLcheckIfInstrumentpass(const PassManagerBuilder &,
+ legacy::PassManagerBase &PM) {
+
+ PM.add(new AFLcheckIfInstrument());
+
+}
+
+static RegisterStandardPasses RegisterAFLcheckIfInstrumentpass(
+ PassManagerBuilder::EP_ModuleOptimizerEarly,
+ registerAFLcheckIfInstrumentpass);
+
+static RegisterStandardPasses RegisterAFLcheckIfInstrumentpass0(
+ PassManagerBuilder::EP_EnabledOnOptLevel0,
+ registerAFLcheckIfInstrumentpass);
+#endif
+
diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc
new file mode 100644
index 00000000..fde785bd
--- /dev/null
+++ b/instrumentation/afl-llvm-pass.so.cc
@@ -0,0 +1,1105 @@
+/*
+ american fuzzy lop++ - LLVM-mode instrumentation pass
+ ---------------------------------------------------
+
+ Written by Laszlo Szekeres <lszekeres@google.com>,
+ Adrian Herrera <adrian.herrera@anu.edu.au>,
+ Michal Zalewski
+
+ LLVM integration design comes from Laszlo Szekeres. C bits copied-and-pasted
+ from afl-as.c are Michal's fault.
+
+ NGRAM previous location coverage comes from Adrian Herrera.
+
+ Copyright 2015, 2016 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ This library is plugged into LLVM when invoking clang through afl-clang-fast.
+ It tells the compiler to add code roughly equivalent to the bits discussed
+ in ../afl-as.h.
+
+ */
+
+#define AFL_LLVM_PASS
+
+#include "config.h"
+#include "debug.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <list>
+#include <string>
+#include <fstream>
+#include <sys/time.h>
+
+#include "llvm/Config/llvm-config.h"
+#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 5
+typedef long double max_align_t;
+#endif
+
+#include "llvm/Pass.h"
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+ #include "llvm/Passes/PassPlugin.h"
+ #include "llvm/Passes/PassBuilder.h"
+ #include "llvm/IR/PassManager.h"
+#else
+ #include "llvm/IR/LegacyPassManager.h"
+ #include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#endif
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/MathExtras.h"
+#if LLVM_VERSION_MAJOR >= 14 /* how about stable interfaces? */
+ #include "llvm/Passes/OptimizationLevel.h"
+#endif
+
+#if LLVM_VERSION_MAJOR >= 4 || \
+ (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
+ #include "llvm/IR/DebugInfo.h"
+ #include "llvm/IR/CFG.h"
+#else
+ #include "llvm/DebugInfo.h"
+ #include "llvm/Support/CFG.h"
+#endif
+
+#include "llvm/IR/IRBuilder.h"
+
+#include "afl-llvm-common.h"
+#include "llvm-alternative-coverage.h"
+
+using namespace llvm;
+
+namespace {
+
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+class AFLCoverage : public PassInfoMixin<AFLCoverage> {
+
+ public:
+ AFLCoverage() {
+
+#else
+class AFLCoverage : public ModulePass {
+
+ public:
+ static char ID;
+ AFLCoverage() : ModulePass(ID) {
+
+#endif
+
+ initInstrumentList();
+
+ }
+
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+ PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
+#else
+ bool runOnModule(Module &M) override;
+#endif
+
+ protected:
+ uint32_t ngram_size = 0;
+ uint32_t ctx_k = 0;
+ uint32_t map_size = MAP_SIZE;
+ uint32_t function_minimum_size = 1;
+ const char *ctx_str = NULL, *caller_str = NULL, *skip_nozero = NULL;
+ const char *use_threadsafe_counters = nullptr;
+
+};
+
+} // namespace
+
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
+llvmGetPassPluginInfo() {
+
+ return {LLVM_PLUGIN_API_VERSION, "AFLCoverage", "v0.1",
+ /* lambda to insert our pass into the pass pipeline. */
+ [](PassBuilder &PB) {
+
+ #if 1
+ #if LLVM_VERSION_MAJOR <= 13
+ using OptimizationLevel = typename PassBuilder::OptimizationLevel;
+ #endif
+ PB.registerOptimizerLastEPCallback(
+ [](ModulePassManager &MPM, OptimizationLevel OL) {
+
+ MPM.addPass(AFLCoverage());
+
+ });
+
+ /* TODO LTO registration */
+ #else
+ using PipelineElement = typename PassBuilder::PipelineElement;
+ PB.registerPipelineParsingCallback([](StringRef Name,
+ ModulePassManager &MPM,
+ ArrayRef<PipelineElement>) {
+
+ if (Name == "AFLCoverage") {
+
+ MPM.addPass(AFLCoverage());
+ return true;
+
+ } else {
+
+ return false;
+
+ }
+
+ });
+
+ #endif
+
+ }};
+
+}
+
+#else
+
+char AFLCoverage::ID = 0;
+#endif
+
+/* needed up to 3.9.0 */
+#if LLVM_VERSION_MAJOR == 3 && \
+ (LLVM_VERSION_MINOR < 9 || \
+ (LLVM_VERSION_MINOR == 9 && LLVM_VERSION_PATCH < 1))
+uint64_t PowerOf2Ceil(unsigned in) {
+
+ uint64_t in64 = in - 1;
+ in64 |= (in64 >> 1);
+ in64 |= (in64 >> 2);
+ in64 |= (in64 >> 4);
+ in64 |= (in64 >> 8);
+ in64 |= (in64 >> 16);
+ in64 |= (in64 >> 32);
+ return in64 + 1;
+
+}
+
+#endif
+
+/* #if LLVM_VERSION_STRING >= "4.0.1" */
+#if LLVM_VERSION_MAJOR >= 5 || \
+ (LLVM_VERSION_MAJOR == 4 && LLVM_VERSION_PATCH >= 1)
+ #define AFL_HAVE_VECTOR_INTRINSICS 1
+#endif
+
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
+
+#else
+bool AFLCoverage::runOnModule(Module &M) {
+
+#endif
+
+ LLVMContext &C = M.getContext();
+
+ IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
+ IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
+#ifdef AFL_HAVE_VECTOR_INTRINSICS
+ IntegerType *IntLocTy =
+ IntegerType::getIntNTy(C, sizeof(PREV_LOC_T) * CHAR_BIT);
+#endif
+ struct timeval tv;
+ struct timezone tz;
+ u32 rand_seed;
+ unsigned int cur_loc = 0;
+
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+ auto PA = PreservedAnalyses::all();
+#endif
+
+ /* Setup random() so we get Actually Random(TM) outputs from AFL_R() */
+ gettimeofday(&tv, &tz);
+ rand_seed = tv.tv_sec ^ tv.tv_usec ^ getpid();
+ AFL_SR(rand_seed);
+
+ /* Show a banner */
+
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ if (getenv("AFL_DEBUG")) debug = 1;
+
+ if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
+
+ SAYF(cCYA "afl-llvm-pass" VERSION cRST
+ " by <lszekeres@google.com> and <adrian.herrera@anu.edu.au>\n");
+
+ } else
+
+ be_quiet = 1;
+
+ /*
+ char *ptr;
+ if ((ptr = getenv("AFL_MAP_SIZE")) || (ptr = getenv("AFL_MAPSIZE"))) {
+
+ map_size = atoi(ptr);
+ if (map_size < 8 || map_size > (1 << 29))
+ FATAL("illegal AFL_MAP_SIZE %u, must be between 2^3 and 2^30",
+ map_size); if (map_size % 8) map_size = (((map_size >> 3) + 1) << 3);
+
+ }
+
+ */
+
+ /* Decide instrumentation ratio */
+
+ char * inst_ratio_str = getenv("AFL_INST_RATIO");
+ unsigned int inst_ratio = 100;
+
+ if (inst_ratio_str) {
+
+ if (sscanf(inst_ratio_str, "%u", &inst_ratio) != 1 || !inst_ratio ||
+ inst_ratio > 100)
+ FATAL("Bad value of AFL_INST_RATIO (must be between 1 and 100)");
+
+ }
+
+#if LLVM_VERSION_MAJOR < 9
+ char *neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO");
+#endif
+ skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
+ use_threadsafe_counters = getenv("AFL_LLVM_THREADSAFE_INST");
+
+ if ((isatty(2) && !getenv("AFL_QUIET")) || !!getenv("AFL_DEBUG")) {
+
+ if (use_threadsafe_counters) {
+
+ // disabled unless there is support for other modules as well
+ // (increases documentation complexity)
+ /* if (!getenv("AFL_LLVM_NOT_ZERO")) { */
+
+ skip_nozero = "1";
+ SAYF(cCYA "afl-llvm-pass" VERSION cRST " using thread safe counters\n");
+
+ /*
+
+ } else {
+
+ SAYF(cCYA "afl-llvm-pass" VERSION cRST
+ " using thread safe not-zero-counters\n");
+
+ }
+
+ */
+
+ } else {
+
+ SAYF(cCYA "afl-llvm-pass" VERSION cRST
+ " using non-thread safe instrumentation\n");
+
+ }
+
+ }
+
+ unsigned PrevLocSize = 0;
+ unsigned PrevCallerSize = 0;
+
+ char *ngram_size_str = getenv("AFL_LLVM_NGRAM_SIZE");
+ if (!ngram_size_str) ngram_size_str = getenv("AFL_NGRAM_SIZE");
+ char *ctx_k_str = getenv("AFL_LLVM_CTX_K");
+ if (!ctx_k_str) ctx_k_str = getenv("AFL_CTX_K");
+ ctx_str = getenv("AFL_LLVM_CTX");
+ caller_str = getenv("AFL_LLVM_CALLER");
+
+ bool instrument_ctx = ctx_str || caller_str;
+
+#ifdef AFL_HAVE_VECTOR_INTRINSICS
+ /* Decide previous location vector size (must be a power of two) */
+ VectorType *PrevLocTy = NULL;
+
+ if (ngram_size_str)
+ if (sscanf(ngram_size_str, "%u", &ngram_size) != 1 || ngram_size < 2 ||
+ ngram_size > NGRAM_SIZE_MAX)
+ FATAL(
+ "Bad value of AFL_NGRAM_SIZE (must be between 2 and NGRAM_SIZE_MAX "
+ "(%u))",
+ NGRAM_SIZE_MAX);
+
+ if (ngram_size == 1) ngram_size = 0;
+ if (ngram_size)
+ PrevLocSize = ngram_size - 1;
+ else
+ PrevLocSize = 1;
+
+ /* Decide K-ctx vector size (must be a power of two) */
+ VectorType *PrevCallerTy = NULL;
+
+ if (ctx_k_str)
+ if (sscanf(ctx_k_str, "%u", &ctx_k) != 1 || ctx_k < 1 || ctx_k > CTX_MAX_K)
+ FATAL("Bad value of AFL_CTX_K (must be between 1 and CTX_MAX_K (%u))",
+ CTX_MAX_K);
+
+ if (ctx_k == 1) {
+
+ ctx_k = 0;
+ instrument_ctx = true;
+ caller_str = ctx_k_str; // Enable CALLER instead
+
+ }
+
+ if (ctx_k) {
+
+ PrevCallerSize = ctx_k;
+ instrument_ctx = true;
+
+ }
+
+#else
+ if (ngram_size_str)
+ #ifndef LLVM_VERSION_PATCH
+ FATAL(
+ "Sorry, NGRAM branch coverage is not supported with llvm version "
+ "%d.%d.%d!",
+ LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR, 0);
+ #else
+ FATAL(
+ "Sorry, NGRAM branch coverage is not supported with llvm version "
+ "%d.%d.%d!",
+ LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR, LLVM_VERSION_PATCH);
+ #endif
+ if (ctx_k_str)
+ #ifndef LLVM_VERSION_PATCH
+ FATAL(
+ "Sorry, K-CTX branch coverage is not supported with llvm version "
+ "%d.%d.%d!",
+ LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR, 0);
+ #else
+ FATAL(
+ "Sorry, K-CTX branch coverage is not supported with llvm version "
+ "%d.%d.%d!",
+ LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR, LLVM_VERSION_PATCH);
+ #endif
+ PrevLocSize = 1;
+#endif
+
+#ifdef AFL_HAVE_VECTOR_INTRINSICS
+ int PrevLocVecSize = PowerOf2Ceil(PrevLocSize);
+ if (ngram_size)
+ PrevLocTy = VectorType::get(IntLocTy, PrevLocVecSize
+ #if LLVM_VERSION_MAJOR >= 12
+ ,
+ false
+ #endif
+ );
+#endif
+
+#ifdef AFL_HAVE_VECTOR_INTRINSICS
+ int PrevCallerVecSize = PowerOf2Ceil(PrevCallerSize);
+ if (ctx_k)
+ PrevCallerTy = VectorType::get(IntLocTy, PrevCallerVecSize
+ #if LLVM_VERSION_MAJOR >= 12
+ ,
+ false
+ #endif
+ );
+#endif
+
+ /* Get globals for the SHM region and the previous location. Note that
+ __afl_prev_loc is thread-local. */
+
+ GlobalVariable *AFLMapPtr =
+ new GlobalVariable(M, PointerType::get(Int8Ty, 0), false,
+ GlobalValue::ExternalLinkage, 0, "__afl_area_ptr");
+ GlobalVariable *AFLPrevLoc;
+ GlobalVariable *AFLPrevCaller;
+ GlobalVariable *AFLContext = NULL;
+
+ if (ctx_str || caller_str)
+#if defined(__ANDROID__) || defined(__HAIKU__)
+ AFLContext = new GlobalVariable(
+ M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx");
+#else
+ AFLContext = new GlobalVariable(
+ M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx", 0,
+ GlobalVariable::GeneralDynamicTLSModel, 0, false);
+#endif
+
+#ifdef AFL_HAVE_VECTOR_INTRINSICS
+ if (ngram_size)
+ #if defined(__ANDROID__) || defined(__HAIKU__)
+ AFLPrevLoc = new GlobalVariable(
+ M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage,
+ /* Initializer */ nullptr, "__afl_prev_loc");
+ #else
+ AFLPrevLoc = new GlobalVariable(
+ M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage,
+ /* Initializer */ nullptr, "__afl_prev_loc",
+ /* InsertBefore */ nullptr, GlobalVariable::GeneralDynamicTLSModel,
+ /* AddressSpace */ 0, /* IsExternallyInitialized */ false);
+ #endif
+ else
+#endif
+#if defined(__ANDROID__) || defined(__HAIKU__)
+ AFLPrevLoc = new GlobalVariable(
+ M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc");
+#else
+ AFLPrevLoc = new GlobalVariable(
+ M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc", 0,
+ GlobalVariable::GeneralDynamicTLSModel, 0, false);
+#endif
+
+#ifdef AFL_HAVE_VECTOR_INTRINSICS
+ if (ctx_k)
+ #if defined(__ANDROID__) || defined(__HAIKU__)
+ AFLPrevCaller = new GlobalVariable(
+ M, PrevCallerTy, /* isConstant */ false, GlobalValue::ExternalLinkage,
+ /* Initializer */ nullptr, "__afl_prev_caller");
+ #else
+ AFLPrevCaller = new GlobalVariable(
+ M, PrevCallerTy, /* isConstant */ false, GlobalValue::ExternalLinkage,
+ /* Initializer */ nullptr, "__afl_prev_caller",
+ /* InsertBefore */ nullptr, GlobalVariable::GeneralDynamicTLSModel,
+ /* AddressSpace */ 0, /* IsExternallyInitialized */ false);
+ #endif
+ else
+#endif
+#if defined(__ANDROID__) || defined(__HAIKU__)
+ AFLPrevCaller =
+ new GlobalVariable(M, Int32Ty, false, GlobalValue::ExternalLinkage, 0,
+ "__afl_prev_caller");
+#else
+ AFLPrevCaller = new GlobalVariable(
+ M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_caller",
+ 0, GlobalVariable::GeneralDynamicTLSModel, 0, false);
+#endif
+
+#ifdef AFL_HAVE_VECTOR_INTRINSICS
+ /* Create the vector shuffle mask for updating the previous block history.
+ Note that the first element of the vector will store cur_loc, so just set
+ it to undef to allow the optimizer to do its thing. */
+
+ SmallVector<Constant *, 32> PrevLocShuffle = {UndefValue::get(Int32Ty)};
+
+ for (unsigned I = 0; I < PrevLocSize - 1; ++I)
+ PrevLocShuffle.push_back(ConstantInt::get(Int32Ty, I));
+
+ for (int I = PrevLocSize; I < PrevLocVecSize; ++I)
+ PrevLocShuffle.push_back(ConstantInt::get(Int32Ty, PrevLocSize));
+
+ Constant *PrevLocShuffleMask = ConstantVector::get(PrevLocShuffle);
+
+ Constant * PrevCallerShuffleMask = NULL;
+ SmallVector<Constant *, 32> PrevCallerShuffle = {UndefValue::get(Int32Ty)};
+
+ if (ctx_k) {
+
+ for (unsigned I = 0; I < PrevCallerSize - 1; ++I)
+ PrevCallerShuffle.push_back(ConstantInt::get(Int32Ty, I));
+
+ for (int I = PrevCallerSize; I < PrevCallerVecSize; ++I)
+ PrevCallerShuffle.push_back(ConstantInt::get(Int32Ty, PrevCallerSize));
+
+ PrevCallerShuffleMask = ConstantVector::get(PrevCallerShuffle);
+
+ }
+
+#endif
+
+ // other constants we need
+ ConstantInt *One = ConstantInt::get(Int8Ty, 1);
+
+ Value * PrevCtx = NULL; // CTX sensitive coverage
+ LoadInst *PrevCaller = NULL; // K-CTX coverage
+
+ /* Instrument all the things! */
+
+ int inst_blocks = 0;
+ scanForDangerousFunctions(&M);
+
+ for (auto &F : M) {
+
+ int has_calls = 0;
+ if (debug)
+ fprintf(stderr, "FUNCTION: %s (%zu)\n", F.getName().str().c_str(),
+ F.size());
+
+ if (!isInInstrumentList(&F, MNAME)) { continue; }
+
+ if (F.size() < function_minimum_size) { continue; }
+
+ std::list<Value *> todo;
+ for (auto &BB : F) {
+
+ BasicBlock::iterator IP = BB.getFirstInsertionPt();
+ IRBuilder<> IRB(&(*IP));
+
+ // Context sensitive coverage
+ if (instrument_ctx && &BB == &F.getEntryBlock()) {
+
+#ifdef AFL_HAVE_VECTOR_INTRINSICS
+ if (ctx_k) {
+
+ PrevCaller = IRB.CreateLoad(
+ #if LLVM_VERSION_MAJOR >= 14
+ PrevCallerTy,
+ #endif
+ AFLPrevCaller);
+ PrevCaller->setMetadata(M.getMDKindID("nosanitize"),
+ MDNode::get(C, None));
+ PrevCtx =
+ IRB.CreateZExt(IRB.CreateXorReduce(PrevCaller), IRB.getInt32Ty());
+
+ } else
+
+#endif
+ {
+
+ // load the context ID of the previous function and write to to a
+ // local variable on the stack
+ LoadInst *PrevCtxLoad = IRB.CreateLoad(
+#if LLVM_VERSION_MAJOR >= 14
+ IRB.getInt32Ty(),
+#endif
+ AFLContext);
+ PrevCtxLoad->setMetadata(M.getMDKindID("nosanitize"),
+ MDNode::get(C, None));
+ PrevCtx = PrevCtxLoad;
+
+ }
+
+ // does the function have calls? and is any of the calls larger than one
+ // basic block?
+ for (auto &BB_2 : F) {
+
+ if (has_calls) break;
+ for (auto &IN : BB_2) {
+
+ CallInst *callInst = nullptr;
+ if ((callInst = dyn_cast<CallInst>(&IN))) {
+
+ Function *Callee = callInst->getCalledFunction();
+ if (!Callee || Callee->size() < function_minimum_size)
+ continue;
+ else {
+
+ has_calls = 1;
+ break;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ // if yes we store a context ID for this function in the global var
+ if (has_calls) {
+
+ Value *NewCtx = ConstantInt::get(Int32Ty, AFL_R(map_size));
+#ifdef AFL_HAVE_VECTOR_INTRINSICS
+ if (ctx_k) {
+
+ Value *ShuffledPrevCaller = IRB.CreateShuffleVector(
+ PrevCaller, UndefValue::get(PrevCallerTy),
+ PrevCallerShuffleMask);
+ Value *UpdatedPrevCaller = IRB.CreateInsertElement(
+ ShuffledPrevCaller, NewCtx, (uint64_t)0);
+
+ StoreInst *Store =
+ IRB.CreateStore(UpdatedPrevCaller, AFLPrevCaller);
+ Store->setMetadata(M.getMDKindID("nosanitize"),
+ MDNode::get(C, None));
+
+ } else
+
+#endif
+ {
+
+ if (ctx_str) NewCtx = IRB.CreateXor(PrevCtx, NewCtx);
+ StoreInst *StoreCtx = IRB.CreateStore(NewCtx, AFLContext);
+ StoreCtx->setMetadata(M.getMDKindID("nosanitize"),
+ MDNode::get(C, None));
+
+ }
+
+ }
+
+ }
+
+ if (AFL_R(100) >= inst_ratio) continue;
+
+ /* Make up cur_loc */
+
+ // cur_loc++;
+ cur_loc = AFL_R(map_size);
+
+/* There is a problem with Ubuntu 18.04 and llvm 6.0 (see issue #63).
+ The inline function successors() is not inlined and also not found at runtime
+ :-( As I am unable to detect Ubuntu18.04 heree, the next best thing is to
+ disable this optional optimization for LLVM 6.0.0 and Linux */
+#if !(LLVM_VERSION_MAJOR == 6 && LLVM_VERSION_MINOR == 0) || !defined __linux__
+ // only instrument if this basic block is the destination of a previous
+ // basic block that has multiple successors
+ // this gets rid of ~5-10% of instrumentations that are unnecessary
+ // result: a little more speed and less map pollution
+ int more_than_one = -1;
+ // fprintf(stderr, "BB %u: ", cur_loc);
+ for (pred_iterator PI = pred_begin(&BB), E = pred_end(&BB); PI != E;
+ ++PI) {
+
+ BasicBlock *Pred = *PI;
+
+ int count = 0;
+ if (more_than_one == -1) more_than_one = 0;
+ // fprintf(stderr, " %p=>", Pred);
+
+ for (succ_iterator SI = succ_begin(Pred), E = succ_end(Pred); SI != E;
+ ++SI) {
+
+ BasicBlock *Succ = *SI;
+
+ // if (count > 0)
+ // fprintf(stderr, "|");
+ if (Succ != NULL) count++;
+ // fprintf(stderr, "%p", Succ);
+
+ }
+
+ if (count > 1) more_than_one = 1;
+
+ }
+
+ // fprintf(stderr, " == %d\n", more_than_one);
+ if (F.size() > 1 && more_than_one != 1) {
+
+ // in CTX mode we have to restore the original context for the caller -
+ // she might be calling other functions which need the correct CTX
+ if (instrument_ctx && has_calls) {
+
+ Instruction *Inst = BB.getTerminator();
+ if (isa<ReturnInst>(Inst) || isa<ResumeInst>(Inst)) {
+
+ IRBuilder<> Post_IRB(Inst);
+
+ StoreInst *RestoreCtx;
+ #ifdef AFL_HAVE_VECTOR_INTRINSICS
+ if (ctx_k)
+ RestoreCtx = IRB.CreateStore(PrevCaller, AFLPrevCaller);
+ else
+ #endif
+ RestoreCtx = Post_IRB.CreateStore(PrevCtx, AFLContext);
+ RestoreCtx->setMetadata(M.getMDKindID("nosanitize"),
+ MDNode::get(C, None));
+
+ }
+
+ }
+
+ continue;
+
+ }
+
+#endif
+
+ ConstantInt *CurLoc;
+
+#ifdef AFL_HAVE_VECTOR_INTRINSICS
+ if (ngram_size)
+ CurLoc = ConstantInt::get(IntLocTy, cur_loc);
+ else
+#endif
+ CurLoc = ConstantInt::get(Int32Ty, cur_loc);
+
+ /* Load prev_loc */
+
+ LoadInst *PrevLoc;
+
+ if (ngram_size) {
+
+ PrevLoc = IRB.CreateLoad(
+#if LLVM_VERSION_MAJOR >= 14
+ PrevLocTy,
+#endif
+ AFLPrevLoc);
+
+ } else {
+
+ PrevLoc = IRB.CreateLoad(
+#if LLVM_VERSION_MAJOR >= 14
+ IRB.getInt32Ty(),
+#endif
+ AFLPrevLoc);
+
+ }
+
+ PrevLoc->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
+ Value *PrevLocTrans;
+
+#ifdef AFL_HAVE_VECTOR_INTRINSICS
+ /* "For efficiency, we propose to hash the tuple as a key into the
+ hit_count map as (prev_block_trans << 1) ^ curr_block_trans, where
+ prev_block_trans = (block_trans_1 ^ ... ^ block_trans_(n-1)" */
+
+ if (ngram_size)
+ PrevLocTrans =
+ IRB.CreateZExt(IRB.CreateXorReduce(PrevLoc), IRB.getInt32Ty());
+ else
+#endif
+ PrevLocTrans = PrevLoc;
+
+ if (instrument_ctx)
+ PrevLocTrans =
+ IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, PrevCtx), Int32Ty);
+ else
+ PrevLocTrans = IRB.CreateZExt(PrevLocTrans, IRB.getInt32Ty());
+
+ /* Load SHM pointer */
+
+ LoadInst *MapPtr = IRB.CreateLoad(
+#if LLVM_VERSION_MAJOR >= 14
+ PointerType::get(Int8Ty, 0),
+#endif
+ AFLMapPtr);
+ MapPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
+
+ Value *MapPtrIdx;
+#ifdef AFL_HAVE_VECTOR_INTRINSICS
+ if (ngram_size)
+ MapPtrIdx = IRB.CreateGEP(
+ Int8Ty, MapPtr,
+ IRB.CreateZExt(
+ IRB.CreateXor(PrevLocTrans, IRB.CreateZExt(CurLoc, Int32Ty)),
+ Int32Ty));
+ else
+#endif
+ MapPtrIdx = IRB.CreateGEP(
+#if LLVM_VERSION_MAJOR >= 14
+ Int8Ty,
+#endif
+ MapPtr, IRB.CreateXor(PrevLocTrans, CurLoc));
+
+ /* Update bitmap */
+
+ if (use_threadsafe_counters) { /* Atomic */
+
+ IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One,
+#if LLVM_VERSION_MAJOR >= 13
+ llvm::MaybeAlign(1),
+#endif
+ llvm::AtomicOrdering::Monotonic);
+ /*
+
+ }
+
+ */
+
+ } else {
+
+ LoadInst *Counter = IRB.CreateLoad(
+#if LLVM_VERSION_MAJOR >= 14
+ IRB.getInt8Ty(),
+#endif
+ MapPtrIdx);
+ Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
+
+ Value *Incr = IRB.CreateAdd(Counter, One);
+
+#if LLVM_VERSION_MAJOR >= 9
+ if (!skip_nozero) {
+
+#else
+ if (neverZero_counters_str != NULL) {
+
+#endif
+ /* hexcoder: Realize a counter that skips zero during overflow.
+ * Once this counter reaches its maximum value, it next increments to
+ * 1
+ *
+ * Instead of
+ * Counter + 1 -> Counter
+ * we inject now this
+ * Counter + 1 -> {Counter, OverflowFlag}
+ * Counter + OverflowFlag -> Counter
+ */
+
+ ConstantInt *Zero = ConstantInt::get(Int8Ty, 0);
+ auto cf = IRB.CreateICmpEQ(Incr, Zero);
+ auto carry = IRB.CreateZExt(cf, Int8Ty);
+ Incr = IRB.CreateAdd(Incr, carry);
+
+ }
+
+ IRB.CreateStore(Incr, MapPtrIdx)
+ ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
+
+ } /* non atomic case */
+
+ /* Update prev_loc history vector (by placing cur_loc at the head of the
+ vector and shuffle the other elements back by one) */
+
+ StoreInst *Store;
+
+#ifdef AFL_HAVE_VECTOR_INTRINSICS
+ if (ngram_size) {
+
+ Value *ShuffledPrevLoc = IRB.CreateShuffleVector(
+ PrevLoc, UndefValue::get(PrevLocTy), PrevLocShuffleMask);
+ Value *UpdatedPrevLoc = IRB.CreateInsertElement(
+ ShuffledPrevLoc, IRB.CreateLShr(CurLoc, (uint64_t)1), (uint64_t)0);
+
+ Store = IRB.CreateStore(UpdatedPrevLoc, AFLPrevLoc);
+ Store->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
+
+ } else
+
+#endif
+ {
+
+ Store = IRB.CreateStore(ConstantInt::get(Int32Ty, cur_loc >> 1),
+ AFLPrevLoc);
+ Store->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
+
+ }
+
+ // in CTX mode we have to restore the original context for the caller -
+ // she might be calling other functions which need the correct CTX.
+ // Currently this is only needed for the Ubuntu clang-6.0 bug
+ if (instrument_ctx && has_calls) {
+
+ Instruction *Inst = BB.getTerminator();
+ if (isa<ReturnInst>(Inst) || isa<ResumeInst>(Inst)) {
+
+ IRBuilder<> Post_IRB(Inst);
+
+ StoreInst *RestoreCtx;
+#ifdef AFL_HAVE_VECTOR_INTRINSICS
+ if (ctx_k)
+ RestoreCtx = IRB.CreateStore(PrevCaller, AFLPrevCaller);
+ else
+#endif
+ RestoreCtx = Post_IRB.CreateStore(PrevCtx, AFLContext);
+ RestoreCtx->setMetadata(M.getMDKindID("nosanitize"),
+ MDNode::get(C, None));
+
+ }
+
+ }
+
+ inst_blocks++;
+
+ }
+
+#if 0
+ if (use_threadsafe_counters) { /*Atomic NeverZero */
+ // handle the list of registered blocks to instrument
+ for (auto val : todo) {
+
+ /* hexcoder: Realize a thread-safe counter that skips zero during
+ * overflow. Once this counter reaches its maximum value, it next
+ * increments to 1
+ *
+ * Instead of
+ * Counter + 1 -> Counter
+ * we inject now this
+ * Counter + 1 -> {Counter, OverflowFlag}
+ * Counter + OverflowFlag -> Counter
+ */
+
+ /* equivalent c code looks like this
+ * Thanks to
+ https://preshing.com/20150402/you-can-do-any-kind-of-atomic-read-modify-write-operation/
+
+ int old = atomic_load_explicit(&Counter, memory_order_relaxed);
+ int new;
+ do {
+
+ if (old == 255) {
+
+ new = 1;
+
+ } else {
+
+ new = old + 1;
+
+ }
+
+ } while (!atomic_compare_exchange_weak_explicit(&Counter, &old, new,
+
+ memory_order_relaxed, memory_order_relaxed));
+
+ */
+
+ Value * MapPtrIdx = val;
+ Instruction * MapPtrIdxInst = cast<Instruction>(val);
+ BasicBlock::iterator it0(&(*MapPtrIdxInst));
+ ++it0;
+ IRBuilder<> IRB(&(*it0));
+
+ // load the old counter value atomically
+ LoadInst *Counter = IRB.CreateLoad(
+ #if LLVM_VERSION_MAJOR >= 14
+ IRB.getInt8Ty(),
+ #endif
+ MapPtrIdx);
+ Counter->setAlignment(llvm::Align());
+ Counter->setAtomic(llvm::AtomicOrdering::Monotonic);
+ Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
+
+ BasicBlock *BB = IRB.GetInsertBlock();
+ // insert a basic block with the corpus of a do while loop
+ // the calculation may need to repeat, if atomic compare_exchange is not
+ // successful
+
+ BasicBlock::iterator it(*Counter);
+ it++; // split after load counter
+ BasicBlock *end_bb = BB->splitBasicBlock(it);
+ end_bb->setName("injected");
+
+ // insert the block before the second half of the split
+ BasicBlock *do_while_bb =
+ BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb);
+
+ // set terminator of BB from target end_bb to target do_while_bb
+ auto term = BB->getTerminator();
+ BranchInst::Create(do_while_bb, BB);
+ term->eraseFromParent();
+
+ // continue to fill instructions into the do_while loop
+ IRB.SetInsertPoint(do_while_bb, do_while_bb->getFirstInsertionPt());
+
+ PHINode *PN = IRB.CreatePHI(Int8Ty, 2);
+
+ // compare with maximum value 0xff
+ auto *Cmp = IRB.CreateICmpEQ(Counter, ConstantInt::get(Int8Ty, -1));
+
+ // increment the counter
+ Value *Incr = IRB.CreateAdd(Counter, One);
+
+ // select the counter value or 1
+ auto *Select = IRB.CreateSelect(Cmp, One, Incr);
+
+ // try to save back the new counter value
+ auto *CmpXchg = IRB.CreateAtomicCmpXchg(
+ MapPtrIdx, PN, Select, llvm::AtomicOrdering::Monotonic,
+ llvm::AtomicOrdering::Monotonic);
+ CmpXchg->setAlignment(llvm::Align());
+ CmpXchg->setWeak(true);
+ CmpXchg->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
+
+ // get the result of trying to update the Counter
+ Value *Success =
+ IRB.CreateExtractValue(CmpXchg, ArrayRef<unsigned>({1}));
+ // get the (possibly updated) value of Counter
+ Value *OldVal =
+ IRB.CreateExtractValue(CmpXchg, ArrayRef<unsigned>({0}));
+
+ // initially we use Counter
+ PN->addIncoming(Counter, BB);
+ // on retry, we use the updated value
+ PN->addIncoming(OldVal, do_while_bb);
+
+ // if the cmpXchg was not successful, retry
+ IRB.CreateCondBr(Success, end_bb, do_while_bb);
+
+ }
+
+ }
+
+#endif
+
+ }
+
+ /*
+ // This is currently disabled because we not only need to create/insert a
+ // function (easy), but also add it as a constructor with an ID < 5
+
+ if (getenv("AFL_LLVM_DONTWRITEID") == NULL) {
+
+ // yes we could create our own function, insert it into ctors ...
+ // but this would be a pain in the butt ... so we use afl-llvm-rt.o
+
+ Function *f = ...
+
+ if (!f) {
+
+ fprintf(stderr,
+ "Error: init function could not be created (this should not
+ happen)\n"); exit(-1);
+
+ }
+
+ ... constructor for f = 4
+
+ BasicBlock *bb = &f->getEntryBlock();
+ if (!bb) {
+
+ fprintf(stderr,
+ "Error: init function does not have an EntryBlock (this should
+ not happen)\n"); exit(-1);
+
+ }
+
+ BasicBlock::iterator IP = bb->getFirstInsertionPt();
+ IRBuilder<> IRB(&(*IP));
+
+ if (map_size <= 0x800000) {
+
+ GlobalVariable *AFLFinalLoc = new GlobalVariable(
+ M, Int32Ty, true, GlobalValue::ExternalLinkage, 0,
+ "__afl_final_loc");
+ ConstantInt *const_loc = ConstantInt::get(Int32Ty, map_size);
+ StoreInst * StoreFinalLoc = IRB.CreateStore(const_loc, AFLFinalLoc);
+ StoreFinalLoc->setMetadata(M.getMDKindID("nosanitize"),
+ MDNode::get(C, None));
+
+ }
+
+ }
+
+ */
+
+ /* Say something nice. */
+
+ if (!be_quiet) {
+
+ if (!inst_blocks)
+ WARNF("No instrumentation targets found.");
+ else {
+
+ char modeline[100];
+ snprintf(modeline, sizeof(modeline), "%s%s%s%s%s%s",
+ getenv("AFL_HARDEN") ? "hardened" : "non-hardened",
+ getenv("AFL_USE_ASAN") ? ", ASAN" : "",
+ getenv("AFL_USE_MSAN") ? ", MSAN" : "",
+ getenv("AFL_USE_CFISAN") ? ", CFISAN" : "",
+ getenv("AFL_USE_TSAN") ? ", TSAN" : "",
+ getenv("AFL_USE_UBSAN") ? ", UBSAN" : "");
+ OKF("Instrumented %d locations (%s mode, ratio %u%%).", inst_blocks,
+ modeline, inst_ratio);
+
+ }
+
+ }
+
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+ return PA;
+#else
+ return true;
+#endif
+
+}
+
+#if LLVM_VERSION_MAJOR < 11 /* use old pass manager */
+static void registerAFLPass(const PassManagerBuilder &,
+ legacy::PassManagerBase &PM) {
+
+ PM.add(new AFLCoverage());
+
+}
+
+static RegisterStandardPasses RegisterAFLPass(
+ PassManagerBuilder::EP_OptimizerLast, registerAFLPass);
+
+static RegisterStandardPasses RegisterAFLPass0(
+ PassManagerBuilder::EP_EnabledOnOptLevel0, registerAFLPass);
+#endif
+
diff --git a/instrumentation/afl-llvm-rt-lto.o.c b/instrumentation/afl-llvm-rt-lto.o.c
new file mode 100644
index 00000000..eb346157
--- /dev/null
+++ b/instrumentation/afl-llvm-rt-lto.o.c
@@ -0,0 +1,27 @@
+/*
+ american fuzzy lop++ - LLVM instrumentation bootstrap
+ -----------------------------------------------------
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+// to prevent the function from being removed
+unsigned char __afl_lto_mode = 0;
+
+/* Proper initialization routine. */
+
+__attribute__((constructor(0))) void __afl_auto_init_globals(void) {
+
+ if (getenv("AFL_DEBUG")) fprintf(stderr, "[__afl_auto_init_globals]\n");
+ __afl_lto_mode = 1;
+
+}
+
diff --git a/instrumentation/cmplog-instructions-pass.cc b/instrumentation/cmplog-instructions-pass.cc
new file mode 100644
index 00000000..4d37bcb2
--- /dev/null
+++ b/instrumentation/cmplog-instructions-pass.cc
@@ -0,0 +1,713 @@
+/*
+ american fuzzy lop++ - LLVM CmpLog instrumentation
+ --------------------------------------------------
+
+ Written by Andrea Fioraldi <andreafioraldi@gmail.com>
+
+ Copyright 2015, 2016 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <list>
+#include <string>
+#include <fstream>
+#include <sys/time.h>
+
+#include "llvm/Config/llvm-config.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#if LLVM_MAJOR >= 11
+ #include "llvm/Passes/PassPlugin.h"
+ #include "llvm/Passes/PassBuilder.h"
+ #include "llvm/IR/PassManager.h"
+#else
+ #include "llvm/IR/LegacyPassManager.h"
+ #include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#endif
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Pass.h"
+#include "llvm/Analysis/ValueTracking.h"
+#if LLVM_VERSION_MAJOR >= 14 /* how about stable interfaces? */
+ #include "llvm/Passes/OptimizationLevel.h"
+#endif
+
+#if LLVM_VERSION_MAJOR >= 4 || \
+ (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
+ #include "llvm/IR/Verifier.h"
+ #include "llvm/IR/DebugInfo.h"
+ #include "llvm/Support/raw_ostream.h"
+#else
+ #include "llvm/Analysis/Verifier.h"
+ #include "llvm/DebugInfo.h"
+ #define nullptr 0
+#endif
+
+#include <set>
+#include "afl-llvm-common.h"
+
+using namespace llvm;
+
+namespace {
+
+#if LLVM_MAJOR >= 11 /* use new pass manager */
+class CmpLogInstructions : public PassInfoMixin<CmpLogInstructions> {
+
+ public:
+ CmpLogInstructions() {
+
+ initInstrumentList();
+
+ }
+
+#else
+class CmpLogInstructions : public ModulePass {
+
+ public:
+ static char ID;
+ CmpLogInstructions() : ModulePass(ID) {
+
+ initInstrumentList();
+
+ }
+
+#endif
+
+#if LLVM_MAJOR >= 11 /* use new pass manager */
+ PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
+#else
+ bool runOnModule(Module &M) override;
+
+ #if LLVM_VERSION_MAJOR >= 4
+ StringRef getPassName() const override {
+
+ #else
+ const char *getPassName() const override {
+
+ #endif
+ return "cmplog instructions";
+
+ }
+
+#endif
+
+ private:
+ bool hookInstrs(Module &M);
+
+};
+
+} // namespace
+
+#if LLVM_MAJOR >= 11
+extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
+llvmGetPassPluginInfo() {
+
+ return {LLVM_PLUGIN_API_VERSION, "cmploginstructions", "v0.1",
+ /* lambda to insert our pass into the pass pipeline. */
+ [](PassBuilder &PB) {
+
+ #if LLVM_VERSION_MAJOR <= 13
+ using OptimizationLevel = typename PassBuilder::OptimizationLevel;
+ #endif
+ PB.registerOptimizerLastEPCallback(
+ [](ModulePassManager &MPM, OptimizationLevel OL) {
+
+ MPM.addPass(CmpLogInstructions());
+
+ });
+
+ }};
+
+}
+
+#else
+char CmpLogInstructions::ID = 0;
+#endif
+
+template <class Iterator>
+Iterator Unique(Iterator first, Iterator last) {
+
+ while (first != last) {
+
+ Iterator next(first);
+ last = std::remove(++next, last, *first);
+ first = next;
+
+ }
+
+ return last;
+
+}
+
+bool CmpLogInstructions::hookInstrs(Module &M) {
+
+ std::vector<Instruction *> icomps;
+ LLVMContext & C = M.getContext();
+
+ Type * VoidTy = Type::getVoidTy(C);
+ IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
+ IntegerType *Int16Ty = IntegerType::getInt16Ty(C);
+ IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
+ IntegerType *Int64Ty = IntegerType::getInt64Ty(C);
+ IntegerType *Int128Ty = IntegerType::getInt128Ty(C);
+
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee
+#else
+ Constant *
+#endif
+ c1 = M.getOrInsertFunction("__cmplog_ins_hook1", VoidTy, Int8Ty, Int8Ty,
+ Int8Ty
+#if LLVM_VERSION_MAJOR < 5
+ ,
+ NULL
+#endif
+ );
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee cmplogHookIns1 = c1;
+#else
+ Function *cmplogHookIns1 = cast<Function>(c1);
+#endif
+
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee
+#else
+ Constant *
+#endif
+ c2 = M.getOrInsertFunction("__cmplog_ins_hook2", VoidTy, Int16Ty, Int16Ty,
+ Int8Ty
+#if LLVM_VERSION_MAJOR < 5
+ ,
+ NULL
+#endif
+ );
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee cmplogHookIns2 = c2;
+#else
+ Function *cmplogHookIns2 = cast<Function>(c2);
+#endif
+
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee
+#else
+ Constant *
+#endif
+ c4 = M.getOrInsertFunction("__cmplog_ins_hook4", VoidTy, Int32Ty, Int32Ty,
+ Int8Ty
+#if LLVM_VERSION_MAJOR < 5
+ ,
+ NULL
+#endif
+ );
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee cmplogHookIns4 = c4;
+#else
+ Function *cmplogHookIns4 = cast<Function>(c4);
+#endif
+
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee
+#else
+ Constant *
+#endif
+ c8 = M.getOrInsertFunction("__cmplog_ins_hook8", VoidTy, Int64Ty, Int64Ty,
+ Int8Ty
+#if LLVM_VERSION_MAJOR < 5
+ ,
+ NULL
+#endif
+ );
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee cmplogHookIns8 = c8;
+#else
+ Function *cmplogHookIns8 = cast<Function>(c8);
+#endif
+
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee
+#else
+ Constant *
+#endif
+ c16 = M.getOrInsertFunction("__cmplog_ins_hook16", VoidTy, Int128Ty,
+ Int128Ty, Int8Ty
+#if LLVM_VERSION_MAJOR < 5
+ ,
+ NULL
+#endif
+ );
+#if LLVM_VERSION_MAJOR < 9
+ Function *cmplogHookIns16 = cast<Function>(c16);
+#else
+ FunctionCallee cmplogHookIns16 = c16;
+#endif
+
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee
+#else
+ Constant *
+#endif
+ cN = M.getOrInsertFunction("__cmplog_ins_hookN", VoidTy, Int128Ty,
+ Int128Ty, Int8Ty, Int8Ty
+#if LLVM_VERSION_MAJOR < 5
+ ,
+ NULL
+#endif
+ );
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee cmplogHookInsN = cN;
+#else
+ Function *cmplogHookInsN = cast<Function>(cN);
+#endif
+
+ GlobalVariable *AFLCmplogPtr = M.getNamedGlobal("__afl_cmp_map");
+
+ if (!AFLCmplogPtr) {
+
+ AFLCmplogPtr = new GlobalVariable(M, PointerType::get(Int8Ty, 0), false,
+ GlobalValue::ExternalWeakLinkage, 0,
+ "__afl_cmp_map");
+
+ }
+
+ Constant *Null = Constant::getNullValue(PointerType::get(Int8Ty, 0));
+
+ /* iterate over all functions, bbs and instruction and add suitable calls */
+ for (auto &F : M) {
+
+ if (!isInInstrumentList(&F, MNAME)) continue;
+
+ for (auto &BB : F) {
+
+ for (auto &IN : BB) {
+
+ CmpInst *selectcmpInst = nullptr;
+ if ((selectcmpInst = dyn_cast<CmpInst>(&IN))) {
+
+ icomps.push_back(selectcmpInst);
+
+ }
+
+ }
+
+ }
+
+ }
+
+ if (icomps.size()) {
+
+ // if (!be_quiet) errs() << "Hooking " << icomps.size() <<
+ // " cmp instructions\n";
+
+ for (auto &selectcmpInst : icomps) {
+
+ IRBuilder<> IRB2(selectcmpInst->getParent());
+ IRB2.SetInsertPoint(selectcmpInst);
+ LoadInst *CmpPtr = IRB2.CreateLoad(
+#if LLVM_VERSION_MAJOR >= 14
+ PointerType::get(Int8Ty, 0),
+#endif
+ AFLCmplogPtr);
+ CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
+ auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
+ auto ThenTerm =
+ SplitBlockAndInsertIfThen(is_not_null, selectcmpInst, false);
+
+ IRBuilder<> IRB(ThenTerm);
+
+ Value *op0 = selectcmpInst->getOperand(0);
+ Value *op1 = selectcmpInst->getOperand(1);
+ Value *op0_saved = op0, *op1_saved = op1;
+ auto ty0 = op0->getType();
+ auto ty1 = op1->getType();
+
+ IntegerType *intTyOp0 = NULL;
+ IntegerType *intTyOp1 = NULL;
+ unsigned max_size = 0, cast_size = 0;
+ unsigned attr = 0, vector_cnt = 0, is_fp = 0;
+ CmpInst * cmpInst = dyn_cast<CmpInst>(selectcmpInst);
+
+ if (!cmpInst) { continue; }
+
+ switch (cmpInst->getPredicate()) {
+
+ case CmpInst::ICMP_NE:
+ case CmpInst::FCMP_UNE:
+ case CmpInst::FCMP_ONE:
+ break;
+ case CmpInst::ICMP_EQ:
+ case CmpInst::FCMP_UEQ:
+ case CmpInst::FCMP_OEQ:
+ attr += 1;
+ break;
+ case CmpInst::ICMP_UGT:
+ case CmpInst::ICMP_SGT:
+ case CmpInst::FCMP_OGT:
+ case CmpInst::FCMP_UGT:
+ attr += 2;
+ break;
+ case CmpInst::ICMP_UGE:
+ case CmpInst::ICMP_SGE:
+ case CmpInst::FCMP_OGE:
+ case CmpInst::FCMP_UGE:
+ attr += 3;
+ break;
+ case CmpInst::ICMP_ULT:
+ case CmpInst::ICMP_SLT:
+ case CmpInst::FCMP_OLT:
+ case CmpInst::FCMP_ULT:
+ attr += 4;
+ break;
+ case CmpInst::ICMP_ULE:
+ case CmpInst::ICMP_SLE:
+ case CmpInst::FCMP_OLE:
+ case CmpInst::FCMP_ULE:
+ attr += 5;
+ break;
+ default:
+ break;
+
+ }
+
+ if (selectcmpInst->getOpcode() == Instruction::FCmp) {
+
+ if (ty0->isVectorTy()) {
+
+ VectorType *tt = dyn_cast<VectorType>(ty0);
+ if (!tt) {
+
+ fprintf(stderr, "Warning: cmplog cmp vector is not a vector!\n");
+ continue;
+
+ }
+
+#if (LLVM_VERSION_MAJOR >= 12)
+ vector_cnt = tt->getElementCount().getKnownMinValue();
+ ty0 = tt->getElementType();
+#endif
+
+ }
+
+ if (ty0->isHalfTy()
+#if LLVM_VERSION_MAJOR >= 11
+ || ty0->isBFloatTy()
+#endif
+ )
+ max_size = 16;
+ else if (ty0->isFloatTy())
+ max_size = 32;
+ else if (ty0->isDoubleTy())
+ max_size = 64;
+ else if (ty0->isX86_FP80Ty())
+ max_size = 80;
+ else if (ty0->isFP128Ty() || ty0->isPPC_FP128Ty())
+ max_size = 128;
+#if (LLVM_VERSION_MAJOR >= 12)
+ else if (ty0->getTypeID() != llvm::Type::PointerTyID && !be_quiet)
+ fprintf(stderr, "Warning: unsupported cmp type for cmplog: %u!\n",
+ ty0->getTypeID());
+#endif
+
+ attr += 8;
+ is_fp = 1;
+ // fprintf(stderr, "HAVE FP %u!\n", vector_cnt);
+
+ } else {
+
+ if (ty0->isVectorTy()) {
+
+#if (LLVM_VERSION_MAJOR >= 12)
+ VectorType *tt = dyn_cast<VectorType>(ty0);
+ if (!tt) {
+
+ fprintf(stderr, "Warning: cmplog cmp vector is not a vector!\n");
+ continue;
+
+ }
+
+ vector_cnt = tt->getElementCount().getKnownMinValue();
+ ty1 = ty0 = tt->getElementType();
+#endif
+
+ }
+
+ intTyOp0 = dyn_cast<IntegerType>(ty0);
+ intTyOp1 = dyn_cast<IntegerType>(ty1);
+
+ if (intTyOp0 && intTyOp1) {
+
+ max_size = intTyOp0->getBitWidth() > intTyOp1->getBitWidth()
+ ? intTyOp0->getBitWidth()
+ : intTyOp1->getBitWidth();
+
+ } else {
+
+#if (LLVM_VERSION_MAJOR >= 12)
+ if (ty0->getTypeID() != llvm::Type::PointerTyID && !be_quiet) {
+
+ fprintf(stderr, "Warning: unsupported cmp type for cmplog: %u\n",
+ ty0->getTypeID());
+
+ }
+
+#endif
+
+ }
+
+ }
+
+ if (!max_size || max_size < 16) {
+
+ // fprintf(stderr, "too small\n");
+ continue;
+
+ }
+
+ if (max_size % 8) { max_size = (((max_size / 8) + 1) * 8); }
+
+ if (max_size > 128) {
+
+ if (!be_quiet) {
+
+ fprintf(stderr,
+ "Cannot handle this compare bit size: %u (truncating)\n",
+ max_size);
+
+ }
+
+ max_size = 128;
+
+ }
+
+ // do we need to cast?
+ switch (max_size) {
+
+ case 8:
+ case 16:
+ case 32:
+ case 64:
+ case 128:
+ cast_size = max_size;
+ break;
+ default:
+ cast_size = 128;
+
+ }
+
+ // XXX FIXME BUG TODO
+ if (is_fp && vector_cnt) { continue; }
+
+ uint64_t cur = 0, last_val0 = 0, last_val1 = 0, cur_val;
+
+ while (1) {
+
+ std::vector<Value *> args;
+ bool skip = false;
+
+ if (vector_cnt) {
+
+ op0 = IRB.CreateExtractElement(op0_saved, cur);
+ op1 = IRB.CreateExtractElement(op1_saved, cur);
+ /*
+ std::string errMsg;
+ raw_string_ostream os(errMsg);
+ op0_saved->print(os);
+ fprintf(stderr, "X: %s\n", os.str().c_str());
+ */
+ if (is_fp) {
+
+ /*
+ ConstantFP *i0 = dyn_cast<ConstantFP>(op0);
+ ConstantFP *i1 = dyn_cast<ConstantFP>(op1);
+ // BUG FIXME TODO: this is null ... but why?
+ // fprintf(stderr, "%p %p\n", i0, i1);
+ if (i0) {
+
+ cur_val = (uint64_t)i0->getValue().convertToDouble();
+ if (last_val0 && last_val0 == cur_val) { skip = true;
+
+ } last_val0 = cur_val;
+
+ }
+
+ if (i1) {
+
+ cur_val = (uint64_t)i1->getValue().convertToDouble();
+ if (last_val1 && last_val1 == cur_val) { skip = true;
+
+ } last_val1 = cur_val;
+
+ }
+
+ */
+
+ } else {
+
+ ConstantInt *i0 = dyn_cast<ConstantInt>(op0);
+ ConstantInt *i1 = dyn_cast<ConstantInt>(op1);
+ if (i0 && i0->uge(0xffffffffffffffff) == false) {
+
+ cur_val = i0->getZExtValue();
+ if (last_val0 && last_val0 == cur_val) { skip = true; }
+ last_val0 = cur_val;
+
+ }
+
+ if (i1 && i1->uge(0xffffffffffffffff) == false) {
+
+ cur_val = i1->getZExtValue();
+ if (last_val1 && last_val1 == cur_val) { skip = true; }
+ last_val1 = cur_val;
+
+ }
+
+ }
+
+ }
+
+ if (!skip) {
+
+ // errs() << "[CMPLOG] cmp " << *cmpInst << "(in function " <<
+ // cmpInst->getFunction()->getName() << ")\n";
+
+ // first bitcast to integer type of the same bitsize as the original
+ // type (this is a nop, if already integer)
+ Value *op0_i = IRB.CreateBitCast(
+ op0, IntegerType::get(C, ty0->getPrimitiveSizeInBits()));
+ // then create a int cast, which does zext, trunc or bitcast. In our
+ // case usually zext to the next larger supported type (this is a nop
+ // if already the right type)
+ Value *V0 =
+ IRB.CreateIntCast(op0_i, IntegerType::get(C, cast_size), false);
+ args.push_back(V0);
+ Value *op1_i = IRB.CreateBitCast(
+ op1, IntegerType::get(C, ty1->getPrimitiveSizeInBits()));
+ Value *V1 =
+ IRB.CreateIntCast(op1_i, IntegerType::get(C, cast_size), false);
+ args.push_back(V1);
+
+ // errs() << "[CMPLOG] casted parameters:\n0: " << *V0 << "\n1: " <<
+ // *V1
+ // << "\n";
+
+ ConstantInt *attribute = ConstantInt::get(Int8Ty, attr);
+ args.push_back(attribute);
+
+ if (cast_size != max_size) {
+
+ ConstantInt *bitsize = ConstantInt::get(Int8Ty, (max_size / 8) - 1);
+ args.push_back(bitsize);
+
+ }
+
+ // fprintf(stderr, "_ExtInt(%u) castTo %u with attr %u didcast %u\n",
+ // max_size, cast_size, attr);
+
+ switch (cast_size) {
+
+ case 8:
+ IRB.CreateCall(cmplogHookIns1, args);
+ break;
+ case 16:
+ IRB.CreateCall(cmplogHookIns2, args);
+ break;
+ case 32:
+ IRB.CreateCall(cmplogHookIns4, args);
+ break;
+ case 64:
+ IRB.CreateCall(cmplogHookIns8, args);
+ break;
+ case 128:
+ if (max_size == 128) {
+
+ IRB.CreateCall(cmplogHookIns16, args);
+
+ } else {
+
+ IRB.CreateCall(cmplogHookInsN, args);
+
+ }
+
+ break;
+
+ }
+
+ }
+
+ /* else fprintf(stderr, "skipped\n"); */
+
+ ++cur;
+ if (cur >= vector_cnt) { break; }
+
+ }
+
+ }
+
+ }
+
+ if (icomps.size())
+ return true;
+ else
+ return false;
+
+}
+
+#if LLVM_MAJOR >= 11 /* use new pass manager */
+PreservedAnalyses CmpLogInstructions::run(Module & M,
+ ModuleAnalysisManager &MAM) {
+
+#else
+bool CmpLogInstructions::runOnModule(Module &M) {
+
+#endif
+
+ if (getenv("AFL_QUIET") == NULL)
+ printf("Running cmplog-instructions-pass by andreafioraldi@gmail.com\n");
+ else
+ be_quiet = 1;
+ hookInstrs(M);
+ verifyModule(M);
+
+#if LLVM_MAJOR >= 11 /* use new pass manager */
+ return PreservedAnalyses::all();
+#else
+ return true;
+#endif
+
+}
+
+#if LLVM_MAJOR < 11 /* use old pass manager */
+static void registerCmpLogInstructionsPass(const PassManagerBuilder &,
+ legacy::PassManagerBase &PM) {
+
+ auto p = new CmpLogInstructions();
+ PM.add(p);
+
+}
+
+static RegisterStandardPasses RegisterCmpLogInstructionsPass(
+ PassManagerBuilder::EP_OptimizerLast, registerCmpLogInstructionsPass);
+
+static RegisterStandardPasses RegisterCmpLogInstructionsPass0(
+ PassManagerBuilder::EP_EnabledOnOptLevel0, registerCmpLogInstructionsPass);
+
+ #if LLVM_VERSION_MAJOR >= 11
+static RegisterStandardPasses RegisterCmpLogInstructionsPassLTO(
+ PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
+ registerCmpLogInstructionsPass);
+ #endif
+#endif
+
diff --git a/instrumentation/cmplog-routines-pass.cc b/instrumentation/cmplog-routines-pass.cc
new file mode 100644
index 00000000..8205cfb0
--- /dev/null
+++ b/instrumentation/cmplog-routines-pass.cc
@@ -0,0 +1,793 @@
+/*
+ american fuzzy lop++ - LLVM CmpLog instrumentation
+ --------------------------------------------------
+
+ Written by Andrea Fioraldi <andreafioraldi@gmail.com>
+
+ Copyright 2015, 2016 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <list>
+#include <string>
+#include <fstream>
+#include <sys/time.h>
+#include "llvm/Config/llvm-config.h"
+
+#include "llvm/ADT/Statistic.h"
+#include "llvm/IR/IRBuilder.h"
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+ #include "llvm/Passes/PassPlugin.h"
+ #include "llvm/Passes/PassBuilder.h"
+ #include "llvm/IR/PassManager.h"
+#else
+ #include "llvm/IR/LegacyPassManager.h"
+ #include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#endif
+#include "llvm/IR/Module.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Pass.h"
+#include "llvm/Analysis/ValueTracking.h"
+
+#include "llvm/IR/IRBuilder.h"
+#if LLVM_VERSION_MAJOR >= 4 || \
+ (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
+ #include "llvm/IR/Verifier.h"
+ #include "llvm/IR/DebugInfo.h"
+#else
+ #include "llvm/Analysis/Verifier.h"
+ #include "llvm/DebugInfo.h"
+ #define nullptr 0
+#endif
+
+#include <set>
+#include "afl-llvm-common.h"
+
+using namespace llvm;
+
+namespace {
+
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+class CmpLogRoutines : public PassInfoMixin<CmpLogRoutines> {
+
+ public:
+ CmpLogRoutines() {
+
+#else
+class CmpLogRoutines : public ModulePass {
+
+ public:
+ static char ID;
+ CmpLogRoutines() : ModulePass(ID) {
+
+#endif
+
+ initInstrumentList();
+
+ }
+
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+ PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
+#else
+ bool runOnModule(Module &M) override;
+
+ #if LLVM_VERSION_MAJOR >= 4
+ StringRef getPassName() const override {
+
+ #else
+ const char *getPassName() const override {
+
+ #endif
+ return "cmplog routines";
+
+ }
+
+#endif
+
+ private:
+ bool hookRtns(Module &M);
+
+};
+
+} // namespace
+
+#if LLVM_MAJOR >= 11
+extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
+llvmGetPassPluginInfo() {
+
+ return {LLVM_PLUGIN_API_VERSION, "cmplogroutines", "v0.1",
+ /* lambda to insert our pass into the pass pipeline. */
+ [](PassBuilder &PB) {
+
+ #if LLVM_VERSION_MAJOR <= 13
+ using OptimizationLevel = typename PassBuilder::OptimizationLevel;
+ #endif
+ PB.registerOptimizerLastEPCallback(
+ [](ModulePassManager &MPM, OptimizationLevel OL) {
+
+ MPM.addPass(CmpLogRoutines());
+
+ });
+
+ }};
+
+}
+
+#else
+char CmpLogRoutines::ID = 0;
+#endif
+
+bool CmpLogRoutines::hookRtns(Module &M) {
+
+ std::vector<CallInst *> calls, llvmStdStd, llvmStdC, gccStdStd, gccStdC,
+ Memcmp, Strcmp, Strncmp;
+ LLVMContext &C = M.getContext();
+
+ Type *VoidTy = Type::getVoidTy(C);
+ // PointerType *VoidPtrTy = PointerType::get(VoidTy, 0);
+ IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
+ IntegerType *Int64Ty = IntegerType::getInt64Ty(C);
+ PointerType *i8PtrTy = PointerType::get(Int8Ty, 0);
+
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee
+#else
+ Constant *
+#endif
+ c = M.getOrInsertFunction("__cmplog_rtn_hook", VoidTy, i8PtrTy, i8PtrTy
+#if LLVM_VERSION_MAJOR < 5
+ ,
+ NULL
+#endif
+ );
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee cmplogHookFn = c;
+#else
+ Function *cmplogHookFn = cast<Function>(c);
+#endif
+
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee
+#else
+ Constant *
+#endif
+ c1 = M.getOrInsertFunction("__cmplog_rtn_llvm_stdstring_stdstring",
+ VoidTy, i8PtrTy, i8PtrTy
+#if LLVM_VERSION_MAJOR < 5
+ ,
+ NULL
+#endif
+ );
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee cmplogLlvmStdStd = c1;
+#else
+ Function *cmplogLlvmStdStd = cast<Function>(c1);
+#endif
+
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee
+#else
+ Constant *
+#endif
+ c2 = M.getOrInsertFunction("__cmplog_rtn_llvm_stdstring_cstring", VoidTy,
+ i8PtrTy, i8PtrTy
+#if LLVM_VERSION_MAJOR < 5
+ ,
+ NULL
+#endif
+ );
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee cmplogLlvmStdC = c2;
+#else
+ Function *cmplogLlvmStdC = cast<Function>(c2);
+#endif
+
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee
+#else
+ Constant *
+#endif
+ c3 = M.getOrInsertFunction("__cmplog_rtn_gcc_stdstring_stdstring", VoidTy,
+ i8PtrTy, i8PtrTy
+#if LLVM_VERSION_MAJOR < 5
+ ,
+ NULL
+#endif
+ );
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee cmplogGccStdStd = c3;
+#else
+ Function *cmplogGccStdStd = cast<Function>(c3);
+#endif
+
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee
+#else
+ Constant *
+#endif
+ c4 = M.getOrInsertFunction("__cmplog_rtn_gcc_stdstring_cstring", VoidTy,
+ i8PtrTy, i8PtrTy
+#if LLVM_VERSION_MAJOR < 5
+ ,
+ NULL
+#endif
+ );
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee cmplogGccStdC = c4;
+#else
+ Function *cmplogGccStdC = cast<Function>(c4);
+#endif
+
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee
+#else
+ Constant *
+#endif
+ c5 = M.getOrInsertFunction("__cmplog_rtn_hook_n", VoidTy, i8PtrTy,
+ i8PtrTy, Int64Ty
+#if LLVM_VERSION_MAJOR < 5
+ ,
+ NULL
+#endif
+ );
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee cmplogHookFnN = c5;
+#else
+ Function *cmplogHookFnN = cast<Function>(c5);
+#endif
+
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee
+#else
+ Constant *
+#endif
+ c6 = M.getOrInsertFunction("__cmplog_rtn_hook_strn", VoidTy, i8PtrTy,
+ i8PtrTy, Int64Ty
+#if LLVM_VERSION_MAJOR < 5
+ ,
+ NULL
+#endif
+ );
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee cmplogHookFnStrN = c6;
+#else
+ Function *cmplogHookFnStrN = cast<Function>(c6);
+#endif
+
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee
+#else
+ Constant *
+#endif
+ c7 = M.getOrInsertFunction("__cmplog_rtn_hook_str", VoidTy, i8PtrTy,
+ i8PtrTy
+#if LLVM_VERSION_MAJOR < 5
+ ,
+ NULL
+#endif
+ );
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee cmplogHookFnStr = c7;
+#else
+ Function *cmplogHookFnStr = cast<Function>(c7);
+#endif
+
+ GlobalVariable *AFLCmplogPtr = M.getNamedGlobal("__afl_cmp_map");
+
+ if (!AFLCmplogPtr) {
+
+ AFLCmplogPtr = new GlobalVariable(M, PointerType::get(Int8Ty, 0), false,
+ GlobalValue::ExternalWeakLinkage, 0,
+ "__afl_cmp_map");
+
+ }
+
+ Constant *Null = Constant::getNullValue(PointerType::get(Int8Ty, 0));
+
+ /* iterate over all functions, bbs and instruction and add suitable calls */
+ for (auto &F : M) {
+
+ if (!isInInstrumentList(&F, MNAME)) continue;
+
+ for (auto &BB : F) {
+
+ for (auto &IN : BB) {
+
+ CallInst *callInst = nullptr;
+
+ if ((callInst = dyn_cast<CallInst>(&IN))) {
+
+ Function *Callee = callInst->getCalledFunction();
+ if (!Callee) continue;
+ if (callInst->getCallingConv() != llvm::CallingConv::C) continue;
+
+ FunctionType *FT = Callee->getFunctionType();
+ std::string FuncName = Callee->getName().str();
+
+ bool isPtrRtn = FT->getNumParams() >= 2 &&
+ !FT->getReturnType()->isVoidTy() &&
+ FT->getParamType(0) == FT->getParamType(1) &&
+ FT->getParamType(0)->isPointerTy();
+
+ bool isPtrRtnN = FT->getNumParams() >= 3 &&
+ !FT->getReturnType()->isVoidTy() &&
+ FT->getParamType(0) == FT->getParamType(1) &&
+ FT->getParamType(0)->isPointerTy() &&
+ FT->getParamType(2)->isIntegerTy();
+ if (isPtrRtnN) {
+
+ auto intTyOp =
+ dyn_cast<IntegerType>(callInst->getArgOperand(2)->getType());
+ if (intTyOp) {
+
+ if (intTyOp->getBitWidth() != 32 &&
+ intTyOp->getBitWidth() != 64) {
+
+ isPtrRtnN = false;
+
+ }
+
+ }
+
+ }
+
+ bool isMemcmp =
+ (!FuncName.compare("memcmp") || !FuncName.compare("bcmp") ||
+ !FuncName.compare("CRYPTO_memcmp") ||
+ !FuncName.compare("OPENSSL_memcmp") ||
+ !FuncName.compare("memcmp_const_time") ||
+ !FuncName.compare("memcmpct"));
+ isMemcmp &= FT->getNumParams() == 3 &&
+ FT->getReturnType()->isIntegerTy(32) &&
+ FT->getParamType(0)->isPointerTy() &&
+ FT->getParamType(1)->isPointerTy() &&
+ FT->getParamType(2)->isIntegerTy();
+
+ bool isStrcmp =
+ (!FuncName.compare("strcmp") || !FuncName.compare("xmlStrcmp") ||
+ !FuncName.compare("xmlStrEqual") ||
+ !FuncName.compare("g_strcmp0") ||
+ !FuncName.compare("curl_strequal") ||
+ !FuncName.compare("strcsequal") ||
+ !FuncName.compare("strcasecmp") ||
+ !FuncName.compare("stricmp") ||
+ !FuncName.compare("ap_cstr_casecmp") ||
+ !FuncName.compare("OPENSSL_strcasecmp") ||
+ !FuncName.compare("xmlStrcasecmp") ||
+ !FuncName.compare("g_strcasecmp") ||
+ !FuncName.compare("g_ascii_strcasecmp") ||
+ !FuncName.compare("Curl_strcasecompare") ||
+ !FuncName.compare("Curl_safe_strcasecompare") ||
+ !FuncName.compare("cmsstrcasecmp") ||
+ !FuncName.compare("strstr") ||
+ !FuncName.compare("g_strstr_len") ||
+ !FuncName.compare("ap_strcasestr") ||
+ !FuncName.compare("xmlStrstr") ||
+ !FuncName.compare("xmlStrcasestr") ||
+ !FuncName.compare("g_str_has_prefix") ||
+ !FuncName.compare("g_str_has_suffix"));
+ isStrcmp &=
+ FT->getNumParams() == 2 && FT->getReturnType()->isIntegerTy(32) &&
+ FT->getParamType(0) == FT->getParamType(1) &&
+ FT->getParamType(0) == IntegerType::getInt8PtrTy(M.getContext());
+
+ bool isStrncmp = (!FuncName.compare("strncmp") ||
+ !FuncName.compare("xmlStrncmp") ||
+ !FuncName.compare("curl_strnequal") ||
+ !FuncName.compare("strncasecmp") ||
+ !FuncName.compare("strnicmp") ||
+ !FuncName.compare("ap_cstr_casecmpn") ||
+ !FuncName.compare("OPENSSL_strncasecmp") ||
+ !FuncName.compare("xmlStrncasecmp") ||
+ !FuncName.compare("g_ascii_strncasecmp") ||
+ !FuncName.compare("Curl_strncasecompare") ||
+ !FuncName.compare("g_strncasecmp"));
+ isStrncmp &= FT->getNumParams() == 3 &&
+ FT->getReturnType()->isIntegerTy(32) &&
+ FT->getParamType(0) == FT->getParamType(1) &&
+ FT->getParamType(0) ==
+ IntegerType::getInt8PtrTy(M.getContext()) &&
+ FT->getParamType(2)->isIntegerTy();
+
+ bool isGccStdStringStdString =
+ Callee->getName().find("__is_charIT_EE7__value") !=
+ std::string::npos &&
+ Callee->getName().find(
+ "St7__cxx1112basic_stringIS2_St11char_traits") !=
+ std::string::npos &&
+ FT->getNumParams() >= 2 &&
+ FT->getParamType(0) == FT->getParamType(1) &&
+ FT->getParamType(0)->isPointerTy();
+
+ bool isGccStdStringCString =
+ Callee->getName().find(
+ "St7__cxx1112basic_stringIcSt11char_"
+ "traitsIcESaIcEE7compareEPK") != std::string::npos &&
+ FT->getNumParams() >= 2 && FT->getParamType(0)->isPointerTy() &&
+ FT->getParamType(1)->isPointerTy();
+
+ bool isLlvmStdStringStdString =
+ Callee->getName().find("_ZNSt3__1eqI") != std::string::npos &&
+ Callee->getName().find("_12basic_stringI") != std::string::npos &&
+ Callee->getName().find("_11char_traits") != std::string::npos &&
+ FT->getNumParams() >= 2 && FT->getParamType(0)->isPointerTy() &&
+ FT->getParamType(1)->isPointerTy();
+
+ bool isLlvmStdStringCString =
+ Callee->getName().find("_ZNSt3__1eqI") != std::string::npos &&
+ Callee->getName().find("_12basic_stringI") != std::string::npos &&
+ FT->getNumParams() >= 2 && FT->getParamType(0)->isPointerTy() &&
+ FT->getParamType(1)->isPointerTy();
+
+ /*
+ {
+
+ fprintf(stderr, "F:%s C:%s argc:%u\n",
+ F.getName().str().c_str(),
+ Callee->getName().str().c_str(), FT->getNumParams());
+ fprintf(stderr, "ptr0:%u ptr1:%u ptr2:%u\n",
+ FT->getParamType(0)->isPointerTy(),
+ FT->getParamType(1)->isPointerTy(),
+ FT->getNumParams() > 2 ?
+ FT->getParamType(2)->isPointerTy() : 22 );
+
+ }
+
+ */
+
+ if (isGccStdStringCString || isGccStdStringStdString ||
+ isLlvmStdStringStdString || isLlvmStdStringCString || isMemcmp ||
+ isStrcmp || isStrncmp) {
+
+ isPtrRtnN = isPtrRtn = false;
+
+ }
+
+ if (isPtrRtnN) { isPtrRtn = false; }
+
+ if (isPtrRtn) { calls.push_back(callInst); }
+ if (isMemcmp || isPtrRtnN) { Memcmp.push_back(callInst); }
+ if (isStrcmp) { Strcmp.push_back(callInst); }
+ if (isStrncmp) { Strncmp.push_back(callInst); }
+ if (isGccStdStringStdString) { gccStdStd.push_back(callInst); }
+ if (isGccStdStringCString) { gccStdC.push_back(callInst); }
+ if (isLlvmStdStringStdString) { llvmStdStd.push_back(callInst); }
+ if (isLlvmStdStringCString) { llvmStdC.push_back(callInst); }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ if (!calls.size() && !gccStdStd.size() && !gccStdC.size() &&
+ !llvmStdStd.size() && !llvmStdC.size() && !Memcmp.size() &&
+ Strcmp.size() && Strncmp.size())
+ return false;
+
+ /*
+ if (!be_quiet)
+ errs() << "Hooking " << calls.size()
+ << " calls with pointers as arguments\n";
+ */
+
+ for (auto &callInst : calls) {
+
+ Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1);
+
+ IRBuilder<> IRB2(callInst->getParent());
+ IRB2.SetInsertPoint(callInst);
+
+ LoadInst *CmpPtr = IRB2.CreateLoad(
+#if LLVM_VERSION_MAJOR >= 14
+ PointerType::get(Int8Ty, 0),
+#endif
+ AFLCmplogPtr);
+ CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
+ auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
+ auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, callInst, false);
+
+ IRBuilder<> IRB(ThenTerm);
+
+ std::vector<Value *> args;
+ Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
+ Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
+ args.push_back(v1Pcasted);
+ args.push_back(v2Pcasted);
+
+ IRB.CreateCall(cmplogHookFn, args);
+
+ // errs() << callInst->getCalledFunction()->getName() << "\n";
+
+ }
+
+ for (auto &callInst : Memcmp) {
+
+ Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1),
+ *v3P = callInst->getArgOperand(2);
+
+ IRBuilder<> IRB2(callInst->getParent());
+ IRB2.SetInsertPoint(callInst);
+
+ LoadInst *CmpPtr = IRB2.CreateLoad(
+#if LLVM_VERSION_MAJOR >= 14
+ PointerType::get(Int8Ty, 0),
+#endif
+ AFLCmplogPtr);
+ CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
+ auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
+ auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, callInst, false);
+
+ IRBuilder<> IRB(ThenTerm);
+
+ std::vector<Value *> args;
+ Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
+ Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
+ Value * v3Pbitcast = IRB.CreateBitCast(
+ v3P, IntegerType::get(C, v3P->getType()->getPrimitiveSizeInBits()));
+ Value *v3Pcasted =
+ IRB.CreateIntCast(v3Pbitcast, IntegerType::get(C, 64), false);
+ args.push_back(v1Pcasted);
+ args.push_back(v2Pcasted);
+ args.push_back(v3Pcasted);
+
+ IRB.CreateCall(cmplogHookFnN, args);
+
+ // errs() << callInst->getCalledFunction()->getName() << "\n";
+
+ }
+
+ for (auto &callInst : Strcmp) {
+
+ Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1);
+
+ IRBuilder<> IRB2(callInst->getParent());
+ IRB2.SetInsertPoint(callInst);
+
+ LoadInst *CmpPtr = IRB2.CreateLoad(
+#if LLVM_VERSION_MAJOR >= 14
+ PointerType::get(Int8Ty, 0),
+#endif
+ AFLCmplogPtr);
+ CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
+ auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
+ auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, callInst, false);
+
+ IRBuilder<> IRB(ThenTerm);
+
+ std::vector<Value *> args;
+ Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
+ Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
+ args.push_back(v1Pcasted);
+ args.push_back(v2Pcasted);
+
+ IRB.CreateCall(cmplogHookFnStr, args);
+
+ // errs() << callInst->getCalledFunction()->getName() << "\n";
+
+ }
+
+ for (auto &callInst : Strncmp) {
+
+ Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1),
+ *v3P = callInst->getArgOperand(2);
+
+ IRBuilder<> IRB2(callInst->getParent());
+ IRB2.SetInsertPoint(callInst);
+
+ LoadInst *CmpPtr = IRB2.CreateLoad(
+#if LLVM_VERSION_MAJOR >= 14
+ PointerType::get(Int8Ty, 0),
+#endif
+ AFLCmplogPtr);
+ CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
+ auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
+ auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, callInst, false);
+
+ IRBuilder<> IRB(ThenTerm);
+
+ std::vector<Value *> args;
+ Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
+ Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
+ Value * v3Pbitcast = IRB.CreateBitCast(
+ v3P, IntegerType::get(C, v3P->getType()->getPrimitiveSizeInBits()));
+ Value *v3Pcasted =
+ IRB.CreateIntCast(v3Pbitcast, IntegerType::get(C, 64), false);
+ args.push_back(v1Pcasted);
+ args.push_back(v2Pcasted);
+ args.push_back(v3Pcasted);
+
+ IRB.CreateCall(cmplogHookFnStrN, args);
+
+ // errs() << callInst->getCalledFunction()->getName() << "\n";
+
+ }
+
+ for (auto &callInst : gccStdStd) {
+
+ Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1);
+
+ IRBuilder<> IRB2(callInst->getParent());
+ IRB2.SetInsertPoint(callInst);
+
+ LoadInst *CmpPtr = IRB2.CreateLoad(
+#if LLVM_VERSION_MAJOR >= 14
+ PointerType::get(Int8Ty, 0),
+#endif
+ AFLCmplogPtr);
+ CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
+ auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
+ auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, callInst, false);
+
+ IRBuilder<> IRB(ThenTerm);
+
+ std::vector<Value *> args;
+ Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
+ Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
+ args.push_back(v1Pcasted);
+ args.push_back(v2Pcasted);
+
+ IRB.CreateCall(cmplogGccStdStd, args);
+
+ // errs() << callInst->getCalledFunction()->getName() << "\n";
+
+ }
+
+ for (auto &callInst : gccStdC) {
+
+ Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1);
+
+ IRBuilder<> IRB2(callInst->getParent());
+ IRB2.SetInsertPoint(callInst);
+
+ LoadInst *CmpPtr = IRB2.CreateLoad(
+#if LLVM_VERSION_MAJOR >= 14
+ PointerType::get(Int8Ty, 0),
+#endif
+ AFLCmplogPtr);
+ CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
+ auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
+ auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, callInst, false);
+
+ IRBuilder<> IRB(ThenTerm);
+
+ std::vector<Value *> args;
+ Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
+ Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
+ args.push_back(v1Pcasted);
+ args.push_back(v2Pcasted);
+
+ IRB.CreateCall(cmplogGccStdC, args);
+
+ // errs() << callInst->getCalledFunction()->getName() << "\n";
+
+ }
+
+ for (auto &callInst : llvmStdStd) {
+
+ Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1);
+
+ IRBuilder<> IRB2(callInst->getParent());
+ IRB2.SetInsertPoint(callInst);
+
+ LoadInst *CmpPtr = IRB2.CreateLoad(
+#if LLVM_VERSION_MAJOR >= 14
+ PointerType::get(Int8Ty, 0),
+#endif
+ AFLCmplogPtr);
+ CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
+ auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
+ auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, callInst, false);
+
+ IRBuilder<> IRB(ThenTerm);
+
+ std::vector<Value *> args;
+ Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
+ Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
+ args.push_back(v1Pcasted);
+ args.push_back(v2Pcasted);
+
+ IRB.CreateCall(cmplogLlvmStdStd, args);
+
+ // errs() << callInst->getCalledFunction()->getName() << "\n";
+
+ }
+
+ for (auto &callInst : llvmStdC) {
+
+ Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1);
+
+ IRBuilder<> IRB2(callInst->getParent());
+ IRB2.SetInsertPoint(callInst);
+
+ LoadInst *CmpPtr = IRB2.CreateLoad(
+#if LLVM_VERSION_MAJOR >= 14
+ PointerType::get(Int8Ty, 0),
+#endif
+ AFLCmplogPtr);
+ CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
+ auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
+ auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, callInst, false);
+
+ IRBuilder<> IRB(ThenTerm);
+
+ std::vector<Value *> args;
+ Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
+ Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
+ args.push_back(v1Pcasted);
+ args.push_back(v2Pcasted);
+
+ IRB.CreateCall(cmplogLlvmStdC, args);
+
+ // errs() << callInst->getCalledFunction()->getName() << "\n";
+
+ }
+
+ return true;
+
+}
+
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+PreservedAnalyses CmpLogRoutines::run(Module &M, ModuleAnalysisManager &MAM) {
+
+#else
+bool CmpLogRoutines::runOnModule(Module &M) {
+
+#endif
+
+ if (getenv("AFL_QUIET") == NULL)
+ printf("Running cmplog-routines-pass by andreafioraldi@gmail.com\n");
+ else
+ be_quiet = 1;
+ hookRtns(M);
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+ auto PA = PreservedAnalyses::all();
+#endif
+ verifyModule(M);
+
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+ return PA;
+#else
+ return true;
+#endif
+
+}
+
+#if LLVM_VERSION_MAJOR < 11 /* use old pass manager */
+static void registerCmpLogRoutinesPass(const PassManagerBuilder &,
+ legacy::PassManagerBase &PM) {
+
+ auto p = new CmpLogRoutines();
+ PM.add(p);
+
+}
+
+static RegisterStandardPasses RegisterCmpLogRoutinesPass(
+ PassManagerBuilder::EP_OptimizerLast, registerCmpLogRoutinesPass);
+
+static RegisterStandardPasses RegisterCmpLogRoutinesPass0(
+ PassManagerBuilder::EP_EnabledOnOptLevel0, registerCmpLogRoutinesPass);
+
+ #if LLVM_VERSION_MAJOR >= 11
+static RegisterStandardPasses RegisterCmpLogRoutinesPassLTO(
+ PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
+ registerCmpLogRoutinesPass);
+ #endif
+#endif
+
diff --git a/instrumentation/cmplog-switches-pass.cc b/instrumentation/cmplog-switches-pass.cc
new file mode 100644
index 00000000..37bf3889
--- /dev/null
+++ b/instrumentation/cmplog-switches-pass.cc
@@ -0,0 +1,478 @@
+/*
+ american fuzzy lop++ - LLVM CmpLog instrumentation
+ --------------------------------------------------
+
+ Written by Andrea Fioraldi <andreafioraldi@gmail.com>
+
+ Copyright 2015, 2016 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <list>
+#include <string>
+#include <fstream>
+#include <sys/time.h>
+
+#include "llvm/Config/llvm-config.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/IR/IRBuilder.h"
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+ #include "llvm/Passes/PassPlugin.h"
+ #include "llvm/Passes/PassBuilder.h"
+ #include "llvm/IR/PassManager.h"
+#else
+ #include "llvm/IR/LegacyPassManager.h"
+ #include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#endif
+#include "llvm/IR/Module.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Pass.h"
+#include "llvm/Analysis/ValueTracking.h"
+
+#include "llvm/IR/IRBuilder.h"
+#if LLVM_VERSION_MAJOR >= 4 || \
+ (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
+ #include "llvm/IR/Verifier.h"
+ #include "llvm/IR/DebugInfo.h"
+#else
+ #include "llvm/Analysis/Verifier.h"
+ #include "llvm/DebugInfo.h"
+ #define nullptr 0
+#endif
+
+#include <set>
+#include "afl-llvm-common.h"
+
+using namespace llvm;
+
+namespace {
+
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+class CmplogSwitches : public PassInfoMixin<CmplogSwitches> {
+
+ public:
+ CmplogSwitches() {
+
+#else
+class CmplogSwitches : public ModulePass {
+
+ public:
+ static char ID;
+ CmplogSwitches() : ModulePass(ID) {
+
+#endif
+ initInstrumentList();
+
+ }
+
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+ PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
+#else
+ bool runOnModule(Module &M) override;
+
+ #if LLVM_VERSION_MAJOR < 4
+ const char *getPassName() const override {
+
+ #else
+ StringRef getPassName() const override {
+
+ #endif
+ return "cmplog switch split";
+
+ }
+
+#endif
+
+ private:
+ bool hookInstrs(Module &M);
+
+};
+
+} // namespace
+
+#if LLVM_MAJOR >= 11
+extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
+llvmGetPassPluginInfo() {
+
+ return {LLVM_PLUGIN_API_VERSION, "cmplogswitches", "v0.1",
+ /* lambda to insert our pass into the pass pipeline. */
+ [](PassBuilder &PB) {
+
+ #if LLVM_VERSION_MAJOR <= 13
+ using OptimizationLevel = typename PassBuilder::OptimizationLevel;
+ #endif
+ PB.registerOptimizerLastEPCallback(
+ [](ModulePassManager &MPM, OptimizationLevel OL) {
+
+ MPM.addPass(CmplogSwitches());
+
+ });
+
+ }};
+
+}
+
+#else
+char CmplogSwitches::ID = 0;
+#endif
+
+template <class Iterator>
+Iterator Unique(Iterator first, Iterator last) {
+
+ while (first != last) {
+
+ Iterator next(first);
+ last = std::remove(++next, last, *first);
+ first = next;
+
+ }
+
+ return last;
+
+}
+
+bool CmplogSwitches::hookInstrs(Module &M) {
+
+ std::vector<SwitchInst *> switches;
+ LLVMContext & C = M.getContext();
+
+ Type * VoidTy = Type::getVoidTy(C);
+ IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
+ IntegerType *Int16Ty = IntegerType::getInt16Ty(C);
+ IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
+ IntegerType *Int64Ty = IntegerType::getInt64Ty(C);
+
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee
+#else
+ Constant *
+#endif
+ c1 = M.getOrInsertFunction("__cmplog_ins_hook1", VoidTy, Int8Ty, Int8Ty,
+ Int8Ty
+#if LLVM_VERSION_MAJOR < 5
+ ,
+ NULL
+#endif
+ );
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee cmplogHookIns1 = c1;
+#else
+ Function *cmplogHookIns1 = cast<Function>(c1);
+#endif
+
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee
+#else
+ Constant *
+#endif
+ c2 = M.getOrInsertFunction("__cmplog_ins_hook2", VoidTy, Int16Ty, Int16Ty,
+ Int8Ty
+#if LLVM_VERSION_MAJOR < 5
+ ,
+ NULL
+#endif
+ );
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee cmplogHookIns2 = c2;
+#else
+ Function *cmplogHookIns2 = cast<Function>(c2);
+#endif
+
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee
+#else
+ Constant *
+#endif
+ c4 = M.getOrInsertFunction("__cmplog_ins_hook4", VoidTy, Int32Ty, Int32Ty,
+ Int8Ty
+#if LLVM_VERSION_MAJOR < 5
+ ,
+ NULL
+#endif
+ );
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee cmplogHookIns4 = c4;
+#else
+ Function *cmplogHookIns4 = cast<Function>(c4);
+#endif
+
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee
+#else
+ Constant *
+#endif
+ c8 = M.getOrInsertFunction("__cmplog_ins_hook8", VoidTy, Int64Ty, Int64Ty,
+ Int8Ty
+#if LLVM_VERSION_MAJOR < 5
+ ,
+ NULL
+#endif
+ );
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee cmplogHookIns8 = c8;
+#else
+ Function *cmplogHookIns8 = cast<Function>(c8);
+#endif
+
+ GlobalVariable *AFLCmplogPtr = M.getNamedGlobal("__afl_cmp_map");
+
+ if (!AFLCmplogPtr) {
+
+ AFLCmplogPtr = new GlobalVariable(M, PointerType::get(Int8Ty, 0), false,
+ GlobalValue::ExternalWeakLinkage, 0,
+ "__afl_cmp_map");
+
+ }
+
+ Constant *Null = Constant::getNullValue(PointerType::get(Int8Ty, 0));
+
+ /* iterate over all functions, bbs and instruction and add suitable calls */
+ for (auto &F : M) {
+
+ if (!isInInstrumentList(&F, MNAME)) continue;
+
+ for (auto &BB : F) {
+
+ SwitchInst *switchInst = nullptr;
+ if ((switchInst = dyn_cast<SwitchInst>(BB.getTerminator()))) {
+
+ if (switchInst->getNumCases() > 1) { switches.push_back(switchInst); }
+
+ }
+
+ }
+
+ }
+
+ // unique the collected switches
+ switches.erase(Unique(switches.begin(), switches.end()), switches.end());
+
+ // Instrument switch values for cmplog
+ if (switches.size()) {
+
+ if (!be_quiet)
+ errs() << "Hooking " << switches.size() << " switch instructions\n";
+
+ for (auto &SI : switches) {
+
+ Value * Val = SI->getCondition();
+ unsigned int max_size = Val->getType()->getIntegerBitWidth(), cast_size;
+ unsigned char do_cast = 0;
+
+ if (!SI->getNumCases() || max_size < 16) {
+
+ // if (!be_quiet) errs() << "skip trivial switch..\n";
+ continue;
+
+ }
+
+ if (max_size % 8) {
+
+ max_size = (((max_size / 8) + 1) * 8);
+ do_cast = 1;
+
+ }
+
+ IRBuilder<> IRB2(SI->getParent());
+ IRB2.SetInsertPoint(SI);
+
+ LoadInst *CmpPtr = IRB2.CreateLoad(
+#if LLVM_VERSION_MAJOR >= 14
+ PointerType::get(Int8Ty, 0),
+#endif
+ AFLCmplogPtr);
+ CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
+ auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
+ auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, SI, false);
+
+ IRBuilder<> IRB(ThenTerm);
+
+ if (max_size > 128) {
+
+ if (!be_quiet) {
+
+ fprintf(stderr,
+ "Cannot handle this switch bit size: %u (truncating)\n",
+ max_size);
+
+ }
+
+ max_size = 128;
+ do_cast = 1;
+
+ }
+
+ // do we need to cast?
+ switch (max_size) {
+
+ case 8:
+ case 16:
+ case 32:
+ case 64:
+ case 128:
+ cast_size = max_size;
+ break;
+ default:
+ cast_size = 128;
+ do_cast = 1;
+
+ }
+
+ Value *CompareTo = Val;
+
+ if (do_cast) {
+
+ CompareTo =
+ IRB.CreateIntCast(CompareTo, IntegerType::get(C, cast_size), false);
+
+ }
+
+ for (SwitchInst::CaseIt i = SI->case_begin(), e = SI->case_end(); i != e;
+ ++i) {
+
+#if LLVM_VERSION_MAJOR < 5
+ ConstantInt *cint = i.getCaseValue();
+#else
+ ConstantInt *cint = i->getCaseValue();
+#endif
+
+ if (cint) {
+
+ std::vector<Value *> args;
+ args.push_back(CompareTo);
+
+ Value *new_param = cint;
+
+ if (do_cast) {
+
+ new_param =
+ IRB.CreateIntCast(cint, IntegerType::get(C, cast_size), false);
+
+ }
+
+ if (new_param) {
+
+ args.push_back(new_param);
+ ConstantInt *attribute = ConstantInt::get(Int8Ty, 1);
+ args.push_back(attribute);
+ if (cast_size != max_size) {
+
+ ConstantInt *bitsize =
+ ConstantInt::get(Int8Ty, (max_size / 8) - 1);
+ args.push_back(bitsize);
+
+ }
+
+ switch (cast_size) {
+
+ case 8:
+ IRB.CreateCall(cmplogHookIns1, args);
+ break;
+ case 16:
+ IRB.CreateCall(cmplogHookIns2, args);
+ break;
+ case 32:
+ IRB.CreateCall(cmplogHookIns4, args);
+ break;
+ case 64:
+ IRB.CreateCall(cmplogHookIns8, args);
+ break;
+ case 128:
+#ifdef WORD_SIZE_64
+ if (max_size == 128) {
+
+ IRB.CreateCall(cmplogHookIns16, args);
+
+ } else {
+
+ IRB.CreateCall(cmplogHookInsN, args);
+
+ }
+
+#endif
+ break;
+ default:
+ break;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ if (switches.size())
+ return true;
+ else
+ return false;
+
+}
+
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+PreservedAnalyses CmplogSwitches::run(Module &M, ModuleAnalysisManager &MAM) {
+
+#else
+bool CmplogSwitches::runOnModule(Module &M) {
+
+#endif
+
+ if (getenv("AFL_QUIET") == NULL)
+ printf("Running cmplog-switches-pass by andreafioraldi@gmail.com\n");
+ else
+ be_quiet = 1;
+ hookInstrs(M);
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+ auto PA = PreservedAnalyses::all();
+#endif
+ verifyModule(M);
+
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+ return PA;
+#else
+ return true;
+#endif
+
+}
+
+#if LLVM_VERSION_MAJOR < 11 /* use old pass manager */
+static void registerCmplogSwitchesPass(const PassManagerBuilder &,
+ legacy::PassManagerBase &PM) {
+
+ auto p = new CmplogSwitches();
+ PM.add(p);
+
+}
+
+static RegisterStandardPasses RegisterCmplogSwitchesPass(
+ PassManagerBuilder::EP_OptimizerLast, registerCmplogSwitchesPass);
+
+static RegisterStandardPasses RegisterCmplogSwitchesPass0(
+ PassManagerBuilder::EP_EnabledOnOptLevel0, registerCmplogSwitchesPass);
+
+ #if LLVM_VERSION_MAJOR >= 11
+static RegisterStandardPasses RegisterCmplogSwitchesPassLTO(
+ PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
+ registerCmplogSwitchesPass);
+ #endif
+#endif
+
diff --git a/instrumentation/compare-transform-pass.so.cc b/instrumentation/compare-transform-pass.so.cc
new file mode 100644
index 00000000..34c88735
--- /dev/null
+++ b/instrumentation/compare-transform-pass.so.cc
@@ -0,0 +1,775 @@
+/*
+ * Copyright 2016 laf-intel
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <list>
+#include <string>
+#include <fstream>
+#include <sys/time.h>
+#include "llvm/Config/llvm-config.h"
+
+#include "llvm/ADT/Statistic.h"
+#include "llvm/IR/IRBuilder.h"
+#if LLVM_MAJOR >= 11 /* use new pass manager */
+ #include "llvm/Passes/PassPlugin.h"
+ #include "llvm/Passes/PassBuilder.h"
+ #include "llvm/IR/PassManager.h"
+#else
+ #include "llvm/IR/LegacyPassManager.h"
+ #include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#endif
+#include "llvm/IR/Module.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Pass.h"
+#include "llvm/Analysis/ValueTracking.h"
+#if LLVM_VERSION_MAJOR >= 14 /* how about stable interfaces? */
+ #include "llvm/Passes/OptimizationLevel.h"
+#endif
+
+#if LLVM_VERSION_MAJOR >= 4 || \
+ (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
+ #include "llvm/IR/Verifier.h"
+ #include "llvm/IR/DebugInfo.h"
+#else
+ #include "llvm/Analysis/Verifier.h"
+ #include "llvm/DebugInfo.h"
+ #define nullptr 0
+#endif
+
+#include <set>
+#include "afl-llvm-common.h"
+
+using namespace llvm;
+
+namespace {
+
+#if LLVM_MAJOR >= 11 /* use new pass manager */
+class CompareTransform : public PassInfoMixin<CompareTransform> {
+
+ public:
+ CompareTransform() {
+
+#else
+class CompareTransform : public ModulePass {
+
+ public:
+ static char ID;
+ CompareTransform() : ModulePass(ID) {
+
+#endif
+
+ initInstrumentList();
+
+ }
+
+#if LLVM_MAJOR < 11
+ #if LLVM_VERSION_MAJOR >= 4
+ StringRef getPassName() const override {
+
+ #else
+ const char *getPassName() const override {
+
+ #endif
+
+ return "cmplog transform";
+
+ }
+
+#endif
+
+#if LLVM_MAJOR >= 11 /* use new pass manager */
+ PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
+#else
+ bool runOnModule(Module &M) override;
+#endif
+
+ private:
+ bool transformCmps(Module &M, const bool processStrcmp,
+ const bool processMemcmp, const bool processStrncmp,
+ const bool processStrcasecmp,
+ const bool processStrncasecmp);
+
+};
+
+} // namespace
+
+#if LLVM_MAJOR >= 11 /* use new pass manager */
+extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
+llvmGetPassPluginInfo() {
+
+ return {LLVM_PLUGIN_API_VERSION, "comparetransform", "v0.1",
+ /* lambda to insert our pass into the pass pipeline. */
+ [](PassBuilder &PB) {
+
+ #if 1
+ #if LLVM_VERSION_MAJOR <= 13
+ using OptimizationLevel = typename PassBuilder::OptimizationLevel;
+ #endif
+ PB.registerOptimizerLastEPCallback(
+ [](ModulePassManager &MPM, OptimizationLevel OL) {
+
+ MPM.addPass(CompareTransform());
+
+ });
+
+ /* TODO LTO registration */
+ #else
+ using PipelineElement = typename PassBuilder::PipelineElement;
+ PB.registerPipelineParsingCallback([](StringRef Name,
+ ModulePassManager &MPM,
+ ArrayRef<PipelineElement>) {
+
+ if (Name == "comparetransform") {
+
+ MPM.addPass(CompareTransform());
+ return true;
+
+ } else {
+
+ return false;
+
+ }
+
+ });
+
+ #endif
+
+ }};
+
+}
+
+#else
+char CompareTransform::ID = 0;
+#endif
+
+bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
+ const bool processMemcmp,
+ const bool processStrncmp,
+ const bool processStrcasecmp,
+ const bool processStrncasecmp) {
+
+ DenseMap<Value *, std::string *> valueMap;
+ std::vector<CallInst *> calls;
+ LLVMContext & C = M.getContext();
+ IntegerType * Int8Ty = IntegerType::getInt8Ty(C);
+ IntegerType * Int32Ty = IntegerType::getInt32Ty(C);
+ IntegerType * Int64Ty = IntegerType::getInt64Ty(C);
+
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee tolowerFn;
+#else
+ Function *tolowerFn;
+#endif
+ {
+
+#if LLVM_VERSION_MAJOR >= 9
+ FunctionCallee
+#else
+ Constant *
+#endif
+ c = M.getOrInsertFunction("tolower", Int32Ty, Int32Ty
+#if LLVM_VERSION_MAJOR < 5
+ ,
+ NULL
+#endif
+ );
+#if LLVM_VERSION_MAJOR >= 9
+ tolowerFn = c;
+#else
+ tolowerFn = cast<Function>(c);
+#endif
+
+ }
+
+ /* iterate over all functions, bbs and instruction and add suitable calls to
+ * strcmp/memcmp/strncmp/strcasecmp/strncasecmp */
+ for (auto &F : M) {
+
+ if (!isInInstrumentList(&F, MNAME)) continue;
+
+ for (auto &BB : F) {
+
+ for (auto &IN : BB) {
+
+ CallInst *callInst = nullptr;
+
+ if ((callInst = dyn_cast<CallInst>(&IN))) {
+
+ bool isStrcmp = processStrcmp;
+ bool isMemcmp = processMemcmp;
+ bool isStrncmp = processStrncmp;
+ bool isStrcasecmp = processStrcasecmp;
+ bool isStrncasecmp = processStrncasecmp;
+ bool isIntMemcpy = true;
+
+ Function *Callee = callInst->getCalledFunction();
+ if (!Callee) continue;
+ if (callInst->getCallingConv() != llvm::CallingConv::C) continue;
+ StringRef FuncName = Callee->getName();
+ isStrcmp &=
+ (!FuncName.compare("strcmp") || !FuncName.compare("xmlStrcmp") ||
+ !FuncName.compare("xmlStrEqual") ||
+ !FuncName.compare("g_strcmp0") ||
+ !FuncName.compare("curl_strequal") ||
+ !FuncName.compare("strcsequal"));
+ isMemcmp &=
+ (!FuncName.compare("memcmp") || !FuncName.compare("bcmp") ||
+ !FuncName.compare("CRYPTO_memcmp") ||
+ !FuncName.compare("OPENSSL_memcmp") ||
+ !FuncName.compare("memcmp_const_time") ||
+ !FuncName.compare("memcmpct"));
+ isStrncmp &= (!FuncName.compare("strncmp") ||
+ !FuncName.compare("xmlStrncmp") ||
+ !FuncName.compare("curl_strnequal"));
+ isStrcasecmp &= (!FuncName.compare("strcasecmp") ||
+ !FuncName.compare("stricmp") ||
+ !FuncName.compare("ap_cstr_casecmp") ||
+ !FuncName.compare("OPENSSL_strcasecmp") ||
+ !FuncName.compare("xmlStrcasecmp") ||
+ !FuncName.compare("g_strcasecmp") ||
+ !FuncName.compare("g_ascii_strcasecmp") ||
+ !FuncName.compare("Curl_strcasecompare") ||
+ !FuncName.compare("Curl_safe_strcasecompare") ||
+ !FuncName.compare("cmsstrcasecmp"));
+ isStrncasecmp &= (!FuncName.compare("strncasecmp") ||
+ !FuncName.compare("strnicmp") ||
+ !FuncName.compare("ap_cstr_casecmpn") ||
+ !FuncName.compare("OPENSSL_strncasecmp") ||
+ !FuncName.compare("xmlStrncasecmp") ||
+ !FuncName.compare("g_ascii_strncasecmp") ||
+ !FuncName.compare("Curl_strncasecompare") ||
+ !FuncName.compare("g_strncasecmp"));
+ isIntMemcpy &= !FuncName.compare("llvm.memcpy.p0i8.p0i8.i64");
+
+ if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
+ !isStrncasecmp && !isIntMemcpy)
+ continue;
+
+ /* Verify the strcmp/memcmp/strncmp/strcasecmp/strncasecmp function
+ * prototype */
+ FunctionType *FT = Callee->getFunctionType();
+
+ isStrcmp &=
+ FT->getNumParams() == 2 && FT->getReturnType()->isIntegerTy(32) &&
+ FT->getParamType(0) == FT->getParamType(1) &&
+ FT->getParamType(0) == IntegerType::getInt8PtrTy(M.getContext());
+ isStrcasecmp &=
+ FT->getNumParams() == 2 && FT->getReturnType()->isIntegerTy(32) &&
+ FT->getParamType(0) == FT->getParamType(1) &&
+ FT->getParamType(0) == IntegerType::getInt8PtrTy(M.getContext());
+ isMemcmp &= FT->getNumParams() == 3 &&
+ FT->getReturnType()->isIntegerTy(32) &&
+ FT->getParamType(0)->isPointerTy() &&
+ FT->getParamType(1)->isPointerTy() &&
+ FT->getParamType(2)->isIntegerTy();
+ isStrncmp &= FT->getNumParams() == 3 &&
+ FT->getReturnType()->isIntegerTy(32) &&
+ FT->getParamType(0) == FT->getParamType(1) &&
+ FT->getParamType(0) ==
+ IntegerType::getInt8PtrTy(M.getContext()) &&
+ FT->getParamType(2)->isIntegerTy();
+ isStrncasecmp &= FT->getNumParams() == 3 &&
+ FT->getReturnType()->isIntegerTy(32) &&
+ FT->getParamType(0) == FT->getParamType(1) &&
+ FT->getParamType(0) ==
+ IntegerType::getInt8PtrTy(M.getContext()) &&
+ FT->getParamType(2)->isIntegerTy();
+
+ if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
+ !isStrncasecmp && !isIntMemcpy)
+ continue;
+
+ /* is a str{n,}{case,}cmp/memcmp, check if we have
+ * str{case,}cmp(x, "const") or str{case,}cmp("const", x)
+ * strn{case,}cmp(x, "const", ..) or strn{case,}cmp("const", x, ..)
+ * memcmp(x, "const", ..) or memcmp("const", x, ..) */
+ Value *Str1P = callInst->getArgOperand(0),
+ *Str2P = callInst->getArgOperand(1);
+ StringRef Str1, Str2;
+ bool HasStr1 = getConstantStringInfo(Str1P, Str1);
+ bool HasStr2 = getConstantStringInfo(Str2P, Str2);
+
+ if (isIntMemcpy && HasStr2) {
+
+ valueMap[Str1P] = new std::string(Str2.str());
+ // fprintf(stderr, "saved %s for %p\n", Str2.str().c_str(), Str1P);
+ continue;
+
+ }
+
+ // not literal? maybe global or local variable
+ if (!(HasStr1 || HasStr2)) {
+
+ auto *Ptr = dyn_cast<ConstantExpr>(Str2P);
+ if (Ptr && Ptr->getOpcode() == Instruction::GetElementPtr) {
+
+ if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
+
+ if (Var->hasInitializer()) {
+
+ if (auto *Array =
+ dyn_cast<ConstantDataArray>(Var->getInitializer())) {
+
+ HasStr2 = true;
+ Str2 = Array->getRawDataValues();
+ valueMap[Str2P] = new std::string(Str2.str());
+ // fprintf(stderr, "glo2 %s\n", Str2.str().c_str());
+
+ }
+
+ }
+
+ }
+
+ }
+
+ if (!HasStr2) {
+
+ Ptr = dyn_cast<ConstantExpr>(Str1P);
+ if (Ptr && Ptr->getOpcode() == Instruction::GetElementPtr) {
+
+ if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
+
+ if (Var->hasInitializer()) {
+
+ if (auto *Array = dyn_cast<ConstantDataArray>(
+ Var->getInitializer())) {
+
+ HasStr1 = true;
+ Str1 = Array->getRawDataValues();
+ valueMap[Str1P] = new std::string(Str1.str());
+ // fprintf(stderr, "glo1 %s\n", Str1.str().c_str());
+
+ }
+
+ }
+
+ }
+
+ }
+
+ } else if (isIntMemcpy) {
+
+ valueMap[Str1P] = new std::string(Str2.str());
+ // fprintf(stderr, "saved\n");
+
+ }
+
+ }
+
+ if (isIntMemcpy) continue;
+
+ if (!(HasStr1 || HasStr2)) {
+
+ // do we have a saved local variable initialization?
+ std::string *val = valueMap[Str1P];
+ if (val && !val->empty()) {
+
+ Str1 = StringRef(*val);
+ HasStr1 = true;
+ // fprintf(stderr, "loaded1 %s\n", Str1.str().c_str());
+
+ } else {
+
+ val = valueMap[Str2P];
+ if (val && !val->empty()) {
+
+ Str2 = StringRef(*val);
+ HasStr2 = true;
+ // fprintf(stderr, "loaded2 %s\n", Str2.str().c_str());
+
+ }
+
+ }
+
+ }
+
+ /* handle cases of one string is const, one string is variable */
+ if (!(HasStr1 || HasStr2)) continue;
+
+ if (isMemcmp || isStrncmp || isStrncasecmp) {
+
+ /* check if third operand is a constant integer
+ * strlen("constStr") and sizeof() are treated as constant */
+ Value * op2 = callInst->getArgOperand(2);
+ ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
+ if (ilen) {
+
+ // if len is zero this is a pointless call but allow real
+ // implementation to worry about that
+ if (ilen->getZExtValue() < 2) { continue; }
+
+ } else if (isMemcmp) {
+
+ // this *may* supply a len greater than the constant string at
+ // runtime so similarly we don't want to have to handle that
+ continue;
+
+ }
+
+ }
+
+ calls.push_back(callInst);
+
+ }
+
+ }
+
+ }
+
+ }
+
+ if (!calls.size()) return false;
+ if (!be_quiet)
+ printf(
+ "Replacing %zu calls to strcmp/memcmp/strncmp/strcasecmp/strncasecmp\n",
+ calls.size());
+
+ for (auto &callInst : calls) {
+
+ Value *Str1P = callInst->getArgOperand(0),
+ *Str2P = callInst->getArgOperand(1);
+ StringRef Str1, Str2, ConstStr;
+ std::string TmpConstStr;
+ Value * VarStr;
+ bool HasStr1 = getConstantStringInfo(Str1P, Str1);
+ bool HasStr2 = getConstantStringInfo(Str2P, Str2);
+ uint64_t constStrLen, unrollLen, constSizedLen = 0;
+ bool isMemcmp = false;
+ bool isSizedcmp = false;
+ bool isCaseInsensitive = false;
+ bool needs_null = false;
+ Function * Callee = callInst->getCalledFunction();
+
+ if (Callee) {
+
+ if (!Callee->getName().compare("memcmp") ||
+ !Callee->getName().compare("bcmp") ||
+ !Callee->getName().compare("CRYPTO_memcmp") ||
+ !Callee->getName().compare("OPENSSL_memcmp") ||
+ !Callee->getName().compare("memcmp_const_time") ||
+ !Callee->getName().compare("memcmpct") ||
+ !Callee->getName().compare("llvm.memcpy.p0i8.p0i8.i64"))
+ isMemcmp = true;
+
+ if (isMemcmp || !Callee->getName().compare("strncmp") ||
+ !Callee->getName().compare("xmlStrncmp") ||
+ !Callee->getName().compare("curl_strnequal") ||
+ !Callee->getName().compare("strncasecmp") ||
+ !Callee->getName().compare("strnicmp") ||
+ !Callee->getName().compare("ap_cstr_casecmpn") ||
+ !Callee->getName().compare("OPENSSL_strncasecmp") ||
+ !Callee->getName().compare("xmlStrncasecmp") ||
+ !Callee->getName().compare("g_ascii_strncasecmp") ||
+ !Callee->getName().compare("Curl_strncasecompare") ||
+ !Callee->getName().compare("g_strncasecmp"))
+ isSizedcmp = true;
+
+ if (!Callee->getName().compare("strcasecmp") ||
+ !Callee->getName().compare("stricmp") ||
+ !Callee->getName().compare("ap_cstr_casecmp") ||
+ !Callee->getName().compare("OPENSSL_strcasecmp") ||
+ !Callee->getName().compare("xmlStrcasecmp") ||
+ !Callee->getName().compare("g_strcasecmp") ||
+ !Callee->getName().compare("g_ascii_strcasecmp") ||
+ !Callee->getName().compare("Curl_strcasecompare") ||
+ !Callee->getName().compare("Curl_safe_strcasecompare") ||
+ !Callee->getName().compare("cmsstrcasecmp") ||
+ !Callee->getName().compare("strncasecmp") ||
+ !Callee->getName().compare("strnicmp") ||
+ !Callee->getName().compare("ap_cstr_casecmpn") ||
+ !Callee->getName().compare("OPENSSL_strncasecmp") ||
+ !Callee->getName().compare("xmlStrncasecmp") ||
+ !Callee->getName().compare("g_ascii_strncasecmp") ||
+ !Callee->getName().compare("Curl_strncasecompare") ||
+ !Callee->getName().compare("g_strncasecmp"))
+ isCaseInsensitive = true;
+
+ }
+
+ if (!isSizedcmp) needs_null = true;
+
+ Value *sizedValue = isSizedcmp ? callInst->getArgOperand(2) : NULL;
+ bool isConstSized = sizedValue && isa<ConstantInt>(sizedValue);
+
+ if (!(HasStr1 || HasStr2)) {
+
+ // do we have a saved local or global variable initialization?
+ std::string *val = valueMap[Str1P];
+ if (val && !val->empty()) {
+
+ Str1 = StringRef(*val);
+ HasStr1 = true;
+
+ } else {
+
+ val = valueMap[Str2P];
+ if (val && !val->empty()) {
+
+ Str2 = StringRef(*val);
+ // HasStr2 = true;
+
+ }
+
+ }
+
+ }
+
+ if (isConstSized) {
+
+ constSizedLen = dyn_cast<ConstantInt>(sizedValue)->getZExtValue();
+
+ }
+
+ if (HasStr1) {
+
+ TmpConstStr = Str1.str();
+ VarStr = Str2P;
+
+ } else {
+
+ TmpConstStr = Str2.str();
+ VarStr = Str1P;
+
+ }
+
+ if (TmpConstStr.length() < 2 ||
+ (TmpConstStr.length() == 2 && TmpConstStr[1] == 0)) {
+
+ continue;
+
+ }
+
+ // the following is in general OK, but strncmp is sometimes used in binary
+ // data structures and this can result in crashes :( so it is commented out
+
+ // add null termination character implicit in c strings
+ if (needs_null && TmpConstStr[TmpConstStr.length() - 1] != 0) {
+
+ TmpConstStr.append("\0", 1);
+
+ }
+
+ // in the unusual case the const str has embedded null
+ // characters, the string comparison functions should terminate
+ // at the first null
+ if (!isMemcmp && TmpConstStr.find('\0') != std::string::npos) {
+
+ TmpConstStr.assign(TmpConstStr, 0, TmpConstStr.find('\0') + 1);
+
+ }
+
+ constStrLen = TmpConstStr.length();
+ // prefer use of StringRef (in comparison to std::string a StringRef has
+ // built-in runtime bounds checking, which makes debugging easier)
+ ConstStr = StringRef(TmpConstStr);
+
+ if (isConstSized)
+ unrollLen = constSizedLen < constStrLen ? constSizedLen : constStrLen;
+ else
+ unrollLen = constStrLen;
+
+ /* split before the call instruction */
+ BasicBlock *bb = callInst->getParent();
+ BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(callInst));
+
+ BasicBlock *next_lenchk_bb = NULL;
+ if (isSizedcmp && !isConstSized) {
+
+ next_lenchk_bb =
+ BasicBlock::Create(C, "len_check", end_bb->getParent(), end_bb);
+ BranchInst::Create(end_bb, next_lenchk_bb);
+
+ }
+
+ BasicBlock *next_cmp_bb =
+ BasicBlock::Create(C, "cmp_added", end_bb->getParent(), end_bb);
+ BranchInst::Create(end_bb, next_cmp_bb);
+ PHINode *PN = PHINode::Create(
+ Int32Ty, (next_lenchk_bb ? 2 : 1) * unrollLen + 1, "cmp_phi");
+
+#if LLVM_VERSION_MAJOR >= 8
+ Instruction *term = bb->getTerminator();
+#else
+ TerminatorInst *term = bb->getTerminator();
+#endif
+ BranchInst::Create(next_lenchk_bb ? next_lenchk_bb : next_cmp_bb, bb);
+ term->eraseFromParent();
+
+ for (uint64_t i = 0; i < unrollLen; i++) {
+
+ BasicBlock * cur_cmp_bb = next_cmp_bb, *cur_lenchk_bb = next_lenchk_bb;
+ unsigned char c;
+
+ if (cur_lenchk_bb) {
+
+ IRBuilder<> cur_lenchk_IRB(&*(cur_lenchk_bb->getFirstInsertionPt()));
+ Value * icmp = cur_lenchk_IRB.CreateICmpEQ(
+ sizedValue, ConstantInt::get(sizedValue->getType(), i));
+ cur_lenchk_IRB.CreateCondBr(icmp, end_bb, cur_cmp_bb);
+ cur_lenchk_bb->getTerminator()->eraseFromParent();
+
+ PN->addIncoming(ConstantInt::get(Int32Ty, 0), cur_lenchk_bb);
+
+ }
+
+ if (isCaseInsensitive)
+ c = (unsigned char)(tolower((int)ConstStr[i]) & 0xff);
+ else
+ c = (unsigned char)ConstStr[i];
+
+ IRBuilder<> cur_cmp_IRB(&*(cur_cmp_bb->getFirstInsertionPt()));
+
+ Value *v = ConstantInt::get(Int64Ty, i);
+ Value *ele = cur_cmp_IRB.CreateInBoundsGEP(
+#if LLVM_VERSION_MAJOR >= 14
+ Int8Ty,
+#endif
+ VarStr, v, "empty");
+ Value *load = cur_cmp_IRB.CreateLoad(
+#if LLVM_VERSION_MAJOR >= 14
+ Int8Ty,
+#endif
+ ele);
+
+ if (isCaseInsensitive) {
+
+ // load >= 'A' && load <= 'Z' ? load | 0x020 : load
+ load = cur_cmp_IRB.CreateZExt(load, Int32Ty);
+ std::vector<Value *> args;
+ args.push_back(load);
+ load = cur_cmp_IRB.CreateCall(tolowerFn, args);
+ load = cur_cmp_IRB.CreateTrunc(load, Int8Ty);
+
+ }
+
+ Value *isub;
+ if (HasStr1)
+ isub = cur_cmp_IRB.CreateSub(ConstantInt::get(Int8Ty, c), load);
+ else
+ isub = cur_cmp_IRB.CreateSub(load, ConstantInt::get(Int8Ty, c));
+
+ Value *sext = cur_cmp_IRB.CreateSExt(isub, Int32Ty);
+ PN->addIncoming(sext, cur_cmp_bb);
+
+ if (i < unrollLen - 1) {
+
+ if (cur_lenchk_bb) {
+
+ next_lenchk_bb =
+ BasicBlock::Create(C, "len_check", end_bb->getParent(), end_bb);
+ BranchInst::Create(end_bb, next_lenchk_bb);
+
+ }
+
+ next_cmp_bb =
+ BasicBlock::Create(C, "cmp_added", end_bb->getParent(), end_bb);
+ BranchInst::Create(end_bb, next_cmp_bb);
+
+ Value *icmp =
+ cur_cmp_IRB.CreateICmpEQ(isub, ConstantInt::get(Int8Ty, 0));
+ cur_cmp_IRB.CreateCondBr(
+ icmp, next_lenchk_bb ? next_lenchk_bb : next_cmp_bb, end_bb);
+ cur_cmp_bb->getTerminator()->eraseFromParent();
+
+ } else {
+
+ // IRB.CreateBr(end_bb);
+
+ }
+
+ // add offset to varstr
+ // create load
+ // create signed isub
+ // create icmp
+ // create jcc
+ // create next_bb
+
+ }
+
+ /* since the call is the first instruction of the bb it is safe to
+ * replace it with a phi instruction */
+ BasicBlock::iterator ii(callInst);
+ ReplaceInstWithInst(callInst->getParent()->getInstList(), ii, PN);
+
+ }
+
+ return true;
+
+}
+
+#if LLVM_MAJOR >= 11 /* use new pass manager */
+PreservedAnalyses CompareTransform::run(Module &M, ModuleAnalysisManager &MAM) {
+
+#else
+bool CompareTransform::runOnModule(Module &M) {
+
+#endif
+
+ if ((isatty(2) && getenv("AFL_QUIET") == NULL) || getenv("AFL_DEBUG") != NULL)
+ printf(
+ "Running compare-transform-pass by laf.intel@gmail.com, extended by "
+ "heiko@hexco.de\n");
+ else
+ be_quiet = 1;
+
+#if LLVM_MAJOR >= 11 /* use new pass manager */
+ auto PA = PreservedAnalyses::all();
+#endif
+
+ transformCmps(M, true, true, true, true, true);
+ verifyModule(M);
+
+#if LLVM_MAJOR >= 11 /* use new pass manager */
+ /* if (modified) {
+
+ PA.abandon<XX_Manager>();
+
+ }*/
+
+ return PA;
+#else
+ return true;
+#endif
+
+}
+
+#if LLVM_MAJOR < 11 /* use old pass manager */
+static void registerCompTransPass(const PassManagerBuilder &,
+ legacy::PassManagerBase &PM) {
+
+ auto p = new CompareTransform();
+ PM.add(p);
+
+}
+
+static RegisterStandardPasses RegisterCompTransPass(
+ PassManagerBuilder::EP_OptimizerLast, registerCompTransPass);
+
+static RegisterStandardPasses RegisterCompTransPass0(
+ PassManagerBuilder::EP_EnabledOnOptLevel0, registerCompTransPass);
+
+ #if LLVM_VERSION_MAJOR >= 11
+static RegisterStandardPasses RegisterCompTransPassLTO(
+ PassManagerBuilder::EP_FullLinkTimeOptimizationLast, registerCompTransPass);
+ #endif
+#endif
+
diff --git a/instrumentation/llvm-alternative-coverage.h b/instrumentation/llvm-alternative-coverage.h
new file mode 100644
index 00000000..0d7b3957
--- /dev/null
+++ b/instrumentation/llvm-alternative-coverage.h
@@ -0,0 +1,21 @@
+#ifndef AFL_NGRAM_CONFIG_H
+#define AFL_NGRAM_CONFIG_H
+
+#include "types.h"
+
+#if (MAP_SIZE_POW2 <= 16)
+typedef u16 PREV_LOC_T;
+#elif (MAP_SIZE_POW2 <= 32)
+typedef u32 PREV_LOC_T;
+#else
+typedef u64 PREV_LOC_T;
+#endif
+
+/* Maximum ngram size */
+#define NGRAM_SIZE_MAX 16U
+
+/* Maximum K for top-K context sensitivity */
+#define CTX_MAX_K 32U
+
+#endif
+
diff --git a/instrumentation/split-compares-pass.so.cc b/instrumentation/split-compares-pass.so.cc
new file mode 100644
index 00000000..d7bb7aba
--- /dev/null
+++ b/instrumentation/split-compares-pass.so.cc
@@ -0,0 +1,1654 @@
+/*
+ * Copyright 2016 laf-intel
+ * extended for floating point by Heiko Eißfeldt
+ * adapted to new pass manager by Heiko Eißfeldt
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <list>
+#include <string>
+#include <fstream>
+#include <sys/time.h>
+
+#include "llvm/Config/llvm-config.h"
+
+#include "llvm/Pass.h"
+#include "llvm/Support/raw_ostream.h"
+
+#if LLVM_MAJOR >= 11
+ #include "llvm/Passes/PassPlugin.h"
+ #include "llvm/Passes/PassBuilder.h"
+ #include "llvm/IR/PassManager.h"
+#else
+ #include "llvm/IR/LegacyPassManager.h"
+ #include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#endif
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/IR/Module.h"
+#if LLVM_VERSION_MAJOR >= 14 /* how about stable interfaces? */
+ #include "llvm/Passes/OptimizationLevel.h"
+#endif
+
+#include "llvm/IR/IRBuilder.h"
+#if LLVM_VERSION_MAJOR >= 4 || \
+ (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
+ #include "llvm/IR/Verifier.h"
+ #include "llvm/IR/DebugInfo.h"
+#else
+ #include "llvm/Analysis/Verifier.h"
+ #include "llvm/DebugInfo.h"
+ #define nullptr 0
+#endif
+
+using namespace llvm;
+#include "afl-llvm-common.h"
+
+// uncomment this toggle function verification at each step. horribly slow, but
+// helps to pinpoint a potential problem in the splitting code.
+//#define VERIFY_TOO_MUCH 1
+
+namespace {
+
+#if LLVM_MAJOR >= 11
+class SplitComparesTransform : public PassInfoMixin<SplitComparesTransform> {
+
+ public:
+ // static char ID;
+ SplitComparesTransform() : enableFPSplit(0) {
+
+#else
+class SplitComparesTransform : public ModulePass {
+
+ public:
+ static char ID;
+ SplitComparesTransform() : ModulePass(ID), enableFPSplit(0) {
+
+#endif
+
+ initInstrumentList();
+
+ }
+
+#if LLVM_MAJOR >= 11
+ PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
+#else
+ bool runOnModule(Module &M) override;
+#endif
+
+ private:
+ int enableFPSplit;
+
+ unsigned target_bitwidth = 8;
+
+ size_t count = 0;
+
+ size_t splitFPCompares(Module &M);
+ bool simplifyFPCompares(Module &M);
+ size_t nextPowerOfTwo(size_t in);
+
+ using CmpWorklist = SmallVector<CmpInst *, 8>;
+
+ /// simplify the comparison and then split the comparison until the
+ /// target_bitwidth is reached.
+ bool simplifyAndSplit(CmpInst *I, Module &M);
+ /// simplify a non-strict comparison (e.g., less than or equals)
+ bool simplifyOrEqualsCompare(CmpInst *IcmpInst, Module &M,
+ CmpWorklist &worklist);
+ /// simplify a signed comparison (signed less or greater than)
+ bool simplifySignedCompare(CmpInst *IcmpInst, Module &M,
+ CmpWorklist &worklist);
+ /// splits an icmp into nested icmps recursivly until target_bitwidth is
+ /// reached
+ bool splitCompare(CmpInst *I, Module &M, CmpWorklist &worklist);
+
+ /// print an error to llvm's errs stream, but only if not ordered to be quiet
+ void reportError(const StringRef msg, Instruction *I, Module &M) {
+
+ if (!be_quiet) {
+
+ errs() << "[AFL++ SplitComparesTransform] ERROR: " << msg << "\n";
+ if (debug) {
+
+ if (I) {
+
+ errs() << "Instruction = " << *I << "\n";
+ if (auto BB = I->getParent()) {
+
+ if (auto F = BB->getParent()) {
+
+ if (F->hasName()) {
+
+ errs() << "|-> in function " << F->getName() << " ";
+
+ }
+
+ }
+
+ }
+
+ }
+
+ auto n = M.getName();
+ if (n.size() > 0) { errs() << "in module " << n << "\n"; }
+
+ }
+
+ }
+
+ }
+
+ bool isSupportedBitWidth(unsigned bitw) {
+
+ // IDK whether the icmp code works on other bitwidths. I guess not? So we
+ // try to avoid dealing with other weird icmp's that llvm might use (looking
+ // at you `icmp i0`).
+ switch (bitw) {
+
+ case 8:
+ case 16:
+ case 32:
+ case 64:
+ case 128:
+ case 256:
+ return true;
+ default:
+ return false;
+
+ }
+
+ }
+
+};
+
+} // namespace
+
+#if LLVM_MAJOR >= 11
+extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
+llvmGetPassPluginInfo() {
+
+ return {LLVM_PLUGIN_API_VERSION, "splitcompares", "v0.1",
+ /* lambda to insert our pass into the pass pipeline. */
+ [](PassBuilder &PB) {
+
+ #if 1
+ #if LLVM_VERSION_MAJOR <= 13
+ using OptimizationLevel = typename PassBuilder::OptimizationLevel;
+ #endif
+ PB.registerOptimizerLastEPCallback(
+ [](ModulePassManager &MPM, OptimizationLevel OL) {
+
+ MPM.addPass(SplitComparesTransform());
+
+ });
+
+ /* TODO LTO registration */
+ #else
+ using PipelineElement = typename PassBuilder::PipelineElement;
+ PB.registerPipelineParsingCallback([](StringRef Name,
+ ModulePassManager &MPM,
+ ArrayRef<PipelineElement>) {
+
+ if (Name == "splitcompares") {
+
+ MPM.addPass(SplitComparesTransform());
+ return true;
+
+ } else {
+
+ return false;
+
+ }
+
+ });
+
+ #endif
+
+ }};
+
+}
+
+#else
+char SplitComparesTransform::ID = 0;
+#endif
+
+/// This function splits FCMP instructions with xGE or xLE predicates into two
+/// FCMP instructions with predicate xGT or xLT and EQ
+bool SplitComparesTransform::simplifyFPCompares(Module &M) {
+
+ LLVMContext & C = M.getContext();
+ std::vector<Instruction *> fcomps;
+ IntegerType * Int1Ty = IntegerType::getInt1Ty(C);
+
+ /* iterate over all functions, bbs and instruction and add
+ * all integer comparisons with >= and <= predicates to the icomps vector */
+ for (auto &F : M) {
+
+ if (!isInInstrumentList(&F, MNAME)) continue;
+
+ for (auto &BB : F) {
+
+ for (auto &IN : BB) {
+
+ CmpInst *selectcmpInst = nullptr;
+
+ if ((selectcmpInst = dyn_cast<CmpInst>(&IN))) {
+
+ if (enableFPSplit &&
+ (selectcmpInst->getPredicate() == CmpInst::FCMP_OGE ||
+ selectcmpInst->getPredicate() == CmpInst::FCMP_UGE ||
+ selectcmpInst->getPredicate() == CmpInst::FCMP_OLE ||
+ selectcmpInst->getPredicate() == CmpInst::FCMP_ULE)) {
+
+ auto op0 = selectcmpInst->getOperand(0);
+ auto op1 = selectcmpInst->getOperand(1);
+
+ Type *TyOp0 = op0->getType();
+ Type *TyOp1 = op1->getType();
+
+ /* this is probably not needed but we do it anyway */
+ if (TyOp0 != TyOp1) { continue; }
+
+ if (TyOp0->isArrayTy() || TyOp0->isVectorTy()) { continue; }
+
+ fcomps.push_back(selectcmpInst);
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ if (!fcomps.size()) { return false; }
+
+ /* transform for floating point */
+ for (auto &FcmpInst : fcomps) {
+
+ BasicBlock *bb = FcmpInst->getParent();
+
+ auto op0 = FcmpInst->getOperand(0);
+ auto op1 = FcmpInst->getOperand(1);
+
+ /* find out what the new predicate is going to be */
+ auto cmp_inst = dyn_cast<CmpInst>(FcmpInst);
+ if (!cmp_inst) { continue; }
+ auto pred = cmp_inst->getPredicate();
+ CmpInst::Predicate new_pred;
+
+ switch (pred) {
+
+ case CmpInst::FCMP_UGE:
+ new_pred = CmpInst::FCMP_UGT;
+ break;
+ case CmpInst::FCMP_OGE:
+ new_pred = CmpInst::FCMP_OGT;
+ break;
+ case CmpInst::FCMP_ULE:
+ new_pred = CmpInst::FCMP_ULT;
+ break;
+ case CmpInst::FCMP_OLE:
+ new_pred = CmpInst::FCMP_OLT;
+ break;
+ default: // keep the compiler happy
+ continue;
+
+ }
+
+ /* split before the fcmp instruction */
+ BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(FcmpInst));
+
+ /* the old bb now contains a unconditional jump to the new one (end_bb)
+ * we need to delete it later */
+
+ /* create the FCMP instruction with new_pred and add it to the old basic
+ * block bb it is now at the position where the old FcmpInst was */
+ Instruction *fcmp_np;
+ fcmp_np = CmpInst::Create(Instruction::FCmp, new_pred, op0, op1);
+ bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()),
+ fcmp_np);
+
+ /* create a new basic block which holds the new EQ fcmp */
+ Instruction *fcmp_eq;
+ /* insert middle_bb before end_bb */
+ BasicBlock *middle_bb =
+ BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb);
+ fcmp_eq = CmpInst::Create(Instruction::FCmp, CmpInst::FCMP_OEQ, op0, op1);
+ middle_bb->getInstList().push_back(fcmp_eq);
+ /* add an unconditional branch to the end of middle_bb with destination
+ * end_bb */
+ BranchInst::Create(end_bb, middle_bb);
+
+ /* replace the uncond branch with a conditional one, which depends on the
+ * new_pred fcmp. True goes to end, false to the middle (injected) bb */
+ auto term = bb->getTerminator();
+ BranchInst::Create(end_bb, middle_bb, fcmp_np, bb);
+ term->eraseFromParent();
+
+ /* replace the old FcmpInst (which is the first inst in end_bb) with a PHI
+ * inst to wire up the loose ends */
+ PHINode *PN = PHINode::Create(Int1Ty, 2, "");
+ /* the first result depends on the outcome of fcmp_eq */
+ PN->addIncoming(fcmp_eq, middle_bb);
+ /* if the source was the original bb we know that the fcmp_np yielded true
+ * hence we can hardcode this value */
+ PN->addIncoming(ConstantInt::get(Int1Ty, 1), bb);
+ /* replace the old FcmpInst with our new and shiny PHI inst */
+ BasicBlock::iterator ii(FcmpInst);
+ ReplaceInstWithInst(FcmpInst->getParent()->getInstList(), ii, PN);
+
+ }
+
+ return true;
+
+}
+
+/// This function splits ICMP instructions with xGE or xLE predicates into two
+/// ICMP instructions with predicate xGT or xLT and EQ
+bool SplitComparesTransform::simplifyOrEqualsCompare(CmpInst * IcmpInst,
+ Module & M,
+ CmpWorklist &worklist) {
+
+ LLVMContext &C = M.getContext();
+ IntegerType *Int1Ty = IntegerType::getInt1Ty(C);
+
+ /* find out what the new predicate is going to be */
+ auto cmp_inst = dyn_cast<CmpInst>(IcmpInst);
+ if (!cmp_inst) { return false; }
+
+ BasicBlock *bb = IcmpInst->getParent();
+
+ auto op0 = IcmpInst->getOperand(0);
+ auto op1 = IcmpInst->getOperand(1);
+
+ CmpInst::Predicate pred = cmp_inst->getPredicate();
+ CmpInst::Predicate new_pred;
+
+ switch (pred) {
+
+ case CmpInst::ICMP_UGE:
+ new_pred = CmpInst::ICMP_UGT;
+ break;
+ case CmpInst::ICMP_SGE:
+ new_pred = CmpInst::ICMP_SGT;
+ break;
+ case CmpInst::ICMP_ULE:
+ new_pred = CmpInst::ICMP_ULT;
+ break;
+ case CmpInst::ICMP_SLE:
+ new_pred = CmpInst::ICMP_SLT;
+ break;
+ default: // keep the compiler happy
+ return false;
+
+ }
+
+ /* split before the icmp instruction */
+ BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(IcmpInst));
+
+ /* the old bb now contains a unconditional jump to the new one (end_bb)
+ * we need to delete it later */
+
+ /* create the ICMP instruction with new_pred and add it to the old basic
+ * block bb it is now at the position where the old IcmpInst was */
+ CmpInst *icmp_np = CmpInst::Create(Instruction::ICmp, new_pred, op0, op1);
+ bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), icmp_np);
+
+ /* create a new basic block which holds the new EQ icmp */
+ CmpInst *icmp_eq;
+ /* insert middle_bb before end_bb */
+ BasicBlock *middle_bb =
+ BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb);
+ icmp_eq = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, op0, op1);
+ middle_bb->getInstList().push_back(icmp_eq);
+ /* add an unconditional branch to the end of middle_bb with destination
+ * end_bb */
+ BranchInst::Create(end_bb, middle_bb);
+
+ /* replace the uncond branch with a conditional one, which depends on the
+ * new_pred icmp. True goes to end, false to the middle (injected) bb */
+ auto term = bb->getTerminator();
+ BranchInst::Create(end_bb, middle_bb, icmp_np, bb);
+ term->eraseFromParent();
+
+ /* replace the old IcmpInst (which is the first inst in end_bb) with a PHI
+ * inst to wire up the loose ends */
+ PHINode *PN = PHINode::Create(Int1Ty, 2, "");
+ /* the first result depends on the outcome of icmp_eq */
+ PN->addIncoming(icmp_eq, middle_bb);
+ /* if the source was the original bb we know that the icmp_np yielded true
+ * hence we can hardcode this value */
+ PN->addIncoming(ConstantInt::get(Int1Ty, 1), bb);
+ /* replace the old IcmpInst with our new and shiny PHI inst */
+ BasicBlock::iterator ii(IcmpInst);
+ ReplaceInstWithInst(IcmpInst->getParent()->getInstList(), ii, PN);
+
+ worklist.push_back(icmp_np);
+ worklist.push_back(icmp_eq);
+
+ return true;
+
+}
+
+/// Simplify a signed comparison operator by splitting it into a unsigned and
+/// bit comparison. add all resulting comparisons to
+/// the worklist passed as a reference.
+bool SplitComparesTransform::simplifySignedCompare(CmpInst *IcmpInst, Module &M,
+ CmpWorklist &worklist) {
+
+ LLVMContext &C = M.getContext();
+ IntegerType *Int1Ty = IntegerType::getInt1Ty(C);
+
+ BasicBlock *bb = IcmpInst->getParent();
+
+ auto op0 = IcmpInst->getOperand(0);
+ auto op1 = IcmpInst->getOperand(1);
+
+ IntegerType *intTyOp0 = dyn_cast<IntegerType>(op0->getType());
+ if (!intTyOp0) { return false; }
+ unsigned bitw = intTyOp0->getBitWidth();
+ IntegerType *IntType = IntegerType::get(C, bitw);
+
+ /* get the new predicate */
+ auto cmp_inst = dyn_cast<CmpInst>(IcmpInst);
+ if (!cmp_inst) { return false; }
+ auto pred = cmp_inst->getPredicate();
+ CmpInst::Predicate new_pred;
+
+ if (pred == CmpInst::ICMP_SGT) {
+
+ new_pred = CmpInst::ICMP_UGT;
+
+ } else {
+
+ new_pred = CmpInst::ICMP_ULT;
+
+ }
+
+ BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(IcmpInst));
+
+ /* create a 1 bit compare for the sign bit. to do this shift and trunc
+ * the original operands so only the first bit remains.*/
+ Value *s_op0, *t_op0, *s_op1, *t_op1, *icmp_sign_bit;
+
+ IRBuilder<> IRB(bb->getTerminator());
+ s_op0 = IRB.CreateLShr(op0, ConstantInt::get(IntType, bitw - 1));
+ t_op0 = IRB.CreateTruncOrBitCast(s_op0, Int1Ty);
+ s_op1 = IRB.CreateLShr(op1, ConstantInt::get(IntType, bitw - 1));
+ t_op1 = IRB.CreateTruncOrBitCast(s_op1, Int1Ty);
+ /* compare of the sign bits */
+ icmp_sign_bit = IRB.CreateICmp(CmpInst::ICMP_EQ, t_op0, t_op1);
+
+ /* create a new basic block which is executed if the signedness bit is
+ * different */
+ CmpInst * icmp_inv_sig_cmp;
+ BasicBlock *sign_bb =
+ BasicBlock::Create(C, "sign", end_bb->getParent(), end_bb);
+ if (pred == CmpInst::ICMP_SGT) {
+
+ /* if we check for > and the op0 positive and op1 negative then the final
+ * result is true. if op0 negative and op1 pos, the cmp must result
+ * in false
+ */
+ icmp_inv_sig_cmp =
+ CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, t_op0, t_op1);
+
+ } else {
+
+ /* just the inverse of the above statement */
+ icmp_inv_sig_cmp =
+ CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, t_op0, t_op1);
+
+ }
+
+ sign_bb->getInstList().push_back(icmp_inv_sig_cmp);
+ BranchInst::Create(end_bb, sign_bb);
+
+ /* create a new bb which is executed if signedness is equal */
+ CmpInst * icmp_usign_cmp;
+ BasicBlock *middle_bb =
+ BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb);
+ /* we can do a normal unsigned compare now */
+ icmp_usign_cmp = CmpInst::Create(Instruction::ICmp, new_pred, op0, op1);
+
+ middle_bb->getInstList().push_back(icmp_usign_cmp);
+ BranchInst::Create(end_bb, middle_bb);
+
+ auto term = bb->getTerminator();
+ /* if the sign is eq do a normal unsigned cmp, else we have to check the
+ * signedness bit */
+ BranchInst::Create(middle_bb, sign_bb, icmp_sign_bit, bb);
+ term->eraseFromParent();
+
+ PHINode *PN = PHINode::Create(Int1Ty, 2, "");
+
+ PN->addIncoming(icmp_usign_cmp, middle_bb);
+ PN->addIncoming(icmp_inv_sig_cmp, sign_bb);
+
+ BasicBlock::iterator ii(IcmpInst);
+ ReplaceInstWithInst(IcmpInst->getParent()->getInstList(), ii, PN);
+
+ // save for later
+ worklist.push_back(icmp_usign_cmp);
+
+ // signed comparisons are not supported by the splitting code, so we must not
+ // add it to the worklist.
+ // worklist.push_back(icmp_inv_sig_cmp);
+
+ return true;
+
+}
+
+bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M,
+ CmpWorklist &worklist) {
+
+ auto pred = cmp_inst->getPredicate();
+ switch (pred) {
+
+ case CmpInst::ICMP_EQ:
+ case CmpInst::ICMP_NE:
+ case CmpInst::ICMP_UGT:
+ case CmpInst::ICMP_ULT:
+ break;
+ default:
+ // unsupported predicate!
+ return false;
+
+ }
+
+ auto op0 = cmp_inst->getOperand(0);
+ auto op1 = cmp_inst->getOperand(1);
+
+ // get bitwidth by checking the bitwidth of the first operator
+ IntegerType *intTyOp0 = dyn_cast<IntegerType>(op0->getType());
+ if (!intTyOp0) {
+
+ // not an integer type
+ return false;
+
+ }
+
+ unsigned bitw = intTyOp0->getBitWidth();
+ if (bitw == target_bitwidth) {
+
+ // already the target bitwidth so we have to do nothing here.
+ return true;
+
+ }
+
+ LLVMContext &C = M.getContext();
+ IntegerType *Int1Ty = IntegerType::getInt1Ty(C);
+ BasicBlock * bb = cmp_inst->getParent();
+ IntegerType *OldIntType = IntegerType::get(C, bitw);
+ IntegerType *NewIntType = IntegerType::get(C, bitw / 2);
+ BasicBlock * end_bb = bb->splitBasicBlock(BasicBlock::iterator(cmp_inst));
+ CmpInst * icmp_high, *icmp_low;
+
+ /* create the comparison of the top halves of the original operands */
+ Value *s_op0, *op0_high, *s_op1, *op1_high;
+
+ IRBuilder<> IRB(bb->getTerminator());
+
+ s_op0 = IRB.CreateBinOp(Instruction::LShr, op0,
+ ConstantInt::get(OldIntType, bitw / 2));
+ op0_high = IRB.CreateTruncOrBitCast(s_op0, NewIntType);
+
+ s_op1 = IRB.CreateBinOp(Instruction::LShr, op1,
+ ConstantInt::get(OldIntType, bitw / 2));
+ op1_high = IRB.CreateTruncOrBitCast(s_op1, NewIntType);
+ icmp_high = cast<CmpInst>(IRB.CreateICmp(pred, op0_high, op1_high));
+
+ PHINode *PN = nullptr;
+
+ /* now we have to destinguish between == != and > < */
+ switch (pred) {
+
+ case CmpInst::ICMP_EQ:
+ case CmpInst::ICMP_NE: {
+
+ /* transformation for == and != icmps */
+
+ /* create a compare for the lower half of the original operands */
+ BasicBlock *cmp_low_bb =
+ BasicBlock::Create(C, "" /*"injected"*/, end_bb->getParent(), end_bb);
+
+ Value * op0_low, *op1_low;
+ IRBuilder<> Builder(cmp_low_bb);
+
+ op0_low = Builder.CreateTrunc(op0, NewIntType);
+ op1_low = Builder.CreateTrunc(op1, NewIntType);
+ icmp_low = cast<CmpInst>(Builder.CreateICmp(pred, op0_low, op1_low));
+
+ BranchInst::Create(end_bb, cmp_low_bb);
+
+ /* dependent on the cmp of the high parts go to the end or go on with
+ * the comparison */
+ auto term = bb->getTerminator();
+
+ if (pred == CmpInst::ICMP_EQ) {
+
+ BranchInst::Create(cmp_low_bb, end_bb, icmp_high, bb);
+
+ } else {
+
+ // CmpInst::ICMP_NE
+ BranchInst::Create(end_bb, cmp_low_bb, icmp_high, bb);
+
+ }
+
+ term->eraseFromParent();
+
+ /* create the PHI and connect the edges accordingly */
+ PN = PHINode::Create(Int1Ty, 2, "");
+ PN->addIncoming(icmp_low, cmp_low_bb);
+ Value *val = nullptr;
+ if (pred == CmpInst::ICMP_EQ) {
+
+ val = ConstantInt::get(Int1Ty, 0);
+
+ } else {
+
+ /* CmpInst::ICMP_NE */
+ val = ConstantInt::get(Int1Ty, 1);
+
+ }
+
+ PN->addIncoming(val, icmp_high->getParent());
+ break;
+
+ }
+
+ case CmpInst::ICMP_UGT:
+ case CmpInst::ICMP_ULT: {
+
+ /* transformations for < and > */
+
+ /* create a basic block which checks for the inverse predicate.
+ * if this is true we can go to the end if not we have to go to the
+ * bb which checks the lower half of the operands */
+ Instruction *op0_low, *op1_low;
+ CmpInst * icmp_inv_cmp = nullptr;
+ BasicBlock * inv_cmp_bb =
+ BasicBlock::Create(C, "inv_cmp", end_bb->getParent(), end_bb);
+ if (pred == CmpInst::ICMP_UGT) {
+
+ icmp_inv_cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT,
+ op0_high, op1_high);
+
+ } else {
+
+ icmp_inv_cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT,
+ op0_high, op1_high);
+
+ }
+
+ inv_cmp_bb->getInstList().push_back(icmp_inv_cmp);
+ worklist.push_back(icmp_inv_cmp);
+
+ auto term = bb->getTerminator();
+ term->eraseFromParent();
+ BranchInst::Create(end_bb, inv_cmp_bb, icmp_high, bb);
+
+ /* create a bb which handles the cmp of the lower halves */
+ BasicBlock *cmp_low_bb =
+ BasicBlock::Create(C, "" /*"injected"*/, end_bb->getParent(), end_bb);
+ op0_low = new TruncInst(op0, NewIntType);
+ cmp_low_bb->getInstList().push_back(op0_low);
+ op1_low = new TruncInst(op1, NewIntType);
+ cmp_low_bb->getInstList().push_back(op1_low);
+
+ icmp_low = CmpInst::Create(Instruction::ICmp, pred, op0_low, op1_low);
+ cmp_low_bb->getInstList().push_back(icmp_low);
+ BranchInst::Create(end_bb, cmp_low_bb);
+
+ BranchInst::Create(end_bb, cmp_low_bb, icmp_inv_cmp, inv_cmp_bb);
+
+ PN = PHINode::Create(Int1Ty, 3);
+ PN->addIncoming(icmp_low, cmp_low_bb);
+ PN->addIncoming(ConstantInt::get(Int1Ty, 1), bb);
+ PN->addIncoming(ConstantInt::get(Int1Ty, 0), inv_cmp_bb);
+ break;
+
+ }
+
+ default:
+ return false;
+
+ }
+
+ BasicBlock::iterator ii(cmp_inst);
+ ReplaceInstWithInst(cmp_inst->getParent()->getInstList(), ii, PN);
+
+ // We split the comparison into low and high. If this isn't our target
+ // bitwidth we recursively split the low and high parts again until we have
+ // target bitwidth.
+ if ((bitw / 2) > target_bitwidth) {
+
+ worklist.push_back(icmp_high);
+ worklist.push_back(icmp_low);
+
+ }
+
+ return true;
+
+}
+
+bool SplitComparesTransform::simplifyAndSplit(CmpInst *I, Module &M) {
+
+ CmpWorklist worklist;
+
+ auto op0 = I->getOperand(0);
+ auto op1 = I->getOperand(1);
+ if (!op0 || !op1) { return false; }
+ auto op0Ty = dyn_cast<IntegerType>(op0->getType());
+ if (!op0Ty || !isa<IntegerType>(op1->getType())) { return true; }
+
+ unsigned bitw = op0Ty->getBitWidth();
+
+#ifdef VERIFY_TOO_MUCH
+ auto F = I->getParent()->getParent();
+#endif
+
+ // we run the comparison simplification on all compares regardless of their
+ // bitwidth.
+ if (I->getPredicate() == CmpInst::ICMP_UGE ||
+ I->getPredicate() == CmpInst::ICMP_SGE ||
+ I->getPredicate() == CmpInst::ICMP_ULE ||
+ I->getPredicate() == CmpInst::ICMP_SLE) {
+
+ if (!simplifyOrEqualsCompare(I, M, worklist)) {
+
+ reportError(
+ "Failed to simplify inequality or equals comparison "
+ "(UGE,SGE,ULE,SLE)",
+ I, M);
+
+ }
+
+ } else if (I->getPredicate() == CmpInst::ICMP_SGT ||
+
+ I->getPredicate() == CmpInst::ICMP_SLT) {
+
+ if (!simplifySignedCompare(I, M, worklist)) {
+
+ reportError("Failed to simplify signed comparison (SGT,SLT)", I, M);
+
+ }
+
+ }
+
+#ifdef VERIFY_TOO_MUCH
+ if (verifyFunction(*F, &errs())) {
+
+ reportError("simpliyfing compare lead to broken function", nullptr, M);
+
+ }
+
+#endif
+
+ // the simplification methods replace the original CmpInst and push the
+ // resulting new CmpInst into the worklist. If the worklist is empty then
+ // we only have to split the original CmpInst.
+ if (worklist.size() == 0) { worklist.push_back(I); }
+
+ while (!worklist.empty()) {
+
+ CmpInst *cmp = worklist.pop_back_val();
+ // we split the simplified compares into comparisons with smaller bitwidths
+ // if they are larger than our target_bitwidth.
+ if (bitw > target_bitwidth) {
+
+ if (!splitCompare(cmp, M, worklist)) {
+
+ reportError("Failed to split comparison", cmp, M);
+
+ }
+
+#ifdef VERIFY_TOO_MUCH
+ if (verifyFunction(*F, &errs())) {
+
+ reportError("splitting compare lead to broken function", nullptr, M);
+
+ }
+
+#endif
+
+ }
+
+ }
+
+ count++;
+ return true;
+
+}
+
+size_t SplitComparesTransform::nextPowerOfTwo(size_t in) {
+
+ --in;
+ in |= in >> 1;
+ in |= in >> 2;
+ in |= in >> 4;
+ // in |= in >> 8;
+ // in |= in >> 16;
+ return in + 1;
+
+}
+
+/* splits fcmps into two nested fcmps with sign compare and the rest */
+size_t SplitComparesTransform::splitFPCompares(Module &M) {
+
+ size_t count = 0;
+
+ LLVMContext &C = M.getContext();
+
+#if LLVM_VERSION_MAJOR >= 4 || \
+ (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 7)
+ const DataLayout &dl = M.getDataLayout();
+
+ /* define unions with floating point and (sign, exponent, mantissa) triples
+ */
+ if (dl.isLittleEndian()) {
+
+ } else if (dl.isBigEndian()) {
+
+ } else {
+
+ return count;
+
+ }
+
+#endif
+
+ std::vector<CmpInst *> fcomps;
+
+ /* get all EQ, NE, GT, and LT fcmps. if the other two
+ * functions were executed only these four predicates should exist */
+ for (auto &F : M) {
+
+ if (!isInInstrumentList(&F, MNAME)) continue;
+
+ for (auto &BB : F) {
+
+ for (auto &IN : BB) {
+
+ CmpInst *selectcmpInst = nullptr;
+
+ if ((selectcmpInst = dyn_cast<CmpInst>(&IN))) {
+
+ if (selectcmpInst->getPredicate() == CmpInst::FCMP_OEQ ||
+ selectcmpInst->getPredicate() == CmpInst::FCMP_UEQ ||
+ selectcmpInst->getPredicate() == CmpInst::FCMP_ONE ||
+ selectcmpInst->getPredicate() == CmpInst::FCMP_UNE ||
+ selectcmpInst->getPredicate() == CmpInst::FCMP_UGT ||
+ selectcmpInst->getPredicate() == CmpInst::FCMP_OGT ||
+ selectcmpInst->getPredicate() == CmpInst::FCMP_ULT ||
+ selectcmpInst->getPredicate() == CmpInst::FCMP_OLT) {
+
+ auto op0 = selectcmpInst->getOperand(0);
+ auto op1 = selectcmpInst->getOperand(1);
+
+ Type *TyOp0 = op0->getType();
+ Type *TyOp1 = op1->getType();
+
+ if (TyOp0 != TyOp1) { continue; }
+
+ if (TyOp0->isArrayTy() || TyOp0->isVectorTy()) { continue; }
+
+ fcomps.push_back(selectcmpInst);
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ if (!fcomps.size()) { return count; }
+
+ IntegerType *Int1Ty = IntegerType::getInt1Ty(C);
+
+ for (auto &FcmpInst : fcomps) {
+
+ BasicBlock *bb = FcmpInst->getParent();
+
+ auto op0 = FcmpInst->getOperand(0);
+ auto op1 = FcmpInst->getOperand(1);
+
+ unsigned op_size;
+ op_size = op0->getType()->getPrimitiveSizeInBits();
+
+ if (op_size != op1->getType()->getPrimitiveSizeInBits()) { continue; }
+
+ const unsigned int sizeInBits = op0->getType()->getPrimitiveSizeInBits();
+
+ // BUG FIXME TODO: u64 does not work for > 64 bit ... e.g. 80 and 128 bit
+ if (sizeInBits > 64) { continue; }
+
+ IntegerType * intType = IntegerType::get(C, op_size);
+ const unsigned int precision = sizeInBits == 32 ? 24
+ : sizeInBits == 64 ? 53
+ : sizeInBits == 128 ? 113
+ : sizeInBits == 16 ? 11
+ : sizeInBits == 80 ? 65
+ : sizeInBits - 8;
+
+ const unsigned shiftR_exponent = precision - 1;
+ const unsigned long long mask_fraction =
+ (1ULL << (shiftR_exponent - 1)) | ((1ULL << (shiftR_exponent - 1)) - 1);
+ const unsigned long long mask_exponent =
+ (1ULL << (sizeInBits - precision)) - 1;
+
+ // round up sizes to the next power of two
+ // this should help with integer compare splitting
+ size_t exTySizeBytes = ((sizeInBits - precision + 7) >> 3);
+ size_t frTySizeBytes = ((precision - 1ULL + 7) >> 3);
+
+ IntegerType *IntExponentTy =
+ IntegerType::get(C, nextPowerOfTwo(exTySizeBytes) << 3);
+ IntegerType *IntFractionTy =
+ IntegerType::get(C, nextPowerOfTwo(frTySizeBytes) << 3);
+
+ // errs() << "Fractions: IntFractionTy size " <<
+ // IntFractionTy->getPrimitiveSizeInBits() << ", op_size " << op_size <<
+ // ", mask " << mask_fraction <<
+ // ", precision " << precision << "\n";
+
+ BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(FcmpInst));
+
+ /* create the integers from floats directly */
+ Instruction *bpre_op0, *bpre_op1;
+ bpre_op0 = CastInst::Create(Instruction::BitCast, op0,
+ IntegerType::get(C, op_size));
+ bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()),
+ bpre_op0);
+
+ bpre_op1 = CastInst::Create(Instruction::BitCast, op1,
+ IntegerType::get(C, op_size));
+ bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()),
+ bpre_op1);
+
+ /* Check if any operand is NaN.
+ * If so, all comparisons except unequal (which yields true) yield false */
+
+ /* build mask for NaN */
+ const unsigned long long NaN_lowend = mask_exponent << precision;
+ // errs() << "Fractions: IntFractionTy size " <<
+ // IntFractionTy->getPrimitiveSizeInBits() << ", op_size " << op_size <<
+ // ", mask_fraction 0x";
+ // errs().write_hex(mask_fraction);
+ // errs() << ", precision " << precision <<
+ // ", NaN_lowend 0x";
+ // errs().write_hex(NaN_lowend); errs() << "\n";
+
+ /* Check op0 for NaN */
+ /* Shift left 1 Bit, ignore sign bit */
+ Instruction *nan_op0, *nan_op1;
+ nan_op0 = BinaryOperator::Create(Instruction::Shl, bpre_op0,
+ ConstantInt::get(bpre_op0->getType(), 1));
+ bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()),
+ nan_op0);
+
+ /* compare to NaN interval */
+ Instruction *is_op0_nan =
+ CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, nan_op0,
+ ConstantInt::get(intType, NaN_lowend));
+ bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()),
+ is_op0_nan);
+
+ /* Check op1 for NaN */
+ /* Shift right 1 Bit, ignore sign bit */
+ nan_op1 = BinaryOperator::Create(Instruction::Shl, bpre_op1,
+ ConstantInt::get(bpre_op1->getType(), 1));
+ bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()),
+ nan_op1);
+
+ /* compare to NaN interval */
+ Instruction *is_op1_nan =
+ CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, nan_op1,
+ ConstantInt::get(intType, NaN_lowend));
+ bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()),
+ is_op1_nan);
+
+ /* combine checks */
+ Instruction *is_nan =
+ BinaryOperator::Create(Instruction::Or, is_op0_nan, is_op1_nan);
+ bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), is_nan);
+
+ /* the result of the comparison, when at least one op is NaN
+ is true only for the "NOT EQUAL" predicates. */
+ bool NaNcmp_result = FcmpInst->getPredicate() == CmpInst::FCMP_ONE ||
+ FcmpInst->getPredicate() == CmpInst::FCMP_UNE;
+
+ BasicBlock *nonan_bb =
+ BasicBlock::Create(C, "noNaN", end_bb->getParent(), end_bb);
+
+ BranchInst::Create(end_bb, nonan_bb);
+
+ auto term = bb->getTerminator();
+ /* if no operand is NaN goto nonan_bb else to handleNaN_bb */
+ BranchInst::Create(end_bb, nonan_bb, is_nan, bb);
+ term->eraseFromParent();
+
+ /*** now working in nonan_bb ***/
+
+ /* Treat -0.0 as equal to +0.0, that is for -0.0 make it +0.0 */
+ Instruction * b_op0, *b_op1;
+ Instruction * isMzero_op0, *isMzero_op1;
+ const unsigned long long MinusZero = 1UL << (sizeInBits - 1U);
+ const unsigned long long PlusZero = 0;
+
+ isMzero_op0 = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, bpre_op0,
+ ConstantInt::get(intType, MinusZero));
+ nonan_bb->getInstList().insert(
+ BasicBlock::iterator(nonan_bb->getTerminator()), isMzero_op0);
+
+ isMzero_op1 = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, bpre_op1,
+ ConstantInt::get(intType, MinusZero));
+ nonan_bb->getInstList().insert(
+ BasicBlock::iterator(nonan_bb->getTerminator()), isMzero_op1);
+
+ b_op0 = SelectInst::Create(isMzero_op0, ConstantInt::get(intType, PlusZero),
+ bpre_op0);
+ nonan_bb->getInstList().insert(
+ BasicBlock::iterator(nonan_bb->getTerminator()), b_op0);
+
+ b_op1 = SelectInst::Create(isMzero_op1, ConstantInt::get(intType, PlusZero),
+ bpre_op1);
+ nonan_bb->getInstList().insert(
+ BasicBlock::iterator(nonan_bb->getTerminator()), b_op1);
+
+ /* isolate signs of value of floating point type */
+
+ /* create a 1 bit compare for the sign bit. to do this shift and trunc
+ * the original operands so only the first bit remains.*/
+ Instruction *s_s0, *t_s0, *s_s1, *t_s1, *icmp_sign_bit;
+
+ s_s0 =
+ BinaryOperator::Create(Instruction::LShr, b_op0,
+ ConstantInt::get(b_op0->getType(), op_size - 1));
+ nonan_bb->getInstList().insert(
+ BasicBlock::iterator(nonan_bb->getTerminator()), s_s0);
+ t_s0 = new TruncInst(s_s0, Int1Ty);
+ nonan_bb->getInstList().insert(
+ BasicBlock::iterator(nonan_bb->getTerminator()), t_s0);
+
+ s_s1 =
+ BinaryOperator::Create(Instruction::LShr, b_op1,
+ ConstantInt::get(b_op1->getType(), op_size - 1));
+ nonan_bb->getInstList().insert(
+ BasicBlock::iterator(nonan_bb->getTerminator()), s_s1);
+ t_s1 = new TruncInst(s_s1, Int1Ty);
+ nonan_bb->getInstList().insert(
+ BasicBlock::iterator(nonan_bb->getTerminator()), t_s1);
+
+ /* compare of the sign bits */
+ icmp_sign_bit =
+ CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, t_s0, t_s1);
+ nonan_bb->getInstList().insert(
+ BasicBlock::iterator(nonan_bb->getTerminator()), icmp_sign_bit);
+
+ /* create a new basic block which is executed if the signedness bits are
+ * equal */
+ BasicBlock *signequal_bb =
+ BasicBlock::Create(C, "signequal", end_bb->getParent(), end_bb);
+
+ BranchInst::Create(end_bb, signequal_bb);
+
+ /* create a new bb which is executed if exponents are satisfying the compare
+ */
+ BasicBlock *middle_bb =
+ BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb);
+
+ BranchInst::Create(end_bb, middle_bb);
+
+ term = nonan_bb->getTerminator();
+ /* if the signs are different goto end_bb else to signequal_bb */
+ BranchInst::Create(signequal_bb, end_bb, icmp_sign_bit, nonan_bb);
+ term->eraseFromParent();
+
+ /* insert code for equal signs */
+
+ /* isolate the exponents */
+ Instruction *s_e0, *m_e0, *t_e0, *s_e1, *m_e1, *t_e1;
+
+ s_e0 = BinaryOperator::Create(
+ Instruction::LShr, b_op0,
+ ConstantInt::get(b_op0->getType(), shiftR_exponent));
+ s_e1 = BinaryOperator::Create(
+ Instruction::LShr, b_op1,
+ ConstantInt::get(b_op1->getType(), shiftR_exponent));
+ signequal_bb->getInstList().insert(
+ BasicBlock::iterator(signequal_bb->getTerminator()), s_e0);
+ signequal_bb->getInstList().insert(
+ BasicBlock::iterator(signequal_bb->getTerminator()), s_e1);
+
+ t_e0 = new TruncInst(s_e0, IntExponentTy);
+ t_e1 = new TruncInst(s_e1, IntExponentTy);
+ signequal_bb->getInstList().insert(
+ BasicBlock::iterator(signequal_bb->getTerminator()), t_e0);
+ signequal_bb->getInstList().insert(
+ BasicBlock::iterator(signequal_bb->getTerminator()), t_e1);
+
+ if (sizeInBits - precision < exTySizeBytes * 8) {
+
+ m_e0 = BinaryOperator::Create(
+ Instruction::And, t_e0,
+ ConstantInt::get(t_e0->getType(), mask_exponent));
+ m_e1 = BinaryOperator::Create(
+ Instruction::And, t_e1,
+ ConstantInt::get(t_e1->getType(), mask_exponent));
+ signequal_bb->getInstList().insert(
+ BasicBlock::iterator(signequal_bb->getTerminator()), m_e0);
+ signequal_bb->getInstList().insert(
+ BasicBlock::iterator(signequal_bb->getTerminator()), m_e1);
+
+ } else {
+
+ m_e0 = t_e0;
+ m_e1 = t_e1;
+
+ }
+
+ /* compare the exponents of the operands */
+ Instruction *icmp_exponents_equal;
+ Instruction *icmp_exponent_result;
+ BasicBlock * signequal2_bb = signequal_bb;
+ switch (FcmpInst->getPredicate()) {
+
+ case CmpInst::FCMP_UEQ:
+ case CmpInst::FCMP_OEQ:
+ icmp_exponent_result =
+ CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, m_e0, m_e1);
+ break;
+ case CmpInst::FCMP_ONE:
+ case CmpInst::FCMP_UNE:
+ icmp_exponent_result =
+ CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_NE, m_e0, m_e1);
+ break;
+ /* compare the exponents of the operands (signs are equal)
+ * if exponents are equal -> proceed to mantissa comparison
+ * else get result depending on sign
+ */
+ case CmpInst::FCMP_OGT:
+ case CmpInst::FCMP_UGT:
+ Instruction *icmp_exponent;
+ icmp_exponents_equal =
+ CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, m_e0, m_e1);
+ signequal_bb->getInstList().insert(
+ BasicBlock::iterator(signequal_bb->getTerminator()),
+ icmp_exponents_equal);
+
+ // shortcut for unequal exponents
+ signequal2_bb = signequal_bb->splitBasicBlock(
+ BasicBlock::iterator(signequal_bb->getTerminator()));
+
+ /* if the exponents are equal goto middle_bb else to signequal2_bb */
+ term = signequal_bb->getTerminator();
+ BranchInst::Create(middle_bb, signequal2_bb, icmp_exponents_equal,
+ signequal_bb);
+ term->eraseFromParent();
+
+ icmp_exponent =
+ CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, m_e0, m_e1);
+ signequal2_bb->getInstList().insert(
+ BasicBlock::iterator(signequal2_bb->getTerminator()),
+ icmp_exponent);
+ icmp_exponent_result =
+ BinaryOperator::Create(Instruction::Xor, icmp_exponent, t_s0);
+ break;
+ case CmpInst::FCMP_OLT:
+ case CmpInst::FCMP_ULT:
+ icmp_exponents_equal =
+ CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, m_e0, m_e1);
+ signequal_bb->getInstList().insert(
+ BasicBlock::iterator(signequal_bb->getTerminator()),
+ icmp_exponents_equal);
+
+ // shortcut for unequal exponents
+ signequal2_bb = signequal_bb->splitBasicBlock(
+ BasicBlock::iterator(signequal_bb->getTerminator()));
+
+ /* if the exponents are equal goto middle_bb else to signequal2_bb */
+ term = signequal_bb->getTerminator();
+ BranchInst::Create(middle_bb, signequal2_bb, icmp_exponents_equal,
+ signequal_bb);
+ term->eraseFromParent();
+
+ icmp_exponent =
+ CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, m_e0, m_e1);
+ signequal2_bb->getInstList().insert(
+ BasicBlock::iterator(signequal2_bb->getTerminator()),
+ icmp_exponent);
+ icmp_exponent_result =
+ BinaryOperator::Create(Instruction::Xor, icmp_exponent, t_s0);
+ break;
+ default:
+ continue;
+
+ }
+
+ signequal2_bb->getInstList().insert(
+ BasicBlock::iterator(signequal2_bb->getTerminator()),
+ icmp_exponent_result);
+
+ {
+
+ term = signequal2_bb->getTerminator();
+
+ switch (FcmpInst->getPredicate()) {
+
+ case CmpInst::FCMP_UEQ:
+ case CmpInst::FCMP_OEQ:
+ /* if the exponents are satifying the compare do a fraction cmp in
+ * middle_bb */
+ BranchInst::Create(middle_bb, end_bb, icmp_exponent_result,
+ signequal2_bb);
+ break;
+ case CmpInst::FCMP_ONE:
+ case CmpInst::FCMP_UNE:
+ /* if the exponents are satifying the compare do a fraction cmp in
+ * middle_bb */
+ BranchInst::Create(end_bb, middle_bb, icmp_exponent_result,
+ signequal2_bb);
+ break;
+ case CmpInst::FCMP_OGT:
+ case CmpInst::FCMP_UGT:
+ case CmpInst::FCMP_OLT:
+ case CmpInst::FCMP_ULT:
+ BranchInst::Create(end_bb, signequal2_bb);
+ break;
+ default:
+ continue;
+
+ }
+
+ term->eraseFromParent();
+
+ }
+
+ /* isolate the mantissa aka fraction */
+ Instruction *t_f0, *t_f1;
+ bool needTrunc = IntFractionTy->getPrimitiveSizeInBits() < op_size;
+
+ if (precision - 1 < frTySizeBytes * 8) {
+
+ Instruction *m_f0, *m_f1;
+ m_f0 = BinaryOperator::Create(
+ Instruction::And, b_op0,
+ ConstantInt::get(b_op0->getType(), mask_fraction));
+ m_f1 = BinaryOperator::Create(
+ Instruction::And, b_op1,
+ ConstantInt::get(b_op1->getType(), mask_fraction));
+ middle_bb->getInstList().insert(
+ BasicBlock::iterator(middle_bb->getTerminator()), m_f0);
+ middle_bb->getInstList().insert(
+ BasicBlock::iterator(middle_bb->getTerminator()), m_f1);
+
+ if (needTrunc) {
+
+ t_f0 = new TruncInst(m_f0, IntFractionTy);
+ t_f1 = new TruncInst(m_f1, IntFractionTy);
+ middle_bb->getInstList().insert(
+ BasicBlock::iterator(middle_bb->getTerminator()), t_f0);
+ middle_bb->getInstList().insert(
+ BasicBlock::iterator(middle_bb->getTerminator()), t_f1);
+
+ } else {
+
+ t_f0 = m_f0;
+ t_f1 = m_f1;
+
+ }
+
+ } else {
+
+ if (needTrunc) {
+
+ t_f0 = new TruncInst(b_op0, IntFractionTy);
+ t_f1 = new TruncInst(b_op1, IntFractionTy);
+ middle_bb->getInstList().insert(
+ BasicBlock::iterator(middle_bb->getTerminator()), t_f0);
+ middle_bb->getInstList().insert(
+ BasicBlock::iterator(middle_bb->getTerminator()), t_f1);
+
+ } else {
+
+ t_f0 = b_op0;
+ t_f1 = b_op1;
+
+ }
+
+ }
+
+ /* compare the fractions of the operands */
+ Instruction *icmp_fraction_result;
+ BasicBlock * middle2_bb = middle_bb;
+ PHINode * PN2 = nullptr;
+ switch (FcmpInst->getPredicate()) {
+
+ case CmpInst::FCMP_UEQ:
+ case CmpInst::FCMP_OEQ:
+ icmp_fraction_result =
+ CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, t_f0, t_f1);
+ middle2_bb->getInstList().insert(
+ BasicBlock::iterator(middle2_bb->getTerminator()),
+ icmp_fraction_result);
+
+ break;
+ case CmpInst::FCMP_UNE:
+ case CmpInst::FCMP_ONE:
+ icmp_fraction_result =
+ CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_NE, t_f0, t_f1);
+ middle2_bb->getInstList().insert(
+ BasicBlock::iterator(middle2_bb->getTerminator()),
+ icmp_fraction_result);
+
+ break;
+ case CmpInst::FCMP_OGT:
+ case CmpInst::FCMP_UGT:
+ case CmpInst::FCMP_OLT:
+ case CmpInst::FCMP_ULT: {
+
+ Instruction *icmp_fraction_result2;
+
+ middle2_bb = middle_bb->splitBasicBlock(
+ BasicBlock::iterator(middle_bb->getTerminator()));
+
+ BasicBlock *negative_bb = BasicBlock::Create(
+ C, "negative_value", middle2_bb->getParent(), middle2_bb);
+ BasicBlock *positive_bb = BasicBlock::Create(
+ C, "positive_value", negative_bb->getParent(), negative_bb);
+
+ if (FcmpInst->getPredicate() == CmpInst::FCMP_OGT ||
+ FcmpInst->getPredicate() == CmpInst::FCMP_UGT) {
+
+ negative_bb->getInstList().push_back(
+ icmp_fraction_result = CmpInst::Create(
+ Instruction::ICmp, CmpInst::ICMP_ULT, t_f0, t_f1));
+ positive_bb->getInstList().push_back(
+ icmp_fraction_result2 = CmpInst::Create(
+ Instruction::ICmp, CmpInst::ICMP_UGT, t_f0, t_f1));
+
+ } else {
+
+ negative_bb->getInstList().push_back(
+ icmp_fraction_result = CmpInst::Create(
+ Instruction::ICmp, CmpInst::ICMP_UGT, t_f0, t_f1));
+ positive_bb->getInstList().push_back(
+ icmp_fraction_result2 = CmpInst::Create(
+ Instruction::ICmp, CmpInst::ICMP_ULT, t_f0, t_f1));
+
+ }
+
+ BranchInst::Create(middle2_bb, negative_bb);
+ BranchInst::Create(middle2_bb, positive_bb);
+
+ term = middle_bb->getTerminator();
+ BranchInst::Create(negative_bb, positive_bb, t_s0, middle_bb);
+ term->eraseFromParent();
+
+ PN2 = PHINode::Create(Int1Ty, 2, "");
+ PN2->addIncoming(icmp_fraction_result, negative_bb);
+ PN2->addIncoming(icmp_fraction_result2, positive_bb);
+ middle2_bb->getInstList().insert(
+ BasicBlock::iterator(middle2_bb->getTerminator()), PN2);
+
+ } break;
+
+ default:
+ continue;
+
+ }
+
+ PHINode *PN = PHINode::Create(Int1Ty, 4, "");
+
+ switch (FcmpInst->getPredicate()) {
+
+ case CmpInst::FCMP_UEQ:
+ case CmpInst::FCMP_OEQ:
+ /* unequal signs cannot be equal values */
+ /* goto false branch */
+ PN->addIncoming(ConstantInt::get(Int1Ty, 0), nonan_bb);
+ /* unequal exponents cannot be equal values, too */
+ PN->addIncoming(ConstantInt::get(Int1Ty, 0), signequal_bb);
+ /* fractions comparison */
+ PN->addIncoming(icmp_fraction_result, middle2_bb);
+ /* NaNs */
+ PN->addIncoming(ConstantInt::get(Int1Ty, NaNcmp_result), bb);
+ break;
+ case CmpInst::FCMP_ONE:
+ case CmpInst::FCMP_UNE:
+ /* unequal signs are unequal values */
+ /* goto true branch */
+ PN->addIncoming(ConstantInt::get(Int1Ty, 1), nonan_bb);
+ /* unequal exponents are unequal values, too */
+ PN->addIncoming(icmp_exponent_result, signequal_bb);
+ /* fractions comparison */
+ PN->addIncoming(icmp_fraction_result, middle2_bb);
+ /* NaNs */
+ PN->addIncoming(ConstantInt::get(Int1Ty, NaNcmp_result), bb);
+ break;
+ case CmpInst::FCMP_OGT:
+ case CmpInst::FCMP_UGT:
+ /* if op1 is negative goto true branch,
+ else go on comparing */
+ PN->addIncoming(t_s1, nonan_bb);
+ PN->addIncoming(icmp_exponent_result, signequal2_bb);
+ PN->addIncoming(PN2, middle2_bb);
+ /* NaNs */
+ PN->addIncoming(ConstantInt::get(Int1Ty, NaNcmp_result), bb);
+ break;
+ case CmpInst::FCMP_OLT:
+ case CmpInst::FCMP_ULT:
+ /* if op0 is negative goto true branch,
+ else go on comparing */
+ PN->addIncoming(t_s0, nonan_bb);
+ PN->addIncoming(icmp_exponent_result, signequal2_bb);
+ PN->addIncoming(PN2, middle2_bb);
+ /* NaNs */
+ PN->addIncoming(ConstantInt::get(Int1Ty, NaNcmp_result), bb);
+ break;
+ default:
+ continue;
+
+ }
+
+ BasicBlock::iterator ii(FcmpInst);
+ ReplaceInstWithInst(FcmpInst->getParent()->getInstList(), ii, PN);
+ ++count;
+
+ }
+
+ return count;
+
+}
+
+#if LLVM_MAJOR >= 11
+PreservedAnalyses SplitComparesTransform::run(Module & M,
+ ModuleAnalysisManager &MAM) {
+
+#else
+bool SplitComparesTransform::runOnModule(Module &M) {
+
+#endif
+
+ char *bitw_env = getenv("AFL_LLVM_LAF_SPLIT_COMPARES_BITW");
+ if (!bitw_env) bitw_env = getenv("LAF_SPLIT_COMPARES_BITW");
+ if (bitw_env) { target_bitwidth = atoi(bitw_env); }
+
+ enableFPSplit = getenv("AFL_LLVM_LAF_SPLIT_FLOATS") != NULL;
+
+ if ((isatty(2) && getenv("AFL_QUIET") == NULL) ||
+ getenv("AFL_DEBUG") != NULL) {
+
+ errs() << "Split-compare-newpass by laf.intel@gmail.com, extended by "
+ "heiko@hexco.de (splitting icmp to "
+ << target_bitwidth << " bit)\n";
+
+ if (getenv("AFL_DEBUG") != NULL && !debug) { debug = 1; }
+
+ } else {
+
+ be_quiet = 1;
+
+ }
+
+#if LLVM_MAJOR >= 11
+ auto PA = PreservedAnalyses::all();
+#endif
+
+ if (enableFPSplit) {
+
+ simplifyFPCompares(M);
+ count = splitFPCompares(M);
+
+ if (!be_quiet && !debug) {
+
+ errs() << "Split-floatingpoint-compare-pass: " << count
+ << " FP comparisons splitted\n";
+
+ }
+
+ }
+
+ std::vector<CmpInst *> worklist;
+ /* iterate over all functions, bbs and instruction search for all integer
+ * compare instructions. Save them into the worklist for later. */
+ for (auto &F : M) {
+
+ if (!isInInstrumentList(&F, MNAME)) continue;
+
+ for (auto &BB : F) {
+
+ for (auto &IN : BB) {
+
+ if (auto CI = dyn_cast<CmpInst>(&IN)) {
+
+ auto op0 = CI->getOperand(0);
+ auto op1 = CI->getOperand(1);
+ if (!op0 || !op1) {
+
+#if LLVM_MAJOR >= 11
+ return PA;
+#else
+ return false;
+#endif
+
+ }
+
+ auto iTy1 = dyn_cast<IntegerType>(op0->getType());
+ if (iTy1 && isa<IntegerType>(op1->getType())) {
+
+ unsigned bitw = iTy1->getBitWidth();
+ if (isSupportedBitWidth(bitw)) { worklist.push_back(CI); }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ // now that we have a list of all integer comparisons we can start replacing
+ // them with the splitted alternatives.
+ for (auto CI : worklist) {
+
+ simplifyAndSplit(CI, M);
+
+ }
+
+ bool brokenDebug = false;
+ if (verifyModule(M, &errs()
+#if LLVM_VERSION_MAJOR >= 4 || \
+ (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 9)
+ ,
+ &brokenDebug // 9th May 2016
+#endif
+ )) {
+
+ reportError(
+ "Module Verifier failed! Consider reporting a bug with the AFL++ "
+ "project.",
+ nullptr, M);
+
+ }
+
+ if (brokenDebug) {
+
+ reportError("Module Verifier reported broken Debug Infos - Stripping!",
+ nullptr, M);
+ StripDebugInfo(M);
+
+ }
+
+ if ((isatty(2) && getenv("AFL_QUIET") == NULL) ||
+ getenv("AFL_DEBUG") != NULL) {
+
+ errs() << count << " comparisons found\n";
+
+ }
+
+#if LLVM_MAJOR >= 11
+ /* if (modified) {
+
+ PA.abandon<XX_Manager>();
+
+ }*/
+
+ return PA;
+#else
+ return true;
+#endif
+
+}
+
+#if LLVM_MAJOR < 11 /* use old pass manager */
+
+static void registerSplitComparesPass(const PassManagerBuilder &,
+ legacy::PassManagerBase &PM) {
+
+ PM.add(new SplitComparesTransform());
+
+}
+
+static RegisterStandardPasses RegisterSplitComparesPass(
+ PassManagerBuilder::EP_OptimizerLast, registerSplitComparesPass);
+
+static RegisterStandardPasses RegisterSplitComparesTransPass0(
+ PassManagerBuilder::EP_EnabledOnOptLevel0, registerSplitComparesPass);
+
+ #if LLVM_VERSION_MAJOR >= 11
+static RegisterStandardPasses RegisterSplitComparesTransPassLTO(
+ PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
+ registerSplitComparesPass);
+ #endif
+
+static RegisterPass<SplitComparesTransform> X("splitcompares",
+ "AFL++ split compares",
+ true /* Only looks at CFG */,
+ true /* Analysis Pass */);
+#endif
+
diff --git a/instrumentation/split-switches-pass.so.cc b/instrumentation/split-switches-pass.so.cc
new file mode 100644
index 00000000..96e01a8b
--- /dev/null
+++ b/instrumentation/split-switches-pass.so.cc
@@ -0,0 +1,541 @@
+/*
+ * Copyright 2016 laf-intel
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <list>
+#include <string>
+#include <fstream>
+#include <sys/time.h>
+
+#include "llvm/Config/llvm-config.h"
+
+#include "llvm/ADT/Statistic.h"
+#include "llvm/IR/IRBuilder.h"
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+ #include "llvm/Passes/PassPlugin.h"
+ #include "llvm/Passes/PassBuilder.h"
+ #include "llvm/IR/PassManager.h"
+#else
+ #include "llvm/IR/LegacyPassManager.h"
+ #include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#endif
+#include "llvm/IR/Module.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Pass.h"
+#include "llvm/Analysis/ValueTracking.h"
+#if LLVM_VERSION_MAJOR >= 14 /* how about stable interfaces? */
+ #include "llvm/Passes/OptimizationLevel.h"
+#endif
+
+#include "llvm/IR/IRBuilder.h"
+#if LLVM_VERSION_MAJOR >= 4 || \
+ (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
+ #include "llvm/IR/Verifier.h"
+ #include "llvm/IR/DebugInfo.h"
+#else
+ #include "llvm/Analysis/Verifier.h"
+ #include "llvm/DebugInfo.h"
+ #define nullptr 0
+#endif
+
+#include <set>
+#include "afl-llvm-common.h"
+
+using namespace llvm;
+
+namespace {
+
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+class SplitSwitchesTransform : public PassInfoMixin<SplitSwitchesTransform> {
+
+ public:
+ SplitSwitchesTransform() {
+
+#else
+class SplitSwitchesTransform : public ModulePass {
+
+ public:
+ static char ID;
+ SplitSwitchesTransform() : ModulePass(ID) {
+
+#endif
+ initInstrumentList();
+
+ }
+
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+ PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
+#else
+ bool runOnModule(Module &M) override;
+
+ #if LLVM_VERSION_MAJOR >= 4
+ StringRef getPassName() const override {
+
+ #else
+ const char *getPassName() const override {
+
+ #endif
+ return "splits switch constructs";
+
+ }
+
+#endif
+
+ struct CaseExpr {
+
+ ConstantInt *Val;
+ BasicBlock * BB;
+
+ CaseExpr(ConstantInt *val = nullptr, BasicBlock *bb = nullptr)
+ : Val(val), BB(bb) {
+
+ }
+
+ };
+
+ using CaseVector = std::vector<CaseExpr>;
+
+ private:
+ bool splitSwitches(Module &M);
+ bool transformCmps(Module &M, const bool processStrcmp,
+ const bool processMemcmp);
+ BasicBlock *switchConvert(CaseVector Cases, std::vector<bool> bytesChecked,
+ BasicBlock *OrigBlock, BasicBlock *NewDefault,
+ Value *Val, unsigned level);
+
+};
+
+} // namespace
+
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
+llvmGetPassPluginInfo() {
+
+ return {LLVM_PLUGIN_API_VERSION, "splitswitches", "v0.1",
+ /* lambda to insert our pass into the pass pipeline. */
+ [](PassBuilder &PB) {
+
+ #if 1
+ #if LLVM_VERSION_MAJOR <= 13
+ using OptimizationLevel = typename PassBuilder::OptimizationLevel;
+ #endif
+ PB.registerOptimizerLastEPCallback(
+ [](ModulePassManager &MPM, OptimizationLevel OL) {
+
+ MPM.addPass(SplitSwitchesTransform());
+
+ });
+
+ /* TODO LTO registration */
+ #else
+ using PipelineElement = typename PassBuilder::PipelineElement;
+ PB.registerPipelineParsingCallback([](StringRef Name,
+ ModulePassManager &MPM,
+ ArrayRef<PipelineElement>) {
+
+ if (Name == "splitswitches") {
+
+ MPM.addPass(SplitSwitchesTransform());
+ return true;
+
+ } else {
+
+ return false;
+
+ }
+
+ });
+
+ #endif
+
+ }};
+
+}
+
+#else
+char SplitSwitchesTransform::ID = 0;
+#endif
+
+/* switchConvert - Transform simple list of Cases into list of CaseRange's */
+BasicBlock *SplitSwitchesTransform::switchConvert(
+ CaseVector Cases, std::vector<bool> bytesChecked, BasicBlock *OrigBlock,
+ BasicBlock *NewDefault, Value *Val, unsigned level) {
+
+ unsigned ValTypeBitWidth = Cases[0].Val->getBitWidth();
+ IntegerType *ValType =
+ IntegerType::get(OrigBlock->getContext(), ValTypeBitWidth);
+ IntegerType * ByteType = IntegerType::get(OrigBlock->getContext(), 8);
+ unsigned BytesInValue = bytesChecked.size();
+ std::vector<uint8_t> setSizes;
+ std::vector<std::set<uint8_t> > byteSets(BytesInValue, std::set<uint8_t>());
+
+ /* for each of the possible cases we iterate over all bytes of the values
+ * build a set of possible values at each byte position in byteSets */
+ for (CaseExpr &Case : Cases) {
+
+ for (unsigned i = 0; i < BytesInValue; i++) {
+
+ uint8_t byte = (Case.Val->getZExtValue() >> (i * 8)) & 0xFF;
+ byteSets[i].insert(byte);
+
+ }
+
+ }
+
+ /* find the index of the first byte position that was not yet checked. then
+ * save the number of possible values at that byte position */
+ unsigned smallestIndex = 0;
+ unsigned smallestSize = 257;
+ for (unsigned i = 0; i < byteSets.size(); i++) {
+
+ if (bytesChecked[i]) continue;
+ if (byteSets[i].size() < smallestSize) {
+
+ smallestIndex = i;
+ smallestSize = byteSets[i].size();
+
+ }
+
+ }
+
+ assert(bytesChecked[smallestIndex] == false);
+
+ /* there are only smallestSize different bytes at index smallestIndex */
+
+ Instruction *Shift, *Trunc;
+ Function * F = OrigBlock->getParent();
+ BasicBlock * NewNode = BasicBlock::Create(Val->getContext(), "NodeBlock", F);
+ Shift = BinaryOperator::Create(Instruction::LShr, Val,
+ ConstantInt::get(ValType, smallestIndex * 8));
+ NewNode->getInstList().push_back(Shift);
+
+ if (ValTypeBitWidth > 8) {
+
+ Trunc = new TruncInst(Shift, ByteType);
+ NewNode->getInstList().push_back(Trunc);
+
+ } else {
+
+ /* not necessary to trunc */
+ Trunc = Shift;
+
+ }
+
+ /* this is a trivial case, we can directly check for the byte,
+ * if the byte is not found go to default. if the byte was found
+ * mark the byte as checked. if this was the last byte to check
+ * we can finally execute the block belonging to this case */
+
+ if (smallestSize == 1) {
+
+ uint8_t byte = *(byteSets[smallestIndex].begin());
+
+ /* insert instructions to check whether the value we are switching on is
+ * equal to byte */
+ ICmpInst *Comp =
+ new ICmpInst(ICmpInst::ICMP_EQ, Trunc, ConstantInt::get(ByteType, byte),
+ "byteMatch");
+ NewNode->getInstList().push_back(Comp);
+
+ bytesChecked[smallestIndex] = true;
+ bool allBytesAreChecked = true;
+
+ for (std::vector<bool>::iterator BCI = bytesChecked.begin(),
+ E = bytesChecked.end();
+ BCI != E; ++BCI) {
+
+ if (!*BCI) {
+
+ allBytesAreChecked = false;
+ break;
+
+ }
+
+ }
+
+ // if (std::all_of(bytesChecked.begin(), bytesChecked.end(),
+ // [](bool b) { return b; })) {
+
+ if (allBytesAreChecked) {
+
+ assert(Cases.size() == 1);
+ BranchInst::Create(Cases[0].BB, NewDefault, Comp, NewNode);
+
+ /* we have to update the phi nodes! */
+ for (BasicBlock::iterator I = Cases[0].BB->begin();
+ I != Cases[0].BB->end(); ++I) {
+
+ if (!isa<PHINode>(&*I)) { continue; }
+ PHINode *PN = cast<PHINode>(I);
+
+ /* Only update the first occurrence. */
+ unsigned Idx = 0, E = PN->getNumIncomingValues();
+ for (; Idx != E; ++Idx) {
+
+ if (PN->getIncomingBlock(Idx) == OrigBlock) {
+
+ PN->setIncomingBlock(Idx, NewNode);
+ break;
+
+ }
+
+ }
+
+ }
+
+ } else {
+
+ BasicBlock *BB = switchConvert(Cases, bytesChecked, OrigBlock, NewDefault,
+ Val, level + 1);
+ BranchInst::Create(BB, NewDefault, Comp, NewNode);
+
+ }
+
+ }
+
+ /* there is no byte which we can directly check on, split the tree */
+ else {
+
+ std::vector<uint8_t> byteVector;
+ std::copy(byteSets[smallestIndex].begin(), byteSets[smallestIndex].end(),
+ std::back_inserter(byteVector));
+ std::sort(byteVector.begin(), byteVector.end());
+ uint8_t pivot = byteVector[byteVector.size() / 2];
+
+ /* we already chose to divide the cases based on the value of byte at index
+ * smallestIndex the pivot value determines the threshold for the decicion;
+ * if a case value
+ * is smaller at this byte index move it to the LHS vector, otherwise to the
+ * RHS vector */
+
+ CaseVector LHSCases, RHSCases;
+
+ for (CaseExpr &Case : Cases) {
+
+ uint8_t byte = (Case.Val->getZExtValue() >> (smallestIndex * 8)) & 0xFF;
+
+ if (byte < pivot) {
+
+ LHSCases.push_back(Case);
+
+ } else {
+
+ RHSCases.push_back(Case);
+
+ }
+
+ }
+
+ BasicBlock *LBB, *RBB;
+ LBB = switchConvert(LHSCases, bytesChecked, OrigBlock, NewDefault, Val,
+ level + 1);
+ RBB = switchConvert(RHSCases, bytesChecked, OrigBlock, NewDefault, Val,
+ level + 1);
+
+ /* insert instructions to check whether the value we are switching on is
+ * equal to byte */
+ ICmpInst *Comp =
+ new ICmpInst(ICmpInst::ICMP_ULT, Trunc,
+ ConstantInt::get(ByteType, pivot), "byteMatch");
+ NewNode->getInstList().push_back(Comp);
+ BranchInst::Create(LBB, RBB, Comp, NewNode);
+
+ }
+
+ return NewNode;
+
+}
+
+bool SplitSwitchesTransform::splitSwitches(Module &M) {
+
+#if (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 7)
+ LLVMContext &C = M.getContext();
+#endif
+
+ std::vector<SwitchInst *> switches;
+
+ /* iterate over all functions, bbs and instruction and add
+ * all switches to switches vector for later processing */
+ for (auto &F : M) {
+
+ if (!isInInstrumentList(&F, MNAME)) continue;
+
+ for (auto &BB : F) {
+
+ SwitchInst *switchInst = nullptr;
+
+ if ((switchInst = dyn_cast<SwitchInst>(BB.getTerminator()))) {
+
+ if (switchInst->getNumCases() < 1) continue;
+ switches.push_back(switchInst);
+
+ }
+
+ }
+
+ }
+
+ if (!switches.size()) return false;
+ /*
+ if (!be_quiet)
+ errs() << "Rewriting " << switches.size() << " switch statements "
+ << "\n";
+ */
+ for (auto &SI : switches) {
+
+ BasicBlock *CurBlock = SI->getParent();
+ BasicBlock *OrigBlock = CurBlock;
+ Function * F = CurBlock->getParent();
+ /* this is the value we are switching on */
+ Value * Val = SI->getCondition();
+ BasicBlock *Default = SI->getDefaultDest();
+ unsigned bitw = Val->getType()->getIntegerBitWidth();
+
+ /*
+ if (!be_quiet)
+ errs() << "switch: " << SI->getNumCases() << " cases " << bitw
+ << " bit\n";
+ */
+
+ /* If there is only the default destination or the condition checks 8 bit or
+ * less, don't bother with the code below. */
+ if (SI->getNumCases() < 2 || bitw % 8 || bitw > 64) {
+
+ // if (!be_quiet) errs() << "skip switch..\n";
+ continue;
+
+ }
+
+ /* Create a new, empty default block so that the new hierarchy of
+ * if-then statements go to this and the PHI nodes are happy.
+ * if the default block is set as an unreachable we avoid creating one
+ * because will never be a valid target.*/
+ BasicBlock *NewDefault = nullptr;
+ NewDefault = BasicBlock::Create(SI->getContext(), "NewDefault", F, Default);
+ BranchInst::Create(Default, NewDefault);
+
+ /* Prepare cases vector. */
+ CaseVector Cases;
+ for (SwitchInst::CaseIt i = SI->case_begin(), e = SI->case_end(); i != e;
+ ++i)
+#if LLVM_VERSION_MAJOR >= 5
+ Cases.push_back(CaseExpr(i->getCaseValue(), i->getCaseSuccessor()));
+#else
+ Cases.push_back(CaseExpr(i.getCaseValue(), i.getCaseSuccessor()));
+#endif
+ /* bugfix thanks to pbst
+ * round up bytesChecked (in case getBitWidth() % 8 != 0) */
+ std::vector<bool> bytesChecked((7 + Cases[0].Val->getBitWidth()) / 8,
+ false);
+ BasicBlock * SwitchBlock =
+ switchConvert(Cases, bytesChecked, OrigBlock, NewDefault, Val, 0);
+
+ /* Branch to our shiny new if-then stuff... */
+ BranchInst::Create(SwitchBlock, OrigBlock);
+
+ /* We are now done with the switch instruction, delete it. */
+ CurBlock->getInstList().erase(SI);
+
+ /* we have to update the phi nodes! */
+ for (BasicBlock::iterator I = Default->begin(); I != Default->end(); ++I) {
+
+ if (!isa<PHINode>(&*I)) { continue; }
+ PHINode *PN = cast<PHINode>(I);
+
+ /* Only update the first occurrence. */
+ unsigned Idx = 0, E = PN->getNumIncomingValues();
+ for (; Idx != E; ++Idx) {
+
+ if (PN->getIncomingBlock(Idx) == OrigBlock) {
+
+ PN->setIncomingBlock(Idx, NewDefault);
+ break;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ verifyModule(M);
+ return true;
+
+}
+
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+PreservedAnalyses SplitSwitchesTransform::run(Module & M,
+ ModuleAnalysisManager &MAM) {
+
+#else
+bool SplitSwitchesTransform::runOnModule(Module &M) {
+
+#endif
+
+ if ((isatty(2) && getenv("AFL_QUIET") == NULL) || getenv("AFL_DEBUG") != NULL)
+ printf("Running split-switches-pass by laf.intel@gmail.com\n");
+ else
+ be_quiet = 1;
+
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+ auto PA = PreservedAnalyses::all();
+#endif
+
+ splitSwitches(M);
+ verifyModule(M);
+
+#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
+ /* if (modified) {
+
+ PA.abandon<XX_Manager>();
+
+ }*/
+
+ return PA;
+#else
+ return true;
+#endif
+
+}
+
+#if LLVM_VERSION_MAJOR < 11 /* use old pass manager */
+static void registerSplitSwitchesTransPass(const PassManagerBuilder &,
+ legacy::PassManagerBase &PM) {
+
+ auto p = new SplitSwitchesTransform();
+ PM.add(p);
+
+}
+
+static RegisterStandardPasses RegisterSplitSwitchesTransPass(
+ PassManagerBuilder::EP_OptimizerLast, registerSplitSwitchesTransPass);
+
+static RegisterStandardPasses RegisterSplitSwitchesTransPass0(
+ PassManagerBuilder::EP_EnabledOnOptLevel0, registerSplitSwitchesTransPass);
+
+ #if LLVM_VERSION_MAJOR >= 11
+static RegisterStandardPasses RegisterSplitSwitchesTransPassLTO(
+ PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
+ registerSplitSwitchesTransPass);
+ #endif
+#endif
+
diff --git a/src/README.md b/src/README.md
new file mode 100644
index 00000000..3f332280
--- /dev/null
+++ b/src/README.md
@@ -0,0 +1,29 @@
+# Source Folder
+
+Quick explanation about the files here:
+
+- `afl-analyze.c` - afl-analyze binary tool
+- `afl-as.c` - afl-as binary tool
+- `afl-cc.c` - afl-cc binary tool
+- `afl-common.c` - common functions, used by afl-analyze, afl-fuzz, afl-showmap and afl-tmin
+- `afl-forkserver.c` - forkserver implementation, used by afl-fuzz afl-showmap, afl-tmin
+- `afl-fuzz-bitmap.c` - afl-fuzz bitmap handling
+- `afl-fuzz.c` - afl-fuzz binary tool (just main() and usage())
+- `afl-fuzz-cmplog.c` - afl-fuzz cmplog functions
+- `afl-fuzz-extras.c` - afl-fuzz the *extra* function calls
+- `afl-fuzz-init.c` - afl-fuzz initialization
+- `afl-fuzz-misc.c` - afl-fuzz misc functions
+- `afl-fuzz-mutators.c` - afl-fuzz custom mutator and python support
+- `afl-fuzz-one.c` - afl-fuzz fuzzer_one big loop, this is where the mutation is happening
+- `afl-fuzz-performance.c` - hash64 and rand functions
+- `afl-fuzz-python.c` - afl-fuzz the python mutator extension
+- `afl-fuzz-queue.c` - afl-fuzz handling the queue
+- `afl-fuzz-redqueen.c` - afl-fuzz redqueen implementation
+- `afl-fuzz-run.c` - afl-fuzz running the target
+- `afl-fuzz-state.c` - afl-fuzz state and globals
+- `afl-fuzz-stats.c` - afl-fuzz writing the statistics file
+- `afl-gotcpu.c` - afl-gotcpu binary tool
+- `afl-ld-lto.c` - LTO linker helper
+- `afl-sharedmem.c` - sharedmem implementation, used by afl-fuzz, afl-showmap, afl-tmin
+- `afl-showmap.c` - afl-showmap binary tool
+- `afl-tmin.c` - afl-tmin binary tool
diff --git a/src/afl-analyze.c b/src/afl-analyze.c
new file mode 100644
index 00000000..fc868603
--- /dev/null
+++ b/src/afl-analyze.c
@@ -0,0 +1,1154 @@
+/*
+ american fuzzy lop++ - file format analyzer
+ -------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Andrea Fioraldi <andreafioraldi@gmail.com>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ A nifty utility that grabs an input file and takes a stab at explaining
+ its structure by observing how changes to it affect the execution path.
+
+ If the output scrolls past the edge of the screen, pipe it to 'less -r'.
+
+ */
+
+#define AFL_MAIN
+
+#include "config.h"
+#include "types.h"
+#include "debug.h"
+#include "alloc-inl.h"
+#include "hash.h"
+#include "sharedmem.h"
+#include "common.h"
+#include "forkserver.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <signal.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <ctype.h>
+
+#include <sys/wait.h>
+#include <sys/time.h>
+#ifndef USEMMAP
+ #include <sys/shm.h>
+#endif
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+
+static u8 *in_file; /* Analyzer input test case */
+
+static u8 *in_data; /* Input data for analysis */
+
+static u32 in_len, /* Input data length */
+ total_execs, /* Total number of execs */
+ exec_hangs, /* Total number of hangs */
+ exec_tmout = EXEC_TIMEOUT; /* Exec timeout (ms) */
+
+static u64 orig_cksum; /* Original checksum */
+
+static u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */
+
+static bool edges_only, /* Ignore hit counts? */
+ use_hex_offsets, /* Show hex offsets? */
+ use_stdin = true; /* Use stdin for program input? */
+
+static volatile u8 stop_soon; /* Ctrl-C pressed? */
+
+static u8 *target_path;
+static u8 frida_mode;
+static u8 qemu_mode;
+static u8 cs_mode;
+static u32 map_size = MAP_SIZE;
+
+static afl_forkserver_t fsrv = {0}; /* The forkserver */
+
+/* Constants used for describing byte behavior. */
+
+#define RESP_NONE 0x00 /* Changing byte is a no-op. */
+#define RESP_MINOR 0x01 /* Some changes have no effect. */
+#define RESP_VARIABLE 0x02 /* Changes produce variable paths. */
+#define RESP_FIXED 0x03 /* Changes produce fixed patterns. */
+
+#define RESP_LEN 0x04 /* Potential length field */
+#define RESP_CKSUM 0x05 /* Potential checksum */
+#define RESP_SUSPECT 0x06 /* Potential "suspect" blob */
+
+/* Classify tuple counts. This is a slow & naive version, but good enough here.
+ */
+
+static u8 count_class_lookup[256] = {
+
+ [0] = 0,
+ [1] = 1,
+ [2] = 2,
+ [3] = 4,
+ [4 ... 7] = 8,
+ [8 ... 15] = 16,
+ [16 ... 31] = 32,
+ [32 ... 127] = 64,
+ [128 ... 255] = 128
+
+};
+
+static void kill_child() {
+
+ if (fsrv.child_pid > 0) {
+
+ kill(fsrv.child_pid, fsrv.kill_signal);
+ fsrv.child_pid = -1;
+
+ }
+
+}
+
+static void classify_counts(u8 *mem) {
+
+ u32 i = map_size;
+
+ if (edges_only) {
+
+ while (i--) {
+
+ if (*mem) { *mem = 1; }
+ mem++;
+
+ }
+
+ } else {
+
+ while (i--) {
+
+ *mem = count_class_lookup[*mem];
+ mem++;
+
+ }
+
+ }
+
+}
+
+/* See if any bytes are set in the bitmap. */
+
+static inline u8 anything_set(void) {
+
+ u32 *ptr = (u32 *)fsrv.trace_bits;
+ u32 i = (map_size >> 2);
+
+ while (i--) {
+
+ if (*(ptr++)) { return 1; }
+
+ }
+
+ return 0;
+
+}
+
+/* Get rid of temp files (atexit handler). */
+
+static void at_exit_handler(void) {
+
+ unlink(fsrv.out_file); /* Ignore errors */
+
+}
+
+/* Read initial file. */
+
+static void read_initial_file(void) {
+
+ struct stat st;
+ s32 fd = open(in_file, O_RDONLY);
+
+ if (fd < 0) { PFATAL("Unable to open '%s'", in_file); }
+
+ if (fstat(fd, &st) || !st.st_size) { FATAL("Zero-sized input file."); }
+
+ if (st.st_size >= TMIN_MAX_FILE) {
+
+ FATAL("Input file is too large (%ld MB max)", TMIN_MAX_FILE / 1024 / 1024);
+
+ }
+
+ in_len = st.st_size;
+ in_data = ck_alloc_nozero(in_len);
+
+ ck_read(fd, in_data, in_len, in_file);
+
+ close(fd);
+
+ OKF("Read %u byte%s from '%s'.", in_len, in_len == 1 ? "" : "s", in_file);
+
+}
+
+/* Execute target application. Returns exec checksum, or 0 if program
+ times out. */
+
+static u32 analyze_run_target(u8 *mem, u32 len, u8 first_run) {
+
+ afl_fsrv_write_to_testcase(&fsrv, mem, len);
+ fsrv_run_result_t ret = afl_fsrv_run_target(&fsrv, exec_tmout, &stop_soon);
+
+ if (ret == FSRV_RUN_ERROR) {
+
+ FATAL("Error in forkserver");
+
+ } else if (ret == FSRV_RUN_NOINST) {
+
+ FATAL("Target not instrumented");
+
+ } else if (ret == FSRV_RUN_NOBITS) {
+
+ FATAL("Failed to run target");
+
+ }
+
+ classify_counts(fsrv.trace_bits);
+ total_execs++;
+
+ if (stop_soon) {
+
+ SAYF(cRST cLRD "\n+++ Analysis aborted by user +++\n" cRST);
+ exit(1);
+
+ }
+
+ /* Always discard inputs that time out. */
+
+ if (fsrv.last_run_timed_out) {
+
+ exec_hangs++;
+ return 0;
+
+ }
+
+ u64 cksum = hash64(fsrv.trace_bits, fsrv.map_size, HASH_CONST);
+
+ if (ret == FSRV_RUN_CRASH) {
+
+ /* We don't actually care if the target is crashing or not,
+ except that when it does, the checksum should be different. */
+
+ cksum ^= 0xffffffff;
+
+ }
+
+ if (first_run) { orig_cksum = cksum; }
+
+ return cksum;
+
+}
+
+#ifdef USE_COLOR
+
+/* Helper function to display a human-readable character. */
+
+static void show_char(u8 val) {
+
+ switch (val) {
+
+ case 0 ... 32:
+ case 127 ... 255:
+ SAYF("#%02x", val);
+ break;
+
+ default:
+ SAYF(" %c ", val);
+
+ }
+
+}
+
+/* Show the legend */
+
+static void show_legend(void) {
+
+ SAYF(" " cLGR bgGRA " 01 " cRST " - no-op block " cBLK bgLGN
+ " 01 " cRST
+ " - suspected length field\n"
+ " " cBRI bgGRA " 01 " cRST " - superficial content " cBLK bgYEL
+ " 01 " cRST
+ " - suspected cksum or magic int\n"
+ " " cBLK bgCYA " 01 " cRST " - critical stream " cBLK bgLRD
+ " 01 " cRST
+ " - suspected checksummed block\n"
+ " " cBLK bgMGN " 01 " cRST " - \"magic value\" section\n\n");
+
+}
+
+#endif /* USE_COLOR */
+
+/* Interpret and report a pattern in the input file. */
+
+static void dump_hex(u32 len, u8 *b_data) {
+
+ u32 i;
+
+ for (i = 0; i < len; i++) {
+
+#ifdef USE_COLOR
+ u32 rlen = 1, off;
+#else
+ u32 rlen = 1;
+#endif /* ^USE_COLOR */
+
+ u8 rtype = b_data[i] & 0x0f;
+
+ /* Look ahead to determine the length of run. */
+
+ while (i + rlen < len && (b_data[i] >> 7) == (b_data[i + rlen] >> 7)) {
+
+ if (rtype < (b_data[i + rlen] & 0x0f)) {
+
+ rtype = b_data[i + rlen] & 0x0f;
+
+ }
+
+ rlen++;
+
+ }
+
+ /* Try to do some further classification based on length & value. */
+
+ if (rtype == RESP_FIXED) {
+
+ switch (rlen) {
+
+ case 2: {
+
+ u16 val = *(u16 *)(in_data + i);
+
+ /* Small integers may be length fields. */
+
+ if (val && (val <= in_len || SWAP16(val) <= in_len)) {
+
+ rtype = RESP_LEN;
+ break;
+
+ }
+
+ /* Uniform integers may be checksums. */
+
+ if (val && abs(in_data[i] - in_data[i + 1]) > 32) {
+
+ rtype = RESP_CKSUM;
+ break;
+
+ }
+
+ break;
+
+ }
+
+ case 4: {
+
+ u32 val = *(u32 *)(in_data + i);
+
+ /* Small integers may be length fields. */
+
+ if (val && (val <= in_len || SWAP32(val) <= in_len)) {
+
+ rtype = RESP_LEN;
+ break;
+
+ }
+
+ /* Uniform integers may be checksums. */
+
+ if (val && (in_data[i] >> 7 != in_data[i + 1] >> 7 ||
+ in_data[i] >> 7 != in_data[i + 2] >> 7 ||
+ in_data[i] >> 7 != in_data[i + 3] >> 7)) {
+
+ rtype = RESP_CKSUM;
+ break;
+
+ }
+
+ break;
+
+ }
+
+ case 1:
+ case 3:
+ case 5 ... MAX_AUTO_EXTRA - 1:
+ break;
+
+ default:
+ rtype = RESP_SUSPECT;
+
+ }
+
+ }
+
+ /* Print out the entire run. */
+
+#ifdef USE_COLOR
+
+ for (off = 0; off < rlen; off++) {
+
+ /* Every 16 digits, display offset. */
+
+ if (!((i + off) % 16)) {
+
+ if (off) { SAYF(cRST cLCY ">"); }
+
+ if (use_hex_offsets) {
+
+ SAYF(cRST cGRA "%s[%06x] " cRST, (i + off) ? "\n" : "", i + off);
+
+ } else {
+
+ SAYF(cRST cGRA "%s[%06u] " cRST, (i + off) ? "\n" : "", i + off);
+
+ }
+
+ }
+
+ switch (rtype) {
+
+ case RESP_NONE:
+ SAYF(cLGR bgGRA);
+ break;
+ case RESP_MINOR:
+ SAYF(cBRI bgGRA);
+ break;
+ case RESP_VARIABLE:
+ SAYF(cBLK bgCYA);
+ break;
+ case RESP_FIXED:
+ SAYF(cBLK bgMGN);
+ break;
+ case RESP_LEN:
+ SAYF(cBLK bgLGN);
+ break;
+ case RESP_CKSUM:
+ SAYF(cBLK bgYEL);
+ break;
+ case RESP_SUSPECT:
+ SAYF(cBLK bgLRD);
+ break;
+
+ }
+
+ show_char(in_data[i + off]);
+
+ if (off != rlen - 1 && (i + off + 1) % 16) {
+
+ SAYF(" ");
+
+ } else {
+
+ SAYF(cRST " ");
+
+ }
+
+ }
+
+#else
+
+ if (use_hex_offsets)
+ SAYF(" Offset %x, length %u: ", i, rlen);
+ else
+ SAYF(" Offset %u, length %u: ", i, rlen);
+
+ switch (rtype) {
+
+ case RESP_NONE:
+ SAYF("no-op block\n");
+ break;
+ case RESP_MINOR:
+ SAYF("superficial content\n");
+ break;
+ case RESP_VARIABLE:
+ SAYF("critical stream\n");
+ break;
+ case RESP_FIXED:
+ SAYF("\"magic value\" section\n");
+ break;
+ case RESP_LEN:
+ SAYF("suspected length field\n");
+ break;
+ case RESP_CKSUM:
+ SAYF("suspected cksum or magic int\n");
+ break;
+ case RESP_SUSPECT:
+ SAYF("suspected checksummed block\n");
+ break;
+
+ }
+
+#endif /* ^USE_COLOR */
+
+ i += rlen - 1;
+
+ }
+
+#ifdef USE_COLOR
+ SAYF(cRST "\n");
+#endif /* USE_COLOR */
+
+}
+
+/* Actually analyze! */
+
+static void analyze() {
+
+ u32 i;
+ u32 boring_len = 0, prev_xff = 0, prev_x01 = 0, prev_s10 = 0, prev_a10 = 0;
+
+ u8 *b_data = ck_alloc(in_len + 1);
+ u8 seq_byte = 0;
+
+ b_data[in_len] = 0xff; /* Intentional terminator. */
+
+ ACTF("Analyzing input file (this may take a while)...\n");
+
+#ifdef USE_COLOR
+ show_legend();
+#endif /* USE_COLOR */
+
+ for (i = 0; i < in_len; i++) {
+
+ u32 xor_ff, xor_01, sub_10, add_10;
+ u8 xff_orig, x01_orig, s10_orig, a10_orig;
+
+ /* Perform walking byte adjustments across the file. We perform four
+ operations designed to elicit some response from the underlying
+ code. */
+
+ in_data[i] ^= 0xff;
+ xor_ff = analyze_run_target(in_data, in_len, 0);
+
+ in_data[i] ^= 0xfe;
+ xor_01 = analyze_run_target(in_data, in_len, 0);
+
+ in_data[i] = (in_data[i] ^ 0x01) - 0x10;
+ sub_10 = analyze_run_target(in_data, in_len, 0);
+
+ in_data[i] += 0x20;
+ add_10 = analyze_run_target(in_data, in_len, 0);
+ in_data[i] -= 0x10;
+
+ /* Classify current behavior. */
+
+ xff_orig = (xor_ff == orig_cksum);
+ x01_orig = (xor_01 == orig_cksum);
+ s10_orig = (sub_10 == orig_cksum);
+ a10_orig = (add_10 == orig_cksum);
+
+ if (xff_orig && x01_orig && s10_orig && a10_orig) {
+
+ b_data[i] = RESP_NONE;
+ boring_len++;
+
+ } else if (xff_orig || x01_orig || s10_orig || a10_orig) {
+
+ b_data[i] = RESP_MINOR;
+ boring_len++;
+
+ } else if (xor_ff == xor_01 && xor_ff == sub_10 && xor_ff == add_10) {
+
+ b_data[i] = RESP_FIXED;
+
+ } else {
+
+ b_data[i] = RESP_VARIABLE;
+
+ }
+
+ /* When all checksums change, flip most significant bit of b_data. */
+
+ if (prev_xff != xor_ff && prev_x01 != xor_01 && prev_s10 != sub_10 &&
+ prev_a10 != add_10) {
+
+ seq_byte ^= 0x80;
+
+ }
+
+ b_data[i] |= seq_byte;
+
+ prev_xff = xor_ff;
+ prev_x01 = xor_01;
+ prev_s10 = sub_10;
+ prev_a10 = add_10;
+
+ }
+
+ dump_hex(in_len, b_data);
+
+ SAYF("\n");
+
+ OKF("Analysis complete. Interesting bits: %0.02f%% of the input file.",
+ 100.0 - ((double)boring_len * 100) / in_len);
+
+ if (exec_hangs) {
+
+ WARNF(cLRD "Encountered %u timeouts - results may be skewed." cRST,
+ exec_hangs);
+
+ }
+
+ ck_free(b_data);
+
+}
+
+/* Handle Ctrl-C and the like. */
+
+static void handle_stop_sig(int sig) {
+
+ (void)sig;
+ stop_soon = 1;
+
+ afl_fsrv_killall();
+
+}
+
+/* Do basic preparations - persistent fds, filenames, etc. */
+
+static void set_up_environment(char **argv) {
+
+ u8 * x;
+ char *afl_preload;
+ char *frida_afl_preload = NULL;
+
+ fsrv.dev_null_fd = open("/dev/null", O_RDWR);
+ if (fsrv.dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
+
+ if (!fsrv.out_file) {
+
+ u8 *use_dir = ".";
+
+ if (access(use_dir, R_OK | W_OK | X_OK)) {
+
+ use_dir = get_afl_env("TMPDIR");
+ if (!use_dir) { use_dir = "/tmp"; }
+
+ }
+
+ fsrv.out_file =
+ alloc_printf("%s/.afl-analyze-temp-%u", use_dir, (u32)getpid());
+
+ }
+
+ unlink(fsrv.out_file);
+ fsrv.out_fd =
+ open(fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
+
+ if (fsrv.out_fd < 0) { PFATAL("Unable to create '%s'", fsrv.out_file); }
+
+ /* Set sane defaults... */
+
+ x = get_afl_env("ASAN_OPTIONS");
+
+ if (x) {
+
+ if (!strstr(x, "abort_on_error=1")) {
+
+ FATAL("Custom ASAN_OPTIONS set without abort_on_error=1 - please fix!");
+
+ }
+
+#ifndef ASAN_BUILD
+ if (!getenv("AFL_DEBUG") && !strstr(x, "symbolize=0")) {
+
+ FATAL("Custom ASAN_OPTIONS set without symbolize=0 - please fix!");
+
+ }
+
+#endif
+
+ }
+
+ x = get_afl_env("MSAN_OPTIONS");
+
+ if (x) {
+
+ if (!strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR))) {
+
+ FATAL("Custom MSAN_OPTIONS set without exit_code=" STRINGIFY(
+ MSAN_ERROR) " - please fix!");
+
+ }
+
+ if (!strstr(x, "symbolize=0")) {
+
+ FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!");
+
+ }
+
+ }
+
+ x = get_afl_env("LSAN_OPTIONS");
+
+ if (x) {
+
+ if (!strstr(x, "symbolize=0")) {
+
+ FATAL("Custom LSAN_OPTIONS set without symbolize=0 - please fix!");
+
+ }
+
+ }
+
+ setenv("ASAN_OPTIONS",
+ "abort_on_error=1:"
+ "detect_leaks=0:"
+ "allocator_may_return_null=1:"
+ "detect_odr_violation=0:"
+ "symbolize=0:"
+ "handle_segv=0:"
+ "handle_sigbus=0:"
+ "handle_abort=0:"
+ "handle_sigfpe=0:"
+ "handle_sigill=0",
+ 0);
+
+ setenv("UBSAN_OPTIONS",
+ "halt_on_error=1:"
+ "abort_on_error=1:"
+ "malloc_context_size=0:"
+ "allocator_may_return_null=1:"
+ "symbolize=0:"
+ "handle_segv=0:"
+ "handle_sigbus=0:"
+ "handle_abort=0:"
+ "handle_sigfpe=0:"
+ "handle_sigill=0",
+ 0);
+
+ setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":"
+ "abort_on_error=1:"
+ "msan_track_origins=0"
+ "allocator_may_return_null=1:"
+ "symbolize=0:"
+ "handle_segv=0:"
+ "handle_sigbus=0:"
+ "handle_abort=0:"
+ "handle_sigfpe=0:"
+ "handle_sigill=0", 0);
+
+ setenv("LSAN_OPTIONS",
+ "exitcode=" STRINGIFY(LSAN_ERROR) ":"
+ "fast_unwind_on_malloc=0:"
+ "symbolize=0:"
+ "print_suppressions=0",
+ 0);
+
+ if (get_afl_env("AFL_PRELOAD")) {
+
+ if (qemu_mode) {
+
+ /* afl-qemu-trace takes care of converting AFL_PRELOAD. */
+
+ } else if (frida_mode) {
+
+ afl_preload = getenv("AFL_PRELOAD");
+ u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
+ if (afl_preload) {
+
+ frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
+
+ } else {
+
+ frida_afl_preload = alloc_printf("%s", frida_binary);
+
+ }
+
+ ck_free(frida_binary);
+
+ setenv("LD_PRELOAD", frida_afl_preload, 1);
+ setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
+
+ } else {
+
+ /* CoreSight mode uses the default behavior. */
+
+ setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
+ setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
+
+ }
+
+ } else if (frida_mode) {
+
+ u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
+ setenv("LD_PRELOAD", frida_binary, 1);
+ setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
+ ck_free(frida_binary);
+
+ }
+
+ if (frida_afl_preload) { ck_free(frida_afl_preload); }
+
+}
+
+/* Setup signal handlers, duh. */
+
+static void setup_signal_handlers(void) {
+
+ struct sigaction sa;
+
+ sa.sa_handler = NULL;
+ sa.sa_flags = SA_RESTART;
+ sa.sa_sigaction = NULL;
+
+ sigemptyset(&sa.sa_mask);
+
+ /* Various ways of saying "stop". */
+
+ sa.sa_handler = handle_stop_sig;
+ sigaction(SIGHUP, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGTERM, &sa, NULL);
+
+}
+
+/* Display usage hints. */
+
+static void usage(u8 *argv0) {
+
+ SAYF(
+ "\n%s [ options ] -- /path/to/target_app [ ... ]\n\n"
+
+ "Required parameters:\n"
+
+ " -i file - input test case to be analyzed by the tool\n\n"
+
+ "Execution control settings:\n"
+
+ " -f file - input file read by the tested program (stdin)\n"
+ " -t msec - timeout for each run (%u ms)\n"
+ " -m megs - memory limit for child process (%u MB)\n"
+#if defined(__linux__) && defined(__aarch64__)
+ " -A - use binary-only instrumentation (ARM CoreSight mode)\n"
+#endif
+ " -O - use binary-only instrumentation (FRIDA mode)\n"
+#if defined(__linux__)
+ " -Q - use binary-only instrumentation (QEMU mode)\n"
+ " -U - use unicorn-based instrumentation (Unicorn mode)\n"
+ " -W - use qemu-based instrumentation with Wine (Wine "
+ "mode)\n"
+#endif
+ "\n"
+
+ "Analysis settings:\n"
+
+ " -e - look for edge coverage only, ignore hit counts\n\n"
+
+ "For additional tips, please consult %s/README.md.\n\n"
+
+ "Environment variables used:\n"
+ "TMPDIR: directory to use for temporary input files\n"
+ "ASAN_OPTIONS: custom settings for ASAN\n"
+ " (must contain abort_on_error=1 and symbolize=0)\n"
+ "MSAN_OPTIONS: custom settings for MSAN\n"
+ " (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n"
+ "AFL_ANALYZE_HEX: print file offsets in hexadecimal instead of decimal\n"
+ "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n"
+ " the target was compiled for\n"
+ "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
+ "AFL_SKIP_BIN_CHECK: skip checking the location of and the target\n"
+
+ , argv0, EXEC_TIMEOUT, MEM_LIMIT, doc_path);
+
+ exit(1);
+
+}
+
+/* Main entry point */
+
+int main(int argc, char **argv_orig, char **envp) {
+
+ s32 opt;
+ u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0;
+ char **use_argv;
+ char **argv = argv_cpy_dup(argc, argv_orig);
+
+ doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
+
+ SAYF(cCYA "afl-analyze" VERSION cRST " by Michal Zalewski\n");
+
+ afl_fsrv_init(&fsrv);
+
+ while ((opt = getopt(argc, argv, "+i:f:m:t:eAOQUWh")) > 0) {
+
+ switch (opt) {
+
+ case 'i':
+
+ if (in_file) { FATAL("Multiple -i options not supported"); }
+ in_file = optarg;
+ break;
+
+ case 'f':
+
+ if (fsrv.out_file) { FATAL("Multiple -f options not supported"); }
+ fsrv.use_stdin = 0;
+ fsrv.out_file = ck_strdup(optarg);
+ break;
+
+ case 'e':
+
+ if (edges_only) { FATAL("Multiple -e options not supported"); }
+ edges_only = 1;
+ break;
+
+ case 'm': {
+
+ u8 suffix = 'M';
+
+ if (mem_limit_given) { FATAL("Multiple -m options not supported"); }
+ mem_limit_given = 1;
+
+ if (!optarg) { FATAL("Wrong usage of -m"); }
+
+ if (!strcmp(optarg, "none")) {
+
+ mem_limit = 0;
+ fsrv.mem_limit = 0;
+ break;
+
+ }
+
+ if (sscanf(optarg, "%llu%c", &mem_limit, &suffix) < 1 ||
+ optarg[0] == '-') {
+
+ FATAL("Bad syntax used for -m");
+
+ }
+
+ switch (suffix) {
+
+ case 'T':
+ mem_limit *= 1024 * 1024;
+ break;
+ case 'G':
+ mem_limit *= 1024;
+ break;
+ case 'k':
+ mem_limit /= 1024;
+ break;
+ case 'M':
+ break;
+
+ default:
+ FATAL("Unsupported suffix or bad syntax for -m");
+
+ }
+
+ if (mem_limit < 5) { FATAL("Dangerously low value of -m"); }
+
+ if (sizeof(rlim_t) == 4 && mem_limit > 2000) {
+
+ FATAL("Value of -m out of range on 32-bit systems");
+
+ }
+
+ fsrv.mem_limit = mem_limit;
+
+ }
+
+ break;
+
+ case 't':
+
+ if (timeout_given) { FATAL("Multiple -t options not supported"); }
+ timeout_given = 1;
+
+ if (!optarg) { FATAL("Wrong usage of -t"); }
+
+ exec_tmout = atoi(optarg);
+
+ if (exec_tmout < 10 || optarg[0] == '-') {
+
+ FATAL("Dangerously low value of -t");
+
+ }
+
+ fsrv.exec_tmout = exec_tmout;
+
+ break;
+
+ case 'A': /* CoreSight mode */
+
+#if !defined(__aarch64__) || !defined(__linux__)
+ FATAL("-A option is not supported on this platform");
+#endif
+
+ if (cs_mode) { FATAL("Multiple -A options not supported"); }
+
+ cs_mode = 1;
+ fsrv.cs_mode = cs_mode;
+ break;
+
+ case 'O': /* FRIDA mode */
+
+ if (frida_mode) { FATAL("Multiple -O options not supported"); }
+
+ frida_mode = 1;
+ fsrv.frida_mode = frida_mode;
+ setenv("AFL_FRIDA_INST_SEED", "1", 1);
+
+ break;
+
+ case 'Q':
+
+ if (qemu_mode) { FATAL("Multiple -Q options not supported"); }
+ if (!mem_limit_given) { mem_limit = MEM_LIMIT_QEMU; }
+
+ qemu_mode = 1;
+ fsrv.mem_limit = mem_limit;
+ fsrv.qemu_mode = qemu_mode;
+ break;
+
+ case 'U':
+
+ if (unicorn_mode) { FATAL("Multiple -U options not supported"); }
+ if (!mem_limit_given) { mem_limit = MEM_LIMIT_UNICORN; }
+
+ unicorn_mode = 1;
+ fsrv.mem_limit = mem_limit;
+ break;
+
+ case 'W': /* Wine+QEMU mode */
+
+ if (use_wine) { FATAL("Multiple -W options not supported"); }
+ qemu_mode = 1;
+ use_wine = 1;
+
+ if (!mem_limit_given) { mem_limit = 0; }
+ fsrv.qemu_mode = qemu_mode;
+ fsrv.mem_limit = mem_limit;
+
+ break;
+
+ case 'h':
+ usage(argv[0]);
+ return -1;
+ break;
+
+ default:
+ usage(argv[0]);
+
+ }
+
+ }
+
+ if (optind == argc || !in_file) { usage(argv[0]); }
+
+ map_size = get_map_size();
+ fsrv.map_size = map_size;
+
+ use_hex_offsets = !!get_afl_env("AFL_ANALYZE_HEX");
+
+ check_environment_vars(envp);
+
+ sharedmem_t shm = {0};
+
+ /* initialize cmplog_mode */
+ shm.cmplog_mode = 0;
+
+ atexit(at_exit_handler);
+ setup_signal_handlers();
+
+ set_up_environment(argv);
+
+ fsrv.target_path = find_binary(argv[optind]);
+ fsrv.trace_bits = afl_shm_init(&shm, map_size, 0);
+ detect_file_args(argv + optind, fsrv.out_file, &use_stdin);
+ signal(SIGALRM, kill_child);
+
+ if (qemu_mode) {
+
+ if (use_wine) {
+
+ use_argv =
+ get_wine_argv(argv[0], &target_path, argc - optind, argv + optind);
+
+ } else {
+
+ use_argv =
+ get_qemu_argv(argv[0], &target_path, argc - optind, argv + optind);
+
+ }
+
+ } else if (cs_mode) {
+
+ use_argv = get_cs_argv(argv[0], &target_path, argc - optind, argv + optind);
+
+ } else {
+
+ use_argv = argv + optind;
+
+ }
+
+ SAYF("\n");
+
+ if (getenv("AFL_FORKSRV_INIT_TMOUT")) {
+
+ s32 forksrv_init_tmout = atoi(getenv("AFL_FORKSRV_INIT_TMOUT"));
+ if (forksrv_init_tmout < 1) {
+
+ FATAL("Bad value specified for AFL_FORKSRV_INIT_TMOUT");
+
+ }
+
+ fsrv.init_tmout = (u32)forksrv_init_tmout;
+
+ }
+
+ fsrv.kill_signal =
+ parse_afl_kill_signal_env(getenv("AFL_KILL_SIGNAL"), SIGKILL);
+
+ read_initial_file();
+ (void)check_binary_signatures(fsrv.target_path);
+
+ ACTF("Performing dry run (mem limit = %llu MB, timeout = %u ms%s)...",
+ mem_limit, exec_tmout, edges_only ? ", edges only" : "");
+
+ afl_fsrv_start(&fsrv, use_argv, &stop_soon, false);
+ analyze_run_target(in_data, in_len, 1);
+
+ if (fsrv.last_run_timed_out) {
+
+ FATAL("Target binary times out (adjusting -t may help).");
+
+ }
+
+ if (get_afl_env("AFL_SKIP_BIN_CHECK") == NULL && !anything_set()) {
+
+ FATAL("No instrumentation detected.");
+
+ }
+
+ analyze();
+
+ OKF("We're done here. Have a nice day!\n");
+
+ afl_shm_deinit(&shm);
+ afl_fsrv_deinit(&fsrv);
+ if (fsrv.target_path) { ck_free(fsrv.target_path); }
+ if (in_data) { ck_free(in_data); }
+
+ exit(0);
+
+}
+
diff --git a/src/afl-as.c b/src/afl-as.c
new file mode 100644
index 00000000..1edc8cca
--- /dev/null
+++ b/src/afl-as.c
@@ -0,0 +1,657 @@
+/*
+ american fuzzy lop++ - wrapper for GNU as
+ -----------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Andrea Fioraldi <andreafioraldi@gmail.com>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ The sole purpose of this wrapper is to preprocess assembly files generated
+ by GCC / clang and inject the instrumentation bits included from afl-as.h. It
+ is automatically invoked by the toolchain when compiling programs using
+ afl-gcc / afl-clang.
+
+ Note that it's an explicit non-goal to instrument hand-written assembly,
+ be it in separate .s files or in __asm__ blocks. The only aspiration this
+ utility has right now is to be able to skip them gracefully and allow the
+ compilation process to continue.
+
+ That said, see utils/clang_asm_normalize/ for a solution that may
+ allow clang users to make things work even with hand-crafted assembly. Just
+ note that there is no equivalent for GCC.
+
+ */
+
+#define AFL_MAIN
+
+#include "config.h"
+#include "types.h"
+#include "debug.h"
+#include "alloc-inl.h"
+
+#include "afl-as.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <limits.h>
+#include <ctype.h>
+#include <fcntl.h>
+
+#include <sys/wait.h>
+#include <sys/time.h>
+
+static u8 **as_params; /* Parameters passed to the real 'as' */
+
+static u8 *input_file; /* Originally specified input file */
+static u8 *modified_file; /* Instrumented file for the real 'as' */
+
+static u8 be_quiet, /* Quiet mode (no stderr output) */
+ clang_mode, /* Running in clang mode? */
+ pass_thru, /* Just pass data through? */
+ just_version, /* Just show version? */
+ sanitizer; /* Using ASAN / MSAN */
+
+static u32 inst_ratio = 100, /* Instrumentation probability (%) */
+ as_par_cnt = 1; /* Number of params to 'as' */
+
+/* If we don't find --32 or --64 in the command line, default to
+ instrumentation for whichever mode we were compiled with. This is not
+ perfect, but should do the trick for almost all use cases. */
+
+#ifdef WORD_SIZE_64
+
+static u8 use_64bit = 1;
+
+#else
+
+static u8 use_64bit = 0;
+
+ #ifdef __APPLE__
+ #error "Sorry, 32-bit Apple platforms are not supported."
+ #endif /* __APPLE__ */
+
+#endif /* ^WORD_SIZE_64 */
+
+/* Examine and modify parameters to pass to 'as'. Note that the file name
+ is always the last parameter passed by GCC, so we exploit this property
+ to keep the code simple. */
+
+static void edit_params(int argc, char **argv) {
+
+ u8 *tmp_dir = getenv("TMPDIR"), *afl_as = getenv("AFL_AS");
+ u32 i;
+
+#ifdef __APPLE__
+
+ u8 use_clang_as = 0;
+
+ /* On MacOS X, the Xcode cctool 'as' driver is a bit stale and does not work
+ with the code generated by newer versions of clang that are hand-built
+ by the user. See the thread here: https://goo.gl/HBWDtn.
+
+ To work around this, when using clang and running without AFL_AS
+ specified, we will actually call 'clang -c' instead of 'as -q' to
+ compile the assembly file.
+
+ The tools aren't cmdline-compatible, but at least for now, we can
+ seemingly get away with this by making only very minor tweaks. Thanks
+ to Nico Weber for the idea. */
+
+ if (clang_mode && !afl_as) {
+
+ use_clang_as = 1;
+
+ afl_as = getenv("AFL_CC");
+ if (!afl_as) afl_as = getenv("AFL_CXX");
+ if (!afl_as) afl_as = "clang";
+
+ }
+
+#endif /* __APPLE__ */
+
+ /* Although this is not documented, GCC also uses TEMP and TMP when TMPDIR
+ is not set. We need to check these non-standard variables to properly
+ handle the pass_thru logic later on. */
+
+ if (!tmp_dir) { tmp_dir = getenv("TEMP"); }
+ if (!tmp_dir) { tmp_dir = getenv("TMP"); }
+ if (!tmp_dir) { tmp_dir = "/tmp"; }
+
+ as_params = ck_alloc((argc + 32) * sizeof(u8 *));
+ if (unlikely((INT_MAX - 32) < argc || !as_params)) {
+
+ FATAL("Too many parameters passed to as");
+
+ }
+
+ as_params[0] = afl_as ? afl_as : (u8 *)"as";
+
+ as_params[argc] = 0;
+
+ for (i = 1; (s32)i < argc - 1; i++) {
+
+ if (!strcmp(argv[i], "--64")) {
+
+ use_64bit = 1;
+
+ } else if (!strcmp(argv[i], "--32")) {
+
+ use_64bit = 0;
+
+ }
+
+#ifdef __APPLE__
+
+ /* The Apple case is a bit different... */
+
+ if (!strcmp(argv[i], "-arch") && i + 1 < (u32)argc) {
+
+ if (!strcmp(argv[i + 1], "x86_64"))
+ use_64bit = 1;
+ else if (!strcmp(argv[i + 1], "i386"))
+ FATAL("Sorry, 32-bit Apple platforms are not supported.");
+
+ }
+
+ /* Strip options that set the preference for a particular upstream
+ assembler in Xcode. */
+
+ if (clang_mode && (!strcmp(argv[i], "-q") || !strcmp(argv[i], "-Q")))
+ continue;
+
+#endif /* __APPLE__ */
+
+ as_params[as_par_cnt++] = argv[i];
+
+ }
+
+#ifdef __APPLE__
+
+ /* When calling clang as the upstream assembler, append -c -x assembler
+ and hope for the best. */
+
+ if (use_clang_as) {
+
+ as_params[as_par_cnt++] = "-c";
+ as_params[as_par_cnt++] = "-x";
+ as_params[as_par_cnt++] = "assembler";
+
+ }
+
+#endif /* __APPLE__ */
+
+ input_file = argv[argc - 1];
+
+ if (input_file[0] == '-') {
+
+ if (!strcmp(input_file + 1, "-version")) {
+
+ just_version = 1;
+ modified_file = input_file;
+ goto wrap_things_up;
+
+ }
+
+ if (input_file[1]) {
+
+ FATAL("Incorrect use (not called through afl-gcc?)");
+
+ } else {
+
+ input_file = NULL;
+
+ }
+
+ } else {
+
+ /* Check if this looks like a standard invocation as a part of an attempt
+ to compile a program, rather than using gcc on an ad-hoc .s file in
+ a format we may not understand. This works around an issue compiling
+ NSS. */
+
+ if (strncmp(input_file, tmp_dir, strlen(tmp_dir)) &&
+ strncmp(input_file, "/var/tmp/", 9) &&
+ strncmp(input_file, "/tmp/", 5) &&
+ getenv("AFL_AS_FORCE_INSTRUMENT") == NULL) {
+
+ pass_thru = 1;
+
+ } else if (getenv("AFL_AS_FORCE_INSTRUMENT")) {
+
+ unsetenv("AFL_AS_FORCE_INSTRUMENT");
+
+ }
+
+ }
+
+ modified_file = alloc_printf("%s/.afl-%u-%u-%u.s", tmp_dir, (u32)getpid(),
+ (u32)time(NULL), (u32)random());
+
+wrap_things_up:
+
+ as_params[as_par_cnt++] = modified_file;
+ as_params[as_par_cnt] = NULL;
+
+}
+
+/* Process input file, generate modified_file. Insert instrumentation in all
+ the appropriate places. */
+
+static void add_instrumentation(void) {
+
+ static u8 line[MAX_LINE];
+
+ FILE *inf;
+ FILE *outf;
+ s32 outfd;
+ u32 ins_lines = 0;
+
+ u8 instr_ok = 0, skip_csect = 0, skip_next_label = 0, skip_intel = 0,
+ skip_app = 0, instrument_next = 0;
+
+#ifdef __APPLE__
+
+ u8 *colon_pos;
+
+#endif /* __APPLE__ */
+
+ if (input_file) {
+
+ inf = fopen(input_file, "r");
+ if (!inf) { PFATAL("Unable to read '%s'", input_file); }
+
+ } else {
+
+ inf = stdin;
+
+ }
+
+ outfd = open(modified_file, O_WRONLY | O_EXCL | O_CREAT, DEFAULT_PERMISSION);
+
+ if (outfd < 0) { PFATAL("Unable to write to '%s'", modified_file); }
+
+ outf = fdopen(outfd, "w");
+
+ if (!outf) { PFATAL("fdopen() failed"); }
+
+ while (fgets(line, MAX_LINE, inf)) {
+
+ /* In some cases, we want to defer writing the instrumentation trampoline
+ until after all the labels, macros, comments, etc. If we're in this
+ mode, and if the line starts with a tab followed by a character, dump
+ the trampoline now. */
+
+ if (!pass_thru && !skip_intel && !skip_app && !skip_csect && instr_ok &&
+ instrument_next && line[0] == '\t' && isalpha(line[1])) {
+
+ fprintf(outf, use_64bit ? trampoline_fmt_64 : trampoline_fmt_32,
+ R(MAP_SIZE));
+
+ instrument_next = 0;
+ ins_lines++;
+
+ }
+
+ /* Output the actual line, call it a day in pass-thru mode. */
+
+ fputs(line, outf);
+
+ if (pass_thru) { continue; }
+
+ /* All right, this is where the actual fun begins. For one, we only want to
+ instrument the .text section. So, let's keep track of that in processed
+ files - and let's set instr_ok accordingly. */
+
+ if (line[0] == '\t' && line[1] == '.') {
+
+ /* OpenBSD puts jump tables directly inline with the code, which is
+ a bit annoying. They use a specific format of p2align directives
+ around them, so we use that as a signal. */
+
+ if (!clang_mode && instr_ok && !strncmp(line + 2, "p2align ", 8) &&
+ isdigit(line[10]) && line[11] == '\n') {
+
+ skip_next_label = 1;
+
+ }
+
+ if (!strncmp(line + 2, "text\n", 5) ||
+ !strncmp(line + 2, "section\t.text", 13) ||
+ !strncmp(line + 2, "section\t__TEXT,__text", 21) ||
+ !strncmp(line + 2, "section __TEXT,__text", 21)) {
+
+ instr_ok = 1;
+ continue;
+
+ }
+
+ if (!strncmp(line + 2, "section\t", 8) ||
+ !strncmp(line + 2, "section ", 8) || !strncmp(line + 2, "bss\n", 4) ||
+ !strncmp(line + 2, "data\n", 5)) {
+
+ instr_ok = 0;
+ continue;
+
+ }
+
+ }
+
+ /* Detect off-flavor assembly (rare, happens in gdb). When this is
+ encountered, we set skip_csect until the opposite directive is
+ seen, and we do not instrument. */
+
+ if (strstr(line, ".code")) {
+
+ if (strstr(line, ".code32")) { skip_csect = use_64bit; }
+ if (strstr(line, ".code64")) { skip_csect = !use_64bit; }
+
+ }
+
+ /* Detect syntax changes, as could happen with hand-written assembly.
+ Skip Intel blocks, resume instrumentation when back to AT&T. */
+
+ if (strstr(line, ".intel_syntax")) { skip_intel = 1; }
+ if (strstr(line, ".att_syntax")) { skip_intel = 0; }
+
+ /* Detect and skip ad-hoc __asm__ blocks, likewise skipping them. */
+
+ if (line[0] == '#' || line[1] == '#') {
+
+ if (strstr(line, "#APP")) { skip_app = 1; }
+ if (strstr(line, "#NO_APP")) { skip_app = 0; }
+
+ }
+
+ /* If we're in the right mood for instrumenting, check for function
+ names or conditional labels. This is a bit messy, but in essence,
+ we want to catch:
+
+ ^main: - function entry point (always instrumented)
+ ^.L0: - GCC branch label
+ ^.LBB0_0: - clang branch label (but only in clang mode)
+ ^\tjnz foo - conditional branches
+
+ ...but not:
+
+ ^# BB#0: - clang comments
+ ^ # BB#0: - ditto
+ ^.Ltmp0: - clang non-branch labels
+ ^.LC0 - GCC non-branch labels
+ ^.LBB0_0: - ditto (when in GCC mode)
+ ^\tjmp foo - non-conditional jumps
+
+ Additionally, clang and GCC on MacOS X follow a different convention
+ with no leading dots on labels, hence the weird maze of #ifdefs
+ later on.
+
+ */
+
+ if (skip_intel || skip_app || skip_csect || !instr_ok || line[0] == '#' ||
+ line[0] == ' ') {
+
+ continue;
+
+ }
+
+ /* Conditional branch instruction (jnz, etc). We append the instrumentation
+ right after the branch (to instrument the not-taken path) and at the
+ branch destination label (handled later on). */
+
+ if (line[0] == '\t') {
+
+ if (line[1] == 'j' && line[2] != 'm' && R(100) < (long)inst_ratio) {
+
+ fprintf(outf, use_64bit ? trampoline_fmt_64 : trampoline_fmt_32,
+ R(MAP_SIZE));
+
+ ins_lines++;
+
+ }
+
+ continue;
+
+ }
+
+ /* Label of some sort. This may be a branch destination, but we need to
+ read carefully and account for several different formatting
+ conventions. */
+
+#ifdef __APPLE__
+
+ /* Apple: L<whatever><digit>: */
+
+ if ((colon_pos = strstr(line, ":"))) {
+
+ if (line[0] == 'L' && isdigit(*(colon_pos - 1))) {
+
+#else
+
+ /* Everybody else: .L<whatever>: */
+
+ if (strstr(line, ":")) {
+
+ if (line[0] == '.') {
+
+#endif /* __APPLE__ */
+
+ /* .L0: or LBB0_0: style jump destination */
+
+#ifdef __APPLE__
+
+ /* Apple: L<num> / LBB<num> */
+
+ if ((isdigit(line[1]) || (clang_mode && !strncmp(line, "LBB", 3))) &&
+ R(100) < (long)inst_ratio) {
+
+#else
+
+ /* Apple: .L<num> / .LBB<num> */
+
+ if ((isdigit(line[2]) ||
+ (clang_mode && !strncmp(line + 1, "LBB", 3))) &&
+ R(100) < (long)inst_ratio) {
+
+#endif /* __APPLE__ */
+
+ /* An optimization is possible here by adding the code only if the
+ label is mentioned in the code in contexts other than call / jmp.
+ That said, this complicates the code by requiring two-pass
+ processing (messy with stdin), and results in a speed gain
+ typically under 10%, because compilers are generally pretty good
+ about not generating spurious intra-function jumps.
+
+ We use deferred output chiefly to avoid disrupting
+ .Lfunc_begin0-style exception handling calculations (a problem on
+ MacOS X). */
+
+ if (!skip_next_label) {
+
+ instrument_next = 1;
+
+ } else {
+
+ skip_next_label = 0;
+
+ }
+
+ }
+
+ } else {
+
+ /* Function label (always instrumented, deferred mode). */
+
+ instrument_next = 1;
+
+ }
+
+ }
+
+ }
+
+ if (ins_lines) { fputs(use_64bit ? main_payload_64 : main_payload_32, outf); }
+
+ if (input_file) { fclose(inf); }
+ fclose(outf);
+
+ if (!be_quiet) {
+
+ if (!ins_lines) {
+
+ WARNF("No instrumentation targets found%s.",
+ pass_thru ? " (pass-thru mode)" : "");
+
+ } else {
+
+ char modeline[100];
+ snprintf(modeline, sizeof(modeline), "%s%s%s%s%s%s",
+ getenv("AFL_HARDEN") ? "hardened" : "non-hardened",
+ getenv("AFL_USE_ASAN") ? ", ASAN" : "",
+ getenv("AFL_USE_MSAN") ? ", MSAN" : "",
+ getenv("AFL_USE_TSAN") ? ", TSAN" : "",
+ getenv("AFL_USE_UBSAN") ? ", UBSAN" : "",
+ getenv("AFL_USE_LSAN") ? ", LSAN" : "");
+
+ OKF("Instrumented %u locations (%s-bit, %s mode, ratio %u%%).", ins_lines,
+ use_64bit ? "64" : "32", modeline, inst_ratio);
+
+ }
+
+ }
+
+}
+
+/* Main entry point */
+
+int main(int argc, char **argv) {
+
+ s32 pid;
+ u32 rand_seed, i, j;
+ int status;
+ u8 *inst_ratio_str = getenv("AFL_INST_RATIO");
+
+ struct timeval tv;
+ struct timezone tz;
+
+ clang_mode = !!getenv(CLANG_ENV_VAR);
+
+ if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
+
+ SAYF(cCYA "afl-as" VERSION cRST " by Michal Zalewski\n");
+
+ } else {
+
+ be_quiet = 1;
+
+ }
+
+ if (argc < 2 || (argc == 2 && strcmp(argv[1], "-h") == 0)) {
+
+ fprintf(
+ stdout,
+ "afl-as" VERSION
+ " by Michal Zalewski\n"
+ "\n%s [-h]\n\n"
+ "This is a helper application for afl-fuzz. It is a wrapper around GNU "
+ "'as',\n"
+ "executed by the toolchain whenever using afl-gcc or afl-clang. You "
+ "probably\n"
+ "don't want to run this program directly.\n\n"
+
+ "Rarely, when dealing with extremely complex projects, it may be "
+ "advisable\n"
+ "to set AFL_INST_RATIO to a value less than 100 in order to reduce "
+ "the\n"
+ "odds of instrumenting every discovered branch.\n\n"
+ "Environment variables used:\n"
+ "AFL_AS: path to assembler to use for instrumented files\n"
+ "AFL_CC: fall back path to assembler\n"
+ "AFL_CXX: fall back path to assembler\n"
+ "TMPDIR: directory to use for temporary files\n"
+ "TEMP: fall back path to directory for temporary files\n"
+ "TMP: fall back path to directory for temporary files\n"
+ "AFL_INST_RATIO: user specified instrumentation ratio\n"
+ "AFL_QUIET: suppress verbose output\n"
+ "AFL_KEEP_ASSEMBLY: leave instrumented assembly files\n"
+ "AFL_AS_FORCE_INSTRUMENT: force instrumentation for asm sources\n"
+ "AFL_HARDEN, AFL_USE_ASAN, AFL_USE_MSAN, AFL_USE_UBSAN, AFL_USE_LSAN:\n"
+ " used in the instrumentation summary message\n",
+ argv[0]);
+
+ exit(1);
+
+ }
+
+ gettimeofday(&tv, &tz);
+
+ rand_seed = tv.tv_sec ^ tv.tv_usec ^ getpid();
+ // in fast systems where pids can repeat in the same seconds we need this
+ for (i = 1; (s32)i < argc; i++)
+ for (j = 0; j < strlen(argv[i]); j++)
+ rand_seed += argv[i][j];
+
+ srandom(rand_seed);
+
+ edit_params(argc, argv);
+
+ if (inst_ratio_str) {
+
+ if (sscanf(inst_ratio_str, "%u", &inst_ratio) != 1 || inst_ratio > 100) {
+
+ FATAL("Bad value of AFL_INST_RATIO (must be between 0 and 100)");
+
+ }
+
+ }
+
+ if (getenv(AS_LOOP_ENV_VAR)) {
+
+ FATAL("Endless loop when calling 'as' (remove '.' from your PATH)");
+
+ }
+
+ setenv(AS_LOOP_ENV_VAR, "1", 1);
+
+ /* When compiling with ASAN, we don't have a particularly elegant way to skip
+ ASAN-specific branches. But we can probabilistically compensate for
+ that... */
+
+ if (getenv("AFL_USE_ASAN") || getenv("AFL_USE_MSAN")) {
+
+ sanitizer = 1;
+ if (!getenv("AFL_INST_RATIO")) { inst_ratio /= 3; }
+
+ }
+
+ if (!just_version) { add_instrumentation(); }
+
+ if (!(pid = fork())) {
+
+ execvp(as_params[0], (char **)as_params);
+ FATAL("Oops, failed to execute '%s' - check your PATH", as_params[0]);
+
+ }
+
+ if (pid < 0) { PFATAL("fork() failed"); }
+
+ if (waitpid(pid, &status, 0) <= 0) { PFATAL("waitpid() failed"); }
+
+ if (!getenv("AFL_KEEP_ASSEMBLY")) { unlink(modified_file); }
+
+ exit(WEXITSTATUS(status));
+
+}
+
diff --git a/src/afl-cc.c b/src/afl-cc.c
new file mode 100644
index 00000000..2667ae28
--- /dev/null
+++ b/src/afl-cc.c
@@ -0,0 +1,2201 @@
+/*
+ american fuzzy lop++ - compiler instrumentation wrapper
+ -------------------------------------------------------
+
+ Written by Michal Zalewski, Laszlo Szekeres and Marc Heuse
+
+ Copyright 2015, 2016 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ */
+
+#define AFL_MAIN
+
+#include "common.h"
+#include "config.h"
+#include "types.h"
+#include "debug.h"
+#include "alloc-inl.h"
+#include "llvm-alternative-coverage.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <limits.h>
+#include <assert.h>
+
+#if (LLVM_MAJOR - 0 == 0)
+ #undef LLVM_MAJOR
+#endif
+#if !defined(LLVM_MAJOR)
+ #define LLVM_MAJOR 0
+#endif
+#if (LLVM_MINOR - 0 == 0)
+ #undef LLVM_MINOR
+#endif
+#if !defined(LLVM_MINOR)
+ #define LLVM_MINOR 0
+#endif
+
+static u8 * obj_path; /* Path to runtime libraries */
+static u8 **cc_params; /* Parameters passed to the real CC */
+static u32 cc_par_cnt = 1; /* Param count, including argv0 */
+static u8 clang_mode; /* Invoked as afl-clang*? */
+static u8 llvm_fullpath[PATH_MAX];
+static u8 instrument_mode, instrument_opt_mode, ngram_size, ctx_k, lto_mode;
+static u8 compiler_mode, plusplus_mode, have_instr_env = 0;
+static u8 have_gcc, have_llvm, have_gcc_plugin, have_lto, have_instr_list = 0;
+static u8 * lto_flag = AFL_CLANG_FLTO, *argvnull;
+static u8 debug;
+static u8 cwd[4096];
+static u8 cmplog_mode;
+u8 use_stdin; /* dummy */
+static int passthrough;
+// static u8 *march_opt = CFLAGS_OPT;
+
+enum {
+
+ INSTRUMENT_DEFAULT = 0,
+ INSTRUMENT_CLASSIC = 1,
+ INSTRUMENT_AFL = 1,
+ INSTRUMENT_PCGUARD = 2,
+ INSTRUMENT_CFG = 3,
+ INSTRUMENT_LTO = 4,
+ INSTRUMENT_LLVMNATIVE = 5,
+ INSTRUMENT_GCC = 6,
+ INSTRUMENT_CLANG = 7,
+ INSTRUMENT_OPT_CTX = 8,
+ INSTRUMENT_OPT_NGRAM = 16,
+ INSTRUMENT_OPT_CALLER = 32,
+ INSTRUMENT_OPT_CTX_K = 64,
+
+};
+
+char instrument_mode_string[18][18] = {
+
+ "DEFAULT",
+ "CLASSIC",
+ "PCGUARD",
+ "CFG",
+ "LTO",
+ "PCGUARD-NATIVE",
+ "GCC",
+ "CLANG",
+ "CTX",
+ "CALLER",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "NGRAM",
+ ""
+
+};
+
+enum {
+
+ UNSET = 0,
+ LTO = 1,
+ LLVM = 2,
+ GCC_PLUGIN = 3,
+ GCC = 4,
+ CLANG = 5
+
+};
+
+char compiler_mode_string[7][12] = {
+
+ "AUTOSELECT", "LLVM-LTO", "LLVM", "GCC_PLUGIN",
+ "GCC", "CLANG", ""
+
+};
+
+u8 *getthecwd() {
+
+ if (getcwd(cwd, sizeof(cwd)) == NULL) {
+
+ static u8 fail[] = "";
+ return fail;
+
+ }
+
+ return cwd;
+
+}
+
+/* Try to find a specific runtime we need, returns NULL on fail. */
+
+/*
+ in find_object() we look here:
+
+ 1. if obj_path is already set we look there first
+ 2. then we check the $AFL_PATH environment variable location if set
+ 3. next we check argv[0] if it has path information and use it
+ a) we also check ../lib/afl
+ 4. if 3. failed we check /proc (only Linux, Android, NetBSD, DragonFly, and
+ FreeBSD with procfs)
+ a) and check here in ../lib/afl too
+ 5. we look into the AFL_PATH define (usually /usr/local/lib/afl)
+ 6. we finally try the current directory
+
+ if all these attempts fail - we return NULL and the caller has to decide
+ what to do.
+*/
+
+static u8 *find_object(u8 *obj, u8 *argv0) {
+
+ u8 *afl_path = getenv("AFL_PATH");
+ u8 *slash = NULL, *tmp;
+
+ if (afl_path) {
+
+ tmp = alloc_printf("%s/%s", afl_path, obj);
+
+ if (debug) DEBUGF("Trying %s\n", tmp);
+
+ if (!access(tmp, R_OK)) {
+
+ obj_path = afl_path;
+ return tmp;
+
+ }
+
+ ck_free(tmp);
+
+ }
+
+ if (argv0) {
+
+ slash = strrchr(argv0, '/');
+
+ if (slash) {
+
+ u8 *dir = ck_strdup(argv0);
+
+ slash = strrchr(dir, '/');
+ *slash = 0;
+
+ tmp = alloc_printf("%s/%s", dir, obj);
+
+ if (debug) DEBUGF("Trying %s\n", tmp);
+
+ if (!access(tmp, R_OK)) {
+
+ obj_path = dir;
+ return tmp;
+
+ }
+
+ ck_free(tmp);
+ tmp = alloc_printf("%s/../lib/afl/%s", dir, obj);
+
+ if (debug) DEBUGF("Trying %s\n", tmp);
+
+ if (!access(tmp, R_OK)) {
+
+ u8 *dir2 = alloc_printf("%s/../lib/afl", dir);
+ obj_path = dir2;
+ ck_free(dir);
+ return tmp;
+
+ }
+
+ ck_free(tmp);
+ ck_free(dir);
+
+ }
+
+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__linux__) || \
+ defined(__ANDROID__) || defined(__NetBSD__)
+ #define HAS_PROC_FS 1
+#endif
+#ifdef HAS_PROC_FS
+ else {
+
+ char *procname = NULL;
+ #if defined(__FreeBSD__) || defined(__DragonFly__)
+ procname = "/proc/curproc/file";
+ #elif defined(__linux__) || defined(__ANDROID__)
+ procname = "/proc/self/exe";
+ #elif defined(__NetBSD__)
+ procname = "/proc/curproc/exe";
+ #endif
+ if (procname) {
+
+ char exepath[PATH_MAX];
+ ssize_t exepath_len = readlink(procname, exepath, sizeof(exepath));
+ if (exepath_len > 0 && exepath_len < PATH_MAX) {
+
+ exepath[exepath_len] = 0;
+ slash = strrchr(exepath, '/');
+
+ if (slash) {
+
+ *slash = 0;
+ tmp = alloc_printf("%s/%s", exepath, obj);
+
+ if (!access(tmp, R_OK)) {
+
+ u8 *dir = alloc_printf("%s", exepath);
+ obj_path = dir;
+ return tmp;
+
+ }
+
+ ck_free(tmp);
+ tmp = alloc_printf("%s/../lib/afl/%s", exepath, obj);
+
+ if (debug) DEBUGF("Trying %s\n", tmp);
+
+ if (!access(tmp, R_OK)) {
+
+ u8 *dir = alloc_printf("%s/../lib/afl/", exepath);
+ obj_path = dir;
+ return tmp;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+#endif
+#undef HAS_PROC_FS
+
+ }
+
+ tmp = alloc_printf("%s/%s", AFL_PATH, obj);
+
+ if (debug) DEBUGF("Trying %s\n", tmp);
+
+ if (!access(tmp, R_OK)) {
+
+ obj_path = AFL_PATH;
+ return tmp;
+
+ }
+
+ ck_free(tmp);
+
+ tmp = alloc_printf("./%s", obj);
+
+ if (debug) DEBUGF("Trying %s\n", tmp);
+
+ if (!access(tmp, R_OK)) {
+
+ obj_path = ".";
+ return tmp;
+
+ }
+
+ ck_free(tmp);
+
+ if (debug) DEBUGF("Trying ... giving up\n");
+
+ return NULL;
+
+}
+
+/* Copy argv to cc_params, making the necessary edits. */
+
+static void edit_params(u32 argc, char **argv, char **envp) {
+
+ u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0, shared_linking = 0,
+ preprocessor_only = 0, have_unroll = 0, have_o = 0, have_pic = 0,
+ have_c = 0, partial_linking = 0;
+
+ cc_params = ck_alloc((argc + 128) * sizeof(u8 *));
+
+ if (lto_mode) {
+
+ if (lto_flag[0] != '-')
+ FATAL(
+ "Using afl-clang-lto is not possible because Makefile magic did not "
+ "identify the correct -flto flag");
+ else
+ compiler_mode = LTO;
+
+ }
+
+ if (plusplus_mode) {
+
+ u8 *alt_cxx = getenv("AFL_CXX");
+
+ if (!alt_cxx) {
+
+ if (compiler_mode >= GCC_PLUGIN) {
+
+ if (compiler_mode == GCC) {
+
+ alt_cxx = clang_mode ? "clang++" : "g++";
+
+ } else if (compiler_mode == CLANG) {
+
+ alt_cxx = "clang++";
+
+ } else {
+
+ alt_cxx = "g++";
+
+ }
+
+ } else {
+
+ if (USE_BINDIR)
+ snprintf(llvm_fullpath, sizeof(llvm_fullpath), "%s/clang++",
+ LLVM_BINDIR);
+ else
+ snprintf(llvm_fullpath, sizeof(llvm_fullpath), CLANGPP_BIN);
+ alt_cxx = llvm_fullpath;
+
+ }
+
+ }
+
+ cc_params[0] = alt_cxx;
+
+ } else {
+
+ u8 *alt_cc = getenv("AFL_CC");
+
+ if (!alt_cc) {
+
+ if (compiler_mode >= GCC_PLUGIN) {
+
+ if (compiler_mode == GCC) {
+
+ alt_cc = clang_mode ? "clang" : "gcc";
+
+ } else if (compiler_mode == CLANG) {
+
+ alt_cc = "clang";
+
+ } else {
+
+ alt_cc = "gcc";
+
+ }
+
+ } else {
+
+ if (USE_BINDIR)
+ snprintf(llvm_fullpath, sizeof(llvm_fullpath), "%s/clang",
+ LLVM_BINDIR);
+ else
+ snprintf(llvm_fullpath, sizeof(llvm_fullpath), CLANG_BIN);
+ alt_cc = llvm_fullpath;
+
+ }
+
+ }
+
+ cc_params[0] = alt_cc;
+
+ }
+
+ if (compiler_mode == GCC || compiler_mode == CLANG) {
+
+ cc_params[cc_par_cnt++] = "-B";
+ cc_params[cc_par_cnt++] = obj_path;
+
+ if (clang_mode || compiler_mode == CLANG) {
+
+ cc_params[cc_par_cnt++] = "-no-integrated-as";
+
+ }
+
+ }
+
+ if (compiler_mode == GCC_PLUGIN) {
+
+ char *fplugin_arg = alloc_printf("-fplugin=%s/afl-gcc-pass.so", obj_path);
+ cc_params[cc_par_cnt++] = fplugin_arg;
+ cc_params[cc_par_cnt++] = "-fno-if-conversion";
+ cc_params[cc_par_cnt++] = "-fno-if-conversion2";
+
+ }
+
+ if (compiler_mode == LLVM || compiler_mode == LTO) {
+
+ cc_params[cc_par_cnt++] = "-Wno-unused-command-line-argument";
+
+ if (lto_mode && have_instr_env) {
+
+#if LLVM_MAJOR >= 11 /* use new pass manager */
+ cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
+ cc_params[cc_par_cnt++] = alloc_printf(
+ "-fpass-plugin=%s/afl-llvm-lto-instrumentlist.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/afl-llvm-lto-instrumentlist.so", obj_path);
+#endif
+
+ }
+
+ if (getenv("AFL_LLVM_DICT2FILE")) {
+
+#if LLVM_MAJOR >= 11 /* use new pass manager */
+ cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
+ cc_params[cc_par_cnt++] =
+ alloc_printf("-fpass-plugin=%s/afl-llvm-dict2file.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/afl-llvm-dict2file.so", obj_path);
+#endif
+
+ }
+
+ // laf
+ if (getenv("LAF_SPLIT_SWITCHES") || getenv("AFL_LLVM_LAF_SPLIT_SWITCHES")) {
+
+#if LLVM_MAJOR >= 11 /* use new pass manager */
+ cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
+ cc_params[cc_par_cnt++] =
+ alloc_printf("-fpass-plugin=%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);
+#endif
+
+ }
+
+ if (getenv("LAF_TRANSFORM_COMPARES") ||
+ getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES")) {
+
+#if LLVM_MAJOR >= 11 /* use new pass manager */
+ cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
+ cc_params[cc_par_cnt++] =
+ alloc_printf("-fpass-plugin=%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);
+#endif
+
+ }
+
+ if (getenv("LAF_SPLIT_COMPARES") || getenv("AFL_LLVM_LAF_SPLIT_COMPARES") ||
+ getenv("AFL_LLVM_LAF_SPLIT_FLOATS")) {
+
+#if LLVM_MAJOR >= 11 /* use new pass manager */
+ cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
+ cc_params[cc_par_cnt++] =
+ alloc_printf("-fpass-plugin=%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);
+#endif
+
+ }
+
+ // /laf
+
+ unsetenv("AFL_LD");
+ unsetenv("AFL_LD_CALLER");
+
+ if (cmplog_mode) {
+
+ cc_params[cc_par_cnt++] = "-fno-inline";
+
+#if LLVM_MAJOR >= 11 /* use new pass manager */
+ cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
+ cc_params[cc_par_cnt++] =
+ alloc_printf("-fpass-plugin=%s/cmplog-switches-pass.so", obj_path);
+ cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
+ cc_params[cc_par_cnt++] =
+ alloc_printf("-fpass-plugin=%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/cmplog-switches-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);
+#endif
+
+ }
+
+ //#if LLVM_MAJOR >= 13
+ // // Use the old pass manager in LLVM 14 which the afl++ passes still
+ // use. cc_params[cc_par_cnt++] = "-flegacy-pass-manager";
+ //#endif
+
+ if (lto_mode && !have_c) {
+
+ u8 *ld_path = NULL;
+ if (getenv("AFL_REAL_LD")) {
+
+ ld_path = strdup(getenv("AFL_REAL_LD"));
+
+ } else {
+
+ ld_path = strdup(AFL_REAL_LD);
+
+ }
+
+ if (!ld_path || !*ld_path) {
+
+ if (ld_path) {
+
+ // Freeing empty string
+ free(ld_path);
+
+ }
+
+ ld_path = strdup("ld.lld");
+
+ }
+
+ if (!ld_path) { PFATAL("Could not allocate mem for ld_path"); }
+#if defined(AFL_CLANG_LDPATH) && LLVM_MAJOR >= 12
+ cc_params[cc_par_cnt++] = alloc_printf("--ld-path=%s", ld_path);
+#else
+ cc_params[cc_par_cnt++] = alloc_printf("-fuse-ld=%s", ld_path);
+#endif
+ free(ld_path);
+
+#if defined(AFL_CLANG_LDPATH) && LLVM_MAJOR >= 13
+ cc_params[cc_par_cnt++] = "-Wl,--lto-legacy-pass-manager";
+#else
+ cc_params[cc_par_cnt++] = "-fno-experimental-new-pass-manager";
+#endif
+
+ cc_params[cc_par_cnt++] = "-Wl,--allow-multiple-definition";
+ cc_params[cc_par_cnt++] =
+ alloc_printf("-Wl,-mllvm=-load=%s/SanitizerCoverageLTO.so", obj_path);
+ cc_params[cc_par_cnt++] = lto_flag;
+
+ } else {
+
+ if (instrument_mode == INSTRUMENT_PCGUARD) {
+
+#if LLVM_MAJOR >= 11
+ #if defined __ANDROID__ || ANDROID
+ cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
+ instrument_mode = INSTRUMENT_LLVMNATIVE;
+ #else
+ if (have_instr_list) {
+
+ if (!be_quiet)
+ SAYF(
+ "Using unoptimized trace-pc-guard, due usage of "
+ "-fsanitize-coverage-allow/denylist, you can use "
+ "AFL_LLVM_ALLOWLIST/AFL_LLMV_DENYLIST instead.\n");
+ cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
+ instrument_mode = INSTRUMENT_LLVMNATIVE;
+
+ } else {
+
+ #if LLVM_MAJOR >= 11 /* use new pass manager */
+ cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
+ cc_params[cc_par_cnt++] = alloc_printf(
+ "-fpass-plugin=%s/SanitizerCoveragePCGUARD.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/SanitizerCoveragePCGUARD.so", obj_path);
+ #endif
+
+ }
+
+ #endif
+#else
+ #if LLVM_MAJOR >= 4
+ if (!be_quiet)
+ SAYF(
+ "Using unoptimized trace-pc-guard, upgrade to llvm 10.0.1+ for "
+ "enhanced version.\n");
+ cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
+ instrument_mode = INSTRUMENT_LLVMNATIVE;
+ #else
+ FATAL("pcguard instrumentation requires llvm 4.0.1+");
+ #endif
+#endif
+
+ } else if (instrument_mode == INSTRUMENT_LLVMNATIVE) {
+
+#if LLVM_MAJOR >= 4
+ cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
+#else
+ FATAL("pcguard instrumentation requires llvm 4.0.1+");
+#endif
+
+ } else {
+
+#if LLVM_MAJOR >= 11 /* use new pass manager */
+ cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
+ cc_params[cc_par_cnt++] =
+ alloc_printf("-fpass-plugin=%s/afl-llvm-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/afl-llvm-pass.so", obj_path);
+#endif
+
+ }
+
+ }
+
+ if (cmplog_mode) {
+
+#if LLVM_MAJOR >= 11
+ cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
+ cc_params[cc_par_cnt++] = alloc_printf(
+ "-fpass-plugin=%s/cmplog-instructions-pass.so", obj_path);
+ cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
+ cc_params[cc_par_cnt++] =
+ alloc_printf("-fpass-plugin=%s/cmplog-routines-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-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-routines-pass.so", obj_path);
+#endif
+
+ }
+
+ // cc_params[cc_par_cnt++] = "-Qunused-arguments";
+
+ if (lto_mode && argc > 1) {
+
+ u32 idx;
+ for (idx = 1; idx < argc; idx++) {
+
+ if (!strncasecmp(argv[idx], "-fpic", 5)) have_pic = 1;
+
+ }
+
+ if (!have_pic) cc_params[cc_par_cnt++] = "-fPIC";
+
+ }
+
+ }
+
+ /* Detect stray -v calls from ./configure scripts. */
+
+ u8 skip_next = 0, non_dash = 0;
+ while (--argc) {
+
+ u8 *cur = *(++argv);
+
+ if (skip_next) {
+
+ skip_next = 0;
+ continue;
+
+ }
+
+ if (cur[0] != '-') { non_dash = 1; }
+ if (!strncmp(cur, "--afl", 5)) continue;
+ if (lto_mode && !strncmp(cur, "-fuse-ld=", 9)) continue;
+ if (lto_mode && !strncmp(cur, "--ld-path=", 10)) continue;
+ if (!strncmp(cur, "-fno-unroll", 11)) continue;
+ if (strstr(cur, "afl-compiler-rt") || strstr(cur, "afl-llvm-rt")) continue;
+ if (!strcmp(cur, "-Wl,-z,defs") || !strcmp(cur, "-Wl,--no-undefined") ||
+ !strcmp(cur, "--no-undefined")) {
+
+ continue;
+
+ }
+
+ if (!strcmp(cur, "-z") || !strcmp(cur, "-Wl,-z")) {
+
+ u8 *param = *(argv + 1);
+ if (!strcmp(param, "defs") || !strcmp(param, "-Wl,defs")) {
+
+ skip_next = 1;
+ continue;
+
+ }
+
+ }
+
+ if ((compiler_mode == GCC || compiler_mode == GCC_PLUGIN) &&
+ !strncmp(cur, "-stdlib=", 8)) {
+
+ if (!be_quiet) { WARNF("Found '%s' - stripping!", cur); }
+ continue;
+
+ }
+
+ if ((!strncmp(cur, "-fsanitize=fuzzer-", strlen("-fsanitize=fuzzer-")) ||
+ !strncmp(cur, "-fsanitize-coverage", strlen("-fsanitize-coverage"))) &&
+ (strncmp(cur, "sanitize-coverage-allow",
+ strlen("sanitize-coverage-allow")) &&
+ strncmp(cur, "sanitize-coverage-deny",
+ strlen("sanitize-coverage-deny")) &&
+ instrument_mode != INSTRUMENT_LLVMNATIVE)) {
+
+ if (!be_quiet) { WARNF("Found '%s' - stripping!", cur); }
+ continue;
+
+ }
+
+ if (!strcmp(cur, "-fsanitize=fuzzer")) {
+
+ u8 *afllib = find_object("libAFLDriver.a", argv[0]);
+
+ if (!be_quiet) {
+
+ OKF("Found '-fsanitize=fuzzer', replacing with libAFLDriver.a");
+
+ }
+
+ if (!afllib) {
+
+ if (!be_quiet) {
+
+ WARNF(
+ "Cannot find 'libAFLDriver.a' to replace '-fsanitize=fuzzer' in "
+ "the flags - this will fail!");
+
+ }
+
+ } else {
+
+ cc_params[cc_par_cnt++] = afllib;
+
+#ifdef __APPLE__
+ cc_params[cc_par_cnt++] = "-undefined";
+ cc_params[cc_par_cnt++] = "dynamic_lookup";
+#endif
+
+ }
+
+ continue;
+
+ }
+
+ if (!strcmp(cur, "-m32")) bit_mode = 32;
+ if (!strcmp(cur, "armv7a-linux-androideabi")) bit_mode = 32;
+ if (!strcmp(cur, "-m64")) bit_mode = 64;
+
+ if (!strncmp(cur, "-fsanitize-coverage-", 20) && strstr(cur, "list="))
+ have_instr_list = 1;
+
+ if (!strcmp(cur, "-fsanitize=address") || !strcmp(cur, "-fsanitize=memory"))
+ asan_set = 1;
+
+ if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1;
+
+ if (!strcmp(cur, "-x")) x_set = 1;
+ if (!strcmp(cur, "-E")) preprocessor_only = 1;
+ if (!strcmp(cur, "-shared")) shared_linking = 1;
+ if (!strcmp(cur, "-dynamiclib")) shared_linking = 1;
+ if (!strcmp(cur, "--target=wasm32-wasi")) passthrough = 1;
+ if (!strcmp(cur, "-Wl,-r")) partial_linking = 1;
+ if (!strcmp(cur, "-Wl,-i")) partial_linking = 1;
+ if (!strcmp(cur, "-Wl,--relocatable")) partial_linking = 1;
+ if (!strcmp(cur, "-r")) partial_linking = 1;
+ if (!strcmp(cur, "--relocatable")) partial_linking = 1;
+ if (!strcmp(cur, "-c")) have_c = 1;
+
+ if (!strncmp(cur, "-O", 2)) have_o = 1;
+ if (!strncmp(cur, "-funroll-loop", 13)) have_unroll = 1;
+
+ cc_params[cc_par_cnt++] = cur;
+
+ }
+
+ // in case LLVM is installed not via a package manager or "make install"
+ // e.g. compiled download or compiled from github then its ./lib directory
+ // might not be in the search path. Add it if so.
+ u8 *libdir = strdup(LLVM_LIBDIR);
+ if (plusplus_mode && strlen(libdir) && strncmp(libdir, "/usr", 4) &&
+ strncmp(libdir, "/lib", 4)) {
+
+ cc_params[cc_par_cnt++] = "-rpath";
+ cc_params[cc_par_cnt++] = libdir;
+
+ } else {
+
+ free(libdir);
+
+ }
+
+ if (getenv("AFL_HARDEN")) {
+
+ cc_params[cc_par_cnt++] = "-fstack-protector-all";
+
+ if (!fortify_set) cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2";
+
+ }
+
+ if (!asan_set) {
+
+ if (getenv("AFL_USE_ASAN")) {
+
+ if (getenv("AFL_USE_MSAN")) FATAL("ASAN and MSAN are mutually exclusive");
+
+ if (getenv("AFL_HARDEN"))
+ FATAL("ASAN and AFL_HARDEN are mutually exclusive");
+
+ cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE";
+ cc_params[cc_par_cnt++] = "-fsanitize=address";
+
+ } else if (getenv("AFL_USE_MSAN")) {
+
+ if (getenv("AFL_USE_ASAN")) FATAL("ASAN and MSAN are mutually exclusive");
+
+ if (getenv("AFL_HARDEN"))
+ FATAL("MSAN and AFL_HARDEN are mutually exclusive");
+
+ cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE";
+ cc_params[cc_par_cnt++] = "-fsanitize=memory";
+
+ }
+
+ }
+
+ if (getenv("AFL_USE_UBSAN")) {
+
+ cc_params[cc_par_cnt++] = "-fsanitize=undefined";
+ cc_params[cc_par_cnt++] = "-fsanitize-undefined-trap-on-error";
+ cc_params[cc_par_cnt++] = "-fno-sanitize-recover=all";
+ cc_params[cc_par_cnt++] = "-fno-omit-frame-pointer";
+
+ }
+
+ if (getenv("AFL_USE_TSAN")) {
+
+ cc_params[cc_par_cnt++] = "-fsanitize=thread";
+ cc_params[cc_par_cnt++] = "-fno-omit-frame-pointer";
+
+ }
+
+ if (getenv("AFL_USE_LSAN")) {
+
+ cc_params[cc_par_cnt++] = "-fsanitize=leak";
+ cc_params[cc_par_cnt++] = "-includesanitizer/lsan_interface.h";
+ cc_params[cc_par_cnt++] =
+ "-D__AFL_LEAK_CHECK()={if(__lsan_do_recoverable_leak_check() > 0) "
+ "_exit(23); }";
+ cc_params[cc_par_cnt++] = "-D__AFL_LSAN_OFF()=__lsan_disable();";
+ cc_params[cc_par_cnt++] = "-D__AFL_LSAN_ON()=__lsan_enable();";
+
+ }
+
+ if (getenv("AFL_USE_CFISAN")) {
+
+ if (!lto_mode) {
+
+ uint32_t i = 0, found = 0;
+ while (envp[i] != NULL && !found)
+ if (strncmp("-flto", envp[i++], 5) == 0) found = 1;
+ if (!found) cc_params[cc_par_cnt++] = "-flto";
+
+ }
+
+ cc_params[cc_par_cnt++] = "-fsanitize=cfi";
+ cc_params[cc_par_cnt++] = "-fvisibility=hidden";
+
+ }
+
+ if (!getenv("AFL_DONT_OPTIMIZE")) {
+
+ cc_params[cc_par_cnt++] = "-g";
+ if (!have_o) cc_params[cc_par_cnt++] = "-O3";
+ if (!have_unroll) cc_params[cc_par_cnt++] = "-funroll-loops";
+ // if (strlen(march_opt) > 1 && march_opt[0] == '-')
+ // cc_params[cc_par_cnt++] = march_opt;
+
+ }
+
+ if (getenv("AFL_NO_BUILTIN") || getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES") ||
+ getenv("LAF_TRANSFORM_COMPARES") || getenv("AFL_LLVM_LAF_ALL") ||
+ lto_mode) {
+
+ cc_params[cc_par_cnt++] = "-fno-builtin-strcmp";
+ cc_params[cc_par_cnt++] = "-fno-builtin-strncmp";
+ cc_params[cc_par_cnt++] = "-fno-builtin-strcasecmp";
+ cc_params[cc_par_cnt++] = "-fno-builtin-strncasecmp";
+ cc_params[cc_par_cnt++] = "-fno-builtin-memcmp";
+ cc_params[cc_par_cnt++] = "-fno-builtin-bcmp";
+ cc_params[cc_par_cnt++] = "-fno-builtin-strstr";
+ cc_params[cc_par_cnt++] = "-fno-builtin-strcasestr";
+
+ }
+
+#if defined(USEMMAP) && !defined(__HAIKU__) && !__APPLE__
+ if (!have_c) cc_params[cc_par_cnt++] = "-lrt";
+#endif
+
+ cc_params[cc_par_cnt++] = "-D__AFL_HAVE_MANUAL_CONTROL=1";
+ cc_params[cc_par_cnt++] = "-D__AFL_COMPILER=1";
+ cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1";
+
+ /* When the user tries to use persistent or deferred forkserver modes by
+ appending a single line to the program, we want to reliably inject a
+ signature into the binary (to be picked up by afl-fuzz) and we want
+ to call a function from the runtime .o file. This is unnecessarily
+ painful for three reasons:
+
+ 1) We need to convince the compiler not to optimize out the signature.
+ This is done with __attribute__((used)).
+
+ 2) We need to convince the linker, when called with -Wl,--gc-sections,
+ not to do the same. This is done by forcing an assignment to a
+ 'volatile' pointer.
+
+ 3) We need to declare __afl_persistent_loop() in the global namespace,
+ but doing this within a method in a class is hard - :: and extern "C"
+ are forbidden and __attribute__((alias(...))) doesn't work. Hence the
+ __asm__ aliasing trick.
+
+ */
+
+ cc_params[cc_par_cnt++] =
+ "-D__AFL_FUZZ_INIT()="
+ "int __afl_sharedmem_fuzzing = 1;"
+ "extern unsigned int *__afl_fuzz_len;"
+ "extern unsigned char *__afl_fuzz_ptr;"
+ "unsigned char __afl_fuzz_alt[1048576];"
+ "unsigned char *__afl_fuzz_alt_ptr = __afl_fuzz_alt;";
+
+ if (plusplus_mode) {
+
+ cc_params[cc_par_cnt++] =
+ "-D__AFL_COVERAGE()=int __afl_selective_coverage = 1;"
+ "extern \"C\" void __afl_coverage_discard();"
+ "extern \"C\" void __afl_coverage_skip();"
+ "extern \"C\" void __afl_coverage_on();"
+ "extern \"C\" void __afl_coverage_off();";
+
+ } else {
+
+ cc_params[cc_par_cnt++] =
+ "-D__AFL_COVERAGE()=int __afl_selective_coverage = 1;"
+ "void __afl_coverage_discard();"
+ "void __afl_coverage_skip();"
+ "void __afl_coverage_on();"
+ "void __afl_coverage_off();";
+
+ }
+
+ cc_params[cc_par_cnt++] =
+ "-D__AFL_COVERAGE_START_OFF()=int __afl_selective_coverage_start_off = "
+ "1;";
+ cc_params[cc_par_cnt++] = "-D__AFL_COVERAGE_ON()=__afl_coverage_on()";
+ cc_params[cc_par_cnt++] = "-D__AFL_COVERAGE_OFF()=__afl_coverage_off()";
+ cc_params[cc_par_cnt++] =
+ "-D__AFL_COVERAGE_DISCARD()=__afl_coverage_discard()";
+ cc_params[cc_par_cnt++] = "-D__AFL_COVERAGE_SKIP()=__afl_coverage_skip()";
+ cc_params[cc_par_cnt++] =
+ "-D__AFL_FUZZ_TESTCASE_BUF=(__afl_fuzz_ptr ? __afl_fuzz_ptr : "
+ "__afl_fuzz_alt_ptr)";
+ cc_params[cc_par_cnt++] =
+ "-D__AFL_FUZZ_TESTCASE_LEN=(__afl_fuzz_ptr ? *__afl_fuzz_len : "
+ "(*__afl_fuzz_len = read(0, __afl_fuzz_alt_ptr, 1048576)) == 0xffffffff "
+ "? 0 : *__afl_fuzz_len)";
+
+ cc_params[cc_par_cnt++] =
+ "-D__AFL_LOOP(_A)="
+ "({ static volatile char *_B __attribute__((used,unused)); "
+ " _B = (char*)\"" PERSIST_SIG
+ "\"; "
+#ifdef __APPLE__
+ "__attribute__((visibility(\"default\"))) "
+ "int _L(unsigned int) __asm__(\"___afl_persistent_loop\"); "
+#else
+ "__attribute__((visibility(\"default\"))) "
+ "int _L(unsigned int) __asm__(\"__afl_persistent_loop\"); "
+#endif /* ^__APPLE__ */
+ "_L(_A); })";
+
+ cc_params[cc_par_cnt++] =
+ "-D__AFL_INIT()="
+ "do { static volatile char *_A __attribute__((used,unused)); "
+ " _A = (char*)\"" DEFER_SIG
+ "\"; "
+#ifdef __APPLE__
+ "__attribute__((visibility(\"default\"))) "
+ "void _I(void) __asm__(\"___afl_manual_init\"); "
+#else
+ "__attribute__((visibility(\"default\"))) "
+ "void _I(void) __asm__(\"__afl_manual_init\"); "
+#endif /* ^__APPLE__ */
+ "_I(); } while (0)";
+
+ if (x_set) {
+
+ cc_params[cc_par_cnt++] = "-x";
+ cc_params[cc_par_cnt++] = "none";
+
+ }
+
+ // prevent unnecessary build errors
+ if (compiler_mode != GCC_PLUGIN && compiler_mode != GCC) {
+
+ cc_params[cc_par_cnt++] = "-Wno-unused-command-line-argument";
+
+ }
+
+ if (preprocessor_only || have_c || !non_dash) {
+
+ /* In the preprocessor_only case (-E), we are not actually compiling at
+ all but requesting the compiler to output preprocessed sources only.
+ We must not add the runtime in this case because the compiler will
+ simply output its binary content back on stdout, breaking any build
+ systems that rely on a separate source preprocessing step. */
+ cc_params[cc_par_cnt] = NULL;
+ return;
+
+ }
+
+#ifndef __ANDROID__
+
+ if (compiler_mode != GCC && compiler_mode != CLANG) {
+
+ switch (bit_mode) {
+
+ case 0:
+ if (!shared_linking && !partial_linking)
+ cc_params[cc_par_cnt++] =
+ alloc_printf("%s/afl-compiler-rt.o", obj_path);
+ if (lto_mode)
+ cc_params[cc_par_cnt++] =
+ alloc_printf("%s/afl-llvm-rt-lto.o", obj_path);
+ break;
+
+ case 32:
+ if (!shared_linking && !partial_linking) {
+
+ cc_params[cc_par_cnt++] =
+ alloc_printf("%s/afl-compiler-rt-32.o", obj_path);
+ if (access(cc_params[cc_par_cnt - 1], R_OK))
+ FATAL("-m32 is not supported by your compiler");
+
+ }
+
+ if (lto_mode) {
+
+ cc_params[cc_par_cnt++] =
+ alloc_printf("%s/afl-llvm-rt-lto-32.o", obj_path);
+ if (access(cc_params[cc_par_cnt - 1], R_OK))
+ FATAL("-m32 is not supported by your compiler");
+
+ }
+
+ break;
+
+ case 64:
+ if (!shared_linking && !partial_linking) {
+
+ cc_params[cc_par_cnt++] =
+ alloc_printf("%s/afl-compiler-rt-64.o", obj_path);
+ if (access(cc_params[cc_par_cnt - 1], R_OK))
+ FATAL("-m64 is not supported by your compiler");
+
+ }
+
+ if (lto_mode) {
+
+ cc_params[cc_par_cnt++] =
+ alloc_printf("%s/afl-llvm-rt-lto-64.o", obj_path);
+ if (access(cc_params[cc_par_cnt - 1], R_OK))
+ FATAL("-m64 is not supported by your compiler");
+
+ }
+
+ break;
+
+ }
+
+ #if !defined(__APPLE__) && !defined(__sun)
+ if (!shared_linking && !partial_linking)
+ cc_params[cc_par_cnt++] =
+ alloc_printf("-Wl,--dynamic-list=%s/dynamic_list.txt", obj_path);
+ #endif
+
+ #if defined(__APPLE__)
+ if (shared_linking || partial_linking) {
+
+ cc_params[cc_par_cnt++] = "-Wl,-U";
+ cc_params[cc_par_cnt++] = "-Wl,___afl_area_ptr";
+ cc_params[cc_par_cnt++] = "-Wl,-U";
+ cc_params[cc_par_cnt++] = "-Wl,___sanitizer_cov_trace_pc_guard_init";
+
+ }
+
+ #endif
+
+ }
+
+ #if defined(USEMMAP) && !defined(__HAIKU__) && !__APPLE__
+ cc_params[cc_par_cnt++] = "-lrt";
+ #endif
+
+#endif
+
+ cc_params[cc_par_cnt] = NULL;
+
+}
+
+/* Main entry point */
+
+int main(int argc, char **argv, char **envp) {
+
+ int i;
+ char *callname = argv[0], *ptr = NULL;
+
+ if (getenv("AFL_DEBUG")) {
+
+ debug = 1;
+ if (strcmp(getenv("AFL_DEBUG"), "0") == 0) unsetenv("AFL_DEBUG");
+
+ } else if (getenv("AFL_QUIET"))
+
+ be_quiet = 1;
+
+ if (getenv("AFL_LLVM_INSTRUMENT_FILE") || getenv("AFL_LLVM_WHITELIST") ||
+ getenv("AFL_LLVM_ALLOWLIST") || getenv("AFL_LLVM_DENYLIST") ||
+ getenv("AFL_LLVM_BLOCKLIST")) {
+
+ have_instr_env = 1;
+
+ }
+
+ if (getenv("AFL_PASSTHROUGH") || getenv("AFL_NOOPT")) {
+
+ passthrough = 1;
+ if (!debug) { be_quiet = 1; }
+
+ }
+
+ if ((ptr = strrchr(callname, '/')) != NULL) callname = ptr + 1;
+ argvnull = (u8 *)argv[0];
+ check_environment_vars(envp);
+
+ if ((ptr = find_object("as", argv[0])) != NULL) {
+
+ have_gcc = 1;
+ ck_free(ptr);
+
+ }
+
+#if (LLVM_MAJOR >= 3)
+
+ if ((ptr = find_object("SanitizerCoverageLTO.so", argv[0])) != NULL) {
+
+ have_lto = 1;
+ ck_free(ptr);
+
+ }
+
+ if ((ptr = find_object("cmplog-routines-pass.so", argv[0])) != NULL) {
+
+ have_llvm = 1;
+ ck_free(ptr);
+
+ }
+
+#endif
+
+#ifdef __ANDROID__
+ have_llvm = 1;
+#endif
+
+ if ((ptr = find_object("afl-gcc-pass.so", argv[0])) != NULL) {
+
+ have_gcc_plugin = 1;
+ ck_free(ptr);
+
+ }
+
+#if (LLVM_MAJOR >= 3)
+
+ if (strncmp(callname, "afl-clang-fast", 14) == 0) {
+
+ compiler_mode = LLVM;
+
+ } else if (strncmp(callname, "afl-clang-lto", 13) == 0 ||
+
+ strncmp(callname, "afl-lto", 7) == 0) {
+
+ compiler_mode = LTO;
+
+ } else
+
+#endif
+ if (strncmp(callname, "afl-gcc-fast", 12) == 0 ||
+
+ strncmp(callname, "afl-g++-fast", 12) == 0) {
+
+ compiler_mode = GCC_PLUGIN;
+
+ } else if (strncmp(callname, "afl-gcc", 7) == 0 ||
+
+ strncmp(callname, "afl-g++", 7) == 0) {
+
+ compiler_mode = GCC;
+
+ } else if (strcmp(callname, "afl-clang") == 0 ||
+
+ strcmp(callname, "afl-clang++") == 0) {
+
+ compiler_mode = CLANG;
+
+ }
+
+ if ((ptr = getenv("AFL_CC_COMPILER"))) {
+
+ if (compiler_mode) {
+
+ if (!be_quiet) {
+
+ WARNF(
+ "\"AFL_CC_COMPILER\" is set but a specific compiler was already "
+ "selected by command line parameter or symlink, ignoring the "
+ "environment variable!");
+
+ }
+
+ } else {
+
+ if (strncasecmp(ptr, "LTO", 3) == 0) {
+
+ compiler_mode = LTO;
+
+ } else if (strncasecmp(ptr, "LLVM", 4) == 0) {
+
+ compiler_mode = LLVM;
+
+ } else if (strncasecmp(ptr, "GCC_P", 5) == 0 ||
+
+ strncasecmp(ptr, "GCC-P", 5) == 0 ||
+ strncasecmp(ptr, "GCCP", 4) == 0) {
+
+ compiler_mode = GCC_PLUGIN;
+
+ } else if (strcasecmp(ptr, "GCC") == 0) {
+
+ compiler_mode = GCC;
+
+ } else
+
+ FATAL("Unknown AFL_CC_COMPILER mode: %s\n", ptr);
+
+ }
+
+ }
+
+ if (strcmp(callname, "afl-clang") == 0 ||
+ strcmp(callname, "afl-clang++") == 0) {
+
+ clang_mode = 1;
+ compiler_mode = CLANG;
+
+ if (strcmp(callname, "afl-clang++") == 0) { plusplus_mode = 1; }
+
+ }
+
+ for (i = 1; i < argc; i++) {
+
+ if (strncmp(argv[i], "--afl", 5) == 0) {
+
+ if (!strcmp(argv[i], "--afl_noopt") || !strcmp(argv[i], "--afl-noopt")) {
+
+ passthrough = 1;
+ argv[i] = "-g"; // we have to overwrite it, -g is always good
+ continue;
+
+ }
+
+ if (compiler_mode && !be_quiet) {
+
+ WARNF(
+ "--afl-... compiler mode supersedes the AFL_CC_COMPILER and "
+ "symlink compiler selection!");
+
+ }
+
+ ptr = argv[i];
+ ptr += 5;
+ while (*ptr == '-')
+ ptr++;
+
+ if (strncasecmp(ptr, "LTO", 3) == 0) {
+
+ compiler_mode = LTO;
+
+ } else if (strncasecmp(ptr, "LLVM", 4) == 0) {
+
+ compiler_mode = LLVM;
+
+ } else if (strncasecmp(ptr, "PCGUARD", 7) == 0 ||
+
+ strncasecmp(ptr, "PC-GUARD", 8) == 0) {
+
+ compiler_mode = LLVM;
+ instrument_mode = INSTRUMENT_PCGUARD;
+
+ } else if (strcasecmp(ptr, "INSTRIM") == 0 ||
+
+ strcasecmp(ptr, "CFG") == 0) {
+
+ FATAL(
+ "InsTrim instrumentation was removed. Use a modern LLVM and "
+ "PCGUARD (default in afl-cc).\n");
+
+ } else if (strcasecmp(ptr, "AFL") == 0 ||
+
+ strcasecmp(ptr, "CLASSIC") == 0) {
+
+ compiler_mode = LLVM;
+ instrument_mode = INSTRUMENT_CLASSIC;
+
+ } else if (strcasecmp(ptr, "LLVMNATIVE") == 0 ||
+
+ strcasecmp(ptr, "NATIVE") == 0 ||
+ strcasecmp(ptr, "LLVM-NATIVE") == 0) {
+
+ compiler_mode = LLVM;
+ instrument_mode = INSTRUMENT_LLVMNATIVE;
+
+ } else if (strncasecmp(ptr, "GCC_P", 5) == 0 ||
+
+ strncasecmp(ptr, "GCC-P", 5) == 0 ||
+ strncasecmp(ptr, "GCCP", 4) == 0) {
+
+ compiler_mode = GCC_PLUGIN;
+
+ } else if (strcasecmp(ptr, "GCC") == 0) {
+
+ compiler_mode = GCC;
+
+ } else if (strncasecmp(ptr, "CLANG", 5) == 0) {
+
+ compiler_mode = CLANG;
+
+ } else
+
+ FATAL("Unknown --afl-... compiler mode: %s\n", argv[i]);
+
+ }
+
+ }
+
+ if (strlen(callname) > 2 &&
+ (strncmp(callname + strlen(callname) - 2, "++", 2) == 0 ||
+ strstr(callname, "-g++") != NULL))
+ plusplus_mode = 1;
+
+ if (getenv("USE_TRACE_PC") || getenv("AFL_USE_TRACE_PC") ||
+ getenv("AFL_LLVM_USE_TRACE_PC") || getenv("AFL_TRACE_PC")) {
+
+ if (instrument_mode == 0)
+ instrument_mode = INSTRUMENT_PCGUARD;
+ else if (instrument_mode != INSTRUMENT_PCGUARD)
+ FATAL("you cannot set AFL_LLVM_INSTRUMENT and AFL_TRACE_PC together");
+
+ }
+
+ if (have_instr_env && getenv("AFL_DONT_OPTIMIZE") && !be_quiet) {
+
+ WARNF(
+ "AFL_LLVM_ALLOWLIST/DENYLIST and AFL_DONT_OPTIMIZE cannot be combined "
+ "for file matching, only function matching!");
+
+ }
+
+ if (getenv("AFL_LLVM_INSTRIM") || getenv("INSTRIM") ||
+ getenv("INSTRIM_LIB")) {
+
+ FATAL(
+ "InsTrim instrumentation was removed. Use a modern LLVM and PCGUARD "
+ "(default in afl-cc).\n");
+
+ }
+
+ if (getenv("AFL_LLVM_CTX")) instrument_opt_mode |= INSTRUMENT_OPT_CTX;
+ if (getenv("AFL_LLVM_CALLER")) instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
+
+ if (getenv("AFL_LLVM_NGRAM_SIZE")) {
+
+ instrument_opt_mode |= INSTRUMENT_OPT_NGRAM;
+ ngram_size = atoi(getenv("AFL_LLVM_NGRAM_SIZE"));
+ if (ngram_size < 2 || ngram_size > NGRAM_SIZE_MAX)
+ FATAL(
+ "NGRAM instrumentation mode must be between 2 and NGRAM_SIZE_MAX "
+ "(%u)",
+ NGRAM_SIZE_MAX);
+
+ }
+
+ if (getenv("AFL_LLVM_CTX_K")) {
+
+ ctx_k = atoi(getenv("AFL_LLVM_CTX_K"));
+ if (ctx_k < 1 || ctx_k > CTX_MAX_K)
+ FATAL("K-CTX instrumentation mode must be between 1 and CTX_MAX_K (%u)",
+ CTX_MAX_K);
+ if (ctx_k == 1) {
+
+ setenv("AFL_LLVM_CALLER", "1", 1);
+ unsetenv("AFL_LLVM_CTX_K");
+ instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
+
+ } else {
+
+ instrument_opt_mode |= INSTRUMENT_OPT_CTX_K;
+
+ }
+
+ }
+
+ if (getenv("AFL_LLVM_INSTRUMENT")) {
+
+ u8 *ptr2 = strtok(getenv("AFL_LLVM_INSTRUMENT"), ":,;");
+
+ while (ptr2) {
+
+ if (strncasecmp(ptr2, "afl", strlen("afl")) == 0 ||
+ strncasecmp(ptr2, "classic", strlen("classic")) == 0) {
+
+ if (instrument_mode == INSTRUMENT_LTO) {
+
+ instrument_mode = INSTRUMENT_CLASSIC;
+ lto_mode = 1;
+
+ } else if (!instrument_mode || instrument_mode == INSTRUMENT_AFL)
+
+ instrument_mode = INSTRUMENT_AFL;
+ else
+ FATAL("main instrumentation mode already set with %s",
+ instrument_mode_string[instrument_mode]);
+
+ }
+
+ if (strncasecmp(ptr2, "pc-guard", strlen("pc-guard")) == 0 ||
+ strncasecmp(ptr2, "pcguard", strlen("pcguard")) == 0) {
+
+ if (!instrument_mode || instrument_mode == INSTRUMENT_PCGUARD)
+ instrument_mode = INSTRUMENT_PCGUARD;
+ else
+ FATAL("main instrumentation mode already set with %s",
+ instrument_mode_string[instrument_mode]);
+
+ }
+
+ if (strncasecmp(ptr2, "llvmnative", strlen("llvmnative")) == 0 ||
+ strncasecmp(ptr2, "llvm-native", strlen("llvm-native")) == 0) {
+
+ if (!instrument_mode || instrument_mode == INSTRUMENT_LLVMNATIVE)
+ instrument_mode = INSTRUMENT_LLVMNATIVE;
+ else
+ FATAL("main instrumentation mode already set with %s",
+ instrument_mode_string[instrument_mode]);
+
+ }
+
+ if (strncasecmp(ptr2, "cfg", strlen("cfg")) == 0 ||
+ strncasecmp(ptr2, "instrim", strlen("instrim")) == 0) {
+
+ FATAL(
+ "InsTrim instrumentation was removed. Use a modern LLVM and "
+ "PCGUARD (default in afl-cc).\n");
+
+ }
+
+ if (strncasecmp(ptr2, "lto", strlen("lto")) == 0) {
+
+ lto_mode = 1;
+ if (!instrument_mode || instrument_mode == INSTRUMENT_LTO)
+ instrument_mode = INSTRUMENT_LTO;
+ else
+ FATAL("main instrumentation mode already set with %s",
+ instrument_mode_string[instrument_mode]);
+
+ }
+
+ if (strcasecmp(ptr2, "gcc") == 0) {
+
+ if (!instrument_mode || instrument_mode == INSTRUMENT_GCC)
+ instrument_mode = INSTRUMENT_GCC;
+ else if (instrument_mode != INSTRUMENT_GCC)
+ FATAL("main instrumentation mode already set with %s",
+ instrument_mode_string[instrument_mode]);
+ compiler_mode = GCC;
+
+ }
+
+ if (strcasecmp(ptr2, "clang") == 0) {
+
+ if (!instrument_mode || instrument_mode == INSTRUMENT_CLANG)
+ instrument_mode = INSTRUMENT_CLANG;
+ else if (instrument_mode != INSTRUMENT_CLANG)
+ FATAL("main instrumentation mode already set with %s",
+ instrument_mode_string[instrument_mode]);
+ compiler_mode = CLANG;
+
+ }
+
+ if (strncasecmp(ptr2, "ctx-", strlen("ctx-")) == 0 ||
+ strncasecmp(ptr2, "kctx-", strlen("c-ctx-")) == 0 ||
+ strncasecmp(ptr2, "k-ctx-", strlen("k-ctx-")) == 0) {
+
+ u8 *ptr3 = ptr2;
+ while (*ptr3 && (*ptr3 < '0' || *ptr3 > '9'))
+ ptr3++;
+
+ if (!*ptr3) {
+
+ if ((ptr3 = getenv("AFL_LLVM_CTX_K")) == NULL)
+ FATAL(
+ "you must set the K-CTX K with (e.g. for value 2) "
+ "AFL_LLVM_INSTRUMENT=ctx-2");
+
+ }
+
+ ctx_k = atoi(ptr3);
+ if (ctx_k < 1 || ctx_k > CTX_MAX_K)
+ FATAL(
+ "K-CTX instrumentation option must be between 1 and CTX_MAX_K "
+ "(%u)",
+ CTX_MAX_K);
+
+ if (ctx_k == 1) {
+
+ instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
+ setenv("AFL_LLVM_CALLER", "1", 1);
+ unsetenv("AFL_LLVM_CTX_K");
+
+ } else {
+
+ instrument_opt_mode |= (INSTRUMENT_OPT_CTX_K);
+ u8 *ptr4 = alloc_printf("%u", ctx_k);
+ setenv("AFL_LLVM_CTX_K", ptr4, 1);
+
+ }
+
+ }
+
+ if (strcasecmp(ptr2, "ctx") == 0) {
+
+ instrument_opt_mode |= INSTRUMENT_OPT_CTX;
+ setenv("AFL_LLVM_CTX", "1", 1);
+
+ }
+
+ if (strncasecmp(ptr2, "caller", strlen("caller")) == 0) {
+
+ instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
+ setenv("AFL_LLVM_CALLER", "1", 1);
+
+ }
+
+ if (strncasecmp(ptr2, "ngram", strlen("ngram")) == 0) {
+
+ u8 *ptr3 = ptr2 + strlen("ngram");
+ while (*ptr3 && (*ptr3 < '0' || *ptr3 > '9'))
+ ptr3++;
+
+ if (!*ptr3) {
+
+ if ((ptr3 = getenv("AFL_LLVM_NGRAM_SIZE")) == NULL)
+ FATAL(
+ "you must set the NGRAM size with (e.g. for value 2) "
+ "AFL_LLVM_INSTRUMENT=ngram-2");
+
+ }
+
+ ngram_size = atoi(ptr3);
+ if (ngram_size < 2 || ngram_size > NGRAM_SIZE_MAX)
+ FATAL(
+ "NGRAM instrumentation option must be between 2 and "
+ "NGRAM_SIZE_MAX (%u)",
+ NGRAM_SIZE_MAX);
+ instrument_opt_mode |= (INSTRUMENT_OPT_NGRAM);
+ u8 *ptr4 = alloc_printf("%u", ngram_size);
+ setenv("AFL_LLVM_NGRAM_SIZE", ptr4, 1);
+
+ }
+
+ ptr2 = strtok(NULL, ":,;");
+
+ }
+
+ }
+
+ if ((instrument_opt_mode & INSTRUMENT_OPT_CTX) &&
+ (instrument_opt_mode & INSTRUMENT_OPT_CALLER)) {
+
+ FATAL("you cannot set CTX and CALLER together");
+
+ }
+
+ if ((instrument_opt_mode & INSTRUMENT_OPT_CTX) &&
+ (instrument_opt_mode & INSTRUMENT_OPT_CTX_K)) {
+
+ FATAL("you cannot set CTX and K-CTX together");
+
+ }
+
+ if ((instrument_opt_mode & INSTRUMENT_OPT_CALLER) &&
+ (instrument_opt_mode & INSTRUMENT_OPT_CTX_K)) {
+
+ FATAL("you cannot set CALLER and K-CTX together");
+
+ }
+
+ if (instrument_opt_mode && instrument_mode == INSTRUMENT_DEFAULT &&
+ (compiler_mode == LLVM || compiler_mode == UNSET)) {
+
+ instrument_mode = INSTRUMENT_CLASSIC;
+ compiler_mode = LLVM;
+
+ }
+
+ if (!compiler_mode) {
+
+ // lto is not a default because outside of afl-cc RANLIB and AR have to
+ // be set to llvm versions so this would work
+ if (have_llvm)
+ compiler_mode = LLVM;
+ else if (have_gcc_plugin)
+ compiler_mode = GCC_PLUGIN;
+ else if (have_gcc)
+#ifdef __APPLE__
+ // on OSX clang masquerades as GCC
+ compiler_mode = CLANG;
+#else
+ compiler_mode = GCC;
+#endif
+ else if (have_lto)
+ compiler_mode = LTO;
+ else
+ FATAL("no compiler mode available");
+
+ }
+
+ if (compiler_mode == GCC) {
+
+ if (clang_mode) {
+
+ instrument_mode = INSTRUMENT_CLANG;
+
+ } else {
+
+ instrument_mode = INSTRUMENT_GCC;
+
+ }
+
+ }
+
+ if (compiler_mode == CLANG) {
+
+ instrument_mode = INSTRUMENT_CLANG;
+ setenv(CLANG_ENV_VAR, "1", 1); // used by afl-as
+
+ }
+
+ if (argc < 2 || strncmp(argv[1], "-h", 2) == 0) {
+
+ printf("afl-cc" VERSION
+ " by Michal Zalewski, Laszlo Szekeres, Marc Heuse\n");
+
+ SAYF(
+ "\n"
+ "afl-cc/afl-c++ [options]\n"
+ "\n"
+ "This is a helper application for afl-fuzz. It serves as a drop-in "
+ "replacement\n"
+ "for gcc and clang, letting you recompile third-party code with the "
+ "required\n"
+ "runtime instrumentation. A common use pattern would be one of the "
+ "following:\n\n"
+
+ " CC=afl-cc CXX=afl-c++ ./configure --disable-shared\n"
+ " cmake -DCMAKE_C_COMPILERC=afl-cc -DCMAKE_CXX_COMPILER=afl-c++ .\n"
+ " CC=afl-cc CXX=afl-c++ meson\n\n");
+
+ SAYF(
+ " |------------- FEATURES "
+ "-------------|\n"
+ "MODES: NCC PERSIST DICT LAF "
+ "CMPLOG SELECT\n"
+ " [LTO] llvm LTO: %s%s\n"
+ " PCGUARD DEFAULT yes yes yes yes yes "
+ " yes\n"
+ " CLASSIC yes yes yes yes yes "
+ " yes\n"
+ " [LLVM] llvm: %s%s\n"
+ " PCGUARD %s yes yes module yes yes "
+ "yes\n"
+ " CLASSIC %s no yes module yes yes "
+ "yes\n"
+ " - NORMAL\n"
+ " - CALLER\n"
+ " - CTX\n"
+ " - NGRAM-{2-16}\n"
+ " [GCC_PLUGIN] gcc plugin: %s%s\n"
+ " CLASSIC DEFAULT no yes no no no "
+ "yes\n"
+ " [GCC/CLANG] simple gcc/clang: %s%s\n"
+ " CLASSIC DEFAULT no no no no no "
+ "no\n\n",
+ have_lto ? "AVAILABLE" : "unavailable!",
+ compiler_mode == LTO ? " [SELECTED]" : "",
+ have_llvm ? "AVAILABLE" : "unavailable!",
+ compiler_mode == LLVM ? " [SELECTED]" : "",
+ LLVM_MAJOR >= 7 ? "DEFAULT" : " ",
+ LLVM_MAJOR >= 7 ? " " : "DEFAULT",
+ have_gcc_plugin ? "AVAILABLE" : "unavailable!",
+ compiler_mode == GCC_PLUGIN ? " [SELECTED]" : "",
+ have_gcc ? "AVAILABLE" : "unavailable!",
+ (compiler_mode == GCC || compiler_mode == CLANG) ? " [SELECTED]" : "");
+
+ SAYF(
+ "Modes:\n"
+ " To select the compiler mode use a symlink version (e.g. "
+ "afl-clang-fast), set\n"
+ " the environment variable AFL_CC_COMPILER to a mode (e.g. LLVM) or "
+ "use the\n"
+ " command line parameter --afl-MODE (e.g. --afl-llvm). If none is "
+ "selected,\n"
+ " afl-cc will select the best available (LLVM -> GCC_PLUGIN -> GCC).\n"
+ " The best is LTO but it often needs RANLIB and AR settings outside "
+ "of afl-cc.\n\n");
+
+#if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0)
+ #define NATIVE_MSG \
+ " LLVM-NATIVE: use llvm's native PCGUARD instrumentation (less " \
+ "performant)\n"
+#else
+ #define NATIVE_MSG ""
+#endif
+
+ SAYF(
+ "Sub-Modes: (set via env AFL_LLVM_INSTRUMENT, afl-cc selects the best "
+ "available)\n"
+ " PCGUARD: Dominator tree instrumentation (best!) (README.llvm.md)\n"
+
+ NATIVE_MSG
+
+ " CLASSIC: decision target instrumentation (README.llvm.md)\n"
+ " CALLER: CLASSIC + single callee context "
+ "(instrumentation/README.ctx.md)\n"
+ " CTX: CLASSIC + full callee context "
+ "(instrumentation/README.ctx.md)\n"
+ " NGRAM-x: CLASSIC + previous path "
+ "((instrumentation/README.ngram.md)\n\n");
+
+#undef NATIVE_MSG
+
+ SAYF(
+ "Features: (see documentation links)\n"
+ " NCC: non-colliding coverage [automatic] (that is an amazing "
+ "thing!)\n"
+ " (instrumentation/README.lto.md)\n"
+ " PERSIST: persistent mode support [code] (huge speed increase!)\n"
+ " (instrumentation/README.persistent_mode.md)\n"
+ " DICT: dictionary in the target [yes=automatic or llvm module "
+ "pass]\n"
+ " (instrumentation/README.lto.md + "
+ "instrumentation/README.llvm.md)\n"
+ " LAF: comparison splitting [env] "
+ "(instrumentation/README.laf-intel.md)\n"
+ " CMPLOG: input2state exploration [env] "
+ "(instrumentation/README.cmplog.md)\n"
+ " SELECT: selective instrumentation (allow/deny) on filename or "
+ "function [env]\n"
+ " (instrumentation/README.instrument_list.md)\n\n");
+
+ if (argc < 2 || strncmp(argv[1], "-hh", 3)) {
+
+ SAYF(
+ "To see all environment variables for the configuration of afl-cc "
+ "use \"-hh\".\n");
+
+ } else {
+
+ SAYF(
+ "Environment variables used:\n"
+ " AFL_CC: path to the C compiler to use\n"
+ " AFL_CXX: path to the C++ compiler to use\n"
+ " AFL_DEBUG: enable developer debugging output\n"
+ " AFL_DONT_OPTIMIZE: disable optimization instead of -O3\n"
+ " AFL_NO_BUILTIN: no builtins for string compare functions (for "
+ "libtokencap.so)\n"
+ " AFL_NOOP: behave like a normal compiler (to pass configure "
+ "tests)\n"
+ " AFL_PATH: path to instrumenting pass and runtime "
+ "(afl-compiler-rt.*o)\n"
+ " AFL_IGNORE_UNKNOWN_ENVS: don't warn on unknown env vars\n"
+ " AFL_INST_RATIO: percentage of branches to instrument\n"
+ " AFL_QUIET: suppress verbose output\n"
+ " AFL_HARDEN: adds code hardening to catch memory bugs\n"
+ " AFL_USE_ASAN: activate address sanitizer\n"
+ " AFL_USE_CFISAN: activate control flow sanitizer\n"
+ " AFL_USE_MSAN: activate memory sanitizer\n"
+ " AFL_USE_UBSAN: activate undefined behaviour sanitizer\n"
+ " AFL_USE_TSAN: activate thread sanitizer\n"
+ " AFL_USE_LSAN: activate leak-checker sanitizer\n");
+
+ if (have_gcc_plugin)
+ SAYF(
+ "\nGCC Plugin-specific environment variables:\n"
+ " AFL_GCC_OUT_OF_LINE: disable inlined instrumentation\n"
+ " AFL_GCC_SKIP_NEVERZERO: do not skip zero on trace counters\n"
+ " AFL_GCC_INSTRUMENT_FILE: enable selective instrumentation by "
+ "filename\n");
+
+#if LLVM_MAJOR >= 9
+ #define COUNTER_BEHAVIOUR \
+ " AFL_LLVM_SKIP_NEVERZERO: do not skip zero on trace counters\n"
+#else
+ #define COUNTER_BEHAVIOUR \
+ " AFL_LLVM_NOT_ZERO: use cycling trace counters that skip zero\n"
+#endif
+ if (have_llvm)
+ SAYF(
+ "\nLLVM/LTO/afl-clang-fast/afl-clang-lto specific environment "
+ "variables:\n"
+ " AFL_LLVM_THREADSAFE_INST: instrument with thread safe counters, "
+ "disables neverzero\n"
+
+ COUNTER_BEHAVIOUR
+
+ " AFL_LLVM_DICT2FILE: generate an afl dictionary based on found "
+ "comparisons\n"
+ " AFL_LLVM_LAF_ALL: enables all LAF splits/transforms\n"
+ " AFL_LLVM_LAF_SPLIT_COMPARES: enable cascaded comparisons\n"
+ " AFL_LLVM_LAF_SPLIT_COMPARES_BITW: size limit (default 8)\n"
+ " AFL_LLVM_LAF_SPLIT_SWITCHES: cascaded comparisons on switches\n"
+ " AFL_LLVM_LAF_SPLIT_FLOATS: cascaded comparisons on floats\n"
+ " AFL_LLVM_LAF_TRANSFORM_COMPARES: cascade comparisons for string "
+ "functions\n"
+ " AFL_LLVM_ALLOWLIST/AFL_LLVM_DENYLIST: enable "
+ "instrument allow/\n"
+ " deny listing (selective instrumentation)\n");
+
+ if (have_llvm)
+ SAYF(
+ " AFL_LLVM_CMPLOG: log operands of comparisons (RedQueen "
+ "mutator)\n"
+ " AFL_LLVM_INSTRUMENT: set instrumentation mode:\n"
+ " CLASSIC, PCGUARD, LTO, GCC, CLANG, CALLER, CTX, NGRAM-2 "
+ "..-16\n"
+ " You can also use the old environment variables instead:\n"
+ " AFL_LLVM_USE_TRACE_PC: use LLVM trace-pc-guard instrumentation\n"
+ " AFL_LLVM_CALLER: use single context sensitive coverage (for "
+ "CLASSIC)\n"
+ " AFL_LLVM_CTX: use full context sensitive coverage (for "
+ "CLASSIC)\n"
+ " AFL_LLVM_NGRAM_SIZE: use ngram prev_loc count coverage (for "
+ "CLASSIC)\n");
+
+#ifdef AFL_CLANG_FLTO
+ if (have_lto)
+ SAYF(
+ "\nLTO/afl-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\n"
+ " 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 "
+ "bb\n"
+ " AFL_REAL_LD: use this lld linker instead of the compiled in "
+ "path\n"
+ "If anything fails - be sure to read README.lto.md!\n");
+#endif
+
+ SAYF(
+ "\nYou can supply --afl-noopt to not instrument, like AFL_NOOPT. "
+ "(this is helpful\n"
+ "in some build systems if you do not want to instrument "
+ "everything.\n");
+
+ }
+
+ SAYF(
+ "\nFor any information on the available instrumentations and options "
+ "please \n"
+ "consult the README.md, especially section 3.1 about instrumenting "
+ "targets.\n\n");
+
+#if (LLVM_MAJOR >= 3)
+ if (have_lto)
+ SAYF("afl-cc LTO with ld=%s %s\n", AFL_REAL_LD, AFL_CLANG_FLTO);
+ if (have_llvm)
+ SAYF("afl-cc LLVM version %d using the binary path \"%s\".\n", LLVM_MAJOR,
+ LLVM_BINDIR);
+#endif
+
+#ifdef USEMMAP
+ #if !defined(__HAIKU__)
+ SAYF("Compiled with shm_open support.\n");
+ #else
+ SAYF("Compiled with shm_open support (adds -lrt when linking).\n");
+ #endif
+#else
+ SAYF("Compiled with shmat support.\n");
+#endif
+ SAYF("\n");
+
+ SAYF(
+ "Do not be overwhelmed :) afl-cc uses good defaults if no options are "
+ "selected.\n"
+ "Read the documentation for FEATURES though, all are good but few are "
+ "defaults.\n"
+ "Recommended is afl-clang-lto with AFL_LLVM_CMPLOG or afl-clang-fast "
+ "with\n"
+ "AFL_LLVM_CMPLOG and AFL_LLVM_DICT2FILE.\n\n");
+
+ exit(1);
+
+ }
+
+ if (compiler_mode == LTO) {
+
+ if (instrument_mode == 0 || instrument_mode == INSTRUMENT_LTO ||
+ instrument_mode == INSTRUMENT_CFG ||
+ instrument_mode == INSTRUMENT_PCGUARD) {
+
+ lto_mode = 1;
+ // force CFG
+ // if (!instrument_mode) {
+
+ instrument_mode = INSTRUMENT_PCGUARD;
+ // ptr = instrument_mode_string[instrument_mode];
+ // }
+
+ } else if (instrument_mode == INSTRUMENT_CLASSIC) {
+
+ lto_mode = 1;
+
+ } else {
+
+ if (!be_quiet) {
+
+ WARNF("afl-clang-lto called with mode %s, using that mode instead",
+ instrument_mode_string[instrument_mode]);
+
+ }
+
+ }
+
+ }
+
+ if (instrument_mode == 0 && compiler_mode < GCC_PLUGIN) {
+
+#if LLVM_MAJOR >= 7
+ #if LLVM_MAJOR < 11 && (LLVM_MAJOR < 10 || LLVM_MINOR < 1)
+ if (have_instr_env) {
+
+ instrument_mode = INSTRUMENT_AFL;
+ if (!be_quiet) {
+
+ WARNF(
+ "Switching to classic instrumentation because "
+ "AFL_LLVM_ALLOWLIST/DENYLIST does not work with PCGUARD < 10.0.1.");
+
+ }
+
+ } else
+
+ #endif
+ instrument_mode = INSTRUMENT_PCGUARD;
+
+#else
+ instrument_mode = INSTRUMENT_AFL;
+#endif
+
+ }
+
+ if (instrument_opt_mode && compiler_mode != LLVM)
+ FATAL("CTX, CALLER and NGRAM can only be used in LLVM mode");
+
+ if (!instrument_opt_mode) {
+
+ if (lto_mode && instrument_mode == INSTRUMENT_CFG)
+ instrument_mode = INSTRUMENT_PCGUARD;
+ ptr = instrument_mode_string[instrument_mode];
+
+ } else {
+
+ char *ptr2 = alloc_printf(" + NGRAM-%u", ngram_size);
+ char *ptr3 = alloc_printf(" + K-CTX-%u", ctx_k);
+
+ ptr = alloc_printf(
+ "%s%s%s%s%s", instrument_mode_string[instrument_mode],
+ (instrument_opt_mode & INSTRUMENT_OPT_CTX) ? " + CTX" : "",
+ (instrument_opt_mode & INSTRUMENT_OPT_CALLER) ? " + CALLER" : "",
+ (instrument_opt_mode & INSTRUMENT_OPT_NGRAM) ? ptr2 : "",
+ (instrument_opt_mode & INSTRUMENT_OPT_CTX_K) ? ptr3 : "");
+
+ ck_free(ptr2);
+ ck_free(ptr3);
+
+ }
+
+#ifndef AFL_CLANG_FLTO
+ if (lto_mode)
+ FATAL(
+ "instrumentation mode LTO specified but LLVM support not available "
+ "(requires LLVM 11 or higher)");
+#endif
+
+ if (instrument_opt_mode && instrument_mode != INSTRUMENT_CLASSIC)
+ FATAL(
+ "CALLER, CTX and NGRAM instrumentation options can only be used with "
+ "the LLVM CLASSIC instrumentation mode.");
+
+ if (getenv("AFL_LLVM_SKIP_NEVERZERO") && getenv("AFL_LLVM_NOT_ZERO"))
+ FATAL(
+ "AFL_LLVM_NOT_ZERO and AFL_LLVM_SKIP_NEVERZERO can not be set "
+ "together");
+
+#if LLVM_MAJOR < 11 && (LLVM_MAJOR < 10 || LLVM_MINOR < 1)
+ if (instrument_mode == INSTRUMENT_PCGUARD && have_instr_env) {
+
+ FATAL(
+ "Instrumentation type PCGUARD does not support "
+ "AFL_LLVM_ALLOWLIST/DENYLIST! Use LLVM 10.0.1+ instead.");
+
+ }
+
+#endif
+
+ u8 *ptr2;
+
+ if ((ptr2 = getenv("AFL_LLVM_DICT2FILE")) != NULL && *ptr2 != '/')
+ FATAL("AFL_LLVM_DICT2FILE must be set to an absolute file path");
+
+ if ((isatty(2) && !be_quiet) || debug) {
+
+ SAYF(cCYA
+ "afl-cc" VERSION cRST
+ " by Michal Zalewski, Laszlo Szekeres, Marc Heuse - mode: %s-%s\n",
+ compiler_mode_string[compiler_mode], ptr);
+
+ }
+
+ if (!be_quiet && (compiler_mode == GCC || compiler_mode == CLANG)) {
+
+ WARNF(
+ "You are using outdated instrumentation, install LLVM and/or "
+ "gcc-plugin and use afl-clang-fast/afl-clang-lto/afl-gcc-fast "
+ "instead!");
+
+ }
+
+ if (debug) {
+
+ DEBUGF("cd '%s';", getthecwd());
+ for (i = 0; i < argc; i++)
+ SAYF(" '%s'", argv[i]);
+ SAYF("\n");
+ fflush(stdout);
+ fflush(stderr);
+
+ }
+
+ if (getenv("AFL_LLVM_LAF_ALL")) {
+
+ setenv("AFL_LLVM_LAF_SPLIT_SWITCHES", "1", 1);
+ setenv("AFL_LLVM_LAF_SPLIT_COMPARES", "1", 1);
+ setenv("AFL_LLVM_LAF_SPLIT_FLOATS", "1", 1);
+ setenv("AFL_LLVM_LAF_TRANSFORM_COMPARES", "1", 1);
+
+ }
+
+ cmplog_mode = getenv("AFL_CMPLOG") || getenv("AFL_LLVM_CMPLOG");
+ if (!be_quiet && cmplog_mode)
+ printf("CmpLog mode by <andreafioraldi@gmail.com>\n");
+
+#if !defined(__ANDROID__) && !defined(ANDROID)
+ ptr = find_object("afl-compiler-rt.o", argv[0]);
+
+ if (!ptr) {
+
+ FATAL(
+ "Unable to find 'afl-compiler-rt.o'. Please set the AFL_PATH "
+ "environment variable.");
+
+ }
+
+ if (debug) { DEBUGF("rt=%s obj_path=%s\n", ptr, obj_path); }
+
+ ck_free(ptr);
+#endif
+
+ edit_params(argc, argv, envp);
+
+ if (debug) {
+
+ DEBUGF("cd '%s';", getthecwd());
+ for (i = 0; i < (s32)cc_par_cnt; i++)
+ SAYF(" '%s'", cc_params[i]);
+ SAYF("\n");
+ fflush(stdout);
+ fflush(stderr);
+
+ }
+
+ if (passthrough) {
+
+ argv[0] = cc_params[0];
+ execvp(cc_params[0], (char **)argv);
+
+ } else {
+
+ execvp(cc_params[0], (char **)cc_params);
+
+ }
+
+ FATAL("Oops, failed to execute '%s' - check your PATH", cc_params[0]);
+
+ return 0;
+
+}
+
diff --git a/src/afl-common.c b/src/afl-common.c
new file mode 100644
index 00000000..eca7d272
--- /dev/null
+++ b/src/afl-common.c
@@ -0,0 +1,1246 @@
+/*
+ american fuzzy lop++ - common routines
+ --------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Andrea Fioraldi <andreafioraldi@gmail.com>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ Gather some functions common to multiple executables
+
+ - detect_file_args
+
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#define _GNU_SOURCE
+#define __USE_GNU
+#include <string.h>
+#include <strings.h>
+#include <math.h>
+#include <sys/mman.h>
+
+#include "debug.h"
+#include "alloc-inl.h"
+#include "envs.h"
+#include "common.h"
+
+/* Detect @@ in args. */
+#include <unistd.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+u8 be_quiet = 0;
+u8 *doc_path = "";
+u8 last_intr = 0;
+
+#ifndef AFL_PATH
+ #define AFL_PATH "/usr/local/lib/afl/"
+#endif
+
+u32 check_binary_signatures(u8 *fn) {
+
+ int ret = 0, fd = open(fn, O_RDONLY);
+ if (fd < 0) { PFATAL("Unable to open '%s'", fn); }
+ struct stat st;
+ if (fstat(fd, &st) < 0) { PFATAL("Unable to fstat '%s'", fn); }
+ u32 f_len = st.st_size;
+ u8 *f_data = mmap(0, f_len, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (f_data == MAP_FAILED) { PFATAL("Unable to mmap file '%s'", fn); }
+ close(fd);
+
+ if (memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG) + 1)) {
+
+ if (!be_quiet) { OKF(cPIN "Persistent mode binary detected."); }
+ setenv(PERSIST_ENV_VAR, "1", 1);
+ ret = 1;
+
+ } else if (getenv("AFL_PERSISTENT")) {
+
+ if (!be_quiet) { OKF(cPIN "Persistent mode enforced."); }
+ setenv(PERSIST_ENV_VAR, "1", 1);
+ ret = 1;
+
+ } else if (getenv("AFL_FRIDA_PERSISTENT_ADDR")) {
+
+ if (!be_quiet) {
+
+ OKF("FRIDA Persistent mode configuration options detected.");
+
+ }
+
+ setenv(PERSIST_ENV_VAR, "1", 1);
+ ret = 1;
+
+ }
+
+ if (memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) {
+
+ if (!be_quiet) { OKF(cPIN "Deferred forkserver binary detected."); }
+ setenv(DEFER_ENV_VAR, "1", 1);
+ ret += 2;
+
+ } else if (getenv("AFL_DEFER_FORKSRV")) {
+
+ if (!be_quiet) { OKF(cPIN "Deferred forkserver enforced."); }
+ setenv(DEFER_ENV_VAR, "1", 1);
+ ret += 2;
+
+ }
+
+ if (munmap(f_data, f_len)) { PFATAL("unmap() failed"); }
+
+ return ret;
+
+}
+
+void detect_file_args(char **argv, u8 *prog_in, bool *use_stdin) {
+
+ u32 i = 0;
+ u8 cwd[PATH_MAX];
+ if (getcwd(cwd, (size_t)sizeof(cwd)) == NULL) { PFATAL("getcwd() failed"); }
+
+ /* we are working with libc-heap-allocated argvs. So do not mix them with
+ * other allocation APIs like ck_alloc. That would disturb the free() calls.
+ */
+ while (argv[i]) {
+
+ u8 *aa_loc = strstr(argv[i], "@@");
+
+ if (aa_loc) {
+
+ if (!prog_in) { FATAL("@@ syntax is not supported by this tool."); }
+
+ *use_stdin = false;
+
+ /* Be sure that we're always using fully-qualified paths. */
+
+ *aa_loc = 0;
+
+ /* Construct a replacement argv value. */
+ u8 *n_arg;
+
+ if (prog_in[0] == '/') {
+
+ n_arg = alloc_printf("%s%s%s", argv[i], prog_in, aa_loc + 2);
+
+ } else {
+
+ n_arg = alloc_printf("%s%s/%s%s", argv[i], cwd, prog_in, aa_loc + 2);
+
+ }
+
+ ck_free(argv[i]);
+ argv[i] = n_arg;
+
+ }
+
+ i++;
+
+ }
+
+ /* argvs are automatically freed at exit. */
+
+}
+
+/* duplicate the system argv so that
+ we can edit (and free!) it later */
+
+char **argv_cpy_dup(int argc, char **argv) {
+
+ int i = 0;
+
+ char **ret = ck_alloc((argc + 1) * sizeof(char *));
+ if (unlikely(!ret)) { FATAL("Amount of arguments specified is too high"); }
+
+ for (i = 0; i < argc; i++) {
+
+ ret[i] = ck_strdup(argv[i]);
+
+ }
+
+ ret[i] = NULL;
+
+ return ret;
+
+}
+
+/* frees all args in the given argv,
+ previously created by argv_cpy_dup */
+
+void argv_cpy_free(char **argv) {
+
+ u32 i = 0;
+ while (argv[i]) {
+
+ ck_free(argv[i]);
+ argv[i] = NULL;
+ i++;
+
+ }
+
+ ck_free(argv);
+
+}
+
+/* Rewrite argv for CoreSight process tracer. */
+
+char **get_cs_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
+
+ if (unlikely(getenv("AFL_CS_CUSTOM_BIN"))) {
+
+ WARNF(
+ "AFL_CS_CUSTOM_BIN is enabled. "
+ "You must run your target under afl-cs-proxy on your own!");
+ return argv;
+
+ }
+
+ char **new_argv = ck_alloc(sizeof(char *) * (argc + 4));
+ if (unlikely(!new_argv)) { FATAL("Illegal amount of arguments specified"); }
+
+ memcpy(&new_argv[3], &argv[1], (int)(sizeof(char *)) * (argc - 1));
+ new_argv[argc + 3] = NULL;
+
+ new_argv[2] = *target_path_p;
+ new_argv[1] = "--";
+
+ /* Now we need to actually find the cs-proxy binary to put in argv[0]. */
+
+ *target_path_p = new_argv[0] = find_afl_binary(own_loc, "afl-cs-proxy");
+ return new_argv;
+
+}
+
+/* Rewrite argv for QEMU. */
+
+char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
+
+ if (unlikely(getenv("AFL_QEMU_CUSTOM_BIN"))) {
+
+ WARNF(
+ "AFL_QEMU_CUSTOM_BIN is enabled. "
+ "You must run your target under afl-qemu-trace on your own!");
+ return argv;
+
+ }
+
+ char **new_argv = ck_alloc(sizeof(char *) * (argc + 3));
+ if (unlikely(!new_argv)) { FATAL("Illegal amount of arguments specified"); }
+
+ memcpy(&new_argv[3], &argv[1], (int)(sizeof(char *)) * (argc - 1));
+
+ new_argv[2] = *target_path_p;
+ new_argv[1] = "--";
+
+ /* Now we need to actually find the QEMU binary to put in argv[0]. */
+
+ *target_path_p = new_argv[0] = find_afl_binary(own_loc, "afl-qemu-trace");
+ return new_argv;
+
+}
+
+/* Rewrite argv for Wine+QEMU. */
+
+char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
+
+ char **new_argv = ck_alloc(sizeof(char *) * (argc + 2));
+ if (unlikely(!new_argv)) { FATAL("Illegal amount of arguments specified"); }
+
+ memcpy(&new_argv[2], &argv[1], (int)(sizeof(char *)) * (argc - 1));
+
+ new_argv[1] = *target_path_p;
+
+ /* Now we need to actually find the QEMU binary to put in argv[0]. */
+
+ u8 *tmp = find_afl_binary(own_loc, "afl-qemu-trace");
+ ck_free(tmp);
+ *target_path_p = new_argv[0] = find_afl_binary(own_loc, "afl-wine-trace");
+ return new_argv;
+
+}
+
+/* Find binary, used by analyze, showmap, tmin
+ @returns the path, allocating the string */
+
+u8 *find_binary(u8 *fname) {
+
+ // TODO: Merge this function with check_binary of afl-fuzz-init.c
+
+ u8 *env_path = NULL;
+ u8 *target_path = NULL;
+
+ struct stat st;
+
+ if (unlikely(!fname)) { FATAL("No binary supplied"); }
+
+ if (strchr(fname, '/') || !(env_path = getenv("PATH"))) {
+
+ target_path = ck_strdup(fname);
+
+ if (stat(target_path, &st) || !S_ISREG(st.st_mode) ||
+ !(st.st_mode & 0111) || st.st_size < 4) {
+
+ ck_free(target_path);
+ FATAL("Program '%s' not found or not executable", fname);
+
+ }
+
+ } else {
+
+ while (env_path) {
+
+ u8 *cur_elem, *delim = strchr(env_path, ':');
+
+ if (delim) {
+
+ cur_elem = ck_alloc(delim - env_path + 1);
+ if (unlikely(!cur_elem)) {
+
+ FATAL(
+ "Unexpected overflow when processing ENV. This should never "
+ "happend.");
+
+ }
+
+ memcpy(cur_elem, env_path, delim - env_path);
+ delim++;
+
+ } else {
+
+ cur_elem = ck_strdup(env_path);
+
+ }
+
+ env_path = delim;
+
+ if (cur_elem[0]) {
+
+ target_path = alloc_printf("%s/%s", cur_elem, fname);
+
+ } else {
+
+ target_path = ck_strdup(fname);
+
+ }
+
+ ck_free(cur_elem);
+
+ if (!stat(target_path, &st) && S_ISREG(st.st_mode) &&
+ (st.st_mode & 0111) && st.st_size >= 4) {
+
+ break;
+
+ }
+
+ ck_free(target_path);
+ target_path = NULL;
+
+ }
+
+ if (!target_path) {
+
+ FATAL("Program '%s' not found or not executable", fname);
+
+ }
+
+ }
+
+ return target_path;
+
+}
+
+u8 *find_afl_binary(u8 *own_loc, u8 *fname) {
+
+ u8 *afl_path = NULL, *target_path, *own_copy, *tmp;
+ int perm = X_OK;
+
+ if ((tmp = strrchr(fname, '.'))) {
+
+ if (!strcasecmp(tmp, ".so") || !strcasecmp(tmp, ".dylib")) { perm = R_OK; }
+
+ }
+
+ if ((afl_path = getenv("AFL_PATH"))) {
+
+ target_path = alloc_printf("%s/%s", afl_path, fname);
+ if (!access(target_path, perm)) {
+
+ return target_path;
+
+ } else {
+
+ ck_free(target_path);
+
+ }
+
+ }
+
+ if (own_loc) {
+
+ own_copy = ck_strdup(own_loc);
+ u8 *rsl = strrchr(own_copy, '/');
+
+ if (rsl) {
+
+ *rsl = 0;
+
+ target_path = alloc_printf("%s/%s", own_copy, fname);
+ ck_free(own_copy);
+
+ if (!access(target_path, perm)) {
+
+ return target_path;
+
+ } else {
+
+ ck_free(target_path);
+
+ }
+
+ } else {
+
+ ck_free(own_copy);
+
+ }
+
+ }
+
+ if (perm == X_OK) {
+
+ target_path = alloc_printf("%s/%s", BIN_PATH, fname);
+
+ } else {
+
+ target_path = alloc_printf("%s/%s", AFL_PATH, fname);
+
+ }
+
+ if (!access(target_path, perm)) {
+
+ return target_path;
+
+ } else {
+
+ ck_free(target_path);
+
+ }
+
+ if (perm == X_OK) {
+
+ return find_binary(fname);
+
+ } else {
+
+ FATAL("Library '%s' not found", fname);
+
+ }
+
+}
+
+/* Parses the kill signal environment variable, FATALs on error.
+ If the env is not set, sets the env to default_signal for the signal handlers
+ and returns the default_signal. */
+int parse_afl_kill_signal_env(u8 *afl_kill_signal_env, int default_signal) {
+
+ if (afl_kill_signal_env && afl_kill_signal_env[0]) {
+
+ char *endptr;
+ u8 signal_code;
+ signal_code = (u8)strtoul(afl_kill_signal_env, &endptr, 10);
+ /* Did we manage to parse the full string? */
+ if (*endptr != '\0' || endptr == (char *)afl_kill_signal_env) {
+
+ FATAL("Invalid AFL_KILL_SIGNAL: %s (expected unsigned int)",
+ afl_kill_signal_env);
+
+ }
+
+ return signal_code;
+
+ } else {
+
+ char *sigstr = alloc_printf("%d", default_signal);
+ if (!sigstr) { FATAL("Failed to alloc mem for signal buf"); }
+
+ /* Set the env for signal handler */
+ setenv("AFL_KILL_SIGNAL", sigstr, 1);
+ free(sigstr);
+ return default_signal;
+
+ }
+
+}
+
+static inline unsigned int helper_min3(unsigned int a, unsigned int b,
+ unsigned int c) {
+
+ return a < b ? (a < c ? a : c) : (b < c ? b : c);
+
+}
+
+// from
+// https://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#C
+static int string_distance_levenshtein(char *s1, char *s2) {
+
+ unsigned int s1len, s2len, x, y, lastdiag, olddiag;
+ s1len = strlen(s1);
+ s2len = strlen(s2);
+ unsigned int column[s1len + 1];
+ column[s1len] = 1;
+
+ for (y = 1; y <= s1len; y++)
+ column[y] = y;
+ for (x = 1; x <= s2len; x++) {
+
+ column[0] = x;
+ for (y = 1, lastdiag = x - 1; y <= s1len; y++) {
+
+ olddiag = column[y];
+ column[y] = helper_min3(column[y] + 1, column[y - 1] + 1,
+ lastdiag + (s1[y - 1] == s2[x - 1] ? 0 : 1));
+ lastdiag = olddiag;
+
+ }
+
+ }
+
+ return column[s1len];
+
+}
+
+#define ENV_SIMILARITY_TRESHOLD 3
+
+void print_suggested_envs(char *mispelled_env) {
+
+ size_t env_name_len =
+ strcspn(mispelled_env, "=") - 4; // remove the AFL_prefix
+ char *env_name = ck_alloc(env_name_len + 1);
+ memcpy(env_name, mispelled_env + 4, env_name_len);
+
+ char *seen = ck_alloc(sizeof(afl_environment_variables) / sizeof(char *));
+ int found = 0;
+
+ int j;
+ for (j = 0; afl_environment_variables[j] != NULL; ++j) {
+
+ char *afl_env = afl_environment_variables[j] + 4;
+ int distance = string_distance_levenshtein(afl_env, env_name);
+ if (distance < ENV_SIMILARITY_TRESHOLD && seen[j] == 0) {
+
+ SAYF("Did you mean %s?\n", afl_environment_variables[j]);
+ seen[j] = 1;
+ found = 1;
+
+ }
+
+ }
+
+ if (found) goto cleanup;
+
+ for (j = 0; afl_environment_variables[j] != NULL; ++j) {
+
+ char * afl_env = afl_environment_variables[j] + 4;
+ size_t afl_env_len = strlen(afl_env);
+ char * reduced = ck_alloc(afl_env_len + 1);
+
+ size_t start = 0;
+ while (start < afl_env_len) {
+
+ size_t end = start + strcspn(afl_env + start, "_") + 1;
+ memcpy(reduced, afl_env, start);
+ if (end < afl_env_len) {
+
+ memcpy(reduced + start, afl_env + end, afl_env_len - end);
+
+ }
+
+ if (afl_env_len + start >= end) {
+
+ reduced[afl_env_len - end + start] = 0;
+
+ }
+
+ int distance = string_distance_levenshtein(reduced, env_name);
+ if (distance < ENV_SIMILARITY_TRESHOLD && seen[j] == 0) {
+
+ SAYF("Did you mean %s?\n", afl_environment_variables[j]);
+ seen[j] = 1;
+ found = 1;
+
+ }
+
+ start = end;
+
+ };
+
+ ck_free(reduced);
+
+ }
+
+ if (found) goto cleanup;
+
+ char * reduced = ck_alloc(env_name_len + 1);
+ size_t start = 0;
+ while (start < env_name_len) {
+
+ size_t end = start + strcspn(env_name + start, "_") + 1;
+ memcpy(reduced, env_name, start);
+ if (end < env_name_len)
+ memcpy(reduced + start, env_name + end, env_name_len - end);
+ reduced[env_name_len - end + start] = 0;
+
+ for (j = 0; afl_environment_variables[j] != NULL; ++j) {
+
+ int distance = string_distance_levenshtein(
+ afl_environment_variables[j] + 4, reduced);
+ if (distance < ENV_SIMILARITY_TRESHOLD && seen[j] == 0) {
+
+ SAYF("Did you mean %s?\n", afl_environment_variables[j]);
+ seen[j] = 1;
+
+ }
+
+ }
+
+ start = end;
+
+ };
+
+ ck_free(reduced);
+
+cleanup:
+ ck_free(env_name);
+ ck_free(seen);
+
+}
+
+void check_environment_vars(char **envp) {
+
+ if (be_quiet) { return; }
+
+ int index = 0, issue_detected = 0;
+ char *env, *val, *ignore = getenv("AFL_IGNORE_UNKNOWN_ENVS");
+ while ((env = envp[index++]) != NULL) {
+
+ if (strncmp(env, "ALF_", 4) == 0 || strncmp(env, "_ALF", 4) == 0 ||
+ strncmp(env, "__ALF", 5) == 0 || strncmp(env, "_AFL", 4) == 0 ||
+ strncmp(env, "__AFL", 5) == 0) {
+
+ WARNF("Potentially mistyped AFL environment variable: %s", env);
+ issue_detected = 1;
+
+ } else if (strncmp(env, "AFL_", 4) == 0) {
+
+ int i = 0, match = 0;
+ while (match == 0 && afl_environment_variables[i] != NULL) {
+
+ if (strncmp(env, afl_environment_variables[i],
+ strlen(afl_environment_variables[i])) == 0 &&
+ env[strlen(afl_environment_variables[i])] == '=') {
+
+ match = 1;
+
+ if ((val = getenv(afl_environment_variables[i])) && !*val) {
+
+ WARNF(
+ "AFL environment variable %s defined but is empty, this can "
+ "lead to unexpected consequences",
+ afl_environment_variables[i]);
+ issue_detected = 1;
+
+ }
+
+ } else {
+
+ i++;
+
+ }
+
+ }
+
+ i = 0;
+ while (match == 0 && afl_environment_deprecated[i] != NULL) {
+
+ if (strncmp(env, afl_environment_deprecated[i],
+ strlen(afl_environment_deprecated[i])) == 0 &&
+ env[strlen(afl_environment_deprecated[i])] == '=') {
+
+ match = 1;
+
+ WARNF("AFL environment variable %s is deprecated!",
+ afl_environment_deprecated[i]);
+ issue_detected = 1;
+
+ } else {
+
+ i++;
+
+ }
+
+ }
+
+ if (match == 0 && !ignore) {
+
+ WARNF("Mistyped AFL environment variable: %s", env);
+ issue_detected = 1;
+
+ print_suggested_envs(env);
+
+ }
+
+ }
+
+ }
+
+ if (issue_detected) { sleep(2); }
+
+}
+
+char *get_afl_env(char *env) {
+
+ char *val;
+
+ if ((val = getenv(env)) != NULL) {
+
+ if (!be_quiet) {
+
+ OKF("Loaded environment variable %s with value %s", env, val);
+
+ }
+
+ }
+
+ return val;
+
+}
+
+bool extract_and_set_env(u8 *env_str) {
+
+ if (!env_str) { return false; }
+
+ bool ret = false; // return false by default
+
+ u8 *p = ck_strdup(env_str);
+ u8 *end = p + strlen((char *)p);
+ u8 *rest = p;
+
+ u8 closing_sym = ' ';
+ u8 c;
+
+ size_t num_pairs = 0;
+
+ while (rest < end) {
+
+ while (*rest == ' ') {
+
+ rest++;
+
+ }
+
+ if (rest + 1 >= end) break;
+
+ u8 *key = rest;
+ // env variable names may not start with numbers or '='
+ if (*key == '=' || (*key >= '0' && *key <= '9')) { goto free_and_return; }
+
+ while (rest < end && *rest != '=' && *rest != ' ') {
+
+ c = *rest;
+ // lowercase is bad but we may still allow it
+ if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') &&
+ (c < '0' || c > '9') && c != '_') {
+
+ goto free_and_return;
+
+ }
+
+ rest++;
+
+ }
+
+ if (*rest != '=') { goto free_and_return; }
+
+ *rest = '\0'; // done with variable name
+
+ rest += 1;
+ if (rest >= end || *rest == ' ') { goto free_and_return; }
+
+ u8 *val = rest;
+ if (*val == '\'' || *val == '"') {
+
+ closing_sym = *val;
+ val += 1;
+ rest += 1;
+ if (rest >= end) { goto free_and_return; }
+
+ } else {
+
+ closing_sym = ' ';
+
+ }
+
+ while (rest < end && *rest != closing_sym) {
+
+ rest++;
+
+ }
+
+ if (closing_sym != ' ' && *rest != closing_sym) { goto free_and_return; }
+
+ *rest = '\0'; // done with variable value
+
+ rest += 1;
+ num_pairs++;
+ setenv(key, val, 1);
+
+ }
+
+ if (num_pairs) { ret = true; }
+
+free_and_return:
+ ck_free(p);
+ return ret;
+
+}
+
+/* Read mask bitmap from file. This is for the -B option. */
+
+void read_bitmap(u8 *fname, u8 *map, size_t len) {
+
+ s32 fd = open(fname, O_RDONLY);
+
+ if (fd < 0) { PFATAL("Unable to open '%s'", fname); }
+
+ ck_read(fd, map, len, fname);
+
+ close(fd);
+
+}
+
+/* Get unix time in milliseconds */
+
+u64 get_cur_time(void) {
+
+ struct timeval tv;
+ struct timezone tz;
+
+ gettimeofday(&tv, &tz);
+
+ return (tv.tv_sec * 1000ULL) + (tv.tv_usec / 1000);
+
+}
+
+/* Get unix time in microseconds */
+
+u64 get_cur_time_us(void) {
+
+ struct timeval tv;
+ struct timezone tz;
+
+ gettimeofday(&tv, &tz);
+
+ return (tv.tv_sec * 1000000ULL) + tv.tv_usec;
+
+}
+
+/* Describe integer. The buf should be
+ at least 6 bytes to fit all ints we randomly see.
+ Will return buf for convenience. */
+
+u8 *stringify_int(u8 *buf, size_t len, u64 val) {
+\
+#define CHK_FORMAT(_divisor, _limit_mult, _fmt, _cast) \
+ do { \
+ \
+ if (val < (_divisor) * (_limit_mult)) { \
+ \
+ snprintf(buf, len, _fmt, ((_cast)val) / (_divisor)); \
+ return buf; \
+ \
+ } \
+ \
+ } while (0)
+
+ /* 0-9999 */
+ CHK_FORMAT(1, 10000, "%llu", u64);
+
+ /* 10.0k - 99.9k */
+ CHK_FORMAT(1000, 99.95, "%0.01fk", double);
+
+ /* 100k - 999k */
+ CHK_FORMAT(1000, 1000, "%lluk", u64);
+
+ /* 1.00M - 9.99M */
+ CHK_FORMAT(1000 * 1000, 9.995, "%0.02fM", double);
+
+ /* 10.0M - 99.9M */
+ CHK_FORMAT(1000 * 1000, 99.95, "%0.01fM", double);
+
+ /* 100M - 999M */
+ CHK_FORMAT(1000 * 1000, 1000, "%lluM", u64);
+
+ /* 1.00G - 9.99G */
+ CHK_FORMAT(1000LL * 1000 * 1000, 9.995, "%0.02fG", double);
+
+ /* 10.0G - 99.9G */
+ CHK_FORMAT(1000LL * 1000 * 1000, 99.95, "%0.01fG", double);
+
+ /* 100G - 999G */
+ CHK_FORMAT(1000LL * 1000 * 1000, 1000, "%lluG", u64);
+
+ /* 1.00T - 9.99G */
+ CHK_FORMAT(1000LL * 1000 * 1000 * 1000, 9.995, "%0.02fT", double);
+
+ /* 10.0T - 99.9T */
+ CHK_FORMAT(1000LL * 1000 * 1000 * 1000, 99.95, "%0.01fT", double);
+
+ /* 100T+ */
+ strncpy(buf, "infty", len);
+ buf[len - 1] = '\0';
+
+ return buf;
+
+}
+
+/* Describe float. Similar as int. */
+
+u8 *stringify_float(u8 *buf, size_t len, double val) {
+
+ if (val < 99.995) {
+
+ snprintf(buf, len, "%0.02f", val);
+
+ } else if (val < 999.95) {
+
+ snprintf(buf, len, "%0.01f", val);
+
+ } else if (unlikely(isnan(val) || isinf(val))) {
+
+ strcpy(buf, "inf");
+
+ } else {
+
+ stringify_int(buf, len, (u64)val);
+
+ }
+
+ return buf;
+
+}
+
+/* Describe integer as memory size. */
+
+u8 *stringify_mem_size(u8 *buf, size_t len, u64 val) {
+
+ /* 0-9999 */
+ CHK_FORMAT(1, 10000, "%llu B", u64);
+
+ /* 10.0k - 99.9k */
+ CHK_FORMAT(1024, 99.95, "%0.01f kB", double);
+
+ /* 100k - 999k */
+ CHK_FORMAT(1024, 1000, "%llu kB", u64);
+
+ /* 1.00M - 9.99M */
+ CHK_FORMAT(1024 * 1024, 9.995, "%0.02f MB", double);
+
+ /* 10.0M - 99.9M */
+ CHK_FORMAT(1024 * 1024, 99.95, "%0.01f MB", double);
+
+ /* 100M - 999M */
+ CHK_FORMAT(1024 * 1024, 1000, "%llu MB", u64);
+
+ /* 1.00G - 9.99G */
+ CHK_FORMAT(1024LL * 1024 * 1024, 9.995, "%0.02f GB", double);
+
+ /* 10.0G - 99.9G */
+ CHK_FORMAT(1024LL * 1024 * 1024, 99.95, "%0.01f GB", double);
+
+ /* 100G - 999G */
+ CHK_FORMAT(1024LL * 1024 * 1024, 1000, "%llu GB", u64);
+
+ /* 1.00T - 9.99G */
+ CHK_FORMAT(1024LL * 1024 * 1024 * 1024, 9.995, "%0.02f TB", double);
+
+ /* 10.0T - 99.9T */
+ CHK_FORMAT(1024LL * 1024 * 1024 * 1024, 99.95, "%0.01f TB", double);
+
+#undef CHK_FORMAT
+
+ /* 100T+ */
+ strncpy(buf, "infty", len - 1);
+ buf[len - 1] = '\0';
+
+ return buf;
+
+}
+
+/* Describe time delta as string.
+ Returns a pointer to buf for convenience. */
+
+u8 *stringify_time_diff(u8 *buf, size_t len, u64 cur_ms, u64 event_ms) {
+
+ if (!event_ms) {
+
+ snprintf(buf, len, "none seen yet");
+
+ } else {
+
+ u64 delta;
+ s32 t_d, t_h, t_m, t_s;
+ u8 val_buf[STRINGIFY_VAL_SIZE_MAX];
+
+ delta = cur_ms - event_ms;
+
+ t_d = delta / 1000 / 60 / 60 / 24;
+ t_h = (delta / 1000 / 60 / 60) % 24;
+ t_m = (delta / 1000 / 60) % 60;
+ t_s = (delta / 1000) % 60;
+
+ stringify_int(val_buf, sizeof(val_buf), t_d);
+ snprintf(buf, len, "%s days, %d hrs, %d min, %d sec", val_buf, t_h, t_m,
+ t_s);
+
+ }
+
+ return buf;
+
+}
+
+/* Unsafe Describe integer. The buf sizes are not checked.
+ This is unsafe but fast.
+ Will return buf for convenience. */
+
+u8 *u_stringify_int(u8 *buf, u64 val) {
+\
+#define CHK_FORMAT(_divisor, _limit_mult, _fmt, _cast) \
+ do { \
+ \
+ if (val < (_divisor) * (_limit_mult)) { \
+ \
+ sprintf(buf, _fmt, ((_cast)val) / (_divisor)); \
+ return buf; \
+ \
+ } \
+ \
+ } while (0)
+
+ /* 0-9999 */
+ CHK_FORMAT(1, 10000, "%llu", u64);
+
+ /* 10.0k - 99.9k */
+ CHK_FORMAT(1000, 99.95, "%0.01fk", double);
+
+ /* 100k - 999k */
+ CHK_FORMAT(1000, 1000, "%lluk", u64);
+
+ /* 1.00M - 9.99M */
+ CHK_FORMAT(1000 * 1000, 9.995, "%0.02fM", double);
+
+ /* 10.0M - 99.9M */
+ CHK_FORMAT(1000 * 1000, 99.95, "%0.01fM", double);
+
+ /* 100M - 999M */
+ CHK_FORMAT(1000 * 1000, 1000, "%lluM", u64);
+
+ /* 1.00G - 9.99G */
+ CHK_FORMAT(1000LL * 1000 * 1000, 9.995, "%0.02fG", double);
+
+ /* 10.0G - 99.9G */
+ CHK_FORMAT(1000LL * 1000 * 1000, 99.95, "%0.01fG", double);
+
+ /* 100G - 999G */
+ CHK_FORMAT(1000LL * 1000 * 1000, 1000, "%lluG", u64);
+
+ /* 1.00T - 9.99G */
+ CHK_FORMAT(1000LL * 1000 * 1000 * 1000, 9.995, "%0.02fT", double);
+
+ /* 10.0T - 99.9T */
+ CHK_FORMAT(1000LL * 1000 * 1000 * 1000, 99.95, "%0.01fT", double);
+
+ /* 100T+ */
+ strcpy(buf, "infty");
+
+ return buf;
+
+}
+
+/* Unsafe describe float. Similar as unsafe int. */
+
+u8 *u_stringify_float(u8 *buf, double val) {
+
+ if (val < 99.995) {
+
+ sprintf(buf, "%0.02f", val);
+
+ } else if (val < 999.95) {
+
+ sprintf(buf, "%0.01f", val);
+
+ } else if (unlikely(isnan(val) || isinf(val))) {
+
+ strcpy(buf, "infinite");
+
+ } else {
+
+ return u_stringify_int(buf, (u64)val);
+
+ }
+
+ return buf;
+
+}
+
+/* Unsafe describe integer as memory size. */
+
+u8 *u_stringify_mem_size(u8 *buf, u64 val) {
+
+ /* 0-9999 */
+ CHK_FORMAT(1, 10000, "%llu B", u64);
+
+ /* 10.0k - 99.9k */
+ CHK_FORMAT(1024, 99.95, "%0.01f kB", double);
+
+ /* 100k - 999k */
+ CHK_FORMAT(1024, 1000, "%llu kB", u64);
+
+ /* 1.00M - 9.99M */
+ CHK_FORMAT(1024 * 1024, 9.995, "%0.02f MB", double);
+
+ /* 10.0M - 99.9M */
+ CHK_FORMAT(1024 * 1024, 99.95, "%0.01f MB", double);
+
+ /* 100M - 999M */
+ CHK_FORMAT(1024 * 1024, 1000, "%llu MB", u64);
+
+ /* 1.00G - 9.99G */
+ CHK_FORMAT(1024LL * 1024 * 1024, 9.995, "%0.02f GB", double);
+
+ /* 10.0G - 99.9G */
+ CHK_FORMAT(1024LL * 1024 * 1024, 99.95, "%0.01f GB", double);
+
+ /* 100G - 999G */
+ CHK_FORMAT(1024LL * 1024 * 1024, 1000, "%llu GB", u64);
+
+ /* 1.00T - 9.99G */
+ CHK_FORMAT(1024LL * 1024 * 1024 * 1024, 9.995, "%0.02f TB", double);
+
+ /* 10.0T - 99.9T */
+ CHK_FORMAT(1024LL * 1024 * 1024 * 1024, 99.95, "%0.01f TB", double);
+
+#undef CHK_FORMAT
+
+ /* 100T+ */
+ strcpy(buf, "infty");
+
+ return buf;
+
+}
+
+/* Unsafe describe time delta as string.
+ Returns a pointer to buf for convenience. */
+
+u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms) {
+
+ if (!event_ms) {
+
+ sprintf(buf, "none seen yet");
+
+ } else {
+
+ u64 delta;
+ s32 t_d, t_h, t_m, t_s;
+ u8 val_buf[STRINGIFY_VAL_SIZE_MAX];
+
+ delta = cur_ms - event_ms;
+
+ t_d = delta / 1000 / 60 / 60 / 24;
+ t_h = (delta / 1000 / 60 / 60) % 24;
+ t_m = (delta / 1000 / 60) % 60;
+ t_s = (delta / 1000) % 60;
+
+ u_stringify_int(val_buf, t_d);
+ sprintf(buf, "%s days, %d hrs, %d min, %d sec", val_buf, t_h, t_m, t_s);
+
+ }
+
+ return buf;
+
+}
+
+/* Reads the map size from ENV */
+u32 get_map_size(void) {
+
+ uint32_t map_size = DEFAULT_SHMEM_SIZE;
+ char * ptr;
+
+ if ((ptr = getenv("AFL_MAP_SIZE")) || (ptr = getenv("AFL_MAPSIZE"))) {
+
+ map_size = atoi(ptr);
+ if (!map_size || map_size > (1 << 29)) {
+
+ FATAL("illegal AFL_MAP_SIZE %u, must be between %u and %u", map_size, 64U,
+ 1U << 29);
+
+ }
+
+ if (map_size % 64) { map_size = (((map_size >> 6) + 1) << 6); }
+
+ } else if (getenv("AFL_SKIP_BIN_CHECK")) {
+
+ map_size = MAP_SIZE;
+
+ }
+
+ return map_size;
+
+}
+
+/* Create a stream file */
+
+FILE *create_ffile(u8 *fn) {
+
+ s32 fd;
+ FILE *f;
+
+ fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
+
+ if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
+
+ f = fdopen(fd, "w");
+
+ if (!f) { PFATAL("fdopen() failed"); }
+
+ return f;
+
+}
+
+/* Create a file */
+
+s32 create_file(u8 *fn) {
+
+ s32 fd;
+
+ fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
+
+ if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
+
+ return fd;
+
+}
+
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
new file mode 100644
index 00000000..628ff590
--- /dev/null
+++ b/src/afl-forkserver.c
@@ -0,0 +1,1691 @@
+/*
+ american fuzzy lop++ - forkserver code
+ --------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Forkserver design by Jann Horn <jannhorn@googlemail.com>
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Andrea Fioraldi <andreafioraldi@gmail.com> and
+ Dominik Maier <mail@dmnk.co>
+
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ Shared code that implements a forkserver. This is used by the fuzzer
+ as well the other components like afl-tmin.
+
+ */
+
+#include "config.h"
+#include "types.h"
+#include "debug.h"
+#include "common.h"
+#include "list.h"
+#include "forkserver.h"
+#include "hash.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/resource.h>
+#include <sys/select.h>
+#include <sys/stat.h>
+
+/**
+ * The correct fds for reading and writing pipes
+ */
+
+/* Describe integer as memory size. */
+
+static list_t fsrv_list = {.element_prealloc_count = 0};
+
+static void fsrv_exec_child(afl_forkserver_t *fsrv, char **argv) {
+
+ if (fsrv->qemu_mode || fsrv->cs_mode) {
+
+ setenv("AFL_DISABLE_LLVM_INSTRUMENTATION", "1", 0);
+
+ }
+
+ execv(fsrv->target_path, argv);
+
+ WARNF("Execv failed in forkserver.");
+
+}
+
+/* Initializes the struct */
+
+void afl_fsrv_init(afl_forkserver_t *fsrv) {
+
+#ifdef __linux__
+ fsrv->nyx_handlers = NULL;
+ fsrv->out_dir_path = NULL;
+ fsrv->nyx_mode = 0;
+ fsrv->nyx_parent = false;
+ fsrv->nyx_standalone = false;
+ fsrv->nyx_runner = NULL;
+ fsrv->nyx_id = 0xFFFFFFFF;
+ fsrv->nyx_bind_cpu_id = 0xFFFFFFFF;
+#endif
+
+ // this structure needs default so we initialize it if this was not done
+ // already
+ fsrv->out_fd = -1;
+ fsrv->out_dir_fd = -1;
+ fsrv->dev_null_fd = -1;
+ fsrv->dev_urandom_fd = -1;
+
+ /* Settings */
+ fsrv->use_stdin = true;
+ fsrv->no_unlink = false;
+ fsrv->exec_tmout = EXEC_TIMEOUT;
+ fsrv->init_tmout = EXEC_TIMEOUT * FORK_WAIT_MULT;
+ fsrv->mem_limit = MEM_LIMIT;
+ fsrv->out_file = NULL;
+ fsrv->kill_signal = SIGKILL;
+
+ /* exec related stuff */
+ fsrv->child_pid = -1;
+ fsrv->map_size = get_map_size();
+ fsrv->real_map_size = fsrv->map_size;
+ fsrv->use_fauxsrv = false;
+ fsrv->last_run_timed_out = false;
+ fsrv->debug = false;
+ fsrv->uses_crash_exitcode = false;
+ fsrv->uses_asan = false;
+
+ fsrv->init_child_func = fsrv_exec_child;
+ list_append(&fsrv_list, fsrv);
+
+}
+
+/* Initialize a new forkserver instance, duplicating "global" settings */
+void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) {
+
+ fsrv_to->use_stdin = from->use_stdin;
+ fsrv_to->dev_null_fd = from->dev_null_fd;
+ fsrv_to->exec_tmout = from->exec_tmout;
+ fsrv_to->init_tmout = from->init_tmout;
+ fsrv_to->mem_limit = from->mem_limit;
+ fsrv_to->map_size = from->map_size;
+ fsrv_to->real_map_size = from->real_map_size;
+ fsrv_to->support_shmem_fuzz = from->support_shmem_fuzz;
+ fsrv_to->out_file = from->out_file;
+ fsrv_to->dev_urandom_fd = from->dev_urandom_fd;
+ fsrv_to->out_fd = from->out_fd; // not sure this is a good idea
+ fsrv_to->no_unlink = from->no_unlink;
+ fsrv_to->uses_crash_exitcode = from->uses_crash_exitcode;
+ fsrv_to->crash_exitcode = from->crash_exitcode;
+ fsrv_to->kill_signal = from->kill_signal;
+ fsrv_to->debug = from->debug;
+
+ // These are forkserver specific.
+ fsrv_to->out_dir_fd = -1;
+ fsrv_to->child_pid = -1;
+ fsrv_to->use_fauxsrv = 0;
+ fsrv_to->last_run_timed_out = 0;
+
+ fsrv_to->init_child_func = from->init_child_func;
+ // Note: do not copy ->add_extra_func or ->persistent_record*
+
+ list_append(&fsrv_list, fsrv_to);
+
+}
+
+/* Wrapper for select() and read(), reading a 32 bit var.
+ 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) {
+
+ fd_set readfds;
+ FD_ZERO(&readfds);
+ FD_SET(fd, &readfds);
+ struct timeval timeout;
+ int sret;
+ ssize_t len_read;
+
+ timeout.tv_sec = (timeout_ms / 1000);
+ timeout.tv_usec = (timeout_ms % 1000) * 1000;
+#if !defined(__linux__)
+ u32 read_start = get_cur_time_us();
+#endif
+
+ /* set exceptfds as well to return when a child exited/closed the pipe. */
+restart_select:
+ sret = select(fd + 1, &readfds, NULL, NULL, &timeout);
+
+ if (likely(sret > 0)) {
+
+ restart_read:
+ if (*stop_soon_p) {
+
+ // Early return - the user wants to quit.
+ return 0;
+
+ }
+
+ len_read = read(fd, (u8 *)buf, 4);
+
+ if (likely(len_read == 4)) { // for speed we put this first
+
+#if defined(__linux__)
+ u32 exec_ms = MIN(
+ timeout_ms,
+ ((u64)timeout_ms - (timeout.tv_sec * 1000 + timeout.tv_usec / 1000)));
+#else
+ u32 exec_ms = MIN(timeout_ms, (get_cur_time_us() - read_start) / 1000);
+#endif
+
+ // ensure to report 1 ms has passed (0 is an error)
+ return exec_ms > 0 ? exec_ms : 1;
+
+ } else if (unlikely(len_read == -1 && errno == EINTR)) {
+
+ goto restart_read;
+
+ } else if (unlikely(len_read < 4)) {
+
+ return 0;
+
+ }
+
+ } else if (unlikely(!sret)) {
+
+ *buf = -1;
+ return timeout_ms + 1;
+
+ } else if (unlikely(sret < 0)) {
+
+ if (likely(errno == EINTR)) goto restart_select;
+
+ *buf = -1;
+ return 0;
+
+ }
+
+ return 0; // not reached
+
+}
+
+/* Internal forkserver for non_instrumented_mode=1 and non-forkserver mode runs.
+ It execvs for each fork, forwarding exit codes and child pids to afl. */
+
+static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) {
+
+ unsigned char tmp[4] = {0, 0, 0, 0};
+ pid_t child_pid;
+
+ if (!be_quiet) { ACTF("Using Fauxserver:"); }
+
+ /* Phone home and tell the parent that we're OK. If parent isn't there,
+ assume we're not running in forkserver mode and just execute program. */
+
+ if (write(FORKSRV_FD + 1, tmp, 4) != 4) {
+
+ abort(); // TODO: Abort?
+
+ }
+
+ void (*old_sigchld_handler)(int) = signal(SIGCHLD, SIG_DFL);
+
+ while (1) {
+
+ uint32_t was_killed;
+ int status;
+
+ /* Wait for parent by reading from the pipe. Exit if read fails. */
+
+ if (read(FORKSRV_FD, &was_killed, 4) != 4) { exit(0); }
+
+ /* Create a clone of our process. */
+
+ child_pid = fork();
+
+ if (child_pid < 0) { PFATAL("Fork failed"); }
+
+ /* In child process: close fds, resume execution. */
+
+ if (!child_pid) { // New child
+
+ close(fsrv->out_dir_fd);
+ close(fsrv->dev_null_fd);
+ close(fsrv->dev_urandom_fd);
+
+ if (fsrv->plot_file != NULL) {
+
+ fclose(fsrv->plot_file);
+ fsrv->plot_file = NULL;
+
+ }
+
+ // enable terminating on sigpipe in the childs
+ struct sigaction sa;
+ memset((char *)&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_DFL;
+ sigaction(SIGPIPE, &sa, NULL);
+
+ signal(SIGCHLD, old_sigchld_handler);
+
+ // FORKSRV_FD is for communication with AFL, we don't need it in the
+ // child
+ close(FORKSRV_FD);
+ close(FORKSRV_FD + 1);
+
+ // finally: exec...
+ execv(fsrv->target_path, argv);
+
+ /* Use a distinctive bitmap signature to tell the parent about execv()
+ falling through. */
+
+ *(u32 *)fsrv->trace_bits = EXEC_FAIL_SIG;
+
+ WARNF("Execv failed in fauxserver.");
+ break;
+
+ }
+
+ /* In parent process: write PID to AFL. */
+
+ if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) { exit(0); }
+
+ /* after child exited, get and relay exit status to parent through waitpid.
+ */
+
+ if (waitpid(child_pid, &status, 0) < 0) {
+
+ // Zombie Child could not be collected. Scary!
+ WARNF("Fauxserver could not determine child's exit code. ");
+
+ }
+
+ /* Relay wait status to AFL pipe, then loop back. */
+
+ if (write(FORKSRV_FD + 1, &status, 4) != 4) { exit(1); }
+
+ }
+
+}
+
+/* Report on the error received via the forkserver controller and exit */
+static void report_error_and_exit(int error) {
+
+ switch (error) {
+
+ case FS_ERROR_MAP_SIZE:
+ FATAL(
+ "AFL_MAP_SIZE is not set and fuzzing target reports that the "
+ "required size is very large. Solution: Run the fuzzing target "
+ "stand-alone with the environment variable AFL_DEBUG=1 set and set "
+ "the value for __afl_final_loc in the AFL_MAP_SIZE environment "
+ "variable for afl-fuzz.");
+ break;
+ case FS_ERROR_MAP_ADDR:
+ FATAL(
+ "the fuzzing target reports that hardcoded map address might be the "
+ "reason the mmap of the shared memory failed. Solution: recompile "
+ "the target with either afl-clang-lto and do not set "
+ "AFL_LLVM_MAP_ADDR or recompile with afl-clang-fast.");
+ break;
+ case FS_ERROR_SHM_OPEN:
+ FATAL("the fuzzing target reports that the shm_open() call failed.");
+ break;
+ case FS_ERROR_SHMAT:
+ FATAL("the fuzzing target reports that the shmat() call failed.");
+ break;
+ case FS_ERROR_MMAP:
+ FATAL(
+ "the fuzzing target reports that the mmap() call to the shared "
+ "memory failed.");
+ break;
+ case FS_ERROR_OLD_CMPLOG:
+ FATAL(
+ "the -c cmplog target was instrumented with an too old afl++ "
+ "version, you need to recompile it.");
+ break;
+ case FS_ERROR_OLD_CMPLOG_QEMU:
+ FATAL(
+ "The AFL++ QEMU/FRIDA loaders are from an older version, for -c you "
+ "need to recompile it.\n");
+ break;
+ default:
+ FATAL("unknown error code %d from fuzzing target!", error);
+
+ }
+
+}
+
+/* Spins up fork server. The idea is explained here:
+
+ https://lcamtuf.blogspot.com/2014/10/fuzzing-binaries-without-execve.html
+
+ In essence, the instrumentation allows us to skip execve(), and just keep
+ 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 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];
+ s32 status;
+ s32 rlen;
+ char *ignore_autodict = getenv("AFL_NO_AUTODICT");
+
+#ifdef __linux__
+ if (unlikely(fsrv->nyx_mode)) {
+
+ if (fsrv->nyx_runner != NULL) { return; }
+
+ if (!be_quiet) { ACTF("Spinning up the NYX backend..."); }
+
+ if (fsrv->out_dir_path == NULL) { FATAL("Nyx workdir path not found..."); }
+
+ char *x = alloc_printf("%s/workdir", fsrv->out_dir_path);
+
+ if (fsrv->nyx_id == 0xFFFFFFFF) { FATAL("Nyx ID is not set..."); }
+
+ if (fsrv->nyx_bind_cpu_id == 0xFFFFFFFF) {
+
+ FATAL("Nyx CPU ID is not set...");
+
+ }
+
+ if (fsrv->nyx_standalone) {
+
+ fsrv->nyx_runner = fsrv->nyx_handlers->nyx_new(
+ fsrv->target_path, x, fsrv->nyx_bind_cpu_id, MAX_FILE, true);
+
+ } else {
+
+ if (fsrv->nyx_parent) {
+
+ fsrv->nyx_runner = fsrv->nyx_handlers->nyx_new_parent(
+ fsrv->target_path, x, fsrv->nyx_bind_cpu_id, MAX_FILE, true);
+
+ } else {
+
+ fsrv->nyx_runner = fsrv->nyx_handlers->nyx_new_child(
+ fsrv->target_path, x, fsrv->nyx_bind_cpu_id, fsrv->nyx_id);
+
+ }
+
+ }
+
+ ck_free(x);
+
+ if (fsrv->nyx_runner == NULL) { FATAL("Something went wrong ..."); }
+
+ u32 tmp_map_size =
+ fsrv->nyx_handlers->nyx_get_bitmap_buffer_size(fsrv->nyx_runner);
+ fsrv->real_map_size = tmp_map_size;
+ fsrv->map_size = (((tmp_map_size + 63) >> 6) << 6);
+ if (!be_quiet) { ACTF("Target map size: %u", fsrv->real_map_size); }
+
+ fsrv->trace_bits =
+ fsrv->nyx_handlers->nyx_get_bitmap_buffer(fsrv->nyx_runner);
+
+ fsrv->nyx_handlers->nyx_option_set_reload_mode(
+ fsrv->nyx_runner, getenv("NYX_DISABLE_SNAPSHOT_MODE") == NULL);
+ fsrv->nyx_handlers->nyx_option_apply(fsrv->nyx_runner);
+
+ fsrv->nyx_handlers->nyx_option_set_timeout(fsrv->nyx_runner, 2, 0);
+ fsrv->nyx_handlers->nyx_option_apply(fsrv->nyx_runner);
+
+ fsrv->nyx_aux_string = malloc(0x1000);
+ memset(fsrv->nyx_aux_string, 0, 0x1000);
+
+ /* dry run */
+ fsrv->nyx_handlers->nyx_set_afl_input(fsrv->nyx_runner, "INIT", 4);
+ switch (fsrv->nyx_handlers->nyx_exec(fsrv->nyx_runner)) {
+
+ case Abort:
+ fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner);
+ FATAL("Error: Nyx abort occured...");
+ break;
+ case IoError:
+ FATAL("Error: QEMU-Nyx has died...");
+ break;
+ case Error:
+ fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner);
+ FATAL("Error: Nyx runtime error has occured...");
+ break;
+ default:
+ break;
+
+ }
+
+ /* autodict in Nyx mode */
+ if (!ignore_autodict) {
+
+ x = alloc_printf("%s/workdir/dump/afl_autodict.txt", fsrv->out_dir_path);
+ int nyx_autodict_fd = open(x, O_RDONLY);
+ ck_free(x);
+
+ if (nyx_autodict_fd >= 0) {
+
+ struct stat st;
+ if (fstat(nyx_autodict_fd, &st) >= 0) {
+
+ u32 f_len = st.st_size;
+ u8 *dict = ck_alloc(f_len);
+ if (dict == NULL) {
+
+ FATAL("Could not allocate %u bytes of autodictionary memory",
+ f_len);
+
+ }
+
+ u32 offset = 0, count = 0;
+ u32 len = f_len;
+
+ while (len != 0) {
+
+ rlen = read(nyx_autodict_fd, dict + offset, len);
+ if (rlen > 0) {
+
+ len -= rlen;
+ offset += rlen;
+
+ } else {
+
+ FATAL(
+ "Reading autodictionary fail at position %u with %u bytes "
+ "left.",
+ offset, len);
+
+ }
+
+ }
+
+ offset = 0;
+ while (offset < (u32)f_len &&
+ (u8)dict[offset] + offset < (u32)f_len) {
+
+ fsrv->add_extra_func(fsrv->afl_ptr, dict + offset + 1,
+ (u8)dict[offset]);
+ offset += (1 + dict[offset]);
+ count++;
+
+ }
+
+ if (!be_quiet) { ACTF("Loaded %u autodictionary entries", count); }
+ ck_free(dict);
+
+ }
+
+ close(nyx_autodict_fd);
+
+ }
+
+ }
+
+ return;
+
+ }
+
+#endif
+
+ if (!be_quiet) { ACTF("Spinning up the fork server..."); }
+
+#ifdef AFL_PERSISTENT_RECORD
+ if (unlikely(fsrv->persistent_record)) {
+
+ fsrv->persistent_record_data =
+ (u8 **)ck_alloc(fsrv->persistent_record * sizeof(u8 *));
+ fsrv->persistent_record_len =
+ (u32 *)ck_alloc(fsrv->persistent_record * sizeof(u32));
+
+ if (!fsrv->persistent_record_data || !fsrv->persistent_record_len) {
+
+ FATAL("Unable to allocate memory for persistent replay.");
+
+ }
+
+ }
+
+#endif
+
+ if (fsrv->use_fauxsrv) {
+
+ /* TODO: Come up with some nice way to initialize this all */
+
+ if (fsrv->init_child_func != fsrv_exec_child) {
+
+ FATAL("Different forkserver not compatible with fauxserver");
+
+ }
+
+ if (!be_quiet) { ACTF("Using AFL++ faux forkserver..."); }
+ fsrv->init_child_func = afl_fauxsrv_execv;
+
+ }
+
+ if (pipe(st_pipe) || pipe(ctl_pipe)) { PFATAL("pipe() failed"); }
+
+ fsrv->last_run_timed_out = 0;
+ fsrv->fsrv_pid = fork();
+
+ if (fsrv->fsrv_pid < 0) { PFATAL("fork() failed"); }
+
+ if (!fsrv->fsrv_pid) {
+
+ /* CHILD PROCESS */
+
+ // enable terminating on sigpipe in the childs
+ struct sigaction sa;
+ memset((char *)&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_DFL;
+ sigaction(SIGPIPE, &sa, NULL);
+
+ struct rlimit r;
+
+ if (!fsrv->cmplog_binary) {
+
+ unsetenv(CMPLOG_SHM_ENV_VAR); // we do not want that in non-cmplog fsrv
+
+ }
+
+ /* Umpf. On OpenBSD, the default fd limit for root users is set to
+ soft 128. Let's try to fix that... */
+ if (!getrlimit(RLIMIT_NOFILE, &r) && r.rlim_cur < FORKSRV_FD + 2) {
+
+ r.rlim_cur = FORKSRV_FD + 2;
+ setrlimit(RLIMIT_NOFILE, &r); /* Ignore errors */
+
+ }
+
+ if (fsrv->mem_limit) {
+
+ r.rlim_max = r.rlim_cur = ((rlim_t)fsrv->mem_limit) << 20;
+
+#ifdef RLIMIT_AS
+ setrlimit(RLIMIT_AS, &r); /* Ignore errors */
+#else
+ /* This takes care of OpenBSD, which doesn't have RLIMIT_AS, but
+ according to reliable sources, RLIMIT_DATA covers anonymous
+ maps - so we should be getting good protection against OOM bugs. */
+
+ setrlimit(RLIMIT_DATA, &r); /* Ignore errors */
+#endif /* ^RLIMIT_AS */
+
+ }
+
+ /* Dumping cores is slow and can lead to anomalies if SIGKILL is delivered
+ before the dump is complete. */
+
+ if (!fsrv->debug) {
+
+ r.rlim_max = r.rlim_cur = 0;
+ setrlimit(RLIMIT_CORE, &r); /* Ignore errors */
+
+ }
+
+ /* Isolate the process and configure standard descriptors. If out_file is
+ specified, stdin is /dev/null; otherwise, out_fd is cloned instead. */
+
+ setsid();
+
+ if (!(debug_child_output)) {
+
+ dup2(fsrv->dev_null_fd, 1);
+ dup2(fsrv->dev_null_fd, 2);
+
+ }
+
+ if (!fsrv->use_stdin) {
+
+ dup2(fsrv->dev_null_fd, 0);
+
+ } else {
+
+ dup2(fsrv->out_fd, 0);
+ close(fsrv->out_fd);
+
+ }
+
+ /* Set up control and status pipes, close the unneeded original fds. */
+
+ if (dup2(ctl_pipe[0], FORKSRV_FD) < 0) { PFATAL("dup2() failed"); }
+ if (dup2(st_pipe[1], FORKSRV_FD + 1) < 0) { PFATAL("dup2() failed"); }
+
+ close(ctl_pipe[0]);
+ close(ctl_pipe[1]);
+ close(st_pipe[0]);
+ close(st_pipe[1]);
+
+ close(fsrv->out_dir_fd);
+ close(fsrv->dev_null_fd);
+ close(fsrv->dev_urandom_fd);
+
+ if (fsrv->plot_file != NULL) {
+
+ fclose(fsrv->plot_file);
+ fsrv->plot_file = NULL;
+
+ }
+
+ /* This should improve performance a bit, since it stops the linker from
+ doing extra work post-fork(). */
+
+ if (!getenv("LD_BIND_LAZY")) { setenv("LD_BIND_NOW", "1", 1); }
+
+ /* Set sane defaults for ASAN if nothing else is specified. */
+
+ if (!getenv("ASAN_OPTIONS"))
+ setenv("ASAN_OPTIONS",
+ "abort_on_error=1:"
+ "detect_leaks=0:"
+ "malloc_context_size=0:"
+ "symbolize=0:"
+ "allocator_may_return_null=1:"
+ "detect_odr_violation=0:"
+ "handle_segv=0:"
+ "handle_sigbus=0:"
+ "handle_abort=0:"
+ "handle_sigfpe=0:"
+ "handle_sigill=0",
+ 1);
+
+ /* Set sane defaults for UBSAN if nothing else is specified. */
+
+ if (!getenv("UBSAN_OPTIONS"))
+ setenv("UBSAN_OPTIONS",
+ "halt_on_error=1:"
+ "abort_on_error=1:"
+ "malloc_context_size=0:"
+ "allocator_may_return_null=1:"
+ "symbolize=0:"
+ "handle_segv=0:"
+ "handle_sigbus=0:"
+ "handle_abort=0:"
+ "handle_sigfpe=0:"
+ "handle_sigill=0",
+ 1);
+
+ /* Envs for QASan */
+ setenv("QASAN_MAX_CALL_STACK", "0", 0);
+ setenv("QASAN_SYMBOLIZE", "0", 0);
+
+ /* MSAN is tricky, because it doesn't support abort_on_error=1 at this
+ point. So, we do this in a very hacky way. */
+
+ if (!getenv("MSAN_OPTIONS"))
+ setenv("MSAN_OPTIONS",
+ "exit_code=" STRINGIFY(MSAN_ERROR) ":"
+ "symbolize=0:"
+ "abort_on_error=1:"
+ "malloc_context_size=0:"
+ "allocator_may_return_null=1:"
+ "msan_track_origins=0:"
+ "handle_segv=0:"
+ "handle_sigbus=0:"
+ "handle_abort=0:"
+ "handle_sigfpe=0:"
+ "handle_sigill=0",
+ 1);
+
+ /* LSAN, too, does not support abort_on_error=1. */
+
+ if (!getenv("LSAN_OPTIONS"))
+ setenv("LSAN_OPTIONS",
+ "exitcode=" STRINGIFY(LSAN_ERROR) ":"
+ "fast_unwind_on_malloc=0:"
+ "symbolize=0:"
+ "print_suppressions=0",
+ 1);
+
+ fsrv->init_child_func(fsrv, argv);
+
+ /* Use a distinctive bitmap signature to tell the parent about execv()
+ falling through. */
+
+ *(u32 *)fsrv->trace_bits = EXEC_FAIL_SIG;
+ FATAL("Error: execv to target failed\n");
+
+ }
+
+ /* PARENT PROCESS */
+
+ char pid_buf[16];
+ sprintf(pid_buf, "%d", fsrv->fsrv_pid);
+ if (fsrv->cmplog_binary)
+ setenv("__AFL_TARGET_PID2", pid_buf, 1);
+ else
+ setenv("__AFL_TARGET_PID1", pid_buf, 1);
+
+ /* Close the unneeded endpoints. */
+
+ close(ctl_pipe[0]);
+ close(st_pipe[1]);
+
+ fsrv->fsrv_ctl_fd = ctl_pipe[1];
+ fsrv->fsrv_st_fd = st_pipe[0];
+
+ /* Wait for the fork server to come up, but don't wait too long. */
+
+ rlen = 0;
+ if (fsrv->init_tmout) {
+
+ u32 time_ms = read_s32_timed(fsrv->fsrv_st_fd, &status, fsrv->init_tmout,
+ stop_soon_p);
+
+ if (!time_ms) {
+
+ s32 tmp_pid = fsrv->fsrv_pid;
+ if (tmp_pid > 0) {
+
+ kill(tmp_pid, fsrv->kill_signal);
+ fsrv->fsrv_pid = -1;
+
+ }
+
+ } else if (time_ms > fsrv->init_tmout) {
+
+ fsrv->last_run_timed_out = 1;
+ s32 tmp_pid = fsrv->fsrv_pid;
+ if (tmp_pid > 0) {
+
+ kill(tmp_pid, fsrv->kill_signal);
+ fsrv->fsrv_pid = -1;
+
+ }
+
+ } else {
+
+ rlen = 4;
+
+ }
+
+ } else {
+
+ rlen = read(fsrv->fsrv_st_fd, &status, 4);
+
+ }
+
+ /* If we have a four-byte "hello" message from the server, we're all set.
+ Otherwise, try to figure out what went wrong. */
+
+ if (rlen == 4) {
+
+ if (!be_quiet) { OKF("All right - fork server is up."); }
+
+ if (getenv("AFL_DEBUG")) {
+
+ ACTF("Extended forkserver functions received (%08x).", status);
+
+ }
+
+ if ((status & FS_OPT_ERROR) == FS_OPT_ERROR)
+ report_error_and_exit(FS_OPT_GET_ERROR(status));
+
+ if ((status & FS_OPT_ENABLED) == FS_OPT_ENABLED) {
+
+ // workaround for recent afl++ versions
+ if ((status & FS_OPT_OLD_AFLPP_WORKAROUND) == FS_OPT_OLD_AFLPP_WORKAROUND)
+ status = (status & 0xf0ffffff);
+
+ if ((status & FS_OPT_NEWCMPLOG) == 0 && fsrv->cmplog_binary) {
+
+ if (fsrv->qemu_mode || fsrv->frida_mode) {
+
+ report_error_and_exit(FS_ERROR_OLD_CMPLOG_QEMU);
+
+ } else {
+
+ report_error_and_exit(FS_ERROR_OLD_CMPLOG);
+
+ }
+
+ }
+
+ if ((status & FS_OPT_SNAPSHOT) == FS_OPT_SNAPSHOT) {
+
+ fsrv->snapshot = 1;
+ if (!be_quiet) { ACTF("Using SNAPSHOT feature."); }
+
+ }
+
+ if ((status & FS_OPT_SHDMEM_FUZZ) == FS_OPT_SHDMEM_FUZZ) {
+
+ if (fsrv->support_shmem_fuzz) {
+
+ fsrv->use_shmem_fuzz = 1;
+ if (!be_quiet) { ACTF("Using SHARED MEMORY FUZZING feature."); }
+
+ if ((status & FS_OPT_AUTODICT) == 0 || ignore_autodict) {
+
+ u32 send_status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ);
+ if (write(fsrv->fsrv_ctl_fd, &send_status, 4) != 4) {
+
+ FATAL("Writing to forkserver failed.");
+
+ }
+
+ }
+
+ } else {
+
+ FATAL(
+ "Target requested sharedmem fuzzing, but we failed to enable "
+ "it.");
+
+ }
+
+ }
+
+ if ((status & FS_OPT_MAPSIZE) == FS_OPT_MAPSIZE) {
+
+ u32 tmp_map_size = FS_OPT_GET_MAPSIZE(status);
+
+ if (!fsrv->map_size) { fsrv->map_size = MAP_SIZE; }
+
+ fsrv->real_map_size = tmp_map_size;
+
+ if (tmp_map_size % 64) {
+
+ tmp_map_size = (((tmp_map_size + 63) >> 6) << 6);
+
+ }
+
+ if (!be_quiet) { ACTF("Target map size: %u", fsrv->real_map_size); }
+ if (tmp_map_size > fsrv->map_size) {
+
+ FATAL(
+ "Target's coverage map size of %u is larger than the one this "
+ "afl++ is set with (%u). Either set AFL_MAP_SIZE=%u and restart "
+ " afl-fuzz, or change MAP_SIZE_POW2 in config.h and recompile "
+ "afl-fuzz",
+ tmp_map_size, fsrv->map_size, tmp_map_size);
+
+ }
+
+ fsrv->map_size = tmp_map_size;
+
+ }
+
+ if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) {
+
+ if (!ignore_autodict) {
+
+ if (fsrv->add_extra_func == NULL || fsrv->afl_ptr == NULL) {
+
+ // this is not afl-fuzz - or it is cmplog - we deny and return
+ if (fsrv->use_shmem_fuzz) {
+
+ status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ);
+
+ } else {
+
+ status = (FS_OPT_ENABLED);
+
+ }
+
+ if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) {
+
+ FATAL("Writing to forkserver failed.");
+
+ }
+
+ return;
+
+ }
+
+ if (!be_quiet) { ACTF("Using AUTODICT feature."); }
+
+ if (fsrv->use_shmem_fuzz) {
+
+ status = (FS_OPT_ENABLED | FS_OPT_AUTODICT | FS_OPT_SHDMEM_FUZZ);
+
+ } else {
+
+ status = (FS_OPT_ENABLED | FS_OPT_AUTODICT);
+
+ }
+
+ if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) {
+
+ FATAL("Writing to forkserver failed.");
+
+ }
+
+ if (read(fsrv->fsrv_st_fd, &status, 4) != 4) {
+
+ FATAL("Reading from forkserver failed.");
+
+ }
+
+ if (status < 2 || (u32)status > 0xffffff) {
+
+ FATAL("Dictionary has an illegal size: %d", status);
+
+ }
+
+ u32 offset = 0, count = 0;
+ u32 len = status;
+ u8 *dict = ck_alloc(len);
+ if (dict == NULL) {
+
+ FATAL("Could not allocate %u bytes of autodictionary memory", len);
+
+ }
+
+ while (len != 0) {
+
+ rlen = read(fsrv->fsrv_st_fd, dict + offset, len);
+ if (rlen > 0) {
+
+ len -= rlen;
+ offset += rlen;
+
+ } else {
+
+ FATAL(
+ "Reading autodictionary fail at position %u with %u bytes "
+ "left.",
+ offset, len);
+
+ }
+
+ }
+
+ offset = 0;
+ while (offset < (u32)status &&
+ (u8)dict[offset] + offset < (u32)status) {
+
+ fsrv->add_extra_func(fsrv->afl_ptr, dict + offset + 1,
+ (u8)dict[offset]);
+ offset += (1 + dict[offset]);
+ count++;
+
+ }
+
+ if (!be_quiet) { ACTF("Loaded %u autodictionary entries", count); }
+ ck_free(dict);
+
+ }
+
+ }
+
+ }
+
+ return;
+
+ }
+
+ if (fsrv->last_run_timed_out) {
+
+ FATAL(
+ "Timeout while initializing fork server (setting "
+ "AFL_FORKSRV_INIT_TMOUT may help)");
+
+ }
+
+ if (waitpid(fsrv->fsrv_pid, &status, 0) <= 0) { PFATAL("waitpid() failed"); }
+
+ if (WIFSIGNALED(status)) {
+
+ if (fsrv->mem_limit && fsrv->mem_limit < 500 && fsrv->uses_asan) {
+
+ SAYF("\n" cLRD "[-] " cRST
+ "Whoops, the target binary crashed suddenly, "
+ "before receiving any input\n"
+ " from the fuzzer! Since it seems to be built with ASAN and you "
+ "have a\n"
+ " restrictive memory limit configured, this is expected; please "
+ "run with '-m 0'.\n");
+
+ } else if (!fsrv->mem_limit) {
+
+ SAYF("\n" cLRD "[-] " cRST
+ "Whoops, the target binary crashed suddenly, "
+ "before receiving any input\n"
+ " from the fuzzer! You can try the following:\n\n"
+
+ " - The target binary crashes because necessary runtime "
+ "conditions it needs\n"
+ " are not met. Try to:\n"
+ " 1. Run again with AFL_DEBUG=1 set and check the output of "
+ "the target\n"
+ " binary for clues.\n"
+ " 2. Run again with AFL_DEBUG=1 and 'ulimit -c unlimited' and "
+ "analyze the\n"
+ " generated core dump.\n\n"
+
+ " - Possibly the target requires a huge coverage map and has "
+ "CTORS.\n"
+ " Retry with setting AFL_MAP_SIZE=10000000.\n\n"
+
+ MSG_FORK_ON_APPLE
+
+ " - Less likely, there is a horrible bug in the fuzzer. If other "
+ "options\n"
+ " fail, poke <afl-users@googlegroups.com> for troubleshooting "
+ "tips.\n");
+
+ } else {
+
+ u8 val_buf[STRINGIFY_VAL_SIZE_MAX];
+
+ SAYF("\n" cLRD "[-] " cRST
+ "Whoops, the target binary crashed suddenly, "
+ "before receiving any input\n"
+ " from the fuzzer! You can try the following:\n\n"
+
+ " - The target binary crashes because necessary runtime "
+ "conditions it needs\n"
+ " are not met. Try to:\n"
+ " 1. Run again with AFL_DEBUG=1 set and check the output of "
+ "the target\n"
+ " binary for clues.\n"
+ " 2. Run again with AFL_DEBUG=1 and 'ulimit -c unlimited' and "
+ "analyze the\n"
+ " generated core dump.\n\n"
+
+ " - The current memory limit (%s) is too restrictive, causing "
+ "the\n"
+ " target to hit an OOM condition in the dynamic linker. Try "
+ "bumping up\n"
+ " the limit with the -m setting in the command line. A simple "
+ "way confirm\n"
+ " this diagnosis would be:\n\n"
+
+ MSG_ULIMIT_USAGE
+ " /path/to/fuzzed_app )\n\n"
+
+ " Tip: you can use https://jwilk.net/software/recidivm to\n"
+ " estimate the required amount of virtual memory for the "
+ "binary.\n\n"
+
+ MSG_FORK_ON_APPLE
+
+ " - Possibly the target requires a huge coverage map and has "
+ "CTORS.\n"
+ " Retry with setting AFL_MAP_SIZE=10000000.\n\n"
+
+ " - Less likely, there is a horrible bug in the fuzzer. If other "
+ "options\n"
+ " fail, poke <afl-users@googlegroups.com> for troubleshooting "
+ "tips.\n",
+ stringify_mem_size(val_buf, sizeof(val_buf), fsrv->mem_limit << 20),
+ fsrv->mem_limit - 1);
+
+ }
+
+ FATAL("Fork server crashed with signal %d", WTERMSIG(status));
+
+ }
+
+ if (*(u32 *)fsrv->trace_bits == EXEC_FAIL_SIG) {
+
+ FATAL("Unable to execute target application ('%s')", argv[0]);
+
+ }
+
+ if (fsrv->mem_limit && fsrv->mem_limit < 500 && fsrv->uses_asan) {
+
+ SAYF("\n" cLRD "[-] " cRST
+ "Hmm, looks like the target binary terminated "
+ "before we could complete a\n"
+ " handshake with the injected code. Since it seems to be built "
+ "with ASAN and\n"
+ " you have a restrictive memory limit configured, this is "
+ "expected; please\n"
+ " run with '-m 0'.\n");
+
+ } else if (!fsrv->mem_limit) {
+
+ SAYF("\n" cLRD "[-] " cRST
+ "Hmm, looks like the target binary terminated before we could complete"
+ " a\n"
+ "handshake with the injected code. You can try the following:\n\n"
+
+ " - The target binary crashes because necessary runtime conditions "
+ "it needs\n"
+ " are not met. Try to:\n"
+ " 1. Run again with AFL_DEBUG=1 set and check the output of the "
+ "target\n"
+ " binary for clues.\n"
+ " 2. Run again with AFL_DEBUG=1 and 'ulimit -c unlimited' and "
+ "analyze the\n"
+ " generated core dump.\n\n"
+
+ " - Possibly the target requires a huge coverage map and has "
+ "CTORS.\n"
+ " Retry with setting AFL_MAP_SIZE=10000000.\n\n"
+
+ "Otherwise there is a horrible bug in the fuzzer.\n"
+ "Poke <afl-users@googlegroups.com> for troubleshooting tips.\n");
+
+ } else {
+
+ u8 val_buf[STRINGIFY_VAL_SIZE_MAX];
+
+ SAYF(
+ "\n" cLRD "[-] " cRST
+ "Hmm, looks like the target binary terminated "
+ "before we could complete a\n"
+ " handshake with the injected code. You can try the following:\n\n"
+
+ "%s"
+
+ " - The target binary crashes because necessary runtime conditions "
+ "it needs\n"
+ " are not met. Try to:\n"
+ " 1. Run again with AFL_DEBUG=1 set and check the output of the "
+ "target\n"
+ " binary for clues.\n"
+ " 2. Run again with AFL_DEBUG=1 and 'ulimit -c unlimited' and "
+ "analyze the\n"
+ " generated core dump.\n\n"
+
+ " - Possibly the target requires a huge coverage map and has "
+ "CTORS.\n"
+ " Retry with setting AFL_MAP_SIZE=10000000.\n\n"
+
+ " - The current memory limit (%s) is too restrictive, causing an "
+ "OOM\n"
+ " fault in the dynamic linker. This can be fixed with the -m "
+ "option. A\n"
+ " simple way to confirm the diagnosis may be:\n\n"
+
+ MSG_ULIMIT_USAGE
+ " /path/to/fuzzed_app )\n\n"
+
+ " Tip: you can use https://jwilk.net/software/recidivm to\n"
+ " estimate the required amount of virtual memory for the "
+ "binary.\n\n"
+
+ " - The target was compiled with afl-clang-lto and a constructor "
+ "was\n"
+ " instrumented, recompiling without AFL_LLVM_MAP_ADDR might solve "
+ "your \n"
+ " problem\n\n"
+
+ " - Less likely, there is a horrible bug in the fuzzer. If other "
+ "options\n"
+ " fail, poke <afl-users@googlegroups.com> for troubleshooting "
+ "tips.\n",
+ getenv(DEFER_ENV_VAR)
+ ? " - You are using deferred forkserver, but __AFL_INIT() is "
+ "never\n"
+ " reached before the program terminates.\n\n"
+ : "",
+ stringify_int(val_buf, sizeof(val_buf), fsrv->mem_limit << 20),
+ fsrv->mem_limit - 1);
+
+ }
+
+ FATAL("Fork server handshake failed");
+
+}
+
+/* Stop the forkserver and child */
+
+void afl_fsrv_kill(afl_forkserver_t *fsrv) {
+
+ if (fsrv->child_pid > 0) { kill(fsrv->child_pid, fsrv->kill_signal); }
+ if (fsrv->fsrv_pid > 0) {
+
+ kill(fsrv->fsrv_pid, fsrv->kill_signal);
+ if (waitpid(fsrv->fsrv_pid, NULL, 0) <= 0) { WARNF("error waitpid\n"); }
+
+ }
+
+ close(fsrv->fsrv_ctl_fd);
+ close(fsrv->fsrv_st_fd);
+ fsrv->fsrv_pid = -1;
+ fsrv->child_pid = -1;
+
+#ifdef __linux__
+ if (fsrv->nyx_mode) {
+
+ free(fsrv->nyx_aux_string);
+ fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner);
+
+ }
+
+#endif
+
+}
+
+/* Get the map size from the target forkserver */
+
+u32 afl_fsrv_get_mapsize(afl_forkserver_t *fsrv, char **argv,
+ volatile u8 *stop_soon_p, u8 debug_child_output) {
+
+ afl_fsrv_start(fsrv, argv, stop_soon_p, debug_child_output);
+ return fsrv->map_size;
+
+}
+
+/* Delete the current testcase and write the buf to the testcase file */
+
+void __attribute__((hot))
+afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) {
+
+#ifdef __linux__
+ if (unlikely(fsrv->nyx_mode)) {
+
+ fsrv->nyx_handlers->nyx_set_afl_input(fsrv->nyx_runner, buf, len);
+ return;
+
+ }
+
+#endif
+
+#ifdef AFL_PERSISTENT_RECORD
+ if (unlikely(fsrv->persistent_record)) {
+
+ fsrv->persistent_record_len[fsrv->persistent_record_idx] = len;
+ fsrv->persistent_record_data[fsrv->persistent_record_idx] = afl_realloc(
+ (void **)&fsrv->persistent_record_data[fsrv->persistent_record_idx],
+ len);
+
+ if (unlikely(!fsrv->persistent_record_data[fsrv->persistent_record_idx])) {
+
+ FATAL("allocating replay memory failed.");
+
+ }
+
+ memcpy(fsrv->persistent_record_data[fsrv->persistent_record_idx], buf, len);
+
+ if (unlikely(++fsrv->persistent_record_idx >= fsrv->persistent_record)) {
+
+ fsrv->persistent_record_idx = 0;
+
+ }
+
+ }
+
+#endif
+
+ if (likely(fsrv->use_shmem_fuzz)) {
+
+ if (unlikely(len > MAX_FILE)) len = MAX_FILE;
+
+ *fsrv->shmem_fuzz_len = len;
+ memcpy(fsrv->shmem_fuzz, buf, len);
+#ifdef _DEBUG
+ if (getenv("AFL_DEBUG")) {
+
+ fprintf(stderr, "FS crc: %016llx len: %u\n",
+ hash64(fsrv->shmem_fuzz, *fsrv->shmem_fuzz_len, HASH_CONST),
+ *fsrv->shmem_fuzz_len);
+ fprintf(stderr, "SHM :");
+ for (u32 i = 0; i < *fsrv->shmem_fuzz_len; i++)
+ fprintf(stderr, "%02x", fsrv->shmem_fuzz[i]);
+ fprintf(stderr, "\nORIG:");
+ for (u32 i = 0; i < *fsrv->shmem_fuzz_len; i++)
+ fprintf(stderr, "%02x", buf[i]);
+ fprintf(stderr, "\n");
+
+ }
+
+#endif
+
+ } else {
+
+ s32 fd = fsrv->out_fd;
+
+ if (!fsrv->use_stdin && fsrv->out_file) {
+
+ if (unlikely(fsrv->no_unlink)) {
+
+ fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_TRUNC,
+ DEFAULT_PERMISSION);
+
+ } else {
+
+ unlink(fsrv->out_file); /* Ignore errors. */
+ fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_EXCL,
+ DEFAULT_PERMISSION);
+
+ }
+
+ if (fd < 0) { PFATAL("Unable to create '%s'", fsrv->out_file); }
+
+ } else if (unlikely(fd <= 0)) {
+
+ // We should have a (non-stdin) fd at this point, else we got a problem.
+ FATAL(
+ "Nowhere to write output to (neither out_fd nor out_file set (fd is "
+ "%d))",
+ fd);
+
+ } else {
+
+ lseek(fd, 0, SEEK_SET);
+
+ }
+
+ // fprintf(stderr, "WRITE %d %u\n", fd, len);
+ ck_write(fd, buf, len, fsrv->out_file);
+
+ if (fsrv->use_stdin) {
+
+ if (ftruncate(fd, len)) { PFATAL("ftruncate() failed"); }
+ lseek(fd, 0, SEEK_SET);
+
+ } else {
+
+ close(fd);
+
+ }
+
+ }
+
+}
+
+/* Execute target application, monitoring for timeouts. Return status
+ information. The called program will update afl->fsrv->trace_bits. */
+
+fsrv_run_result_t __attribute__((hot))
+afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
+ volatile u8 *stop_soon_p) {
+
+ s32 res;
+ u32 exec_ms;
+ u32 write_value = fsrv->last_run_timed_out;
+
+#ifdef __linux__
+ if (fsrv->nyx_mode) {
+
+ static uint32_t last_timeout_value = 0;
+
+ if (last_timeout_value != timeout) {
+
+ fsrv->nyx_handlers->nyx_option_set_timeout(
+ fsrv->nyx_runner, timeout / 1000, (timeout % 1000) * 1000);
+ fsrv->nyx_handlers->nyx_option_apply(fsrv->nyx_runner);
+ last_timeout_value = timeout;
+
+ }
+
+ enum NyxReturnValue ret_val =
+ fsrv->nyx_handlers->nyx_exec(fsrv->nyx_runner);
+
+ fsrv->total_execs++;
+
+ switch (ret_val) {
+
+ case Normal:
+ return FSRV_RUN_OK;
+ case Crash:
+ case Asan:
+ return FSRV_RUN_CRASH;
+ case Timout:
+ return FSRV_RUN_TMOUT;
+ case InvalidWriteToPayload:
+ /* ??? */
+ FATAL("FixMe: Nyx InvalidWriteToPayload handler is missing");
+ break;
+ case Abort:
+ fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner);
+ FATAL("Error: Nyx abort occured...");
+ case IoError:
+ if (*stop_soon_p) {
+
+ return 0;
+
+ } else {
+
+ FATAL("Error: QEMU-Nyx has died...");
+
+ }
+
+ break;
+ case Error:
+ FATAL("Error: Nyx runtime error has occured...");
+ break;
+
+ }
+
+ return FSRV_RUN_OK;
+
+ }
+
+#endif
+ /* After this memset, fsrv->trace_bits[] are effectively volatile, so we
+ must prevent any earlier operations from venturing into that
+ territory. */
+
+#ifdef __linux__
+ if (!fsrv->nyx_mode) {
+
+ memset(fsrv->trace_bits, 0, fsrv->map_size);
+ MEM_BARRIER();
+
+ }
+
+#else
+ memset(fsrv->trace_bits, 0, fsrv->map_size);
+ MEM_BARRIER();
+#endif
+
+ /* we have the fork server (or faux server) up and running
+ First, tell it if the previous run timed out. */
+
+ if ((res = write(fsrv->fsrv_ctl_fd, &write_value, 4)) != 4) {
+
+ if (*stop_soon_p) { return 0; }
+ RPFATAL(res, "Unable to request new process from fork server (OOM?)");
+
+ }
+
+ fsrv->last_run_timed_out = 0;
+
+ if ((res = read(fsrv->fsrv_st_fd, &fsrv->child_pid, 4)) != 4) {
+
+ if (*stop_soon_p) { return 0; }
+ RPFATAL(res, "Unable to request new process from fork server (OOM?)");
+
+ }
+
+#ifdef AFL_PERSISTENT_RECORD
+ // end of persistent loop?
+ if (unlikely(fsrv->persistent_record &&
+ fsrv->persistent_record_pid != fsrv->child_pid)) {
+
+ fsrv->persistent_record_pid = fsrv->child_pid;
+ u32 idx, val;
+ if (unlikely(!fsrv->persistent_record_idx))
+ idx = fsrv->persistent_record - 1;
+ else
+ idx = fsrv->persistent_record_idx - 1;
+ val = fsrv->persistent_record_len[idx];
+ memset((void *)fsrv->persistent_record_len, 0,
+ fsrv->persistent_record * sizeof(u32));
+ fsrv->persistent_record_len[idx] = val;
+
+ }
+
+#endif
+
+ if (fsrv->child_pid <= 0) {
+
+ if (*stop_soon_p) { return 0; }
+
+ if ((fsrv->child_pid & FS_OPT_ERROR) &&
+ FS_OPT_GET_ERROR(fsrv->child_pid) == FS_ERROR_SHM_OPEN)
+ FATAL(
+ "Target reported shared memory access failed (perhaps increase "
+ "shared memory available).");
+
+ FATAL("Fork server is misbehaving (OOM?)");
+
+ }
+
+ exec_ms = read_s32_timed(fsrv->fsrv_st_fd, &fsrv->child_status, timeout,
+ stop_soon_p);
+
+ if (exec_ms > timeout) {
+
+ /* If there was no response from forkserver after timeout seconds,
+ we kill the child. The forkserver should inform us afterwards */
+
+ s32 tmp_pid = fsrv->child_pid;
+ if (tmp_pid > 0) {
+
+ kill(tmp_pid, fsrv->kill_signal);
+ fsrv->child_pid = -1;
+
+ }
+
+ fsrv->last_run_timed_out = 1;
+ if (read(fsrv->fsrv_st_fd, &fsrv->child_status, 4) < 4) { exec_ms = 0; }
+
+ }
+
+ if (!exec_ms) {
+
+ if (*stop_soon_p) { return 0; }
+ SAYF("\n" cLRD "[-] " cRST
+ "Unable to communicate with fork server. Some possible reasons:\n\n"
+ " - You've run out of memory. Use -m to increase the the memory "
+ "limit\n"
+ " to something higher than %llu.\n"
+ " - The binary or one of the libraries it uses manages to "
+ "create\n"
+ " threads before the forkserver initializes.\n"
+ " - The binary, at least in some circumstances, exits in a way "
+ "that\n"
+ " also kills the parent process - raise() could be the "
+ "culprit.\n"
+ " - If using persistent mode with QEMU, "
+ "AFL_QEMU_PERSISTENT_ADDR "
+ "is\n"
+ " probably not valid (hint: add the base address in case of "
+ "PIE)"
+ "\n\n"
+ "If all else fails you can disable the fork server via "
+ "AFL_NO_FORKSRV=1.\n",
+ fsrv->mem_limit);
+ RPFATAL(res, "Unable to communicate with fork server");
+
+ }
+
+ if (!WIFSTOPPED(fsrv->child_status)) { fsrv->child_pid = -1; }
+
+ fsrv->total_execs++;
+
+ /* Any subsequent operations on fsrv->trace_bits must not be moved by the
+ compiler below this point. Past this location, fsrv->trace_bits[]
+ behave very normally and do not have to be treated as volatile. */
+
+ MEM_BARRIER();
+
+ /* Report outcome to caller. */
+
+ /* Was the run unsuccessful? */
+ if (unlikely(*(u32 *)fsrv->trace_bits == EXEC_FAIL_SIG)) {
+
+ return FSRV_RUN_ERROR;
+
+ }
+
+ /* Did we timeout? */
+ if (unlikely(fsrv->last_run_timed_out)) {
+
+ fsrv->last_kill_signal = fsrv->kill_signal;
+ return FSRV_RUN_TMOUT;
+
+ }
+
+ /* Did we crash?
+ In a normal case, (abort) WIFSIGNALED(child_status) will be set.
+ MSAN in uses_asan mode uses a special exit code as it doesn't support
+ abort_on_error. On top, a user may specify a custom AFL_CRASH_EXITCODE.
+ Handle all three cases here. */
+
+ if (unlikely(
+ /* A normal crash/abort */
+ (WIFSIGNALED(fsrv->child_status)) ||
+ /* special handling for msan and lsan */
+ (fsrv->uses_asan &&
+ (WEXITSTATUS(fsrv->child_status) == MSAN_ERROR ||
+ WEXITSTATUS(fsrv->child_status) == LSAN_ERROR)) ||
+ /* the custom crash_exitcode was returned by the target */
+ (fsrv->uses_crash_exitcode &&
+ WEXITSTATUS(fsrv->child_status) == fsrv->crash_exitcode))) {
+
+#ifdef AFL_PERSISTENT_RECORD
+ if (unlikely(fsrv->persistent_record)) {
+
+ char fn[PATH_MAX];
+ u32 i, writecnt = 0;
+ for (i = 0; i < fsrv->persistent_record; ++i) {
+
+ u32 entry = (i + fsrv->persistent_record_idx) % fsrv->persistent_record;
+ u8 *data = fsrv->persistent_record_data[entry];
+ u32 len = fsrv->persistent_record_len[entry];
+ if (likely(len && data)) {
+
+ snprintf(fn, sizeof(fn), "%s/RECORD:%06u,cnt:%06u",
+ fsrv->persistent_record_dir, fsrv->persistent_record_cnt,
+ writecnt++);
+ int fd = open(fn, O_CREAT | O_TRUNC | O_WRONLY, 0644);
+ if (fd >= 0) {
+
+ ck_write(fd, data, len, fn);
+ close(fd);
+
+ }
+
+ }
+
+ }
+
+ ++fsrv->persistent_record_cnt;
+
+ }
+
+#endif
+
+ /* For a proper crash, set last_kill_signal to WTERMSIG, else set it to 0 */
+ fsrv->last_kill_signal =
+ WIFSIGNALED(fsrv->child_status) ? WTERMSIG(fsrv->child_status) : 0;
+ return FSRV_RUN_CRASH;
+
+ }
+
+ /* success :) */
+ return FSRV_RUN_OK;
+
+}
+
+void afl_fsrv_killall() {
+
+ LIST_FOREACH(&fsrv_list, afl_forkserver_t, {
+
+ afl_fsrv_kill(el);
+
+ });
+
+}
+
+void afl_fsrv_deinit(afl_forkserver_t *fsrv) {
+
+ afl_fsrv_kill(fsrv);
+ list_remove(&fsrv_list, fsrv);
+
+}
+
diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c
new file mode 100644
index 00000000..26e70d81
--- /dev/null
+++ b/src/afl-fuzz-bitmap.c
@@ -0,0 +1,824 @@
+/*
+ american fuzzy lop++ - bitmap related routines
+ ----------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Andrea Fioraldi <andreafioraldi@gmail.com>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ This is the real deal: the program takes an instrumented binary and
+ attempts a variety of basic fuzzing tricks, paying close attention to
+ how they affect the execution path.
+
+ */
+
+#include "afl-fuzz.h"
+#include <limits.h>
+#if !defined NAME_MAX
+ #define NAME_MAX _XOPEN_NAME_MAX
+#endif
+
+/* Write bitmap to file. The bitmap is useful mostly for the secret
+ -B option, to focus a separate fuzzing session on a particular
+ interesting input without rediscovering all the others. */
+
+void write_bitmap(afl_state_t *afl) {
+
+ u8 fname[PATH_MAX];
+ s32 fd;
+
+ if (!afl->bitmap_changed) { return; }
+ afl->bitmap_changed = 0;
+
+ snprintf(fname, PATH_MAX, "%s/fuzz_bitmap", afl->out_dir);
+ fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
+
+ if (fd < 0) { PFATAL("Unable to open '%s'", fname); }
+
+ ck_write(fd, afl->virgin_bits, afl->fsrv.map_size, fname);
+
+ close(fd);
+
+}
+
+/* Count the number of bits set in the provided bitmap. Used for the status
+ screen several times every second, does not have to be fast. */
+
+u32 count_bits(afl_state_t *afl, u8 *mem) {
+
+ u32 *ptr = (u32 *)mem;
+ u32 i = ((afl->fsrv.real_map_size + 3) >> 2);
+ u32 ret = 0;
+
+ while (i--) {
+
+ u32 v = *(ptr++);
+
+ /* This gets called on the inverse, virgin bitmap; optimize for sparse
+ data. */
+
+ if (likely(v == 0xffffffff)) {
+
+ ret += 32;
+ continue;
+
+ }
+
+ v -= ((v >> 1) & 0x55555555);
+ v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
+ ret += (((v + (v >> 4)) & 0xF0F0F0F) * 0x01010101) >> 24;
+
+ }
+
+ return ret;
+
+}
+
+/* Count the number of bytes set in the bitmap. Called fairly sporadically,
+ mostly to update the status screen or calibrate and examine confirmed
+ new paths. */
+
+u32 count_bytes(afl_state_t *afl, u8 *mem) {
+
+ u32 *ptr = (u32 *)mem;
+ u32 i = ((afl->fsrv.real_map_size + 3) >> 2);
+ u32 ret = 0;
+
+ while (i--) {
+
+ u32 v = *(ptr++);
+
+ if (likely(!v)) { continue; }
+ if (v & 0x000000ffU) { ++ret; }
+ if (v & 0x0000ff00U) { ++ret; }
+ if (v & 0x00ff0000U) { ++ret; }
+ if (v & 0xff000000U) { ++ret; }
+
+ }
+
+ return ret;
+
+}
+
+/* Count the number of non-255 bytes set in the bitmap. Used strictly for the
+ status screen, several calls per second or so. */
+
+u32 count_non_255_bytes(afl_state_t *afl, u8 *mem) {
+
+ u32 *ptr = (u32 *)mem;
+ u32 i = ((afl->fsrv.real_map_size + 3) >> 2);
+ u32 ret = 0;
+
+ while (i--) {
+
+ u32 v = *(ptr++);
+
+ /* This is called on the virgin bitmap, so optimize for the most likely
+ case. */
+
+ if (likely(v == 0xffffffffU)) { continue; }
+ if ((v & 0x000000ffU) != 0x000000ffU) { ++ret; }
+ if ((v & 0x0000ff00U) != 0x0000ff00U) { ++ret; }
+ if ((v & 0x00ff0000U) != 0x00ff0000U) { ++ret; }
+ if ((v & 0xff000000U) != 0xff000000U) { ++ret; }
+
+ }
+
+ return ret;
+
+}
+
+/* Destructively simplify trace by eliminating hit count information
+ and replacing it with 0x80 or 0x01 depending on whether the tuple
+ is hit or not. Called on every new crash or timeout, should be
+ reasonably fast. */
+const u8 simplify_lookup[256] = {
+
+ [0] = 1, [1 ... 255] = 128
+
+};
+
+/* Destructively classify execution counts in a trace. This is used as a
+ preprocessing step for any newly acquired traces. Called on every exec,
+ must be fast. */
+
+const u8 count_class_lookup8[256] = {
+
+ [0] = 0,
+ [1] = 1,
+ [2] = 2,
+ [3] = 4,
+ [4 ... 7] = 8,
+ [8 ... 15] = 16,
+ [16 ... 31] = 32,
+ [32 ... 127] = 64,
+ [128 ... 255] = 128
+
+};
+
+u16 count_class_lookup16[65536];
+
+void init_count_class16(void) {
+
+ u32 b1, b2;
+
+ for (b1 = 0; b1 < 256; b1++) {
+
+ for (b2 = 0; b2 < 256; b2++) {
+
+ count_class_lookup16[(b1 << 8) + b2] =
+ (count_class_lookup8[b1] << 8) | count_class_lookup8[b2];
+
+ }
+
+ }
+
+}
+
+/* Import coverage processing routines. */
+
+#ifdef WORD_SIZE_64
+ #include "coverage-64.h"
+#else
+ #include "coverage-32.h"
+#endif
+
+/* Check if the current execution path brings anything new to the table.
+ Update virgin bits to reflect the finds. Returns 1 if the only change is
+ the hit-count for a particular tuple; 2 if there are new tuples seen.
+ Updates the map, so subsequent calls will always return 0.
+
+ 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. */
+
+inline u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) {
+
+#ifdef WORD_SIZE_64
+
+ u64 *current = (u64 *)afl->fsrv.trace_bits;
+ u64 *virgin = (u64 *)virgin_map;
+
+ u32 i = ((afl->fsrv.real_map_size + 7) >> 3);
+
+#else
+
+ u32 *current = (u32 *)afl->fsrv.trace_bits;
+ u32 *virgin = (u32 *)virgin_map;
+
+ u32 i = ((afl->fsrv.real_map_size + 3) >> 2);
+
+#endif /* ^WORD_SIZE_64 */
+
+ u8 ret = 0;
+ while (i--) {
+
+ if (unlikely(*current)) discover_word(&ret, current, virgin);
+
+ current++;
+ virgin++;
+
+ }
+
+ if (unlikely(ret) && likely(virgin_map == afl->virgin_bits))
+ afl->bitmap_changed = 1;
+
+ return ret;
+
+}
+
+/* A combination of classify_counts and has_new_bits. If 0 is returned, then the
+ * trace bits are kept as-is. Otherwise, the trace bits are overwritten with
+ * classified values.
+ *
+ * This accelerates the processing: in most cases, no interesting behavior
+ * happen, and the trace bits will be discarded soon. This function optimizes
+ * for such cases: one-pass scan on trace bits without modifying anything. Only
+ * on rare cases it fall backs to the slow path: classify_counts() first, then
+ * return has_new_bits(). */
+
+inline u8 has_new_bits_unclassified(afl_state_t *afl, u8 *virgin_map) {
+
+ /* Handle the hot path first: no new coverage */
+ u8 *end = afl->fsrv.trace_bits + afl->fsrv.map_size;
+
+#ifdef WORD_SIZE_64
+
+ if (!skim((u64 *)virgin_map, (u64 *)afl->fsrv.trace_bits, (u64 *)end))
+ return 0;
+
+#else
+
+ if (!skim((u32 *)virgin_map, (u32 *)afl->fsrv.trace_bits, (u32 *)end))
+ return 0;
+
+#endif /* ^WORD_SIZE_64 */
+ classify_counts(&afl->fsrv);
+ return has_new_bits(afl, virgin_map);
+
+}
+
+/* Compact trace bytes into a smaller bitmap. We effectively just drop the
+ count information here. This is called only sporadically, for some
+ new paths. */
+
+void minimize_bits(afl_state_t *afl, u8 *dst, u8 *src) {
+
+ u32 i = 0;
+
+ while (i < afl->fsrv.map_size) {
+
+ if (*(src++)) { dst[i >> 3] |= 1 << (i & 7); }
+ ++i;
+
+ }
+
+}
+
+#ifndef SIMPLE_FILES
+
+/* Construct a file name for a new test case, capturing the operation
+ that led to its discovery. Returns a ptr to afl->describe_op_buf_256. */
+
+u8 *describe_op(afl_state_t *afl, u8 new_bits, size_t max_description_len) {
+
+ u8 is_timeout = 0;
+
+ if (new_bits & 0xf0) {
+
+ new_bits -= 0x80;
+ is_timeout = 1;
+
+ }
+
+ size_t real_max_len =
+ MIN(max_description_len, sizeof(afl->describe_op_buf_256));
+ u8 *ret = afl->describe_op_buf_256;
+
+ if (unlikely(afl->syncing_party)) {
+
+ sprintf(ret, "sync:%s,src:%06u", afl->syncing_party, afl->syncing_case);
+
+ } else {
+
+ sprintf(ret, "src:%06u", afl->current_entry);
+
+ if (afl->splicing_with >= 0) {
+
+ sprintf(ret + strlen(ret), "+%06d", afl->splicing_with);
+
+ }
+
+ sprintf(ret + strlen(ret), ",time:%llu,execs:%llu",
+ get_cur_time() + afl->prev_run_time - afl->start_time,
+ afl->fsrv.total_execs);
+
+ if (afl->current_custom_fuzz &&
+ afl->current_custom_fuzz->afl_custom_describe) {
+
+ /* We are currently in a custom mutator that supports afl_custom_describe,
+ * use it! */
+
+ size_t len_current = strlen(ret);
+ ret[len_current++] = ',';
+ ret[len_current] = '\0';
+
+ ssize_t size_left = real_max_len - len_current - strlen(",+cov") - 2;
+ if (is_timeout) { size_left -= strlen(",+tout"); }
+ if (unlikely(size_left <= 0)) FATAL("filename got too long");
+
+ const char *custom_description =
+ afl->current_custom_fuzz->afl_custom_describe(
+ afl->current_custom_fuzz->data, size_left);
+ if (!custom_description || !custom_description[0]) {
+
+ DEBUGF("Error getting a description from afl_custom_describe");
+ /* Take the stage name as description fallback */
+ sprintf(ret + len_current, "op:%s", afl->stage_short);
+
+ } else {
+
+ /* We got a proper custom description, use it */
+ strncat(ret + len_current, custom_description, size_left);
+
+ }
+
+ } else {
+
+ /* Normal testcase descriptions start here */
+ sprintf(ret + strlen(ret), ",op:%s", afl->stage_short);
+
+ if (afl->stage_cur_byte >= 0) {
+
+ sprintf(ret + strlen(ret), ",pos:%d", afl->stage_cur_byte);
+
+ if (afl->stage_val_type != STAGE_VAL_NONE) {
+
+ sprintf(ret + strlen(ret), ",val:%s%+d",
+ (afl->stage_val_type == STAGE_VAL_BE) ? "be:" : "",
+ afl->stage_cur_val);
+
+ }
+
+ } else {
+
+ sprintf(ret + strlen(ret), ",rep:%d", afl->stage_cur_val);
+
+ }
+
+ }
+
+ }
+
+ if (is_timeout) { strcat(ret, ",+tout"); }
+
+ if (new_bits == 2) { strcat(ret, ",+cov"); }
+
+ if (unlikely(strlen(ret) >= max_description_len))
+ FATAL("describe string is too long");
+
+ return ret;
+
+}
+
+#endif /* !SIMPLE_FILES */
+
+/* Write a message accompanying the crash directory :-) */
+
+void write_crash_readme(afl_state_t *afl) {
+
+ u8 fn[PATH_MAX];
+ s32 fd;
+ FILE *f;
+
+ u8 val_buf[STRINGIFY_VAL_SIZE_MAX];
+
+ sprintf(fn, "%s/crashes/README.txt", afl->out_dir);
+
+ fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
+
+ /* Do not die on errors here - that would be impolite. */
+
+ if (unlikely(fd < 0)) { return; }
+
+ f = fdopen(fd, "w");
+
+ if (unlikely(!f)) {
+
+ close(fd);
+ return;
+
+ }
+
+ fprintf(
+ f,
+ "Command line used to find this crash:\n\n"
+
+ "%s\n\n"
+
+ "If you can't reproduce a bug outside of afl-fuzz, be sure to set the "
+ "same\n"
+ "memory limit. The limit used for this fuzzing session was %s.\n\n"
+
+ "Need a tool to minimize test cases before investigating the crashes or "
+ "sending\n"
+ "them to a vendor? Check out the afl-tmin that comes with the fuzzer!\n\n"
+
+ "Found any cool bugs in open-source tools using afl-fuzz? If yes, please "
+ "post\n"
+ "to https://github.com/AFLplusplus/AFLplusplus/issues/286 once the "
+ "issues\n"
+ " are fixed :)\n\n",
+
+ afl->orig_cmdline,
+ stringify_mem_size(val_buf, sizeof(val_buf),
+ afl->fsrv.mem_limit << 20)); /* ignore errors */
+
+ fclose(f);
+
+}
+
+/* Check if the result of an execve() during routine fuzzing is interesting,
+ 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) {
+
+ if (unlikely(len == 0)) { return 0; }
+
+ u8 fn[PATH_MAX];
+ u8 *queue_fn = "";
+ u8 new_bits = 0, keeping = 0, res, classified = 0, is_timeout = 0;
+ s32 fd;
+ u64 cksum = 0;
+
+ /* Update path frequency. */
+
+ /* Generating a hash on every input is super expensive. Bad idea and should
+ only be used for special schedules */
+ if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) {
+
+ cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
+
+ /* Saturated increment */
+ if (afl->n_fuzz[cksum % N_FUZZ_SIZE] < 0xFFFFFFFF)
+ afl->n_fuzz[cksum % N_FUZZ_SIZE]++;
+
+ }
+
+ if (likely(fault == afl->crash_mode)) {
+
+ /* Keep only if there are new bits in the map, add to queue for
+ future fuzzing, etc. */
+
+ new_bits = has_new_bits_unclassified(afl, afl->virgin_bits);
+
+ if (likely(!new_bits)) {
+
+ if (unlikely(afl->crash_mode)) { ++afl->total_crashes; }
+ return 0;
+
+ }
+
+ classified = new_bits;
+
+ save_to_queue:
+
+#ifndef SIMPLE_FILES
+
+ queue_fn =
+ alloc_printf("%s/queue/id:%06u,%s", afl->out_dir, afl->queued_items,
+ describe_op(afl, new_bits + is_timeout,
+ NAME_MAX - strlen("id:000000,")));
+
+#else
+
+ queue_fn =
+ alloc_printf("%s/queue/id_%06u", afl->out_dir, afl->queued_items);
+
+#endif /* ^!SIMPLE_FILES */
+ fd = open(queue_fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
+ if (unlikely(fd < 0)) { PFATAL("Unable to create '%s'", queue_fn); }
+ ck_write(fd, mem, len, queue_fn);
+ close(fd);
+ add_to_queue(afl, queue_fn, len, 0);
+
+#ifdef INTROSPECTION
+ if (afl->custom_mutators_count && afl->current_custom_fuzz) {
+
+ LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+ if (afl->current_custom_fuzz == el && el->afl_custom_introspection) {
+
+ const char *ptr = el->afl_custom_introspection(el->data);
+
+ if (ptr != NULL && *ptr != 0) {
+
+ fprintf(afl->introspection_file, "QUEUE CUSTOM %s = %s\n", ptr,
+ afl->queue_top->fname);
+
+ }
+
+ }
+
+ });
+
+ } else if (afl->mutation[0] != 0) {
+
+ fprintf(afl->introspection_file, "QUEUE %s = %s\n", afl->mutation,
+ afl->queue_top->fname);
+
+ }
+
+#endif
+
+ if (new_bits == 2) {
+
+ afl->queue_top->has_new_cov = 1;
+ ++afl->queued_with_cov;
+
+ }
+
+ /* AFLFast schedule? update the new queue entry */
+ if (cksum) {
+
+ afl->queue_top->n_fuzz_entry = cksum % N_FUZZ_SIZE;
+ afl->n_fuzz[afl->queue_top->n_fuzz_entry] = 1;
+
+ }
+
+ /* due to classify counts we have to recalculate the checksum */
+ afl->queue_top->exec_cksum =
+ hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
+
+ /* Try to calibrate inline; this also calls update_bitmap_score() when
+ successful. */
+
+ res = calibrate_case(afl, afl->queue_top, mem, afl->queue_cycle - 1, 0);
+
+ if (unlikely(res == FSRV_RUN_ERROR)) {
+
+ FATAL("Unable to execute target application");
+
+ }
+
+ if (likely(afl->q_testcase_max_cache_size)) {
+
+ queue_testcase_store_mem(afl, afl->queue_top, mem);
+
+ }
+
+ keeping = 1;
+
+ }
+
+ switch (fault) {
+
+ case FSRV_RUN_TMOUT:
+
+ /* Timeouts are not very interesting, but we're still obliged to keep
+ a handful of samples. We use the presence of new bits in the
+ hang-specific bitmap as a signal of uniqueness. In "non-instrumented"
+ mode, we just keep everything. */
+
+ ++afl->total_tmouts;
+
+ if (afl->saved_hangs >= KEEP_UNIQUE_HANG) { return keeping; }
+
+ if (likely(!afl->non_instrumented_mode)) {
+
+ if (!classified) {
+
+ classify_counts(&afl->fsrv);
+ classified = 1;
+
+ }
+
+ simplify_trace(afl, afl->fsrv.trace_bits);
+
+ if (!has_new_bits(afl, afl->virgin_tmout)) { return keeping; }
+
+ }
+
+ is_timeout = 0x80;
+#ifdef INTROSPECTION
+ if (afl->custom_mutators_count && afl->current_custom_fuzz) {
+
+ LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+ if (afl->current_custom_fuzz == el && el->afl_custom_introspection) {
+
+ const char *ptr = el->afl_custom_introspection(el->data);
+
+ if (ptr != NULL && *ptr != 0) {
+
+ fprintf(afl->introspection_file,
+ "UNIQUE_TIMEOUT CUSTOM %s = %s\n", ptr,
+ afl->queue_top->fname);
+
+ }
+
+ }
+
+ });
+
+ } else if (afl->mutation[0] != 0) {
+
+ fprintf(afl->introspection_file, "UNIQUE_TIMEOUT %s\n", afl->mutation);
+
+ }
+
+#endif
+
+ /* Before saving, we make sure that it's a genuine hang by re-running
+ the target with a more generous timeout (unless the default timeout
+ is already generous). */
+
+ if (afl->fsrv.exec_tmout < afl->hang_tmout) {
+
+ u8 new_fault;
+ len = write_to_testcase(afl, &mem, len, 0);
+ new_fault = fuzz_run_target(afl, &afl->fsrv, afl->hang_tmout);
+ classify_counts(&afl->fsrv);
+
+ /* A corner case that one user reported bumping into: increasing the
+ timeout actually uncovers a crash. Make sure we don't discard it if
+ so. */
+
+ if (!afl->stop_soon && new_fault == FSRV_RUN_CRASH) {
+
+ goto keep_as_crash;
+
+ }
+
+ if (afl->stop_soon || new_fault != FSRV_RUN_TMOUT) {
+
+ if (afl->afl_env.afl_keep_timeouts) {
+
+ ++afl->saved_tmouts;
+ goto save_to_queue;
+
+ } else {
+
+ return keeping;
+
+ }
+
+ }
+
+ }
+
+#ifndef SIMPLE_FILES
+
+ snprintf(fn, PATH_MAX, "%s/hangs/id:%06llu,%s", afl->out_dir,
+ afl->saved_hangs,
+ describe_op(afl, 0, NAME_MAX - strlen("id:000000,")));
+
+#else
+
+ snprintf(fn, PATH_MAX, "%s/hangs/id_%06llu", afl->out_dir,
+ afl->saved_hangs);
+
+#endif /* ^!SIMPLE_FILES */
+
+ ++afl->saved_hangs;
+
+ afl->last_hang_time = get_cur_time();
+
+ break;
+
+ case FSRV_RUN_CRASH:
+
+ keep_as_crash:
+
+ /* This is handled in a manner roughly similar to timeouts,
+ except for slightly different limits and no need to re-run test
+ cases. */
+
+ ++afl->total_crashes;
+
+ if (afl->saved_crashes >= KEEP_UNIQUE_CRASH) { return keeping; }
+
+ if (likely(!afl->non_instrumented_mode)) {
+
+ if (!classified) { classify_counts(&afl->fsrv); }
+
+ simplify_trace(afl, afl->fsrv.trace_bits);
+
+ if (!has_new_bits(afl, afl->virgin_crash)) { return keeping; }
+
+ }
+
+ if (unlikely(!afl->saved_crashes)) { write_crash_readme(afl); }
+
+#ifndef SIMPLE_FILES
+
+ snprintf(fn, PATH_MAX, "%s/crashes/id:%06llu,sig:%02u,%s", afl->out_dir,
+ afl->saved_crashes, afl->fsrv.last_kill_signal,
+ describe_op(afl, 0, NAME_MAX - strlen("id:000000,sig:00,")));
+
+#else
+
+ snprintf(fn, PATH_MAX, "%s/crashes/id_%06llu_%02u", afl->out_dir,
+ afl->saved_crashes, afl->fsrv.last_kill_signal);
+
+#endif /* ^!SIMPLE_FILES */
+
+ ++afl->saved_crashes;
+#ifdef INTROSPECTION
+ if (afl->custom_mutators_count && afl->current_custom_fuzz) {
+
+ LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+ if (afl->current_custom_fuzz == el && el->afl_custom_introspection) {
+
+ const char *ptr = el->afl_custom_introspection(el->data);
+
+ if (ptr != NULL && *ptr != 0) {
+
+ fprintf(afl->introspection_file, "UNIQUE_CRASH CUSTOM %s = %s\n",
+ ptr, afl->queue_top->fname);
+
+ }
+
+ }
+
+ });
+
+ } else if (afl->mutation[0] != 0) {
+
+ fprintf(afl->introspection_file, "UNIQUE_CRASH %s\n", afl->mutation);
+
+ }
+
+#endif
+ if (unlikely(afl->infoexec)) {
+
+ // if the user wants to be informed on new crashes - do that
+#if !TARGET_OS_IPHONE
+ // we dont care if system errors, but we dont want a
+ // compiler warning either
+ // See
+ // https://stackoverflow.com/questions/11888594/ignoring-return-values-in-c
+ (void)(system(afl->infoexec) + 1);
+#else
+ WARNF("command execution unsupported");
+#endif
+
+ }
+
+ afl->last_crash_time = get_cur_time();
+ afl->last_crash_execs = afl->fsrv.total_execs;
+
+ break;
+
+ case FSRV_RUN_ERROR:
+ FATAL("Unable to execute target application");
+
+ default:
+ return keeping;
+
+ }
+
+ /* If we're here, we apparently want to save the crash or hang
+ test case, too. */
+
+ fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
+ if (unlikely(fd < 0)) { PFATAL("Unable to create '%s'", fn); }
+ ck_write(fd, mem, len, fn);
+ close(fd);
+
+#ifdef __linux__
+ if (afl->fsrv.nyx_mode && fault == FSRV_RUN_CRASH) {
+
+ u8 fn_log[PATH_MAX];
+
+ (void)(snprintf(fn_log, PATH_MAX, "%s.log", fn) + 1);
+ fd = open(fn_log, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
+ if (unlikely(fd < 0)) { PFATAL("Unable to create '%s'", fn_log); }
+
+ u32 nyx_aux_string_len = afl->fsrv.nyx_handlers->nyx_get_aux_string(
+ afl->fsrv.nyx_runner, afl->fsrv.nyx_aux_string, 0x1000);
+
+ ck_write(fd, afl->fsrv.nyx_aux_string, nyx_aux_string_len, fn_log);
+ close(fd);
+
+ }
+
+#endif
+
+ return keeping;
+
+}
+
diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c
new file mode 100644
index 00000000..258d9ea7
--- /dev/null
+++ b/src/afl-fuzz-cmplog.c
@@ -0,0 +1,87 @@
+/*
+ american fuzzy lop++ - cmplog execution routines
+ ------------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Forkserver design by Jann Horn <jannhorn@googlemail.com>
+
+ Now maintained by by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Andrea Fioraldi <andreafioraldi@gmail.com>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ Shared code to handle the shared memory. This is used by the fuzzer
+ as well the other components like afl-tmin, afl-showmap, etc...
+
+ */
+
+#include <sys/select.h>
+
+#include "afl-fuzz.h"
+#include "cmplog.h"
+
+void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv) {
+
+ setenv("___AFL_EINS_ZWEI_POLIZEI___", "1", 1);
+
+ if (fsrv->qemu_mode) { setenv("AFL_DISABLE_LLVM_INSTRUMENTATION", "1", 0); }
+
+ if (!fsrv->qemu_mode && !fsrv->frida_mode && argv[0] != fsrv->cmplog_binary) {
+
+ argv[0] = fsrv->cmplog_binary;
+
+ }
+
+ execv(argv[0], argv);
+
+}
+
+u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
+
+ u8 fault;
+
+ write_to_testcase(afl, (void **)&out_buf, len, 0);
+
+ fault = fuzz_run_target(afl, &afl->cmplog_fsrv, afl->fsrv.exec_tmout);
+
+ if (afl->stop_soon) { return 1; }
+
+ if (fault == FSRV_RUN_TMOUT) {
+
+ if (afl->subseq_tmouts++ > TMOUT_LIMIT) {
+
+ ++afl->cur_skipped_items;
+ return 1;
+
+ }
+
+ } else {
+
+ afl->subseq_tmouts = 0;
+
+ }
+
+ /* Users can hit us with SIGUSR1 to request the current input
+ to be abandoned. */
+
+ if (afl->skip_requested) {
+
+ afl->skip_requested = 0;
+ ++afl->cur_skipped_items;
+ return 1;
+
+ }
+
+ return 0;
+
+}
+
diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c
new file mode 100644
index 00000000..535ffdc3
--- /dev/null
+++ b/src/afl-fuzz-extras.c
@@ -0,0 +1,828 @@
+/*
+ american fuzzy lop++ - extras relates routines
+ ----------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Andrea Fioraldi <andreafioraldi@gmail.com>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ This is the real deal: the program takes an instrumented binary and
+ attempts a variety of basic fuzzing tricks, paying close attention to
+ how they affect the execution path.
+
+ */
+
+#include "afl-fuzz.h"
+
+/* 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;
+
+}
+
+/* descending order */
+
+static int compare_auto_extras_use_d(const void *ae1, const void *ae2) {
+
+ return ((struct auto_extra_data *)ae2)->hit_cnt -
+ ((struct auto_extra_data *)ae1)->hit_cnt;
+
+}
+
+/* Helper function for load_extras. */
+
+static int compare_extras_len(const void *e1, const void *e2) {
+
+ return ((struct extra_data *)e1)->len - ((struct extra_data *)e2)->len;
+
+}
+
+/* Read extras from a file, sort by size. */
+
+void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len,
+ u32 dict_level) {
+
+ FILE *f;
+ u8 buf[MAX_LINE];
+ u8 * lptr;
+ u32 cur_line = 0;
+
+ u8 val_bufs[2][STRINGIFY_VAL_SIZE_MAX];
+
+ f = fopen(fname, "r");
+
+ if (!f) { PFATAL("Unable to open '%s'", fname); }
+
+ while ((lptr = fgets(buf, MAX_LINE, f))) {
+
+ u8 *rptr, *wptr;
+ u32 klen = 0;
+
+ ++cur_line;
+
+ /* Trim on left and right. */
+
+ while (isspace(*lptr)) {
+
+ ++lptr;
+
+ }
+
+ rptr = lptr + strlen(lptr) - 1;
+ while (rptr >= lptr && isspace(*rptr)) {
+
+ --rptr;
+
+ }
+
+ ++rptr;
+ *rptr = 0;
+
+ /* Skip empty lines and comments. */
+
+ if (!*lptr || *lptr == '#') { continue; }
+
+ /* All other lines must end with '"', which we can consume. */
+
+ --rptr;
+
+ if (rptr < lptr || *rptr != '"') {
+
+ WARNF("Malformed name=\"value\" pair in line %u.", cur_line);
+ continue;
+
+ }
+
+ *rptr = 0;
+
+ /* Skip alphanumerics and dashes (label). */
+
+ while (isalnum(*lptr) || *lptr == '_') {
+
+ ++lptr;
+
+ }
+
+ /* If @number follows, parse that. */
+
+ if (*lptr == '@') {
+
+ ++lptr;
+ if (atoi(lptr) > (s32)dict_level) { continue; }
+ while (isdigit(*lptr)) {
+
+ ++lptr;
+
+ }
+
+ }
+
+ /* Skip [number] */
+
+ if (*lptr == '[') {
+
+ do {
+
+ ++lptr;
+
+ } while (*lptr >= '0' && *lptr <= '9');
+
+ if (*lptr == ']') { ++lptr; }
+
+ }
+
+ /* Skip whitespace and = signs. */
+
+ while (isspace(*lptr) || *lptr == '=') {
+
+ ++lptr;
+
+ }
+
+ /* Consume opening '"'. */
+
+ if (*lptr != '"') {
+
+ WARNF("Malformed name=\"keyword\" pair in line %u.", cur_line);
+ continue;
+
+ }
+
+ ++lptr;
+
+ if (!*lptr) {
+
+ WARNF("Empty keyword in line %u.", cur_line);
+ continue;
+
+ }
+
+ /* Okay, let's allocate memory and copy data between "...", handling
+ \xNN escaping, \\, and \". */
+
+ afl->extras =
+ afl_realloc((void **)&afl->extras,
+ (afl->extras_cnt + 1) * sizeof(struct extra_data));
+ if (unlikely(!afl->extras)) { PFATAL("alloc"); }
+
+ wptr = afl->extras[afl->extras_cnt].data = ck_alloc(rptr - lptr);
+
+ if (!wptr) { PFATAL("no mem for data"); }
+
+ while (*lptr) {
+
+ char *hexdigits = "0123456789abcdef";
+
+ switch (*lptr) {
+
+ case 1 ... 31:
+ case 128 ... 255:
+ WARNF("Non-printable characters in line %u.", cur_line);
+ continue;
+ break;
+
+ case '\\':
+
+ ++lptr;
+
+ if (*lptr == '\\' || *lptr == '"') {
+
+ *(wptr++) = *(lptr++);
+ klen++;
+ break;
+
+ }
+
+ if (*lptr != 'x' || !isxdigit(lptr[1]) || !isxdigit(lptr[2])) {
+
+ WARNF("Invalid escaping (not \\xNN) in line %u.", cur_line);
+ continue;
+
+ }
+
+ *(wptr++) = ((strchr(hexdigits, tolower(lptr[1])) - hexdigits) << 4) |
+ (strchr(hexdigits, tolower(lptr[2])) - hexdigits);
+
+ lptr += 3;
+ ++klen;
+
+ break;
+
+ default:
+ *(wptr++) = *(lptr++);
+ ++klen;
+
+ }
+
+ }
+
+ afl->extras[afl->extras_cnt].len = klen;
+
+ if (afl->extras[afl->extras_cnt].len > MAX_DICT_FILE) {
+
+ WARNF(
+ "Keyword too big in line %u (%s, limit is %s)", cur_line,
+ stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), klen),
+ stringify_mem_size(val_bufs[1], sizeof(val_bufs[1]), MAX_DICT_FILE));
+ continue;
+
+ }
+
+ if (*min_len > klen) { *min_len = klen; }
+ if (*max_len < klen) { *max_len = klen; }
+
+ ++afl->extras_cnt;
+
+ }
+
+ fclose(f);
+
+}
+
+static void extras_check_and_sort(afl_state_t *afl, u32 min_len, u32 max_len,
+ u8 *dir) {
+
+ u8 val_bufs[2][STRINGIFY_VAL_SIZE_MAX];
+
+ if (!afl->extras_cnt) {
+
+ WARNF("No usable data in '%s'", dir);
+ return;
+
+ }
+
+ qsort(afl->extras, afl->extras_cnt, sizeof(struct extra_data),
+ compare_extras_len);
+
+ ACTF("Loaded %u extra tokens, size range %s to %s.", afl->extras_cnt,
+ stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), min_len),
+ stringify_mem_size(val_bufs[1], sizeof(val_bufs[1]), max_len));
+
+ if (max_len > 32) {
+
+ WARNF("Some tokens are relatively large (%s) - consider trimming.",
+ stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), max_len));
+
+ }
+
+ if (afl->extras_cnt > afl->max_det_extras) {
+
+ WARNF("More than %u tokens - will use them probabilistically.",
+ afl->max_det_extras);
+
+ }
+
+}
+
+/* Read extras from the extras directory and sort them by size. */
+
+void load_extras(afl_state_t *afl, u8 *dir) {
+
+ DIR * d;
+ struct dirent *de;
+ u32 min_len = MAX_DICT_FILE, max_len = 0, dict_level = 0;
+ u8 * x;
+
+ u8 val_bufs[2][STRINGIFY_VAL_SIZE_MAX];
+
+ /* If the name ends with @, extract level and continue. */
+
+ if ((x = strchr(dir, '@'))) {
+
+ *x = 0;
+ dict_level = atoi(x + 1);
+
+ }
+
+ ACTF("Loading extra dictionary from '%s' (level %u)...", dir, dict_level);
+
+ d = opendir(dir);
+
+ if (!d) {
+
+ if (errno == ENOTDIR) {
+
+ load_extras_file(afl, dir, &min_len, &max_len, dict_level);
+ extras_check_and_sort(afl, min_len, max_len, dir);
+ return;
+
+ }
+
+ PFATAL("Unable to open '%s'", dir);
+
+ }
+
+ if (x) { FATAL("Dictionary levels not supported for directories."); }
+
+ while ((de = readdir(d))) {
+
+ struct stat st;
+ u8 * fn = alloc_printf("%s/%s", dir, de->d_name);
+ s32 fd;
+
+ if (lstat(fn, &st) || access(fn, R_OK)) {
+
+ PFATAL("Unable to access '%s'", fn);
+
+ }
+
+ /* This also takes care of . and .. */
+ if (!S_ISREG(st.st_mode) || !st.st_size) {
+
+ ck_free(fn);
+ continue;
+
+ }
+
+ if (st.st_size > MAX_DICT_FILE) {
+
+ WARNF(
+ "Extra '%s' is too big (%s, limit is %s)", fn,
+ stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), st.st_size),
+ stringify_mem_size(val_bufs[1], sizeof(val_bufs[1]), MAX_DICT_FILE));
+ continue;
+
+ }
+
+ if (min_len > st.st_size) { min_len = st.st_size; }
+ if (max_len < st.st_size) { max_len = st.st_size; }
+
+ afl->extras =
+ afl_realloc((void **)&afl->extras,
+ (afl->extras_cnt + 1) * sizeof(struct extra_data));
+ if (unlikely(!afl->extras)) { PFATAL("alloc"); }
+
+ afl->extras[afl->extras_cnt].data = ck_alloc(st.st_size);
+ afl->extras[afl->extras_cnt].len = st.st_size;
+
+ fd = open(fn, O_RDONLY);
+
+ if (fd < 0) { PFATAL("Unable to open '%s'", fn); }
+
+ ck_read(fd, afl->extras[afl->extras_cnt].data, st.st_size, fn);
+
+ close(fd);
+ ck_free(fn);
+
+ ++afl->extras_cnt;
+
+ }
+
+ closedir(d);
+
+ extras_check_and_sort(afl, min_len, max_len, dir);
+
+}
+
+/* Helper function for maybe_add_auto(afl, ) */
+
+static inline u8 memcmp_nocase(u8 *m1, u8 *m2, u32 len) {
+
+ while (len--) {
+
+ if (tolower(*(m1++)) ^ tolower(*(m2++))) { return 1; }
+
+ }
+
+ return 0;
+
+}
+
+/* add an extra/dict/token - no checks performed, no sorting */
+
+static void add_extra_nocheck(afl_state_t *afl, u8 *mem, u32 len) {
+
+ afl->extras = afl_realloc((void **)&afl->extras,
+ (afl->extras_cnt + 1) * sizeof(struct extra_data));
+
+ if (unlikely(!afl->extras)) { PFATAL("alloc"); }
+
+ afl->extras[afl->extras_cnt].data = ck_alloc(len);
+ afl->extras[afl->extras_cnt].len = len;
+ memcpy(afl->extras[afl->extras_cnt].data, mem, len);
+ afl->extras_cnt++;
+
+ /* We only want to print this once */
+
+ if (afl->extras_cnt == afl->max_det_extras + 1) {
+
+ WARNF("More than %u tokens - will use them probabilistically.",
+ afl->max_det_extras);
+
+ }
+
+}
+
+/* Sometimes strings in input is transformed to unicode internally, so for
+ fuzzing we should attempt to de-unicode if it looks like simple unicode */
+
+void deunicode_extras(afl_state_t *afl) {
+
+ if (!afl->extras_cnt) return;
+
+ u32 i, j, orig_cnt = afl->extras_cnt;
+ u8 buf[64];
+
+ for (i = 0; i < orig_cnt; ++i) {
+
+ if (afl->extras[i].len < 6 || afl->extras[i].len > 64 ||
+ afl->extras[i].len % 2) {
+
+ continue;
+
+ }
+
+ u32 k = 0, z1 = 0, z2 = 0, z3 = 0, z4 = 0, half = afl->extras[i].len >> 1;
+ u32 quarter = half >> 1;
+
+ for (j = 0; j < afl->extras[i].len; ++j) {
+
+ switch (j % 4) {
+
+ case 2:
+ if (!afl->extras[i].data[j]) { ++z3; }
+ // fall through
+ case 0:
+ if (!afl->extras[i].data[j]) { ++z1; }
+ break;
+ case 3:
+ if (!afl->extras[i].data[j]) { ++z4; }
+ // fall through
+ case 1:
+ if (!afl->extras[i].data[j]) { ++z2; }
+ break;
+
+ }
+
+ }
+
+ if ((z1 < half && z2 < half) || z1 + z2 == afl->extras[i].len) { continue; }
+
+ // also maybe 32 bit unicode?
+ if (afl->extras[i].len % 4 == 0 && afl->extras[i].len >= 12 &&
+ (z3 == quarter || z4 == quarter) && z1 + z2 == quarter * 3) {
+
+ for (j = 0; j < afl->extras[i].len; ++j) {
+
+ if (z4 < quarter) {
+
+ if (j % 4 == 3) { buf[k++] = afl->extras[i].data[j]; }
+
+ } else if (z3 < quarter) {
+
+ if (j % 4 == 2) { buf[k++] = afl->extras[i].data[j]; }
+
+ } else if (z2 < half) {
+
+ if (j % 4 == 1) { buf[k++] = afl->extras[i].data[j]; }
+
+ } else {
+
+ if (j % 4 == 0) { buf[k++] = afl->extras[i].data[j]; }
+
+ }
+
+ }
+
+ add_extra_nocheck(afl, buf, k);
+ k = 0;
+
+ }
+
+ for (j = 0; j < afl->extras[i].len; ++j) {
+
+ if (z1 < half) {
+
+ if (j % 2 == 0) { buf[k++] = afl->extras[i].data[j]; }
+
+ } else {
+
+ if (j % 2 == 1) { buf[k++] = afl->extras[i].data[j]; }
+
+ }
+
+ }
+
+ add_extra_nocheck(afl, buf, k);
+
+ }
+
+ qsort(afl->extras, afl->extras_cnt, sizeof(struct extra_data),
+ compare_extras_len);
+
+}
+
+/* Removes duplicates from the loaded extras. This can happen if multiple files
+ are loaded */
+
+void dedup_extras(afl_state_t *afl) {
+
+ if (afl->extras_cnt < 2) return;
+
+ u32 i, j, orig_cnt = afl->extras_cnt;
+
+ for (i = 0; i < afl->extras_cnt - 1; ++i) {
+
+ for (j = i + 1; j < afl->extras_cnt; ++j) {
+
+ restart_dedup:
+
+ // if the goto was used we could be at the end of the list
+ if (j >= afl->extras_cnt || afl->extras[i].len != afl->extras[j].len)
+ break;
+
+ if (memcmp(afl->extras[i].data, afl->extras[j].data,
+ afl->extras[i].len) == 0) {
+
+ ck_free(afl->extras[j].data);
+ if (j + 1 < afl->extras_cnt) // not at the end of the list?
+ memmove((char *)&afl->extras[j], (char *)&afl->extras[j + 1],
+ (afl->extras_cnt - j - 1) * sizeof(struct extra_data));
+ --afl->extras_cnt;
+ goto restart_dedup; // restart if several duplicates are in a row
+
+ }
+
+ }
+
+ }
+
+ if (afl->extras_cnt != orig_cnt)
+ afl->extras = afl_realloc_exact(
+ (void **)&afl->extras, afl->extras_cnt * sizeof(struct extra_data));
+
+}
+
+/* Adds a new extra / dict entry. */
+void add_extra(afl_state_t *afl, u8 *mem, u32 len) {
+
+ u32 i, found = 0;
+
+ for (i = 0; i < afl->extras_cnt; i++) {
+
+ if (afl->extras[i].len == len) {
+
+ if (memcmp(afl->extras[i].data, mem, len) == 0) return;
+ found = 1;
+
+ } else {
+
+ if (found) break;
+
+ }
+
+ }
+
+ if (len > MAX_DICT_FILE) {
+
+ u8 val_bufs[2][STRINGIFY_VAL_SIZE_MAX];
+ WARNF("Extra '%.*s' is too big (%s, limit is %s), skipping file!", (int)len,
+ mem, stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), len),
+ stringify_mem_size(val_bufs[1], sizeof(val_bufs[1]), MAX_DICT_FILE));
+ return;
+
+ } else if (len > 32) {
+
+ WARNF("Extra '%.*s' is pretty large, consider trimming.", (int)len, mem);
+
+ }
+
+ add_extra_nocheck(afl, mem, len);
+
+ qsort(afl->extras, afl->extras_cnt, sizeof(struct extra_data),
+ compare_extras_len);
+
+}
+
+/* Maybe add automatic extra. */
+
+void maybe_add_auto(afl_state_t *afl, u8 *mem, u32 len) {
+
+ u32 i;
+
+ /* Allow users to specify that they don't want auto dictionaries. */
+
+ if (!MAX_AUTO_EXTRAS || !USE_AUTO_EXTRAS) { return; }
+
+ /* Skip runs of identical bytes. */
+
+ for (i = 1; i < len; ++i) {
+
+ if (mem[0] ^ mem[i]) { break; }
+
+ }
+
+ if (i == len || unlikely(len > MAX_AUTO_EXTRA)) { return; }
+
+ /* Reject builtin interesting values. */
+
+ if (len == 2) {
+
+ i = sizeof(interesting_16) >> 1;
+
+ while (i--) {
+
+ if (*((u16 *)mem) == interesting_16[i] ||
+ *((u16 *)mem) == SWAP16(interesting_16[i])) {
+
+ return;
+
+ }
+
+ }
+
+ }
+
+ if (len == 4) {
+
+ i = sizeof(interesting_32) >> 2;
+
+ while (i--) {
+
+ if (*((u32 *)mem) == (u32)interesting_32[i] ||
+ *((u32 *)mem) == SWAP32(interesting_32[i])) {
+
+ return;
+
+ }
+
+ }
+
+ }
+
+ /* Reject anything that matches existing extras. Do a case-insensitive
+ match. We optimize by exploiting the fact that extras[] are sorted
+ by size. */
+
+ for (i = 0; i < afl->extras_cnt; ++i) {
+
+ if (afl->extras[i].len >= len) { break; }
+
+ }
+
+ for (; i < afl->extras_cnt && afl->extras[i].len == len; ++i) {
+
+ if (!memcmp_nocase(afl->extras[i].data, mem, len)) { return; }
+
+ }
+
+ /* Last but not least, check afl->a_extras[] for matches. There are no
+ guarantees of a particular sort order. */
+
+ afl->auto_changed = 1;
+
+ for (i = 0; i < afl->a_extras_cnt; ++i) {
+
+ if (afl->a_extras[i].len == len &&
+ !memcmp_nocase(afl->a_extras[i].data, mem, len)) {
+
+ afl->a_extras[i].hit_cnt++;
+ goto sort_a_extras;
+
+ }
+
+ }
+
+ /* At this point, looks like we're dealing with a new entry. So, let's
+ append it if we have room. Otherwise, let's randomly evict some other
+ entry from the bottom half of the list. */
+
+ if (afl->a_extras_cnt < MAX_AUTO_EXTRAS) {
+
+ memcpy(afl->a_extras[afl->a_extras_cnt].data, mem, len);
+ afl->a_extras[afl->a_extras_cnt].len = len;
+ ++afl->a_extras_cnt;
+
+ } else {
+
+ i = MAX_AUTO_EXTRAS / 2 + rand_below(afl, (MAX_AUTO_EXTRAS + 1) / 2);
+
+ memcpy(afl->a_extras[i].data, mem, len);
+ afl->a_extras[i].len = len;
+ afl->a_extras[i].hit_cnt = 0;
+
+ }
+
+sort_a_extras:
+
+ /* First, sort all auto extras by use count, descending order. */
+
+ 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 auto_extra_data), compare_auto_extras_len);
+
+}
+
+/* Save automatically generated extras. */
+
+void save_auto(afl_state_t *afl) {
+
+ u32 i;
+
+ if (!afl->auto_changed) { return; }
+ afl->auto_changed = 0;
+
+ for (i = 0; i < MIN((u32)USE_AUTO_EXTRAS, afl->a_extras_cnt); ++i) {
+
+ u8 *fn =
+ alloc_printf("%s/queue/.state/auto_extras/auto_%06u", afl->out_dir, i);
+ s32 fd;
+
+ fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
+
+ if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
+
+ ck_write(fd, afl->a_extras[i].data, afl->a_extras[i].len, fn);
+
+ close(fd);
+ ck_free(fn);
+
+ }
+
+}
+
+/* Load automatically generated extras. */
+
+void load_auto(afl_state_t *afl) {
+
+ u32 i;
+
+ for (i = 0; i < USE_AUTO_EXTRAS; ++i) {
+
+ u8 tmp[MAX_AUTO_EXTRA + 1];
+ u8 *fn = alloc_printf("%s/.state/auto_extras/auto_%06u", afl->in_dir, i);
+ s32 fd, len;
+
+ fd = open(fn, O_RDONLY);
+
+ if (fd < 0) {
+
+ if (errno != ENOENT) { PFATAL("Unable to open '%s'", fn); }
+ ck_free(fn);
+ break;
+
+ }
+
+ /* We read one byte more to cheaply detect tokens that are too
+ long (and skip them). */
+
+ len = read(fd, tmp, MAX_AUTO_EXTRA + 1);
+
+ if (len < 0) { PFATAL("Unable to read from '%s'", fn); }
+
+ if (len >= MIN_AUTO_EXTRA && len <= MAX_AUTO_EXTRA) {
+
+ maybe_add_auto(afl, tmp, len);
+
+ }
+
+ close(fd);
+ ck_free(fn);
+
+ }
+
+ if (i) {
+
+ OKF("Loaded %u auto-discovered dictionary tokens.", i);
+
+ } else {
+
+ ACTF("No auto-generated dictionary tokens to reuse.");
+
+ }
+
+}
+
+/* Destroy extras. */
+
+void destroy_extras(afl_state_t *afl) {
+
+ u32 i;
+
+ for (i = 0; i < afl->extras_cnt; ++i) {
+
+ ck_free(afl->extras[i].data);
+
+ }
+
+ afl_free(afl->extras);
+
+}
+
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c
new file mode 100644
index 00000000..6a653a00
--- /dev/null
+++ b/src/afl-fuzz-init.c
@@ -0,0 +1,2960 @@
+/*
+ american fuzzy lop++ - initialization related routines
+ ------------------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Andrea Fioraldi <andreafioraldi@gmail.com>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ This is the real deal: the program takes an instrumented binary and
+ attempts a variety of basic fuzzing tricks, paying close attention to
+ how they affect the execution path.
+
+ */
+
+#include "afl-fuzz.h"
+#include <limits.h>
+#include "cmplog.h"
+
+#ifdef HAVE_AFFINITY
+
+/* bind process to a specific cpu. Returns 0 on failure. */
+
+static u8 bind_cpu(afl_state_t *afl, s32 cpuid) {
+
+ #if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)
+ cpu_set_t c;
+ #elif defined(__NetBSD__)
+ cpuset_t *c;
+ #elif defined(__sun)
+ psetid_t c;
+ #endif
+
+ afl->cpu_aff = cpuid;
+
+ #if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)
+
+ CPU_ZERO(&c);
+ CPU_SET(cpuid, &c);
+
+ #elif defined(__NetBSD__)
+
+ c = cpuset_create();
+ if (c == NULL) { PFATAL("cpuset_create failed"); }
+ cpuset_set(cpuid, c);
+
+ #elif defined(__sun)
+
+ pset_create(&c);
+ if (pset_assign(c, cpuid, NULL)) { PFATAL("pset_assign failed"); }
+
+ #endif
+
+ #if defined(__linux__)
+
+ return (sched_setaffinity(0, sizeof(c), &c) == 0);
+
+ #elif defined(__FreeBSD__) || defined(__DragonFly__)
+
+ return (pthread_setaffinity_np(pthread_self(), sizeof(c), &c) == 0);
+
+ #elif defined(__NetBSD__)
+
+ if (pthread_setaffinity_np(pthread_self(), cpuset_size(c), c)) {
+
+ cpuset_destroy(c);
+ return 0;
+
+ }
+
+ cpuset_destroy(c);
+ return 1;
+
+ #elif defined(__sun)
+
+ if (pset_bind(c, P_PID, getpid(), NULL)) {
+
+ pset_destroy(c);
+ return 0;
+
+ }
+
+ pset_destroy(c);
+ return 1;
+
+ #else
+
+ // this will need something for other platforms
+ // TODO: Solaris/Illumos has processor_bind ... might worth a try
+ WARNF("Cannot bind to CPU yet on this platform.");
+ return 1;
+
+ #endif
+
+}
+
+/* Build a list of processes bound to specific cores. Returns -1 if nothing
+ can be found. Assumes an upper bound of 4k CPUs. */
+
+void bind_to_free_cpu(afl_state_t *afl) {
+
+ u8 cpu_used[4096] = {0};
+ u8 lockfile[PATH_MAX] = "";
+ s32 i;
+
+ if (afl->afl_env.afl_no_affinity && !afl->afl_env.afl_try_affinity) {
+
+ if (afl->cpu_to_bind != -1) {
+
+ FATAL("-b and AFL_NO_AFFINITY are mututally exclusive.");
+
+ }
+
+ WARNF("Not binding to a CPU core (AFL_NO_AFFINITY set).");
+ return;
+
+ }
+
+ if (afl->cpu_to_bind != -1) {
+
+ if (!bind_cpu(afl, afl->cpu_to_bind)) {
+
+ if (afl->afl_env.afl_try_affinity) {
+
+ WARNF(
+ "Could not bind to requested CPU %d! Make sure you passed a valid "
+ "-b.",
+ afl->cpu_to_bind);
+
+ } else {
+
+ FATAL(
+ "Could not bind to requested CPU %d! Make sure you passed a valid "
+ "-b.",
+ afl->cpu_to_bind);
+
+ }
+
+ }
+
+ return;
+
+ }
+
+ if (afl->cpu_core_count < 2) { return; }
+
+ if (afl->sync_id) {
+
+ s32 lockfd, first = 1;
+
+ snprintf(lockfile, sizeof(lockfile), "%s/.affinity_lock", afl->sync_dir);
+ setenv(CPU_AFFINITY_ENV_VAR, lockfile, 1);
+
+ do {
+
+ if ((lockfd = open(lockfile, O_RDWR | O_CREAT | O_EXCL,
+ DEFAULT_PERMISSION)) < 0) {
+
+ if (first) {
+
+ WARNF("CPU affinity lock file present, waiting ...");
+ first = 0;
+
+ }
+
+ usleep(1000);
+
+ }
+
+ } while (lockfd < 0);
+
+ close(lockfd);
+
+ }
+
+ #if defined(__linux__)
+
+ DIR * d;
+ struct dirent *de;
+ d = opendir("/proc");
+
+ if (!d) {
+
+ if (lockfile[0]) unlink(lockfile);
+ WARNF("Unable to access /proc - can't scan for free CPU cores.");
+ return;
+
+ }
+
+ ACTF("Checking CPU core loadout...");
+
+ /* Scan all /proc/<pid>/status entries, checking for Cpus_allowed_list.
+ Flag all processes bound to a specific CPU using cpu_used[]. This will
+ fail for some exotic binding setups, but is likely good enough in almost
+ all real-world use cases. */
+
+ while ((de = readdir(d))) {
+
+ u8 fn[PATH_MAX];
+ FILE *f;
+ u8 tmp[MAX_LINE];
+ u8 has_vmsize = 0;
+
+ if (!isdigit(de->d_name[0])) { continue; }
+
+ snprintf(fn, PATH_MAX, "/proc/%s/status", de->d_name);
+
+ if (!(f = fopen(fn, "r"))) { continue; }
+
+ while (fgets(tmp, MAX_LINE, f)) {
+
+ u32 hval;
+
+ /* Processes without VmSize are probably kernel tasks. */
+
+ if (!strncmp(tmp, "VmSize:\t", 8)) { has_vmsize = 1; }
+
+ if (!strncmp(tmp, "Cpus_allowed_list:\t", 19) && !strchr(tmp, '-') &&
+ !strchr(tmp, ',') && sscanf(tmp + 19, "%u", &hval) == 1 &&
+ hval < sizeof(cpu_used) && has_vmsize) {
+
+ cpu_used[hval] = 1;
+ break;
+
+ }
+
+ }
+
+ fclose(f);
+
+ }
+
+ closedir(d);
+
+ #elif defined(__FreeBSD__) || defined(__DragonFly__)
+
+ struct kinfo_proc *procs;
+ size_t nprocs;
+ size_t proccount;
+ int s_name[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL};
+ size_t s_name_l = sizeof(s_name) / sizeof(s_name[0]);
+
+ if (sysctl(s_name, s_name_l, NULL, &nprocs, NULL, 0) != 0) {
+
+ if (lockfile[0]) unlink(lockfile);
+ return;
+
+ }
+
+ proccount = nprocs / sizeof(*procs);
+ nprocs = nprocs * 4 / 3;
+
+ procs = ck_alloc(nprocs);
+ if (sysctl(s_name, s_name_l, procs, &nprocs, NULL, 0) != 0) {
+
+ if (lockfile[0]) unlink(lockfile);
+ ck_free(procs);
+ return;
+
+ }
+
+ for (i = 0; i < (s32)proccount; i++) {
+
+ #if defined(__FreeBSD__)
+
+ if (!strcmp(procs[i].ki_comm, "idle")) continue;
+
+ // fix when ki_oncpu = -1
+ s32 oncpu;
+ oncpu = procs[i].ki_oncpu;
+ if (oncpu == -1) oncpu = procs[i].ki_lastcpu;
+
+ if (oncpu != -1 && oncpu < (s32)sizeof(cpu_used) && procs[i].ki_pctcpu > 60)
+ cpu_used[oncpu] = 1;
+
+ #elif defined(__DragonFly__)
+
+ if (procs[i].kp_lwp.kl_cpuid < (s32)sizeof(cpu_used) &&
+ procs[i].kp_lwp.kl_pctcpu > 10)
+ cpu_used[procs[i].kp_lwp.kl_cpuid] = 1;
+
+ #endif
+
+ }
+
+ ck_free(procs);
+
+ #elif defined(__NetBSD__)
+
+ struct kinfo_proc2 *procs;
+ size_t nprocs;
+ size_t proccount;
+ int s_name[] = {
+
+ CTL_KERN, KERN_PROC2, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2), 0};
+ size_t s_name_l = sizeof(s_name) / sizeof(s_name[0]);
+
+ if (sysctl(s_name, s_name_l, NULL, &nprocs, NULL, 0) != 0) {
+
+ if (lockfile[0]) unlink(lockfile);
+ return;
+
+ }
+
+ proccount = nprocs / sizeof(struct kinfo_proc2);
+ procs = ck_alloc(nprocs * sizeof(struct kinfo_proc2));
+ s_name[5] = proccount;
+
+ if (sysctl(s_name, s_name_l, procs, &nprocs, NULL, 0) != 0) {
+
+ if (lockfile[0]) unlink(lockfile);
+ ck_free(procs);
+ return;
+
+ }
+
+ for (i = 0; i < (s32)proccount; i++) {
+
+ if (procs[i].p_cpuid < sizeof(cpu_used) && procs[i].p_pctcpu > 0)
+ cpu_used[procs[i].p_cpuid] = 1;
+
+ }
+
+ ck_free(procs);
+
+ #elif defined(__sun)
+
+ kstat_named_t *n;
+ kstat_ctl_t * m;
+ kstat_t * k;
+ cpu_stat_t cs;
+ u32 ncpus;
+
+ m = kstat_open();
+
+ if (!m) FATAL("kstat_open failed");
+
+ k = kstat_lookup(m, "unix", 0, "system_misc");
+
+ if (!k) {
+
+ if (lockfile[0]) unlink(lockfile);
+ kstat_close(m);
+ return;
+
+ }
+
+ if (kstat_read(m, k, NULL)) {
+
+ if (lockfile[0]) unlink(lockfile);
+ kstat_close(m);
+ return;
+
+ }
+
+ n = kstat_data_lookup(k, "ncpus");
+ ncpus = n->value.i32;
+
+ if (ncpus > sizeof(cpu_used)) ncpus = sizeof(cpu_used);
+
+ for (i = 0; i < (s32)ncpus; i++) {
+
+ k = kstat_lookup(m, "cpu_stat", i, NULL);
+ if (kstat_read(m, k, &cs)) {
+
+ if (lockfile[0]) unlink(lockfile);
+ kstat_close(m);
+ return;
+
+ }
+
+ if (cs.cpu_sysinfo.cpu[CPU_IDLE] > 0) continue;
+
+ if (cs.cpu_sysinfo.cpu[CPU_USER] > 0 || cs.cpu_sysinfo.cpu[CPU_KERNEL] > 0)
+ cpu_used[i] = 1;
+
+ }
+
+ kstat_close(m);
+
+ #else
+ #warning \
+ "For this platform we do not have free CPU binding code yet. If possible, please supply a PR to https://github.com/AFLplusplus/AFLplusplus"
+ #endif
+
+ #if !defined(__aarch64__) && !defined(__arm__) && !defined(__arm64__)
+
+ for (i = 0; i < afl->cpu_core_count; i++) {
+
+ #else
+
+ /* many ARM devices have performance and efficiency cores, the slower
+ efficiency cores seem to always come first */
+
+ for (i = afl->cpu_core_count - 1; i > -1; i--) {
+
+ #endif
+
+ if (cpu_used[i]) { continue; }
+
+ OKF("Found a free CPU core, try binding to #%u.", i);
+
+ if (bind_cpu(afl, i)) {
+
+ #ifdef __linux__
+ if (afl->fsrv.nyx_mode) { afl->fsrv.nyx_bind_cpu_id = i; }
+ #endif
+ /* Success :) */
+ break;
+
+ }
+
+ WARNF("setaffinity failed to CPU %d, trying next CPU", i);
+
+ }
+
+ if (lockfile[0]) unlink(lockfile);
+
+ if (i == afl->cpu_core_count || i == -1) {
+
+ SAYF("\n" cLRD "[-] " cRST
+ "Uh-oh, looks like all %d CPU cores on your system are allocated to\n"
+ " other instances of afl-fuzz (or similar CPU-locked tasks). "
+ "Starting\n"
+ " another fuzzer on this machine is probably a bad plan.\n"
+ "%s",
+ afl->cpu_core_count,
+ afl->afl_env.afl_try_affinity ? ""
+ : " If you are sure, you can set "
+ "AFL_NO_AFFINITY and try again.\n");
+
+ if (!afl->afl_env.afl_try_affinity) { FATAL("No more free CPU cores"); }
+
+ }
+
+}
+
+#endif /* HAVE_AFFINITY */
+
+/* Shuffle an array of pointers. Might be slightly biased. */
+
+static void shuffle_ptrs(afl_state_t *afl, void **ptrs, u32 cnt) {
+
+ u32 i;
+
+ for (i = 0; i < cnt - 2; ++i) {
+
+ u32 j = i + rand_below(afl, cnt - i);
+ void *s = ptrs[i];
+ ptrs[i] = ptrs[j];
+ ptrs[j] = s;
+
+ }
+
+}
+
+/* Read all testcases from foreign input directories, then queue them for
+ testing. Called at startup and at sync intervals.
+ Does not descend into subdirectories! */
+
+void read_foreign_testcases(afl_state_t *afl, int first) {
+
+ if (!afl->foreign_sync_cnt) return;
+
+ struct dirent **nl;
+ s32 nl_cnt;
+ u32 i, iter;
+
+ u8 val_buf[2][STRINGIFY_VAL_SIZE_MAX];
+ u8 foreign_name[16];
+
+ for (iter = 0; iter < afl->foreign_sync_cnt; iter++) {
+
+ if (afl->foreign_syncs[iter].dir && afl->foreign_syncs[iter].dir[0]) {
+
+ if (first) ACTF("Scanning '%s'...", afl->foreign_syncs[iter].dir);
+ time_t mtime_max = 0;
+
+ u8 *name = strrchr(afl->foreign_syncs[iter].dir, '/');
+ if (!name) {
+
+ name = afl->foreign_syncs[iter].dir;
+
+ } else {
+
+ ++name;
+
+ }
+
+ if (!strcmp(name, "queue") || !strcmp(name, "out") ||
+ !strcmp(name, "default")) {
+
+ snprintf(foreign_name, sizeof(foreign_name), "foreign_%u", iter);
+
+ } else {
+
+ snprintf(foreign_name, sizeof(foreign_name), "%s_%u", name, iter);
+
+ }
+
+ /* We do not use sorting yet and do a more expensive mtime check instead.
+ a mtimesort() implementation would be better though. */
+
+ nl_cnt = scandir(afl->foreign_syncs[iter].dir, &nl, NULL, NULL);
+
+ if (nl_cnt < 0) {
+
+ if (first) {
+
+ WARNF("Unable to open directory '%s'", afl->foreign_syncs[iter].dir);
+ sleep(1);
+
+ }
+
+ continue;
+
+ }
+
+ if (nl_cnt == 0) {
+
+ if (first) {
+
+ WARNF("directory %s is currently empty",
+ afl->foreign_syncs[iter].dir);
+
+ }
+
+ continue;
+
+ }
+
+ /* Show stats */
+
+ snprintf(afl->stage_name_buf, STAGE_BUF_SIZE, "foreign sync %u", iter);
+
+ afl->stage_name = afl->stage_name_buf;
+ afl->stage_cur = 0;
+ afl->stage_max = 0;
+
+ for (i = 0; i < (u32)nl_cnt; ++i) {
+
+ struct stat st;
+
+ u8 *fn2 =
+ alloc_printf("%s/%s", afl->foreign_syncs[iter].dir, nl[i]->d_name);
+
+ free(nl[i]); /* not tracked */
+
+ if (unlikely(lstat(fn2, &st) || access(fn2, R_OK))) {
+
+ if (first) PFATAL("Unable to access '%s'", fn2);
+ continue;
+
+ }
+
+ /* we detect new files by their mtime */
+ if (likely(st.st_mtime <= afl->foreign_syncs[iter].mtime)) {
+
+ ck_free(fn2);
+ continue;
+
+ }
+
+ /* This also takes care of . and .. */
+
+ if (!S_ISREG(st.st_mode) || !st.st_size || strstr(fn2, "/README.txt")) {
+
+ ck_free(fn2);
+ continue;
+
+ }
+
+ if (st.st_size > MAX_FILE) {
+
+ if (first) {
+
+ WARNF(
+ "Test case '%s' is too big (%s, limit is %s), skipping", fn2,
+ stringify_mem_size(val_buf[0], sizeof(val_buf[0]), st.st_size),
+ stringify_mem_size(val_buf[1], sizeof(val_buf[1]), MAX_FILE));
+
+ }
+
+ ck_free(fn2);
+ continue;
+
+ }
+
+ // lets do not use add_to_queue(afl, fn2, st.st_size, 0);
+ // as this could add duplicates of the startup input corpus
+
+ int fd = open(fn2, O_RDONLY);
+ if (fd < 0) {
+
+ ck_free(fn2);
+ continue;
+
+ }
+
+ u8 fault;
+ u8 *mem = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+
+ if (mem == MAP_FAILED) {
+
+ ck_free(fn2);
+ continue;
+
+ }
+
+ u32 len = write_to_testcase(afl, (void **)&mem, st.st_size, 1);
+ fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
+ afl->syncing_party = foreign_name;
+ afl->queued_imported += save_if_interesting(afl, mem, len, fault);
+ afl->syncing_party = 0;
+ munmap(mem, st.st_size);
+ close(fd);
+
+ if (st.st_mtime > mtime_max) mtime_max = st.st_mtime;
+
+ }
+
+ afl->foreign_syncs[iter].mtime = mtime_max;
+ free(nl); /* not tracked */
+
+ }
+
+ }
+
+ if (first) {
+
+ afl->last_find_time = 0;
+ afl->queued_at_start = afl->queued_items;
+
+ }
+
+}
+
+/* Read all testcases from the input directory, then queue them for testing.
+ Called at startup. */
+
+void read_testcases(afl_state_t *afl, u8 *directory) {
+
+ struct dirent **nl;
+ s32 nl_cnt, subdirs = 1;
+ u32 i;
+ u8 * fn1, *dir = directory;
+ u8 val_buf[2][STRINGIFY_VAL_SIZE_MAX];
+
+ /* Auto-detect non-in-place resumption attempts. */
+
+ if (dir == NULL) {
+
+ fn1 = alloc_printf("%s/queue", afl->in_dir);
+ if (!access(fn1, F_OK)) {
+
+ afl->in_dir = fn1;
+ subdirs = 0;
+
+ } else {
+
+ ck_free(fn1);
+
+ }
+
+ dir = afl->in_dir;
+
+ }
+
+ ACTF("Scanning '%s'...", dir);
+
+ /* We use scandir() + alphasort() rather than readdir() because otherwise,
+ the ordering of test cases would vary somewhat randomly and would be
+ difficult to control. */
+
+ nl_cnt = scandir(dir, &nl, NULL, alphasort);
+
+ if (nl_cnt < 0 && directory == NULL) {
+
+ if (errno == ENOENT || errno == ENOTDIR) {
+
+ SAYF("\n" cLRD "[-] " cRST
+ "The input directory does not seem to be valid - try again. The "
+ "fuzzer needs\n"
+ " one or more test case to start with - ideally, a small file "
+ "under 1 kB\n"
+ " or so. The cases must be stored as regular files directly in "
+ "the input\n"
+ " directory.\n");
+
+ }
+
+ PFATAL("Unable to open '%s'", dir);
+
+ }
+
+ if (unlikely(afl->old_seed_selection && afl->shuffle_queue && nl_cnt > 1)) {
+
+ ACTF("Shuffling queue...");
+ shuffle_ptrs(afl, (void **)nl, nl_cnt);
+
+ }
+
+ if (nl_cnt) {
+
+ i = nl_cnt;
+ do {
+
+ --i;
+
+ struct stat st;
+ u8 dfn[PATH_MAX];
+ snprintf(dfn, PATH_MAX, "%s/.state/deterministic_done/%s", afl->in_dir,
+ nl[i]->d_name);
+ u8 *fn2 = alloc_printf("%s/%s", dir, nl[i]->d_name);
+
+ u8 passed_det = 0;
+
+ if (lstat(fn2, &st) || access(fn2, R_OK)) {
+
+ PFATAL("Unable to access '%s'", fn2);
+
+ }
+
+ /* obviously we want to skip "descending" into . and .. directories,
+ however it is a good idea to skip also directories that start with
+ a dot */
+ if (subdirs && S_ISDIR(st.st_mode) && nl[i]->d_name[0] != '.') {
+
+ free(nl[i]); /* not tracked */
+ read_testcases(afl, fn2);
+ ck_free(fn2);
+ continue;
+
+ }
+
+ free(nl[i]);
+
+ if (!S_ISREG(st.st_mode) || !st.st_size || strstr(fn2, "/README.txt")) {
+
+ ck_free(fn2);
+ continue;
+
+ }
+
+ if (st.st_size > MAX_FILE) {
+
+ WARNF("Test case '%s' is too big (%s, limit is %s), partial reading",
+ fn2,
+ stringify_mem_size(val_buf[0], sizeof(val_buf[0]), st.st_size),
+ stringify_mem_size(val_buf[1], sizeof(val_buf[1]), MAX_FILE));
+
+ }
+
+ /* Check for metadata that indicates that deterministic fuzzing
+ is complete for this entry. We don't want to repeat deterministic
+ fuzzing when resuming aborted scans, because it would be pointless
+ and probably very time-consuming. */
+
+ if (!access(dfn, F_OK)) { passed_det = 1; }
+
+ add_to_queue(afl, fn2, st.st_size >= MAX_FILE ? MAX_FILE : st.st_size,
+ passed_det);
+
+ if (unlikely(afl->shm.cmplog_mode)) {
+
+ if (afl->cmplog_lvl == 1) {
+
+ if (!afl->cmplog_max_filesize ||
+ afl->cmplog_max_filesize < st.st_size) {
+
+ afl->cmplog_max_filesize = st.st_size;
+
+ }
+
+ } else if (afl->cmplog_lvl == 2) {
+
+ if (!afl->cmplog_max_filesize ||
+ afl->cmplog_max_filesize > st.st_size) {
+
+ afl->cmplog_max_filesize = st.st_size;
+
+ }
+
+ }
+
+ }
+
+ /*
+ if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) {
+
+ u64 cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size,
+ HASH_CONST); afl->queue_top->n_fuzz_entry = cksum % N_FUZZ_SIZE;
+ afl->n_fuzz[afl->queue_top->n_fuzz_entry] = 1;
+
+ }
+
+ */
+
+ } while (i > 0);
+
+ }
+
+ free(nl); /* not tracked */
+
+ if (!afl->queued_items && directory == NULL) {
+
+ SAYF("\n" cLRD "[-] " cRST
+ "Looks like there are no valid test cases in the input directory! The "
+ "fuzzer\n"
+ " needs one or more test case to start with - ideally, a small "
+ "file under\n"
+ " 1 kB or so. The cases must be stored as regular files directly "
+ "in the\n"
+ " input directory.\n");
+
+ FATAL("No usable test cases in '%s'", afl->in_dir);
+
+ }
+
+ if (unlikely(afl->shm.cmplog_mode)) {
+
+ if (afl->cmplog_max_filesize < 1024) {
+
+ afl->cmplog_max_filesize = 1024;
+
+ } else {
+
+ afl->cmplog_max_filesize = (((afl->cmplog_max_filesize >> 10) + 1) << 10);
+
+ }
+
+ }
+
+ afl->last_find_time = 0;
+ afl->queued_at_start = afl->queued_items;
+
+}
+
+/* Perform dry run of all test cases to confirm that the app is working as
+ expected. This is done only for the initial inputs, and only once. */
+
+void perform_dry_run(afl_state_t *afl) {
+
+ struct queue_entry *q;
+ u32 cal_failures = 0, idx;
+ u8 * use_mem;
+
+ for (idx = 0; idx < afl->queued_items; idx++) {
+
+ q = afl->queue_buf[idx];
+ if (unlikely(!q || q->disabled)) { continue; }
+
+ u8 res;
+ s32 fd;
+
+ if (unlikely(!q->len)) {
+
+ WARNF("Skipping 0-sized entry in queue (%s)", q->fname);
+ continue;
+
+ }
+
+ if (afl->afl_env.afl_cmplog_only_new) { q->colorized = CMPLOG_LVL_MAX; }
+
+ u8 *fn = strrchr(q->fname, '/') + 1;
+
+ ACTF("Attempting dry run with '%s'...", fn);
+
+ fd = open(q->fname, O_RDONLY);
+ if (fd < 0) { PFATAL("Unable to open '%s'", q->fname); }
+
+ u32 read_len = MIN(q->len, (u32)MAX_FILE);
+ use_mem = afl_realloc(AFL_BUF_PARAM(in), read_len);
+ ck_read(fd, use_mem, read_len, q->fname);
+
+ close(fd);
+
+ res = calibrate_case(afl, q, use_mem, 0, 1);
+
+ if (afl->stop_soon) { return; }
+
+ if (res == afl->crash_mode || res == FSRV_RUN_NOBITS) {
+
+ SAYF(cGRA " len = %u, map size = %u, exec speed = %llu us\n" cRST,
+ q->len, q->bitmap_size, q->exec_us);
+
+ }
+
+ switch (res) {
+
+ case FSRV_RUN_OK:
+
+ if (afl->crash_mode) { FATAL("Test case '%s' does *NOT* crash", fn); }
+
+ break;
+
+ case FSRV_RUN_TMOUT:
+
+ if (afl->timeout_given && !afl->afl_env.afl_exit_on_seed_issues) {
+
+ /* if we have a timeout but a timeout value was given then always
+ skip. The '+' meaning has been changed! */
+ WARNF("Test case results in a timeout (skipping)");
+ ++cal_failures;
+ q->cal_failed = CAL_CHANCES;
+ q->disabled = 1;
+ q->perf_score = 0;
+
+ if (!q->was_fuzzed) {
+
+ q->was_fuzzed = 1;
+ --afl->pending_not_fuzzed;
+ --afl->active_items;
+
+ }
+
+ break;
+
+ } else {
+
+ SAYF("\n" cLRD "[-] " cRST
+ "The program took more than %u ms to process one of the initial "
+ "test cases.\n"
+ " This is bad news; raising the limit with the -t option is "
+ "possible, but\n"
+ " will probably make the fuzzing process extremely slow.\n\n"
+
+ " If this test case is just a fluke, the other option is to "
+ "just avoid it\n"
+ " altogether, and find one that is less of a CPU hog.\n",
+ afl->fsrv.exec_tmout);
+
+ FATAL("Test case '%s' results in a timeout", fn);
+
+ }
+
+ case FSRV_RUN_CRASH:
+
+ if (afl->crash_mode) { break; }
+
+ if (afl->fsrv.mem_limit) {
+
+ u8 val_buf[STRINGIFY_VAL_SIZE_MAX];
+
+ SAYF("\n" cLRD "[-] " cRST
+ "Oops, the program crashed with one of the test cases provided. "
+ "There are\n"
+ " several possible explanations:\n\n"
+
+ " - The test case causes known crashes under normal working "
+ "conditions. If\n"
+ " so, please remove it. The fuzzer should be seeded with "
+ "interesting\n"
+ " inputs - but not ones that cause an outright crash.\n\n"
+
+ " - The current memory limit (%s) is too low for this "
+ "program, causing\n"
+ " it to die due to OOM when parsing valid files. To fix "
+ "this, try\n"
+ " bumping it up with the -m setting in the command line. "
+ "If in doubt,\n"
+ " try something along the lines of:\n\n"
+
+ MSG_ULIMIT_USAGE
+ " /path/to/binary [...] <testcase )\n\n"
+
+ " Tip: you can use https://jwilk.net/software/recidivm to\n"
+ " estimate the required amount of virtual memory for the "
+ "binary. Also,\n"
+ " if you are using ASAN, set '-m 0'.\n\n"
+
+ " - In QEMU persistent mode the selected address(es) for the "
+ "loop are not\n"
+ " properly cleaning up variables and memory. Try adding\n"
+ " AFL_QEMU_PERSISTENT_GPR=1 or select better addresses in "
+ "the binary.\n\n"
+
+ MSG_FORK_ON_APPLE
+
+ " - Least likely, there is a horrible bug in the fuzzer. If "
+ "other options\n"
+ " fail, poke <afl-users@googlegroups.com> for "
+ "troubleshooting tips.\n",
+ stringify_mem_size(val_buf, sizeof(val_buf),
+ afl->fsrv.mem_limit << 20),
+ afl->fsrv.mem_limit - 1);
+
+ } else {
+
+ SAYF("\n" cLRD "[-] " cRST
+ "Oops, the program crashed with one of the test cases provided. "
+ "There are\n"
+ " several possible explanations:\n\n"
+
+ " - The test case causes known crashes under normal working "
+ "conditions. If\n"
+ " so, please remove it. The fuzzer should be seeded with "
+ "interesting\n"
+ " inputs - but not ones that cause an outright crash.\n\n"
+
+ " - In QEMU persistent mode the selected address(es) for the "
+ "loop are not\n"
+ " properly cleaning up variables and memory. Try adding\n"
+ " AFL_QEMU_PERSISTENT_GPR=1 or select better addresses in "
+ "the binary.\n\n"
+
+ MSG_FORK_ON_APPLE
+
+ " - Least likely, there is a horrible bug in the fuzzer. If "
+ "other options\n"
+ " fail, poke <afl-users@googlegroups.com> for "
+ "troubleshooting tips.\n");
+
+ }
+
+#undef MSG_ULIMIT_USAGE
+#undef MSG_FORK_ON_APPLE
+
+ if (afl->fsrv.uses_crash_exitcode) {
+
+ WARNF(
+ "Test case '%s' results in a crash or AFL_CRASH_EXITCODE %d, "
+ "skipping",
+ fn, (int)(s8)afl->fsrv.crash_exitcode);
+
+ } else {
+
+ WARNF("Test case '%s' results in a crash, skipping", fn);
+
+ }
+
+ if (afl->afl_env.afl_exit_on_seed_issues) {
+
+ FATAL("As AFL_EXIT_ON_SEED_ISSUES is set, afl-fuzz exits.");
+
+ }
+
+ /* Remove from fuzzing queue but keep for splicing */
+
+ if (!q->was_fuzzed) {
+
+ q->was_fuzzed = 1;
+ --afl->pending_not_fuzzed;
+ --afl->active_items;
+
+ }
+
+ q->disabled = 1;
+ q->perf_score = 0;
+
+ u32 i = 0;
+ while (unlikely(i < afl->queued_items && afl->queue_buf[i] &&
+ afl->queue_buf[i]->disabled)) {
+
+ ++i;
+
+ }
+
+ if (i < afl->queued_items && afl->queue_buf[i]) {
+
+ afl->queue = afl->queue_buf[i];
+
+ } else {
+
+ afl->queue = afl->queue_buf[0];
+
+ }
+
+ afl->max_depth = 0;
+ for (i = 0; i < afl->queued_items && likely(afl->queue_buf[i]); i++) {
+
+ if (!afl->queue_buf[i]->disabled &&
+ afl->queue_buf[i]->depth > afl->max_depth)
+ afl->max_depth = afl->queue_buf[i]->depth;
+
+ }
+
+ break;
+
+ case FSRV_RUN_ERROR:
+
+ FATAL("Unable to execute target application ('%s')", afl->argv[0]);
+
+ case FSRV_RUN_NOINST:
+#ifdef __linux__
+ if (afl->fsrv.nyx_mode && afl->fsrv.nyx_runner != NULL) {
+
+ afl->fsrv.nyx_handlers->nyx_shutdown(afl->fsrv.nyx_runner);
+
+ }
+
+#endif
+ FATAL("No instrumentation detected");
+
+ case FSRV_RUN_NOBITS:
+
+ ++afl->useless_at_start;
+
+ if (!afl->in_bitmap && !afl->shuffle_queue) {
+
+ WARNF("No new instrumentation output, test case may be useless.");
+
+ }
+
+ break;
+
+ }
+
+ if (q->var_behavior) {
+
+ WARNF("Instrumentation output varies across runs.");
+
+ }
+
+ }
+
+ if (cal_failures) {
+
+ if (cal_failures == afl->queued_items) {
+
+ FATAL("All test cases time out or crash, giving up!");
+
+ }
+
+ WARNF("Skipped %u test cases (%0.02f%%) due to timeouts or crashes.",
+ cal_failures, ((double)cal_failures) * 100 / afl->queued_items);
+
+ if (cal_failures * 5 > afl->queued_items) {
+
+ WARNF(cLRD "High percentage of rejected test cases, check settings!");
+
+ }
+
+ }
+
+ /* Now we remove all entries from the queue that have a duplicate trace map */
+
+ u32 duplicates = 0, i;
+
+ for (idx = 0; idx < afl->queued_items; idx++) {
+
+ q = afl->queue_buf[idx];
+ if (!q || q->disabled || q->cal_failed || !q->exec_cksum) { continue; }
+
+ u32 done = 0;
+ for (i = idx + 1;
+ i < afl->queued_items && !done && likely(afl->queue_buf[i]); i++) {
+
+ struct queue_entry *p = afl->queue_buf[i];
+ if (p->disabled || p->cal_failed || !p->exec_cksum) { continue; }
+
+ if (p->exec_cksum == q->exec_cksum) {
+
+ duplicates = 1;
+
+ // we keep the shorter file
+ if (p->len >= q->len) {
+
+ if (!p->was_fuzzed) {
+
+ p->was_fuzzed = 1;
+ --afl->pending_not_fuzzed;
+ --afl->active_items;
+
+ }
+
+ p->disabled = 1;
+ p->perf_score = 0;
+
+ } else {
+
+ if (!q->was_fuzzed) {
+
+ q->was_fuzzed = 1;
+ --afl->pending_not_fuzzed;
+ --afl->active_items;
+
+ }
+
+ q->disabled = 1;
+ q->perf_score = 0;
+
+ done = 1;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ if (duplicates) {
+
+ afl->max_depth = 0;
+
+ for (idx = 0; idx < afl->queued_items; idx++) {
+
+ if (afl->queue_buf[idx] && !afl->queue_buf[idx]->disabled &&
+ afl->queue_buf[idx]->depth > afl->max_depth)
+ afl->max_depth = afl->queue_buf[idx]->depth;
+
+ }
+
+ afl->queue_top = afl->queue;
+
+ }
+
+ OKF("All test cases processed.");
+
+}
+
+/* Helper function: link() if possible, copy otherwise. */
+
+static void link_or_copy(u8 *old_path, u8 *new_path) {
+
+ s32 i = link(old_path, new_path);
+ s32 sfd, dfd;
+ u8 *tmp;
+
+ if (!i) { return; }
+
+ sfd = open(old_path, O_RDONLY);
+ if (sfd < 0) { PFATAL("Unable to open '%s'", old_path); }
+
+ dfd = open(new_path, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
+ if (dfd < 0) { PFATAL("Unable to create '%s'", new_path); }
+
+ tmp = ck_alloc(64 * 1024);
+
+ while ((i = read(sfd, tmp, 64 * 1024)) > 0) {
+
+ ck_write(dfd, tmp, i, new_path);
+
+ }
+
+ if (i < 0) { PFATAL("read() failed"); }
+
+ ck_free(tmp);
+ close(sfd);
+ close(dfd);
+
+}
+
+/* Create hard links for input test cases in the output directory, choosing
+ good names and pivoting accordingly. */
+
+void pivot_inputs(afl_state_t *afl) {
+
+ struct queue_entry *q;
+ u32 id = 0, i;
+
+ ACTF("Creating hard links for all input files...");
+
+ for (i = 0; i < afl->queued_items && likely(afl->queue_buf[i]); i++) {
+
+ q = afl->queue_buf[i];
+
+ if (unlikely(q->disabled)) { continue; }
+
+ u8 *nfn, *rsl = strrchr(q->fname, '/');
+ u32 orig_id;
+
+ if (!rsl) {
+
+ rsl = q->fname;
+
+ } else {
+
+ ++rsl;
+
+ }
+
+ /* If the original file name conforms to the syntax and the recorded
+ ID matches the one we'd assign, just use the original file name.
+ This is valuable for resuming fuzzing runs. */
+
+ if (!strncmp(rsl, CASE_PREFIX, 3) &&
+ sscanf(rsl + 3, "%06u", &orig_id) == 1 && orig_id == id) {
+
+ u8 *src_str;
+ u32 src_id;
+
+ afl->resuming_fuzz = 1;
+ nfn = alloc_printf("%s/queue/%s", afl->out_dir, rsl);
+
+ /* Since we're at it, let's also get the parent and figure out the
+ appropriate depth for this entry. */
+
+ src_str = strchr(rsl + 3, ':');
+
+ if (src_str && sscanf(src_str + 1, "%06u", &src_id) == 1) {
+
+ if (src_id < afl->queued_items) {
+
+ struct queue_entry *s = afl->queue_buf[src_id];
+
+ if (s) { q->depth = s->depth + 1; }
+
+ }
+
+ if (afl->max_depth < q->depth) { afl->max_depth = q->depth; }
+
+ }
+
+ } else {
+
+ /* No dice - invent a new name, capturing the original one as a
+ substring. */
+
+#ifndef SIMPLE_FILES
+
+ u8 *use_name = strstr(rsl, ",orig:");
+
+ if (use_name) {
+
+ use_name += 6;
+
+ } else {
+
+ use_name = rsl;
+
+ }
+
+ nfn = alloc_printf("%s/queue/id:%06u,time:0,execs:%llu,orig:%s",
+ afl->out_dir, id, afl->fsrv.total_execs, use_name);
+
+#else
+
+ nfn = alloc_printf("%s/queue/id_%06u", afl->out_dir, id);
+
+#endif /* ^!SIMPLE_FILES */
+
+ }
+
+ /* Pivot to the new queue entry. */
+
+ link_or_copy(q->fname, nfn);
+ ck_free(q->fname);
+ q->fname = nfn;
+
+ /* Make sure that the passed_det value carries over, too. */
+
+ if (q->passed_det) { mark_as_det_done(afl, q); }
+
+ if (afl->custom_mutators_count) {
+
+ run_afl_custom_queue_new_entry(afl, q, q->fname, NULL);
+
+ }
+
+ ++id;
+
+ }
+
+ if (afl->in_place_resume) { nuke_resume_dir(afl); }
+
+}
+
+/* When resuming, try to find the queue position to start from. This makes sense
+ only when resuming, and when we can find the original fuzzer_stats. */
+
+u32 find_start_position(afl_state_t *afl) {
+
+ u8 tmp[4096] = {0}; /* Ought to be enough for anybody. */
+
+ u8 *fn, *off;
+ s32 fd, i;
+ u32 ret;
+
+ if (!afl->resuming_fuzz) { return 0; }
+
+ if (afl->in_place_resume) {
+
+ fn = alloc_printf("%s/fuzzer_stats", afl->out_dir);
+
+ } else {
+
+ fn = alloc_printf("%s/../fuzzer_stats", afl->in_dir);
+
+ }
+
+ fd = open(fn, O_RDONLY);
+ ck_free(fn);
+
+ if (fd < 0) { return 0; }
+
+ i = read(fd, tmp, sizeof(tmp) - 1);
+ (void)i; /* Ignore errors */
+ close(fd);
+
+ off = strstr(tmp, "cur_item : ");
+ if (!off) { return 0; }
+
+ ret = atoi(off + 20);
+ if (ret >= afl->queued_items) { ret = 0; }
+ return ret;
+
+}
+
+/* The same, but for timeouts. The idea is that when resuming sessions without
+ -t given, we don't want to keep auto-scaling the timeout over and over
+ again to prevent it from growing due to random flukes. */
+
+void find_timeout(afl_state_t *afl) {
+
+ u8 tmp[4096] = {0}; /* Ought to be enough for anybody. */
+
+ u8 *fn, *off;
+ s32 fd, i;
+ u32 ret;
+
+ if (!afl->resuming_fuzz) { return; }
+
+ if (afl->in_place_resume) {
+
+ fn = alloc_printf("%s/fuzzer_stats", afl->out_dir);
+
+ } else {
+
+ fn = alloc_printf("%s/../fuzzer_stats", afl->in_dir);
+
+ }
+
+ fd = open(fn, O_RDONLY);
+ ck_free(fn);
+
+ if (fd < 0) { return; }
+
+ i = read(fd, tmp, sizeof(tmp) - 1);
+ (void)i; /* Ignore errors */
+ close(fd);
+
+ off = strstr(tmp, "exec_timeout : ");
+ if (!off) { return; }
+
+ ret = atoi(off + 20);
+ if (ret <= 4) { return; }
+
+ afl->fsrv.exec_tmout = ret;
+ afl->timeout_given = 3;
+
+}
+
+/* A helper function for handle_existing_out_dir(), deleting all prefixed
+ files in a directory. */
+
+static u8 delete_files(u8 *path, u8 *prefix) {
+
+ DIR * d;
+ struct dirent *d_ent;
+
+ d = opendir(path);
+
+ if (!d) { return 0; }
+
+ while ((d_ent = readdir(d))) {
+
+ if (d_ent->d_name[0] != '.' &&
+ (!prefix || !strncmp(d_ent->d_name, prefix, strlen(prefix)))) {
+
+ u8 *fname = alloc_printf("%s/%s", path, d_ent->d_name);
+ if (unlink(fname)) { PFATAL("Unable to delete '%s'", fname); }
+ ck_free(fname);
+
+ }
+
+ }
+
+ closedir(d);
+
+ return !!rmdir(path);
+
+}
+
+/* Get the number of runnable processes, with some simple smoothing. */
+
+double get_runnable_processes(void) {
+
+ double res = 0;
+
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
+ defined(__NetBSD__) || defined(__DragonFly__)
+
+ /* I don't see any portable sysctl or so that would quickly give us the
+ number of runnable processes; the 1-minute load average can be a
+ semi-decent approximation, though. */
+
+ if (getloadavg(&res, 1) != 1) return 0;
+
+#else
+
+ /* On Linux, /proc/stat is probably the best way; load averages are
+ computed in funny ways and sometimes don't reflect extremely short-lived
+ processes well. */
+
+ FILE *f = fopen("/proc/stat", "r");
+ u8 tmp[1024];
+ u32 val = 0;
+
+ if (!f) { return 0; }
+
+ while (fgets(tmp, sizeof(tmp), f)) {
+
+ if (!strncmp(tmp, "procs_running ", 14) ||
+ !strncmp(tmp, "procs_blocked ", 14)) {
+
+ val += atoi(tmp + 14);
+
+ }
+
+ }
+
+ fclose(f);
+
+ if (!res) {
+
+ res = val;
+
+ } else {
+
+ res = res * (1.0 - 1.0 / AVG_SMOOTHING) +
+ ((double)val) * (1.0 / AVG_SMOOTHING);
+
+ }
+
+#endif /* ^(__APPLE__ || __FreeBSD__ || __OpenBSD__ || __NetBSD__) */
+
+ return res;
+
+}
+
+/* Delete the temporary directory used for in-place session resume. */
+
+void nuke_resume_dir(afl_state_t *afl) {
+
+ u8 *fn;
+
+ fn = alloc_printf("%s/_resume/.state/deterministic_done", afl->out_dir);
+ if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
+ ck_free(fn);
+
+ fn = alloc_printf("%s/_resume/.state/auto_extras", afl->out_dir);
+ if (delete_files(fn, "auto_")) { goto dir_cleanup_failed; }
+ ck_free(fn);
+
+ fn = alloc_printf("%s/_resume/.state/redundant_edges", afl->out_dir);
+ if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
+ ck_free(fn);
+
+ fn = alloc_printf("%s/_resume/.state/variable_behavior", afl->out_dir);
+ if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
+ ck_free(fn);
+
+ fn = alloc_printf("%s/_resume/.state", afl->out_dir);
+ if (rmdir(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
+ ck_free(fn);
+
+ fn = alloc_printf("%s/_resume", afl->out_dir);
+ if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
+ ck_free(fn);
+
+ return;
+
+dir_cleanup_failed:
+
+ FATAL("_resume directory cleanup failed");
+
+}
+
+/* Delete fuzzer output directory if we recognize it as ours, if the fuzzer
+ is not currently running, and if the last run time isn't too great.
+ Resume fuzzing if `-` is set as in_dir or if AFL_AUTORESUME is set */
+
+static void handle_existing_out_dir(afl_state_t *afl) {
+
+ FILE *f;
+ u8 * fn = alloc_printf("%s/fuzzer_stats", afl->out_dir);
+
+ /* See if the output directory is locked. If yes, bail out. If not,
+ create a lock that will persist for the lifetime of the process
+ (this requires leaving the descriptor open).*/
+
+ afl->fsrv.out_dir_fd = open(afl->out_dir, O_RDONLY);
+ if (afl->fsrv.out_dir_fd < 0) { PFATAL("Unable to open '%s'", afl->out_dir); }
+
+#ifndef __sun
+
+ if (flock(afl->fsrv.out_dir_fd, LOCK_EX | LOCK_NB) && errno == EWOULDBLOCK) {
+
+ SAYF("\n" cLRD "[-] " cRST
+ "Looks like the job output directory is being actively used by "
+ "another\n"
+ " instance of afl-fuzz. You will need to choose a different %s\n"
+ " or stop the other process first.\n",
+ afl->sync_id ? "fuzzer ID" : "output location");
+
+ FATAL("Directory '%s' is in use", afl->out_dir);
+
+ }
+
+#endif /* !__sun */
+
+ f = fopen(fn, "r");
+
+ if (f) {
+
+ u64 start_time2, last_update;
+
+ if (fscanf(f,
+ "start_time : %llu\n"
+ "last_update : %llu\n",
+ &start_time2, &last_update) != 2) {
+
+ FATAL("Malformed data in '%s'", fn);
+
+ }
+
+ fclose(f);
+
+ /* Autoresume treats a normal run as in_place_resume if a valid out dir
+ * already exists */
+
+ if (!afl->in_place_resume && afl->autoresume) {
+
+ OKF("Detected prior run with AFL_AUTORESUME set. Resuming.");
+ afl->in_place_resume = 1;
+
+ }
+
+ /* Let's see how much work is at stake. */
+
+ if (!afl->in_place_resume && last_update > start_time2 &&
+ last_update - start_time2 > OUTPUT_GRACE * 60) {
+
+ SAYF("\n" cLRD "[-] " cRST
+ "The job output directory already exists and contains the results "
+ "of more\n"
+ " than %d minutes worth of fuzzing. To avoid data loss, afl-fuzz "
+ "will *NOT*\n"
+ " automatically delete this data for you.\n\n"
+
+ " If you wish to start a new session, remove or rename the "
+ "directory manually,\n"
+ " or specify a different output location for this job. To resume "
+ "the old\n"
+ " session, pass '-' as input directory in the command line ('-i "
+ "-')\n"
+ " or set the 'AFL_AUTORESUME=1' env variable and try again.\n",
+ OUTPUT_GRACE);
+
+ FATAL("At-risk data found in '%s'", afl->out_dir);
+
+ }
+
+ }
+
+ ck_free(fn);
+
+ /* The idea for in-place resume is pretty simple: we temporarily move the old
+ queue/ to a new location that gets deleted once import to the new queue/
+ is finished. If _resume/ already exists, the current queue/ may be
+ incomplete due to an earlier abort, so we want to use the old _resume/
+ dir instead, and we let rename() fail silently. */
+
+ if (afl->in_place_resume) {
+
+ u8 *orig_q = alloc_printf("%s/queue", afl->out_dir);
+
+ afl->in_dir = alloc_printf("%s/_resume", afl->out_dir);
+
+ rename(orig_q, afl->in_dir); /* Ignore errors */
+
+ OKF("Output directory exists, will attempt session resume.");
+
+ ck_free(orig_q);
+
+ } else {
+
+ OKF("Output directory exists but deemed OK to reuse.");
+
+ }
+
+ ACTF("Deleting old session data...");
+
+ /* Okay, let's get the ball rolling! First, we need to get rid of the entries
+ in <afl->out_dir>/.synced/.../id:*, if any are present. */
+
+ if (!afl->in_place_resume) {
+
+ fn = alloc_printf("%s/.synced", afl->out_dir);
+ if (delete_files(fn, NULL)) { goto dir_cleanup_failed; }
+ ck_free(fn);
+
+ }
+
+ /* Next, we need to clean up <afl->out_dir>/queue/.state/ subdirectories: */
+
+ fn = alloc_printf("%s/queue/.state/deterministic_done", afl->out_dir);
+ if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
+ ck_free(fn);
+
+ fn = alloc_printf("%s/queue/.state/auto_extras", afl->out_dir);
+ if (delete_files(fn, "auto_")) { goto dir_cleanup_failed; }
+ ck_free(fn);
+
+ fn = alloc_printf("%s/queue/.state/redundant_edges", afl->out_dir);
+ if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
+ ck_free(fn);
+
+ fn = alloc_printf("%s/queue/.state/variable_behavior", afl->out_dir);
+ if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
+ ck_free(fn);
+
+ /* Then, get rid of the .state subdirectory itself (should be empty by now)
+ and everything matching <afl->out_dir>/queue/id:*. */
+
+ fn = alloc_printf("%s/queue/.state", afl->out_dir);
+ if (rmdir(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
+ ck_free(fn);
+
+ fn = alloc_printf("%s/queue", afl->out_dir);
+ if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
+ ck_free(fn);
+
+ /* All right, let's do <afl->out_dir>/crashes/id:* and
+ * <afl->out_dir>/hangs/id:*. */
+
+ if (!afl->in_place_resume) {
+
+ fn = alloc_printf("%s/crashes/README.txt", afl->out_dir);
+ unlink(fn); /* Ignore errors */
+ ck_free(fn);
+
+ }
+
+ fn = alloc_printf("%s/crashes", afl->out_dir);
+
+ /* Make backup of the crashes directory if it's not empty and if we're
+ doing in-place resume. */
+
+ if (afl->in_place_resume && rmdir(fn)) {
+
+ time_t cur_t = time(0);
+ struct tm t;
+ localtime_r(&cur_t, &t);
+
+#ifndef SIMPLE_FILES
+
+ u8 *nfn =
+ alloc_printf("%s.%04d-%02d-%02d-%02d:%02d:%02d", fn, t.tm_year + 1900,
+ t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
+
+#else
+
+ u8 *nfn =
+ alloc_printf("%s_%04d%02d%02d%02d%02d%02d", fn, t.tm_year + 1900,
+ t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
+
+#endif /* ^!SIMPLE_FILES */
+
+ rename(fn, nfn); /* Ignore errors. */
+ ck_free(nfn);
+
+ }
+
+ if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
+ ck_free(fn);
+
+ fn = alloc_printf("%s/hangs", afl->out_dir);
+
+ /* Backup hangs, too. */
+
+ if (afl->in_place_resume && rmdir(fn)) {
+
+ time_t cur_t = time(0);
+ struct tm t;
+ localtime_r(&cur_t, &t);
+
+#ifndef SIMPLE_FILES
+
+ u8 *nfn =
+ alloc_printf("%s.%04d-%02d-%02d-%02d:%02d:%02d", fn, t.tm_year + 1900,
+ t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
+
+#else
+
+ u8 *nfn =
+ alloc_printf("%s_%04d%02d%02d%02d%02d%02d", fn, t.tm_year + 1900,
+ t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
+
+#endif /* ^!SIMPLE_FILES */
+
+ rename(fn, nfn); /* Ignore errors. */
+ ck_free(nfn);
+
+ }
+
+ if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
+ ck_free(fn);
+
+ /* And now, for some finishing touches. */
+
+ if (afl->file_extension) {
+
+ fn = alloc_printf("%s/.cur_input.%s", afl->tmp_dir, afl->file_extension);
+
+ } else {
+
+ fn = alloc_printf("%s/.cur_input", afl->tmp_dir);
+
+ }
+
+ if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
+ ck_free(fn);
+
+ fn = alloc_printf("%s/fuzz_bitmap", afl->out_dir);
+ if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
+ ck_free(fn);
+
+ if (!afl->in_place_resume) {
+
+ fn = alloc_printf("%s/fuzzer_stats", afl->out_dir);
+ if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
+ ck_free(fn);
+
+ }
+
+ if (!afl->in_place_resume) {
+
+ fn = alloc_printf("%s/plot_data", afl->out_dir);
+ if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
+ ck_free(fn);
+
+ }
+
+ fn = alloc_printf("%s/cmdline", afl->out_dir);
+ if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
+ ck_free(fn);
+
+ OKF("Output dir cleanup successful.");
+
+ /* Wow... is that all? If yes, celebrate! */
+
+ return;
+
+dir_cleanup_failed:
+
+ SAYF("\n" cLRD "[-] " cRST
+ "Whoops, the fuzzer tried to reuse your output directory, but bumped "
+ "into\n"
+ " some files that shouldn't be there or that couldn't be removed - "
+ "so it\n"
+ " decided to abort! This happened while processing this path:\n\n"
+
+ " %s\n\n"
+ " Please examine and manually delete the files, or specify a "
+ "different\n"
+ " output location for the tool.\n",
+ fn);
+
+ FATAL("Output directory cleanup failed");
+
+}
+
+/* If this is a -S secondary node, ensure a -M main node is running,
+ if a main node is running when another main is started, then warn */
+
+int check_main_node_exists(afl_state_t *afl) {
+
+ DIR * sd;
+ struct dirent *sd_ent;
+ u8 * fn;
+
+ sd = opendir(afl->sync_dir);
+ if (!sd) { return 0; }
+
+ while ((sd_ent = readdir(sd))) {
+
+ /* Skip dot files and our own output directory. */
+
+ if (sd_ent->d_name[0] == '.' || !strcmp(afl->sync_id, sd_ent->d_name)) {
+
+ continue;
+
+ }
+
+ fn = alloc_printf("%s/%s/is_main_node", afl->sync_dir, sd_ent->d_name);
+ int res = access(fn, F_OK);
+ free(fn);
+ if (res == 0) return 1;
+
+ }
+
+ return 0;
+
+}
+
+/* Prepare output directories and fds. */
+
+void setup_dirs_fds(afl_state_t *afl) {
+
+ u8 *tmp;
+
+ ACTF("Setting up output directories...");
+
+ if (afl->sync_id && mkdir(afl->sync_dir, 0700) && errno != EEXIST) {
+
+ PFATAL("Unable to create '%s'", afl->sync_dir);
+
+ }
+
+ if (mkdir(afl->out_dir, 0700)) {
+
+ if (errno != EEXIST) { PFATAL("Unable to create '%s'", afl->out_dir); }
+
+ handle_existing_out_dir(afl);
+
+ } else {
+
+ if (afl->in_place_resume) {
+
+ FATAL("Resume attempted but old output directory not found");
+
+ }
+
+ afl->fsrv.out_dir_fd = open(afl->out_dir, O_RDONLY);
+
+#ifndef __sun
+
+ if (afl->fsrv.out_dir_fd < 0 ||
+ flock(afl->fsrv.out_dir_fd, LOCK_EX | LOCK_NB)) {
+
+ PFATAL("Unable to flock() output directory.");
+
+ }
+
+#endif /* !__sun */
+
+ }
+
+ if (afl->is_main_node) {
+
+ u8 *x = alloc_printf("%s/is_main_node", afl->out_dir);
+ int fd = open(x, O_CREAT | O_RDWR, 0644);
+ if (fd < 0) FATAL("cannot create %s", x);
+ free(x);
+ close(fd);
+
+ }
+
+ /* Queue directory for any starting & discovered paths. */
+
+ tmp = alloc_printf("%s/queue", afl->out_dir);
+ if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
+ ck_free(tmp);
+
+ /* Top-level directory for queue metadata used for session
+ resume and related tasks. */
+
+ tmp = alloc_printf("%s/queue/.state/", afl->out_dir);
+ if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
+ ck_free(tmp);
+
+ /* Directory for flagging queue entries that went through
+ deterministic fuzzing in the past. */
+
+ tmp = alloc_printf("%s/queue/.state/deterministic_done/", afl->out_dir);
+ if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
+ ck_free(tmp);
+
+ /* Directory with the auto-selected dictionary entries. */
+
+ tmp = alloc_printf("%s/queue/.state/auto_extras/", afl->out_dir);
+ if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
+ ck_free(tmp);
+
+ /* The set of paths currently deemed redundant. */
+
+ tmp = alloc_printf("%s/queue/.state/redundant_edges/", afl->out_dir);
+ if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
+ ck_free(tmp);
+
+ /* The set of paths showing variable behavior. */
+
+ tmp = alloc_printf("%s/queue/.state/variable_behavior/", afl->out_dir);
+ if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
+ ck_free(tmp);
+
+ /* Sync directory for keeping track of cooperating fuzzers. */
+
+ if (afl->sync_id) {
+
+ tmp = alloc_printf("%s/.synced/", afl->out_dir);
+
+ if (mkdir(tmp, 0700) && (!afl->in_place_resume || errno != EEXIST)) {
+
+ PFATAL("Unable to create '%s'", tmp);
+
+ }
+
+ ck_free(tmp);
+
+ }
+
+ /* All recorded crashes. */
+
+ tmp = alloc_printf("%s/crashes", afl->out_dir);
+ if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
+ ck_free(tmp);
+
+ /* All recorded hangs. */
+
+ tmp = alloc_printf("%s/hangs", afl->out_dir);
+ if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
+ ck_free(tmp);
+
+ /* Generally useful file descriptors. */
+
+ afl->fsrv.dev_null_fd = open("/dev/null", O_RDWR);
+ if (afl->fsrv.dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
+
+ afl->fsrv.dev_urandom_fd = open("/dev/urandom", O_RDONLY);
+ if (afl->fsrv.dev_urandom_fd < 0) { PFATAL("Unable to open /dev/urandom"); }
+
+ /* Gnuplot output file. */
+
+ tmp = alloc_printf("%s/plot_data", afl->out_dir);
+
+ if (!afl->in_place_resume) {
+
+ int fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
+ if (fd < 0) { PFATAL("Unable to create '%s'", tmp); }
+ ck_free(tmp);
+
+ afl->fsrv.plot_file = fdopen(fd, "w");
+ if (!afl->fsrv.plot_file) { PFATAL("fdopen() failed"); }
+
+ fprintf(
+ afl->fsrv.plot_file,
+ "# relative_time, cycles_done, cur_item, corpus_count, "
+ "pending_total, pending_favs, map_size, saved_crashes, "
+ "saved_hangs, max_depth, execs_per_sec, total_execs, edges_found\n");
+
+ } else {
+
+ int fd = open(tmp, O_WRONLY | O_CREAT, DEFAULT_PERMISSION);
+ if (fd < 0) { PFATAL("Unable to create '%s'", tmp); }
+ ck_free(tmp);
+
+ afl->fsrv.plot_file = fdopen(fd, "w");
+ if (!afl->fsrv.plot_file) { PFATAL("fdopen() failed"); }
+
+ fseek(afl->fsrv.plot_file, 0, SEEK_END);
+
+ }
+
+ fflush(afl->fsrv.plot_file);
+
+ /* ignore errors */
+
+}
+
+void setup_cmdline_file(afl_state_t *afl, char **argv) {
+
+ u8 *tmp;
+ s32 fd;
+ u32 i = 0;
+
+ FILE *cmdline_file = NULL;
+
+ /* Store the command line to reproduce our findings */
+ tmp = alloc_printf("%s/cmdline", afl->out_dir);
+ fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
+ if (fd < 0) { PFATAL("Unable to create '%s'", tmp); }
+ ck_free(tmp);
+
+ cmdline_file = fdopen(fd, "w");
+ if (!cmdline_file) { PFATAL("fdopen() failed"); }
+
+ while (argv[i]) {
+
+ fprintf(cmdline_file, "%s\n", argv[i]);
+ ++i;
+
+ }
+
+ fclose(cmdline_file);
+
+}
+
+/* Setup the output file for fuzzed data, if not using -f. */
+
+void setup_stdio_file(afl_state_t *afl) {
+
+ if (afl->file_extension) {
+
+ afl->fsrv.out_file =
+ alloc_printf("%s/.cur_input.%s", afl->tmp_dir, afl->file_extension);
+
+ } else {
+
+ afl->fsrv.out_file = alloc_printf("%s/.cur_input", afl->tmp_dir);
+
+ }
+
+ unlink(afl->fsrv.out_file); /* Ignore errors */
+
+ afl->fsrv.out_fd =
+ open(afl->fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
+
+ if (afl->fsrv.out_fd < 0) {
+
+ PFATAL("Unable to create '%s'", afl->fsrv.out_file);
+
+ }
+
+}
+
+/* Make sure that core dumps don't go to a program. */
+
+void check_crash_handling(void) {
+
+#ifdef __APPLE__
+
+ /* Yuck! There appears to be no simple C API to query for the state of
+ loaded daemons on MacOS X, and I'm a bit hesitant to do something
+ more sophisticated, such as disabling crash reporting via Mach ports,
+ until I get a box to test the code. So, for now, we check for crash
+ reporting the awful way. */
+
+ #if !TARGET_OS_IPHONE
+ if (system("launchctl list 2>/dev/null | grep -q '\\.ReportCrash$'")) return;
+
+ SAYF(
+ "\n" cLRD "[-] " cRST
+ "Whoops, your system is configured to forward crash notifications to an\n"
+ " external crash reporting utility. This will cause issues due to "
+ "the\n"
+ " extended delay between the fuzzed binary malfunctioning and this "
+ "fact\n"
+ " being relayed to the fuzzer via the standard waitpid() API.\n\n"
+ " To avoid having crashes misinterpreted as timeouts, please run the\n"
+ " following commands:\n\n"
+
+ " SL=/System/Library; PL=com.apple.ReportCrash\n"
+ " launchctl unload -w ${SL}/LaunchAgents/${PL}.plist\n"
+ " sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist\n");
+
+ #endif
+ if (!get_afl_env("AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES"))
+ FATAL("Crash reporter detected");
+
+#else
+
+ /* This is Linux specific, but I don't think there's anything equivalent on
+ *BSD, so we can just let it slide for now. */
+
+ s32 fd = open("/proc/sys/kernel/core_pattern", O_RDONLY);
+ u8 fchar;
+
+ if (fd < 0) { return; }
+
+ ACTF("Checking core_pattern...");
+
+ if (read(fd, &fchar, 1) == 1 && fchar == '|') {
+
+ SAYF(
+ "\n" cLRD "[-] " cRST
+ "Hmm, your system is configured to send core dump notifications to an\n"
+ " external utility. This will cause issues: there will be an "
+ "extended delay\n"
+ " between stumbling upon a crash and having this information "
+ "relayed to the\n"
+ " fuzzer via the standard waitpid() API.\n"
+ " If you're just testing, set "
+ "'AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1'.\n\n"
+
+ " To avoid having crashes misinterpreted as timeouts, please log in "
+ "as root\n"
+ " and temporarily modify /proc/sys/kernel/core_pattern, like so:\n\n"
+
+ " echo core >/proc/sys/kernel/core_pattern\n");
+
+ if (!getenv("AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES")) {
+
+ FATAL("Pipe at the beginning of 'core_pattern'");
+
+ }
+
+ }
+
+ close(fd);
+
+#endif /* ^__APPLE__ */
+
+}
+
+/* Check CPU governor. */
+
+void check_cpu_governor(afl_state_t *afl) {
+
+#ifdef __linux__
+ FILE *f;
+ u8 tmp[128];
+ u64 min = 0, max = 0;
+
+ if (afl->afl_env.afl_skip_cpufreq) { return; }
+
+ if (afl->cpu_aff > 0) {
+
+ snprintf(tmp, sizeof(tmp), "%s%d%s", "/sys/devices/system/cpu/cpu",
+ afl->cpu_aff, "/cpufreq/scaling_governor");
+
+ } else {
+
+ snprintf(tmp, sizeof(tmp), "%s",
+ "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor");
+
+ }
+
+ f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor", "r");
+ if (!f) {
+
+ if (afl->cpu_aff > 0) {
+
+ snprintf(tmp, sizeof(tmp), "%s%d%s",
+ "/sys/devices/system/cpu/cpufreq/policy", afl->cpu_aff,
+ "/scaling_governor");
+
+ } else {
+
+ snprintf(tmp, sizeof(tmp), "%s",
+ "/sys/devices/system/cpu/cpufreq/policy0/scaling_governor");
+
+ }
+
+ f = fopen(tmp, "r");
+
+ }
+
+ if (!f) {
+
+ WARNF("Could not check CPU scaling governor");
+ return;
+
+ }
+
+ ACTF("Checking CPU scaling governor...");
+
+ if (!fgets(tmp, 128, f)) { PFATAL("fgets() failed"); }
+
+ fclose(f);
+
+ if (!strncmp(tmp, "perf", 4)) { return; }
+
+ f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq", "r");
+
+ if (f) {
+
+ if (fscanf(f, "%llu", &min) != 1) { min = 0; }
+ fclose(f);
+
+ }
+
+ f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq", "r");
+
+ if (f) {
+
+ if (fscanf(f, "%llu", &max) != 1) { max = 0; }
+ fclose(f);
+
+ }
+
+ if (min == max) { return; }
+
+ SAYF("\n" cLRD "[-] " cRST
+ "Whoops, your system uses on-demand CPU frequency scaling, adjusted\n"
+ " between %llu and %llu MHz. Unfortunately, the scaling algorithm in "
+ "the\n"
+ " kernel is imperfect and can miss the short-lived processes spawned "
+ "by\n"
+ " afl-fuzz. To keep things moving, run these commands as root:\n\n"
+
+ " cd /sys/devices/system/cpu\n"
+ " echo performance | tee cpu*/cpufreq/scaling_governor\n\n"
+
+ " You can later go back to the original state by replacing "
+ "'performance'\n"
+ " with 'ondemand' or 'powersave'. If you don't want to change the "
+ "settings,\n"
+ " set AFL_SKIP_CPUFREQ to make afl-fuzz skip this check - but expect "
+ "some\n"
+ " performance drop.\n",
+ min / 1024, max / 1024);
+ FATAL("Suboptimal CPU scaling governor");
+
+#elif defined __APPLE__
+ u64 min = 0, max = 0;
+ size_t mlen = sizeof(min);
+ if (afl->afl_env.afl_skip_cpufreq) return;
+
+ ACTF("Checking CPU scaling governor...");
+
+ if (sysctlbyname("hw.cpufrequency_min", &min, &mlen, NULL, 0) == -1) {
+
+ WARNF("Could not check CPU min frequency");
+ return;
+
+ }
+
+ if (sysctlbyname("hw.cpufrequency_max", &max, &mlen, NULL, 0) == -1) {
+
+ WARNF("Could not check CPU max frequency");
+ return;
+
+ }
+
+ if (min == max) return;
+
+ SAYF("\n" cLRD "[-] " cRST
+ "Whoops, your system uses on-demand CPU frequency scaling, adjusted\n"
+ " between %llu and %llu MHz.\n"
+ " If you don't want to check those settings, set "
+ "AFL_SKIP_CPUFREQ\n"
+ " to make afl-fuzz skip this check - but expect some performance "
+ "drop.\n",
+ min / 1024, max / 1024);
+ FATAL("Suboptimal CPU scaling governor");
+#else
+ (void)afl;
+#endif
+
+}
+
+/* Count the number of logical CPU cores. */
+
+void get_core_count(afl_state_t *afl) {
+
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
+ defined(__DragonFly__)
+
+ size_t s = sizeof(afl->cpu_core_count);
+
+ /* On *BSD systems, we can just use a sysctl to get the number of CPUs. */
+
+ #ifdef __APPLE__
+
+ if (sysctlbyname("hw.logicalcpu", &afl->cpu_core_count, &s, NULL, 0) < 0)
+ return;
+
+ #else
+
+ int s_name[2] = {CTL_HW, HW_NCPU};
+
+ if (sysctl(s_name, 2, &afl->cpu_core_count, &s, NULL, 0) < 0) return;
+
+ #endif /* ^__APPLE__ */
+
+#else
+
+ #ifdef HAVE_AFFINITY
+
+ afl->cpu_core_count = sysconf(_SC_NPROCESSORS_ONLN);
+
+ #else
+
+ FILE *f = fopen("/proc/stat", "r");
+ u8 tmp[1024];
+
+ if (!f) return;
+
+ while (fgets(tmp, sizeof(tmp), f))
+ if (!strncmp(tmp, "cpu", 3) && isdigit(tmp[3])) ++afl->cpu_core_count;
+
+ fclose(f);
+
+ #endif /* ^HAVE_AFFINITY */
+
+#endif /* ^(__APPLE__ || __FreeBSD__ || __OpenBSD__) */
+
+ if (afl->cpu_core_count > 0) {
+
+ u32 cur_runnable = 0;
+
+ cur_runnable = (u32)get_runnable_processes();
+
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
+ defined(__DragonFly__)
+
+ /* Add ourselves, since the 1-minute average doesn't include that yet. */
+
+ ++cur_runnable;
+
+#endif /* __APPLE__ || __FreeBSD__ || __OpenBSD__ */
+
+ OKF("You have %d CPU core%s and %u runnable tasks (utilization: %0.0f%%).",
+ afl->cpu_core_count, afl->cpu_core_count > 1 ? "s" : "", cur_runnable,
+ cur_runnable * 100.0 / afl->cpu_core_count);
+
+ if (afl->cpu_core_count > 1) {
+
+ if (cur_runnable > afl->cpu_core_count * 1.5) {
+
+ WARNF("System under apparent load, performance may be spotty.");
+
+ } else if ((s64)cur_runnable + 1 <= (s64)afl->cpu_core_count) {
+
+ OKF("Try parallel jobs - see %s/parallel_fuzzing.md.", doc_path);
+
+ }
+
+ }
+
+ } else {
+
+ afl->cpu_core_count = 0;
+ WARNF("Unable to figure out the number of CPU cores.");
+
+ }
+
+}
+
+/* Validate and fix up afl->out_dir and sync_dir when using -S. */
+
+void fix_up_sync(afl_state_t *afl) {
+
+ u8 *x = afl->sync_id;
+
+ while (*x) {
+
+ if (!isalnum(*x) && *x != '_' && *x != '-') {
+
+ FATAL("Non-alphanumeric fuzzer ID specified via -S or -M");
+
+ }
+
+ ++x;
+
+ }
+
+ if (strlen(afl->sync_id) > 32) { FATAL("Fuzzer ID too long"); }
+
+ x = alloc_printf("%s/%s", afl->out_dir, afl->sync_id);
+
+#ifdef __linux__
+ if (afl->fsrv.nyx_mode) { afl->fsrv.out_dir_path = afl->out_dir; }
+#endif
+ afl->sync_dir = afl->out_dir;
+ afl->out_dir = x;
+
+}
+
+/* Handle screen resize (SIGWINCH). */
+
+static void handle_resize(int sig) {
+
+ (void)sig;
+ afl_states_clear_screen();
+
+}
+
+/* Check ASAN options. */
+
+void check_asan_opts(afl_state_t *afl) {
+
+ u8 *x = get_afl_env("ASAN_OPTIONS");
+
+ (void)(afl);
+
+ if (x) {
+
+ if (!strstr(x, "abort_on_error=1")) {
+
+ FATAL("Custom ASAN_OPTIONS set without abort_on_error=1 - please fix!");
+
+ }
+
+#ifndef ASAN_BUILD
+ if (!afl->debug && !strstr(x, "symbolize=0")) {
+
+ FATAL("Custom ASAN_OPTIONS set without symbolize=0 - please fix!");
+
+ }
+
+#endif
+
+ }
+
+ x = get_afl_env("MSAN_OPTIONS");
+
+ if (x) {
+
+ if (!strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR))) {
+
+ FATAL("Custom MSAN_OPTIONS set without exit_code=" STRINGIFY(
+ MSAN_ERROR) " - please fix!");
+
+ }
+
+ if (!afl->debug && !strstr(x, "symbolize=0")) {
+
+ FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!");
+
+ }
+
+ }
+
+ x = get_afl_env("LSAN_OPTIONS");
+
+ if (x) {
+
+ if (!strstr(x, "symbolize=0")) {
+
+ FATAL("Custom LSAN_OPTIONS set without symbolize=0 - please fix!");
+
+ }
+
+ }
+
+}
+
+/* Handle stop signal (Ctrl-C, etc). */
+
+static void handle_stop_sig(int sig) {
+
+ (void)sig;
+ afl_states_stop();
+
+}
+
+/* Handle skip request (SIGUSR1). */
+
+static void handle_skipreq(int sig) {
+
+ (void)sig;
+ afl_states_request_skip();
+
+}
+
+/* Setup shared map for fuzzing with input via sharedmem */
+
+void setup_testcase_shmem(afl_state_t *afl) {
+
+ afl->shm_fuzz = ck_alloc(sizeof(sharedmem_t));
+
+ // we need to set the non-instrumented mode to not overwrite the SHM_ENV_VAR
+ u8 *map = afl_shm_init(afl->shm_fuzz, MAX_FILE + sizeof(u32), 1);
+ afl->shm_fuzz->shmemfuzz_mode = 1;
+
+ if (!map) { FATAL("BUG: Zero return from afl_shm_init."); }
+
+#ifdef USEMMAP
+ setenv(SHM_FUZZ_ENV_VAR, afl->shm_fuzz->g_shm_file_path, 1);
+#else
+ u8 *shm_str = alloc_printf("%d", afl->shm_fuzz->shm_id);
+ setenv(SHM_FUZZ_ENV_VAR, shm_str, 1);
+ ck_free(shm_str);
+#endif
+ afl->fsrv.support_shmem_fuzz = 1;
+ afl->fsrv.shmem_fuzz_len = (u32 *)map;
+ afl->fsrv.shmem_fuzz = map + sizeof(u32);
+
+}
+
+/* Do a PATH search and find target binary to see that it exists and
+ isn't a shell script - a common and painful mistake. We also check for
+ a valid ELF header and for evidence of AFL instrumentation. */
+
+void check_binary(afl_state_t *afl, u8 *fname) {
+
+ if (unlikely(!fname)) { FATAL("BUG: Binary name is NULL"); }
+
+ u8 * env_path = 0;
+ struct stat st;
+
+ s32 fd;
+ u8 *f_data;
+ u32 f_len = 0;
+
+ ACTF("Validating target binary...");
+
+ if (strchr(fname, '/') || !(env_path = getenv("PATH"))) {
+
+ afl->fsrv.target_path = ck_strdup(fname);
+#ifdef __linux__
+ if (afl->fsrv.nyx_mode) {
+
+ /* check if target_path is a nyx sharedir */
+ if (stat(afl->fsrv.target_path, &st) || S_ISDIR(st.st_mode)) {
+
+ char *tmp = alloc_printf("%s/config.ron", afl->fsrv.target_path);
+ if (stat(tmp, &st) || S_ISREG(st.st_mode)) {
+
+ free(tmp);
+ return;
+
+ }
+
+ }
+
+ FATAL("Directory '%s' not found or is not a nyx share directory",
+ afl->fsrv.target_path);
+
+ }
+
+#endif
+ if (stat(afl->fsrv.target_path, &st) || !S_ISREG(st.st_mode) ||
+ !(st.st_mode & 0111) || (f_len = st.st_size) < 4) {
+
+ FATAL("Program '%s' not found or not executable", fname);
+
+ }
+
+ } else {
+
+ while (env_path) {
+
+ u8 *cur_elem, *delim = strchr(env_path, ':');
+
+ if (delim) {
+
+ cur_elem = ck_alloc(delim - env_path + 1);
+ if (unlikely(!cur_elem)) { FATAL("Unexpected large PATH"); }
+ memcpy(cur_elem, env_path, delim - env_path);
+ ++delim;
+
+ } else {
+
+ cur_elem = ck_strdup(env_path);
+
+ }
+
+ env_path = delim;
+
+ if (cur_elem[0]) {
+
+ afl->fsrv.target_path = alloc_printf("%s/%s", cur_elem, fname);
+
+ } else {
+
+ afl->fsrv.target_path = ck_strdup(fname);
+
+ }
+
+ ck_free(cur_elem);
+
+ if (!stat(afl->fsrv.target_path, &st) && S_ISREG(st.st_mode) &&
+ (st.st_mode & 0111) && (f_len = st.st_size) >= 4) {
+
+ break;
+
+ }
+
+ ck_free(afl->fsrv.target_path);
+ afl->fsrv.target_path = 0;
+
+ }
+
+ if (!afl->fsrv.target_path) {
+
+ FATAL("Program '%s' not found or not executable", fname);
+
+ }
+
+ }
+
+ if (afl->afl_env.afl_skip_bin_check || afl->use_wine || afl->unicorn_mode ||
+ (afl->fsrv.qemu_mode && getenv("AFL_QEMU_CUSTOM_BIN")) ||
+ (afl->fsrv.cs_mode && getenv("AFL_CS_CUSTOM_BIN")) ||
+ afl->non_instrumented_mode) {
+
+ return;
+
+ }
+
+ /* Check for blatant user errors. */
+
+ /* disabled. not a real-worl scenario where this is a problem.
+ if ((!strncmp(afl->fsrv.target_path, "/tmp/", 5) &&
+ !strchr(afl->fsrv.target_path + 5, '/')) ||
+ (!strncmp(afl->fsrv.target_path, "/var/tmp/", 9) &&
+ !strchr(afl->fsrv.target_path + 9, '/'))) {
+
+ FATAL("Please don't keep binaries in /tmp or /var/tmp");
+
+ }
+
+ */
+
+ fd = open(afl->fsrv.target_path, O_RDONLY);
+
+ if (fd < 0) { PFATAL("Unable to open '%s'", afl->fsrv.target_path); }
+
+ f_data = mmap(0, f_len, PROT_READ, MAP_PRIVATE, fd, 0);
+
+ if (f_data == MAP_FAILED) {
+
+ PFATAL("Unable to mmap file '%s'", afl->fsrv.target_path);
+
+ }
+
+ close(fd);
+
+ if (f_data[0] == '#' && f_data[1] == '!') {
+
+ SAYF("\n" cLRD "[-] " cRST
+ "Oops, the target binary looks like a shell script. Some build "
+ "systems will\n"
+ " sometimes generate shell stubs for dynamically linked programs; "
+ "try static\n"
+ " library mode (./configure --disable-shared) if that's the "
+ "case.\n\n"
+
+ " Another possible cause is that you are actually trying to use a "
+ "shell\n"
+ " wrapper around the fuzzed component. Invoking shell can slow "
+ "down the\n"
+ " fuzzing process by a factor of 20x or more; it's best to write "
+ "the wrapper\n"
+ " in a compiled language instead.\n");
+
+ FATAL("Program '%s' is a shell script", afl->fsrv.target_path);
+
+ }
+
+#ifndef __APPLE__
+
+ if (f_data[0] != 0x7f || memcmp(f_data + 1, "ELF", 3)) {
+
+ FATAL("Program '%s' is not an ELF binary", afl->fsrv.target_path);
+
+ }
+
+#else
+
+ #if !defined(__arm__) && !defined(__arm64__)
+ if ((f_data[0] != 0xCF || f_data[1] != 0xFA || f_data[2] != 0xED) &&
+ (f_data[0] != 0xCA || f_data[1] != 0xFE || f_data[2] != 0xBA))
+ FATAL("Program '%s' is not a 64-bit or universal Mach-O binary",
+ afl->fsrv.target_path);
+ #endif
+
+#endif /* ^!__APPLE__ */
+
+ if (!afl->fsrv.qemu_mode && !afl->fsrv.frida_mode && !afl->unicorn_mode &&
+#ifdef __linux__
+ !afl->fsrv.nyx_mode &&
+#endif
+ !afl->fsrv.cs_mode && !afl->non_instrumented_mode &&
+ !memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
+
+ SAYF("\n" cLRD "[-] " cRST
+ "Looks like the target binary is not instrumented! The fuzzer depends "
+ "on\n"
+ " compile-time instrumentation to isolate interesting test cases "
+ "while\n"
+ " mutating the input data. For more information, and for tips on "
+ "how to\n"
+ " instrument binaries, please see %s/README.md.\n\n"
+
+ " When source code is not available, you may be able to leverage "
+ "QEMU\n"
+ " mode support. Consult the README.md for tips on how to enable "
+ "this.\n\n"
+
+ " If your target is an instrumented binary (e.g. with zafl, "
+ "retrowrite,\n"
+ " etc.) then set 'AFL_SKIP_BIN_CHECK=1'\n\n"
+
+ " (It is also possible to use afl-fuzz as a traditional, "
+ "non-instrumented\n"
+ " fuzzer. For that use the -n option - but expect much worse "
+ "results.)\n",
+ doc_path);
+
+ FATAL("No instrumentation detected");
+
+ }
+
+ if ((afl->fsrv.cs_mode || afl->fsrv.qemu_mode || afl->fsrv.frida_mode) &&
+ memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
+
+ SAYF("\n" cLRD "[-] " cRST
+ "This program appears to be instrumented with afl-gcc, but is being "
+ "run in\n"
+ " QEMU mode (-Q). This is probably not what you "
+ "want -\n"
+ " this setup will be slow and offer no practical benefits.\n");
+
+ FATAL("Instrumentation found in -Q mode");
+
+ }
+
+ if (memmem(f_data, f_len, "__asan_init", 11) ||
+ memmem(f_data, f_len, "__msan_init", 11) ||
+ memmem(f_data, f_len, "__lsan_init", 11)) {
+
+ afl->fsrv.uses_asan = 1;
+
+ }
+
+ /* Detect persistent & deferred init signatures in the binary. */
+
+ if (memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG) + 1)) {
+
+ OKF(cPIN "Persistent mode binary detected.");
+ setenv(PERSIST_ENV_VAR, "1", 1);
+ afl->persistent_mode = 1;
+ afl->fsrv.persistent_mode = 1;
+ afl->shmem_testcase_mode = 1;
+
+ } else if (getenv("AFL_PERSISTENT")) {
+
+ OKF(cPIN "Persistent mode enforced.");
+ setenv(PERSIST_ENV_VAR, "1", 1);
+ afl->persistent_mode = 1;
+ afl->fsrv.persistent_mode = 1;
+ afl->shmem_testcase_mode = 1;
+
+ } else if (getenv("AFL_FRIDA_PERSISTENT_ADDR")) {
+
+ OKF("FRIDA Persistent mode configuration options detected.");
+ setenv(PERSIST_ENV_VAR, "1", 1);
+ afl->persistent_mode = 1;
+ afl->fsrv.persistent_mode = 1;
+ afl->shmem_testcase_mode = 1;
+
+ }
+
+ if (afl->fsrv.frida_mode ||
+ memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) {
+
+ OKF(cPIN "Deferred forkserver binary detected.");
+ setenv(DEFER_ENV_VAR, "1", 1);
+ afl->deferred_mode = 1;
+
+ } else if (getenv("AFL_DEFER_FORKSRV")) {
+
+ OKF(cPIN "Deferred forkserver enforced.");
+ setenv(DEFER_ENV_VAR, "1", 1);
+ afl->deferred_mode = 1;
+
+ }
+
+ if (munmap(f_data, f_len)) { PFATAL("unmap() failed"); }
+
+}
+
+/* Check if we're on TTY. */
+
+void check_if_tty(afl_state_t *afl) {
+
+ struct winsize ws;
+
+ if (afl->afl_env.afl_no_ui) {
+
+ OKF("Disabling the UI because AFL_NO_UI is set.");
+ afl->not_on_tty = 1;
+ return;
+
+ }
+
+ if (ioctl(1, TIOCGWINSZ, &ws)) {
+
+ if (errno == ENOTTY) {
+
+ OKF("Looks like we're not running on a tty, so I'll be a bit less "
+ "verbose.");
+ afl->not_on_tty = 1;
+
+ }
+
+ return;
+
+ }
+
+}
+
+/* Set up signal handlers. More complicated that needs to be, because libc on
+ Solaris doesn't resume interrupted reads(), sets SA_RESETHAND when you call
+ siginterrupt(), and does other stupid things. */
+
+void setup_signal_handlers(void) {
+
+ struct sigaction sa;
+
+ sa.sa_handler = NULL;
+ sa.sa_flags = SA_RESTART;
+ sa.sa_sigaction = NULL;
+
+ sigemptyset(&sa.sa_mask);
+
+ /* Various ways of saying "stop". */
+
+ sa.sa_handler = handle_stop_sig;
+ sigaction(SIGHUP, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGTERM, &sa, NULL);
+
+ /* Window resize */
+
+ sa.sa_handler = handle_resize;
+ sigaction(SIGWINCH, &sa, NULL);
+
+ /* SIGUSR1: skip entry */
+
+ sa.sa_handler = handle_skipreq;
+ sigaction(SIGUSR1, &sa, NULL);
+
+ /* Things we don't care about. */
+
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGTSTP, &sa, NULL);
+ sigaction(SIGPIPE, &sa, NULL);
+
+}
+
+/* Make a copy of the current command line. */
+
+void save_cmdline(afl_state_t *afl, u32 argc, char **argv) {
+
+ u32 len = 1, i;
+ u8 *buf;
+
+ for (i = 0; i < argc; ++i) {
+
+ len += strlen(argv[i]) + 1;
+
+ }
+
+ buf = afl->orig_cmdline = ck_alloc(len);
+
+ for (i = 0; i < argc; ++i) {
+
+ u32 l = strlen(argv[i]);
+
+ if (!argv[i] || !buf) { FATAL("null deref detected"); }
+
+ memcpy(buf, argv[i], l);
+ buf += l;
+
+ if (i != argc - 1) { *(buf++) = ' '; }
+
+ }
+
+ *buf = 0;
+
+}
+
diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c
new file mode 100644
index 00000000..9407adfb
--- /dev/null
+++ b/src/afl-fuzz-mutators.c
@@ -0,0 +1,545 @@
+/*
+ american fuzzy lop++ - custom mutators related routines
+ -------------------------------------------------------
+
+ Originally written by Shengtuo Hu
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Andrea Fioraldi <andreafioraldi@gmail.com>
+ Dominik Maier <mail@dmnk.co>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ This is the real deal: the program takes an instrumented binary and
+ attempts a variety of basic fuzzing tricks, paying close attention to
+ how they affect the execution path.
+
+ */
+
+#include "afl-fuzz.h"
+
+struct custom_mutator *load_custom_mutator(afl_state_t *, const char *);
+#ifdef USE_PYTHON
+struct custom_mutator *load_custom_mutator_py(afl_state_t *, char *);
+#endif
+
+void run_afl_custom_queue_new_entry(afl_state_t *afl, struct queue_entry *q,
+ u8 *fname, u8 *mother_fname) {
+
+ if (afl->custom_mutators_count) {
+
+ u8 updated = 0;
+
+ LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+ if (el->afl_custom_queue_new_entry) {
+
+ if (el->afl_custom_queue_new_entry(el->data, fname, mother_fname)) {
+
+ updated = 1;
+
+ }
+
+ }
+
+ });
+
+ if (updated) {
+
+ struct stat st;
+ if (stat(fname, &st)) { PFATAL("File %s is gone!", fname); }
+ if (!st.st_size) {
+
+ FATAL("File %s became empty in custom mutator!", fname);
+
+ }
+
+ q->len = st.st_size;
+
+ }
+
+ }
+
+}
+
+void setup_custom_mutators(afl_state_t *afl) {
+
+ /* Try mutator library first */
+ struct custom_mutator *mutator;
+ u8 * fn = afl->afl_env.afl_custom_mutator_library;
+ u32 prev_mutator_count = 0;
+
+ if (fn) {
+
+ if (afl->limit_time_sig && afl->limit_time_sig != -1)
+ FATAL(
+ "MOpt and custom mutator are mutually exclusive. We accept pull "
+ "requests that integrates MOpt with the optional mutators "
+ "(custom/redqueen/...).");
+
+ u8 *fn_token = (u8 *)strsep((char **)&fn, ";:,");
+
+ if (likely(!fn_token)) {
+
+ mutator = load_custom_mutator(afl, fn);
+ list_append(&afl->custom_mutator_list, mutator);
+ afl->custom_mutators_count++;
+
+ } else {
+
+ while (fn_token) {
+
+ if (*fn_token) { // strsep can be empty if ";;"
+
+ if (afl->not_on_tty && afl->debug)
+ SAYF("[Custom] Processing: %s\n", fn_token);
+ prev_mutator_count = afl->custom_mutators_count;
+ mutator = load_custom_mutator(afl, fn_token);
+ list_append(&afl->custom_mutator_list, mutator);
+ afl->custom_mutators_count++;
+ if (prev_mutator_count > afl->custom_mutators_count)
+ FATAL("Maximum Custom Mutator count reached.");
+ fn_token = (u8 *)strsep((char **)&fn, ";:,");
+
+ }
+
+ }
+
+ }
+
+ }
+
+ /* Try Python module */
+#ifdef USE_PYTHON
+ u8 *module_name = afl->afl_env.afl_python_module;
+
+ if (module_name) {
+
+ if (afl->limit_time_sig) {
+
+ FATAL(
+ "MOpt and Python mutator are mutually exclusive. We accept pull "
+ "requests that integrates MOpt with the optional mutators "
+ "(custom/redqueen/...).");
+
+ }
+
+ struct custom_mutator *m = load_custom_mutator_py(afl, module_name);
+ afl->custom_mutators_count++;
+ list_append(&afl->custom_mutator_list, m);
+
+ }
+
+#else
+ if (afl->afl_env.afl_python_module) {
+
+ FATAL("Your AFL binary was built without Python support");
+
+ }
+
+#endif
+
+}
+
+void destroy_custom_mutators(afl_state_t *afl) {
+
+ if (afl->custom_mutators_count) {
+
+ LIST_FOREACH_CLEAR(&afl->custom_mutator_list, struct custom_mutator, {
+
+ if (!el->data) { FATAL("Deintializing NULL mutator"); }
+ if (el->afl_custom_deinit) el->afl_custom_deinit(el->data);
+ if (el->dh) dlclose(el->dh);
+
+ if (el->post_process_buf) {
+
+ afl_free(el->post_process_buf);
+ el->post_process_buf = NULL;
+
+ }
+
+ ck_free(el);
+
+ });
+
+ }
+
+}
+
+struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
+
+ void * dh;
+ struct custom_mutator *mutator = ck_alloc(sizeof(struct custom_mutator));
+
+ mutator->name = fn;
+ if (memchr(fn, '/', strlen(fn)))
+ mutator->name_short = strrchr(fn, '/') + 1;
+ else
+ mutator->name_short = strdup(fn);
+ ACTF("Loading custom mutator library from '%s'...", fn);
+
+ dh = dlopen(fn, RTLD_NOW);
+ if (!dh) FATAL("%s", dlerror());
+ mutator->dh = dh;
+
+ /* Mutator */
+ /* "afl_custom_init", optional for backward compatibility */
+ mutator->afl_custom_init = dlsym(dh, "afl_custom_init");
+ if (!mutator->afl_custom_init) {
+
+ FATAL("Symbol 'afl_custom_init' not found.");
+
+ }
+
+ /* "afl_custom_fuzz" or "afl_custom_mutator", required */
+ mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_fuzz");
+ if (!mutator->afl_custom_fuzz) {
+
+ /* Try "afl_custom_mutator" for backward compatibility */
+ WARNF("Symbol 'afl_custom_fuzz' not found. Try 'afl_custom_mutator'.");
+
+ mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_mutator");
+ if (!mutator->afl_custom_fuzz) {
+
+ WARNF("Symbol 'afl_custom_mutator' not found.");
+
+ }
+
+ }
+
+ /* "afl_custom_introspection", optional */
+#ifdef INTROSPECTION
+ mutator->afl_custom_introspection = dlsym(dh, "afl_custom_introspection");
+ if (!mutator->afl_custom_introspection) {
+
+ ACTF("optional symbol 'afl_custom_introspection' not found.");
+
+ }
+
+#endif
+
+ /* "afl_custom_fuzz_count", optional */
+ mutator->afl_custom_fuzz_count = dlsym(dh, "afl_custom_fuzz_count");
+ if (!mutator->afl_custom_fuzz_count) {
+
+ ACTF("optional symbol 'afl_custom_fuzz_count' not found.");
+
+ }
+
+ /* "afl_custom_deinit", optional for backward compatibility */
+ mutator->afl_custom_deinit = dlsym(dh, "afl_custom_deinit");
+ if (!mutator->afl_custom_deinit) {
+
+ FATAL("Symbol 'afl_custom_deinit' not found.");
+
+ }
+
+ /* "afl_custom_post_process", optional */
+ mutator->afl_custom_post_process = dlsym(dh, "afl_custom_post_process");
+ if (!mutator->afl_custom_post_process) {
+
+ ACTF("optional symbol 'afl_custom_post_process' not found.");
+
+ }
+
+ u8 notrim = 0;
+ /* "afl_custom_init_trim", optional */
+ mutator->afl_custom_init_trim = dlsym(dh, "afl_custom_init_trim");
+ if (!mutator->afl_custom_init_trim) {
+
+ notrim = 1;
+ ACTF("optional symbol 'afl_custom_init_trim' not found.");
+
+ }
+
+ /* "afl_custom_trim", optional */
+ mutator->afl_custom_trim = dlsym(dh, "afl_custom_trim");
+ if (!mutator->afl_custom_trim) {
+
+ notrim = 1;
+ ACTF("optional symbol 'afl_custom_trim' not found.");
+
+ }
+
+ /* "afl_custom_post_trim", optional */
+ mutator->afl_custom_post_trim = dlsym(dh, "afl_custom_post_trim");
+ if (!mutator->afl_custom_post_trim) {
+
+ notrim = 1;
+ ACTF("optional symbol 'afl_custom_post_trim' not found.");
+
+ }
+
+ if (notrim) {
+
+ mutator->afl_custom_init_trim = NULL;
+ mutator->afl_custom_trim = NULL;
+ mutator->afl_custom_post_trim = NULL;
+ ACTF(
+ "Custom mutator does not implement all three trim APIs, standard "
+ "trimming will be used.");
+
+ }
+
+ /* "afl_custom_havoc_mutation", optional */
+ mutator->afl_custom_havoc_mutation = dlsym(dh, "afl_custom_havoc_mutation");
+ if (!mutator->afl_custom_havoc_mutation) {
+
+ ACTF("optional symbol 'afl_custom_havoc_mutation' not found.");
+
+ }
+
+ /* "afl_custom_havoc_mutation", optional */
+ mutator->afl_custom_havoc_mutation_probability =
+ dlsym(dh, "afl_custom_havoc_mutation_probability");
+ if (!mutator->afl_custom_havoc_mutation_probability) {
+
+ ACTF("optional symbol 'afl_custom_havoc_mutation_probability' not found.");
+
+ }
+
+ /* "afl_custom_queue_get", optional */
+ mutator->afl_custom_queue_get = dlsym(dh, "afl_custom_queue_get");
+ if (!mutator->afl_custom_queue_get) {
+
+ ACTF("optional symbol 'afl_custom_queue_get' not found.");
+
+ }
+
+ /* "afl_custom_queue_new_entry", optional */
+ mutator->afl_custom_queue_new_entry = dlsym(dh, "afl_custom_queue_new_entry");
+ if (!mutator->afl_custom_queue_new_entry) {
+
+ ACTF("optional symbol 'afl_custom_queue_new_entry' not found");
+
+ }
+
+ /* "afl_custom_describe", optional */
+ mutator->afl_custom_describe = dlsym(dh, "afl_custom_describe");
+ if (!mutator->afl_custom_describe) {
+
+ ACTF("Symbol 'afl_custom_describe' not found.");
+
+ }
+
+ OKF("Custom mutator '%s' installed successfully.", fn);
+
+ /* Initialize the custom mutator */
+ if (mutator->afl_custom_init) {
+
+ mutator->data = mutator->afl_custom_init(afl, rand_below(afl, 0xFFFFFFFF));
+
+ }
+
+ mutator->stacked_custom = (mutator && mutator->afl_custom_havoc_mutation);
+ mutator->stacked_custom_prob =
+ 6; // like one of the default mutations in havoc
+
+ return mutator;
+
+}
+
+u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf,
+ struct custom_mutator *mutator) {
+
+ u8 fault = 0;
+ u32 trim_exec = 0;
+ u32 orig_len = q->len;
+ u32 out_len = 0;
+ u8 *out_buf = NULL;
+
+ u8 val_buf[STRINGIFY_VAL_SIZE_MAX];
+
+ afl->stage_name = afl->stage_name_buf;
+ afl->bytes_trim_in += q->len;
+
+ /* Initialize trimming in the custom mutator */
+ afl->stage_cur = 0;
+ s32 retval = mutator->afl_custom_init_trim(mutator->data, in_buf, q->len);
+ if (unlikely(retval) < 0) {
+
+ FATAL("custom_init_trim error ret: %d", retval);
+
+ } else {
+
+ afl->stage_max = retval;
+
+ }
+
+ if (afl->not_on_tty && afl->debug) {
+
+ SAYF("[Custom Trimming] START: Max %u iterations, %u bytes", afl->stage_max,
+ q->len);
+
+ }
+
+ while (afl->stage_cur < afl->stage_max) {
+
+ u8 *retbuf = NULL;
+
+ sprintf(afl->stage_name_buf, "ptrim %s",
+ u_stringify_int(val_buf, trim_exec));
+
+ u64 cksum;
+
+ size_t retlen = mutator->afl_custom_trim(mutator->data, &retbuf);
+
+ if (unlikely(!retbuf)) {
+
+ FATAL("custom_trim failed (ret %zu)", retlen);
+
+ } else if (unlikely(retlen > orig_len)) {
+
+ /* Do not exit the fuzzer, even if the trimmed data returned by the custom
+ mutator is larger than the original data. For some use cases, like the
+ grammar mutator, the definition of "size" may have different meanings.
+ For example, the trimming function in a grammar mutator aims at
+ reducing the objects in a grammar structure, but does not guarantee to
+ generate a smaller binary buffer.
+
+ Thus, we allow the custom mutator to generate the trimmed data that is
+ larger than the original data. */
+
+ if (afl->not_on_tty && afl->debug) {
+
+ WARNF(
+ "Trimmed data returned by custom mutator is larger than original "
+ "data");
+
+ }
+
+ } else if (unlikely(retlen == 0)) {
+
+ /* Do not run the empty test case on the target. To keep the custom
+ trimming function running, we simply treat the empty test case as an
+ unsuccessful trimming and skip it, instead of aborting the trimming. */
+
+ ++afl->trim_execs;
+
+ }
+
+ if (likely(retlen)) {
+
+ retlen = write_to_testcase(afl, (void **)&retbuf, retlen, 0);
+
+ fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
+ ++afl->trim_execs;
+
+ if (afl->stop_soon || fault == FSRV_RUN_ERROR) { goto abort_trimming; }
+
+ classify_counts(&afl->fsrv);
+ cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
+
+ }
+
+ if (likely(retlen && cksum == q->exec_cksum)) {
+
+ /* Let's save a clean trace, which will be needed by
+ update_bitmap_score once we're done with the trimming stuff.
+ Use out_buf NULL check to make this only happen once per trim. */
+
+ if (!out_buf) {
+
+ memcpy(afl->clean_trace_custom, afl->fsrv.trace_bits,
+ afl->fsrv.map_size);
+
+ }
+
+ if (afl_realloc((void **)&out_buf, retlen) == NULL) {
+
+ FATAL("can not allocate memory for trim");
+
+ }
+
+ out_len = retlen;
+ // TODO are we sure that retbuf fits into out_buf if retbuf can actually
+ // increase in size?
+ memcpy(out_buf, retbuf, retlen);
+
+ /* Tell the custom mutator that the trimming was successful */
+ afl->stage_cur = mutator->afl_custom_post_trim(mutator->data, 1);
+
+ if (afl->not_on_tty && afl->debug) {
+
+ SAYF("[Custom Trimming] SUCCESS: %u/%u iterations (now at %u bytes)",
+ afl->stage_cur, afl->stage_max, out_len);
+
+ }
+
+ } else {
+
+ /* Tell the custom mutator that the trimming was unsuccessful */
+ s32 retval2 = mutator->afl_custom_post_trim(mutator->data, 0);
+ if (unlikely(retval2 < 0)) {
+
+ FATAL("Error ret in custom_post_trim: %d", retval2);
+
+ } else {
+
+ afl->stage_cur = retval2;
+
+ }
+
+ if (afl->not_on_tty && afl->debug) {
+
+ SAYF("[Custom Trimming] FAILURE: %u/%u iterations", afl->stage_cur,
+ afl->stage_max);
+
+ }
+
+ }
+
+ /* Since this can be slow, update the screen every now and then. */
+
+ if (!(trim_exec++ % afl->stats_update_freq)) { show_stats(afl); }
+
+ }
+
+ /* If we have made changes, we also need to update the on-disk
+ version of the test case. */
+
+ if (out_buf) {
+
+ s32 fd;
+
+ unlink(q->fname); /* ignore errors */
+
+ fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
+
+ if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); }
+
+ ck_write(fd, out_buf, out_len, q->fname);
+ close(fd);
+
+ /* Update the queue's knowledge of length as soon as we write the file.
+ We do this here so that exit/error cases that *don't* update the file
+ also don't update q->len. */
+ q->len = out_len;
+
+ memcpy(afl->fsrv.trace_bits, afl->clean_trace_custom, afl->fsrv.map_size);
+ update_bitmap_score(afl, q);
+
+ }
+
+ if (afl->not_on_tty && afl->debug) {
+
+ SAYF("[Custom Trimming] DONE: %u bytes -> %u bytes", orig_len, q->len);
+
+ }
+
+abort_trimming:
+
+ if (out_buf) afl_free(out_buf);
+ afl->bytes_trim_out += q->len;
+ return fault;
+
+}
+
diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c
new file mode 100644
index 00000000..19f41ebe
--- /dev/null
+++ b/src/afl-fuzz-one.c
@@ -0,0 +1,5735 @@
+/*
+ american fuzzy lop++ - fuzze_one routines in different flavours
+ ---------------------------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Andrea Fioraldi <andreafioraldi@gmail.com>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ This is the real deal: the program takes an instrumented binary and
+ attempts a variety of basic fuzzing tricks, paying close attention to
+ how they affect the execution path.
+
+ */
+
+#include "afl-fuzz.h"
+#include <string.h>
+#include <limits.h>
+#include "cmplog.h"
+
+/* MOpt */
+
+static int select_algorithm(afl_state_t *afl, u32 max_algorithm) {
+
+ int i_puppet, j_puppet = 0, operator_number = max_algorithm;
+
+ double range_sele =
+ (double)afl->probability_now[afl->swarm_now][operator_number - 1];
+ double sele = ((double)(rand_below(afl, 10000) * 0.0001 * range_sele));
+
+ for (i_puppet = 0; i_puppet < operator_num; ++i_puppet) {
+
+ if (unlikely(i_puppet == 0)) {
+
+ if (sele < afl->probability_now[afl->swarm_now][i_puppet]) { break; }
+
+ } else {
+
+ if (sele < afl->probability_now[afl->swarm_now][i_puppet]) {
+
+ j_puppet = 1;
+ break;
+
+ }
+
+ }
+
+ }
+
+ if ((j_puppet == 1 &&
+ sele < afl->probability_now[afl->swarm_now][i_puppet - 1]) ||
+ (i_puppet + 1 < operator_num &&
+ sele > afl->probability_now[afl->swarm_now][i_puppet + 1])) {
+
+ FATAL("error select_algorithm");
+
+ }
+
+ return i_puppet;
+
+}
+
+/* Helper to choose random block len for block operations in fuzz_one().
+ Doesn't return zero, provided that max_len is > 0. */
+
+static inline u32 choose_block_len(afl_state_t *afl, u32 limit) {
+
+ u32 min_value, max_value;
+ u32 rlim = MIN(afl->queue_cycle, (u32)3);
+
+ if (unlikely(!afl->run_over10m)) { rlim = 1; }
+
+ switch (rand_below(afl, rlim)) {
+
+ case 0:
+ min_value = 1;
+ max_value = HAVOC_BLK_SMALL;
+ break;
+
+ case 1:
+ min_value = HAVOC_BLK_SMALL;
+ max_value = HAVOC_BLK_MEDIUM;
+ break;
+
+ default:
+
+ if (likely(rand_below(afl, 10))) {
+
+ min_value = HAVOC_BLK_MEDIUM;
+ max_value = HAVOC_BLK_LARGE;
+
+ } else {
+
+ min_value = HAVOC_BLK_LARGE;
+ max_value = HAVOC_BLK_XL;
+
+ }
+
+ }
+
+ if (min_value >= limit) { min_value = 1; }
+
+ return min_value + rand_below(afl, MIN(max_value, limit) - min_value + 1);
+
+}
+
+/* Helper function to see if a particular change (xor_val = old ^ new) could
+ be a product of deterministic bit flips with the lengths and stepovers
+ attempted by afl-fuzz. This is used to avoid dupes in some of the
+ deterministic fuzzing operations that follow bit flips. We also
+ return 1 if xor_val is zero, which implies that the old and attempted new
+ values are identical and the exec would be a waste of time. */
+
+static u8 could_be_bitflip(u32 xor_val) {
+
+ u32 sh = 0;
+
+ if (!xor_val) { return 1; }
+
+ /* Shift left until first bit set. */
+
+ while (!(xor_val & 1)) {
+
+ ++sh;
+ xor_val >>= 1;
+
+ }
+
+ /* 1-, 2-, and 4-bit patterns are OK anywhere. */
+
+ if (xor_val == 1 || xor_val == 3 || xor_val == 15) { return 1; }
+
+ /* 8-, 16-, and 32-bit patterns are OK only if shift factor is
+ divisible by 8, since that's the stepover for these ops. */
+
+ if (sh & 7) { return 0; }
+
+ if (xor_val == 0xff || xor_val == 0xffff || xor_val == 0xffffffff) {
+
+ return 1;
+
+ }
+
+ return 0;
+
+}
+
+/* Helper function to see if a particular value is reachable through
+ arithmetic operations. Used for similar purposes. */
+
+static u8 could_be_arith(u32 old_val, u32 new_val, u8 blen) {
+
+ u32 i, ov = 0, nv = 0, diffs = 0;
+
+ if (old_val == new_val) { return 1; }
+
+ /* See if one-byte adjustments to any byte could produce this result. */
+
+ for (i = 0; (u8)i < blen; ++i) {
+
+ u8 a = old_val >> (8 * i), b = new_val >> (8 * i);
+
+ if (a != b) {
+
+ ++diffs;
+ ov = a;
+ nv = b;
+
+ }
+
+ }
+
+ /* If only one byte differs and the values are within range, return 1. */
+
+ if (diffs == 1) {
+
+ if ((u8)(ov - nv) <= ARITH_MAX || (u8)(nv - ov) <= ARITH_MAX) { return 1; }
+
+ }
+
+ if (blen == 1) { return 0; }
+
+ /* See if two-byte adjustments to any byte would produce this result. */
+
+ diffs = 0;
+
+ for (i = 0; (u8)i < blen / 2; ++i) {
+
+ u16 a = old_val >> (16 * i), b = new_val >> (16 * i);
+
+ if (a != b) {
+
+ ++diffs;
+ ov = a;
+ nv = b;
+
+ }
+
+ }
+
+ /* If only one word differs and the values are within range, return 1. */
+
+ if (diffs == 1) {
+
+ if ((u16)(ov - nv) <= ARITH_MAX || (u16)(nv - ov) <= ARITH_MAX) {
+
+ return 1;
+
+ }
+
+ ov = SWAP16(ov);
+ nv = SWAP16(nv);
+
+ if ((u16)(ov - nv) <= ARITH_MAX || (u16)(nv - ov) <= ARITH_MAX) {
+
+ return 1;
+
+ }
+
+ }
+
+ /* Finally, let's do the same thing for dwords. */
+
+ if (blen == 4) {
+
+ if ((u32)(old_val - new_val) <= ARITH_MAX ||
+ (u32)(new_val - old_val) <= ARITH_MAX) {
+
+ return 1;
+
+ }
+
+ new_val = SWAP32(new_val);
+ old_val = SWAP32(old_val);
+
+ if ((u32)(old_val - new_val) <= ARITH_MAX ||
+ (u32)(new_val - old_val) <= ARITH_MAX) {
+
+ return 1;
+
+ }
+
+ }
+
+ return 0;
+
+}
+
+/* Last but not least, a similar helper to see if insertion of an
+ interesting integer is redundant given the insertions done for
+ shorter blen. The last param (check_le) is set if the caller
+ already executed LE insertion for current blen and wants to see
+ if BE variant passed in new_val is unique. */
+
+static u8 could_be_interest(u32 old_val, u32 new_val, u8 blen, u8 check_le) {
+
+ u32 i, j;
+
+ if (old_val == new_val) { return 1; }
+
+ /* See if one-byte insertions from interesting_8 over old_val could
+ produce new_val. */
+
+ for (i = 0; i < blen; ++i) {
+
+ for (j = 0; j < sizeof(interesting_8); ++j) {
+
+ u32 tval =
+ (old_val & ~(0xff << (i * 8))) | (((u8)interesting_8[j]) << (i * 8));
+
+ if (new_val == tval) { return 1; }
+
+ }
+
+ }
+
+ /* Bail out unless we're also asked to examine two-byte LE insertions
+ as a preparation for BE attempts. */
+
+ if (blen == 2 && !check_le) { return 0; }
+
+ /* See if two-byte insertions over old_val could give us new_val. */
+
+ for (i = 0; (u8)i < blen - 1; ++i) {
+
+ for (j = 0; j < sizeof(interesting_16) / 2; ++j) {
+
+ u32 tval = (old_val & ~(0xffff << (i * 8))) |
+ (((u16)interesting_16[j]) << (i * 8));
+
+ if (new_val == tval) { return 1; }
+
+ /* Continue here only if blen > 2. */
+
+ if (blen > 2) {
+
+ tval = (old_val & ~(0xffff << (i * 8))) |
+ (SWAP16(interesting_16[j]) << (i * 8));
+
+ if (new_val == tval) { return 1; }
+
+ }
+
+ }
+
+ }
+
+ if (blen == 4 && check_le) {
+
+ /* See if four-byte insertions could produce the same result
+ (LE only). */
+
+ for (j = 0; j < sizeof(interesting_32) / 4; ++j) {
+
+ if (new_val == (u32)interesting_32[j]) { return 1; }
+
+ }
+
+ }
+
+ return 0;
+
+}
+
+#ifndef IGNORE_FINDS
+
+/* Helper function to compare buffers; returns first and last differing offset.
+ We use this to find reasonable locations for splicing two files. */
+
+static void locate_diffs(u8 *ptr1, u8 *ptr2, u32 len, s32 *first, s32 *last) {
+
+ s32 f_loc = -1;
+ s32 l_loc = -1;
+ u32 pos;
+
+ for (pos = 0; pos < len; ++pos) {
+
+ if (*(ptr1++) != *(ptr2++)) {
+
+ if (f_loc == -1) { f_loc = pos; }
+ l_loc = pos;
+
+ }
+
+ }
+
+ *first = f_loc;
+ *last = l_loc;
+
+ return;
+
+}
+
+#endif /* !IGNORE_FINDS */
+
+/* Take the current entry from the queue, fuzz it for a while. This
+ function is a tad too long... returns 0 if fuzzed successfully, 1 if
+ skipped or bailed out. */
+
+u8 fuzz_one_original(afl_state_t *afl) {
+
+ u32 len, temp_len;
+ u32 j;
+ u32 i;
+ u8 *in_buf, *out_buf, *orig_in, *ex_tmp, *eff_map = 0;
+ u64 havoc_queued = 0, orig_hit_cnt, new_hit_cnt = 0, prev_cksum, _prev_cksum;
+ u32 splice_cycle = 0, perf_score = 100, orig_perf, eff_cnt = 1;
+
+ u8 ret_val = 1, doing_det = 0;
+
+ u8 a_collect[MAX_AUTO_EXTRA];
+ u32 a_len = 0;
+
+#ifdef IGNORE_FINDS
+
+ /* In IGNORE_FINDS mode, skip any entries that weren't in the
+ initial data set. */
+
+ if (afl->queue_cur->depth > 1) return 1;
+
+#else
+
+ if (unlikely(afl->custom_mutators_count)) {
+
+ /* The custom mutator will decide to skip this test case or not. */
+
+ LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+ if (el->afl_custom_queue_get &&
+ !el->afl_custom_queue_get(el->data, afl->queue_cur->fname)) {
+
+ return 1;
+
+ }
+
+ });
+
+ }
+
+ if (likely(afl->pending_favored)) {
+
+ /* If we have any favored, non-fuzzed new arrivals in the queue,
+ possibly skip to them at the expense of already-fuzzed or non-favored
+ cases. */
+
+ if ((afl->queue_cur->fuzz_level || !afl->queue_cur->favored) &&
+ likely(rand_below(afl, 100) < SKIP_TO_NEW_PROB)) {
+
+ return 1;
+
+ }
+
+ } else if (!afl->non_instrumented_mode && !afl->queue_cur->favored &&
+
+ afl->queued_items > 10) {
+
+ /* Otherwise, still possibly skip non-favored cases, albeit less often.
+ The odds of skipping stuff are higher for already-fuzzed inputs and
+ lower for never-fuzzed entries. */
+
+ if (afl->queue_cycle > 1 && !afl->queue_cur->fuzz_level) {
+
+ if (likely(rand_below(afl, 100) < SKIP_NFAV_NEW_PROB)) { return 1; }
+
+ } else {
+
+ if (likely(rand_below(afl, 100) < SKIP_NFAV_OLD_PROB)) { return 1; }
+
+ }
+
+ }
+
+#endif /* ^IGNORE_FINDS */
+
+ if (unlikely(afl->not_on_tty)) {
+
+ ACTF(
+ "Fuzzing test case #%u (%u total, %llu crashes saved, "
+ "perf_score=%0.0f, exec_us=%llu, hits=%u, map=%u, ascii=%u)...",
+ afl->current_entry, afl->queued_items, afl->saved_crashes,
+ afl->queue_cur->perf_score, afl->queue_cur->exec_us,
+ likely(afl->n_fuzz) ? afl->n_fuzz[afl->queue_cur->n_fuzz_entry] : 0,
+ afl->queue_cur->bitmap_size, afl->queue_cur->is_ascii);
+ fflush(stdout);
+
+ }
+
+ orig_in = in_buf = queue_testcase_get(afl, afl->queue_cur);
+ len = afl->queue_cur->len;
+
+ out_buf = afl_realloc(AFL_BUF_PARAM(out), len);
+ if (unlikely(!out_buf)) { PFATAL("alloc"); }
+
+ afl->subseq_tmouts = 0;
+
+ afl->cur_depth = afl->queue_cur->depth;
+
+ /*******************************************
+ * CALIBRATION (only if failed earlier on) *
+ *******************************************/
+
+ if (unlikely(afl->queue_cur->cal_failed)) {
+
+ u8 res = FSRV_RUN_TMOUT;
+
+ if (afl->queue_cur->cal_failed < CAL_CHANCES) {
+
+ afl->queue_cur->exec_cksum = 0;
+
+ res =
+ calibrate_case(afl, afl->queue_cur, in_buf, afl->queue_cycle - 1, 0);
+
+ if (unlikely(res == FSRV_RUN_ERROR)) {
+
+ FATAL("Unable to execute target application");
+
+ }
+
+ }
+
+ if (unlikely(afl->stop_soon) || res != afl->crash_mode) {
+
+ ++afl->cur_skipped_items;
+ goto abandon_entry;
+
+ }
+
+ }
+
+ /************
+ * TRIMMING *
+ ************/
+
+ if (unlikely(!afl->non_instrumented_mode && !afl->queue_cur->trim_done &&
+ !afl->disable_trim)) {
+
+ u32 old_len = afl->queue_cur->len;
+
+ u8 res = trim_case(afl, afl->queue_cur, in_buf);
+ orig_in = in_buf = queue_testcase_get(afl, afl->queue_cur);
+
+ if (unlikely(res == FSRV_RUN_ERROR)) {
+
+ FATAL("Unable to execute target application");
+
+ }
+
+ if (unlikely(afl->stop_soon)) {
+
+ ++afl->cur_skipped_items;
+ goto abandon_entry;
+
+ }
+
+ /* Don't retry trimming, even if it failed. */
+
+ afl->queue_cur->trim_done = 1;
+
+ len = afl->queue_cur->len;
+
+ /* maybe current entry is not ready for splicing anymore */
+ if (unlikely(len <= 4 && old_len > 4)) --afl->ready_for_splicing_count;
+
+ }
+
+ memcpy(out_buf, in_buf, len);
+
+ /*********************
+ * PERFORMANCE SCORE *
+ *********************/
+
+ if (likely(!afl->old_seed_selection))
+ orig_perf = perf_score = afl->queue_cur->perf_score;
+ else
+ afl->queue_cur->perf_score = orig_perf = perf_score =
+ calculate_score(afl, afl->queue_cur);
+
+ if (unlikely(perf_score <= 0 && afl->active_items > 1)) {
+
+ goto abandon_entry;
+
+ }
+
+ if (unlikely(afl->shm.cmplog_mode &&
+ afl->queue_cur->colorized < afl->cmplog_lvl &&
+ (u32)len <= afl->cmplog_max_filesize)) {
+
+ if (unlikely(len < 4)) {
+
+ afl->queue_cur->colorized = CMPLOG_LVL_MAX;
+
+ } else {
+
+ if (afl->cmplog_lvl == 3 ||
+ (afl->cmplog_lvl == 2 && afl->queue_cur->tc_ref) ||
+ afl->queue_cur->favored ||
+ !(afl->fsrv.total_execs % afl->queued_items) ||
+ get_cur_time() - afl->last_find_time > 300000) { // 300 seconds
+
+ if (input_to_state_stage(afl, in_buf, out_buf, len)) {
+
+ goto abandon_entry;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ /* Skip right away if -d is given, if it has not been chosen sufficiently
+ often to warrant the expensive deterministic stage (fuzz_level), or
+ if it has gone through deterministic testing in earlier, resumed runs
+ (passed_det). */
+
+ if (likely(afl->queue_cur->passed_det) || likely(afl->skip_deterministic) ||
+ likely(perf_score <
+ (afl->queue_cur->depth * 30 <= afl->havoc_max_mult * 100
+ ? afl->queue_cur->depth * 30
+ : afl->havoc_max_mult * 100))) {
+
+ goto custom_mutator_stage;
+
+ }
+
+ /* Skip deterministic fuzzing if exec path checksum puts this out of scope
+ for this main instance. */
+
+ if (unlikely(afl->main_node_max &&
+ (afl->queue_cur->exec_cksum % afl->main_node_max) !=
+ afl->main_node_id - 1)) {
+
+ goto custom_mutator_stage;
+
+ }
+
+ doing_det = 1;
+
+ /*********************************************
+ * SIMPLE BITFLIP (+dictionary construction) *
+ *********************************************/
+
+#define FLIP_BIT(_ar, _b) \
+ do { \
+ \
+ u8 *_arf = (u8 *)(_ar); \
+ u32 _bf = (_b); \
+ _arf[(_bf) >> 3] ^= (128 >> ((_bf)&7)); \
+ \
+ } while (0)
+
+ /* Single walking bit. */
+
+ afl->stage_short = "flip1";
+ afl->stage_max = len << 3;
+ afl->stage_name = "bitflip 1/1";
+
+ afl->stage_val_type = STAGE_VAL_NONE;
+
+ orig_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ /* Get a clean cksum. */
+
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+
+ prev_cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
+ _prev_cksum = prev_cksum;
+
+ /* Now flip bits. */
+
+ for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) {
+
+ afl->stage_cur_byte = afl->stage_cur >> 3;
+
+ FLIP_BIT(out_buf, afl->stage_cur);
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s FLIP_BIT1-%u",
+ afl->queue_cur->fname, afl->stage_cur);
+#endif
+
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+
+ FLIP_BIT(out_buf, afl->stage_cur);
+
+ /* While flipping the least significant bit in every byte, pull of an extra
+ trick to detect possible syntax tokens. In essence, the idea is that if
+ you have a binary blob like this:
+
+ xxxxxxxxIHDRxxxxxxxx
+
+ ...and changing the leading and trailing bytes causes variable or no
+ changes in program flow, but touching any character in the "IHDR" string
+ always produces the same, distinctive path, it's highly likely that
+ "IHDR" is an atomically-checked magic value of special significance to
+ the fuzzed format.
+
+ We do this here, rather than as a separate stage, because it's a nice
+ way to keep the operation approximately "free" (i.e., no extra execs).
+
+ Empirically, performing the check when flipping the least significant bit
+ is advantageous, compared to doing it at the time of more disruptive
+ changes, where the program flow may be affected in more violent ways.
+
+ The caveat is that we won't generate dictionaries in the -d mode or -S
+ mode - but that's probably a fair trade-off.
+
+ This won't work particularly well with paths that exhibit variable
+ behavior, but fails gracefully, so we'll carry out the checks anyway.
+
+ */
+
+ if (!afl->non_instrumented_mode && (afl->stage_cur & 7) == 7) {
+
+ u64 cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
+
+ if (afl->stage_cur == afl->stage_max - 1 && cksum == prev_cksum) {
+
+ /* If at end of file and we are still collecting a string, grab the
+ final character and force output. */
+
+ if (a_len < MAX_AUTO_EXTRA) {
+
+ a_collect[a_len] = out_buf[afl->stage_cur >> 3];
+
+ }
+
+ ++a_len;
+
+ if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA) {
+
+ maybe_add_auto(afl, a_collect, a_len);
+
+ }
+
+ } else if (cksum != prev_cksum) {
+
+ /* Otherwise, if the checksum has changed, see if we have something
+ worthwhile queued up, and collect that if the answer is yes. */
+
+ if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA) {
+
+ maybe_add_auto(afl, a_collect, a_len);
+
+ }
+
+ a_len = 0;
+ prev_cksum = cksum;
+
+ }
+
+ /* Continue collecting string, but only if the bit flip actually made
+ any difference - we don't want no-op tokens. */
+
+ if (cksum != _prev_cksum) {
+
+ if (a_len < MAX_AUTO_EXTRA) {
+
+ a_collect[a_len] = out_buf[afl->stage_cur >> 3];
+
+ }
+
+ ++a_len;
+
+ }
+
+ }
+
+ }
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_FLIP1] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_FLIP1] += afl->stage_max;
+
+ /* Two walking bits. */
+
+ afl->stage_name = "bitflip 2/1";
+ afl->stage_short = "flip2";
+ afl->stage_max = (len << 3) - 1;
+
+ orig_hit_cnt = new_hit_cnt;
+
+ for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) {
+
+ afl->stage_cur_byte = afl->stage_cur >> 3;
+
+ FLIP_BIT(out_buf, afl->stage_cur);
+ FLIP_BIT(out_buf, afl->stage_cur + 1);
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s FLIP_BIT2-%u",
+ afl->queue_cur->fname, afl->stage_cur);
+#endif
+
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+
+ FLIP_BIT(out_buf, afl->stage_cur);
+ FLIP_BIT(out_buf, afl->stage_cur + 1);
+
+ }
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_FLIP2] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_FLIP2] += afl->stage_max;
+
+ /* Four walking bits. */
+
+ afl->stage_name = "bitflip 4/1";
+ afl->stage_short = "flip4";
+ afl->stage_max = (len << 3) - 3;
+
+ orig_hit_cnt = new_hit_cnt;
+
+ for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) {
+
+ afl->stage_cur_byte = afl->stage_cur >> 3;
+
+ FLIP_BIT(out_buf, afl->stage_cur);
+ FLIP_BIT(out_buf, afl->stage_cur + 1);
+ FLIP_BIT(out_buf, afl->stage_cur + 2);
+ FLIP_BIT(out_buf, afl->stage_cur + 3);
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s FLIP_BIT4-%u",
+ afl->queue_cur->fname, afl->stage_cur);
+#endif
+
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+
+ FLIP_BIT(out_buf, afl->stage_cur);
+ FLIP_BIT(out_buf, afl->stage_cur + 1);
+ FLIP_BIT(out_buf, afl->stage_cur + 2);
+ FLIP_BIT(out_buf, afl->stage_cur + 3);
+
+ }
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_FLIP4] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_FLIP4] += afl->stage_max;
+
+ /* Effector map setup. These macros calculate:
+
+ EFF_APOS - position of a particular file offset in the map.
+ EFF_ALEN - length of a map with a particular number of bytes.
+ EFF_SPAN_ALEN - map span for a sequence of bytes.
+
+ */
+
+#define EFF_APOS(_p) ((_p) >> EFF_MAP_SCALE2)
+#define EFF_REM(_x) ((_x) & ((1 << EFF_MAP_SCALE2) - 1))
+#define EFF_ALEN(_l) (EFF_APOS(_l) + !!EFF_REM(_l))
+#define EFF_SPAN_ALEN(_p, _l) (EFF_APOS((_p) + (_l)-1) - EFF_APOS(_p) + 1)
+
+ /* Initialize effector map for the next step (see comments below). Always
+ flag first and last byte as doing something. */
+
+ eff_map = afl_realloc(AFL_BUF_PARAM(eff), EFF_ALEN(len));
+ if (unlikely(!eff_map)) { PFATAL("alloc"); }
+ eff_map[0] = 1;
+
+ if (EFF_APOS(len - 1) != 0) {
+
+ eff_map[EFF_APOS(len - 1)] = 1;
+ ++eff_cnt;
+
+ }
+
+ /* Walking byte. */
+
+ afl->stage_name = "bitflip 8/8";
+ afl->stage_short = "flip8";
+ afl->stage_max = len;
+
+ orig_hit_cnt = new_hit_cnt;
+ prev_cksum = _prev_cksum;
+
+ for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) {
+
+ afl->stage_cur_byte = afl->stage_cur;
+
+ out_buf[afl->stage_cur] ^= 0xFF;
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s FLIP_BIT8-%u",
+ afl->queue_cur->fname, afl->stage_cur);
+#endif
+
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+
+ /* We also use this stage to pull off a simple trick: we identify
+ bytes that seem to have no effect on the current execution path
+ even when fully flipped - and we skip them during more expensive
+ deterministic stages, such as arithmetics or known ints. */
+
+ if (!eff_map[EFF_APOS(afl->stage_cur)]) {
+
+ u64 cksum;
+
+ /* If in non-instrumented mode or if the file is very short, just flag
+ everything without wasting time on checksums. */
+
+ if (!afl->non_instrumented_mode && len >= EFF_MIN_LEN) {
+
+ cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
+
+ } else {
+
+ cksum = ~prev_cksum;
+
+ }
+
+ if (cksum != prev_cksum) {
+
+ eff_map[EFF_APOS(afl->stage_cur)] = 1;
+ ++eff_cnt;
+
+ }
+
+ }
+
+ out_buf[afl->stage_cur] ^= 0xFF;
+
+ }
+
+ /* If the effector map is more than EFF_MAX_PERC dense, just flag the
+ whole thing as worth fuzzing, since we wouldn't be saving much time
+ anyway. */
+
+ if (eff_cnt != (u32)EFF_ALEN(len) &&
+ eff_cnt * 100 / EFF_ALEN(len) > EFF_MAX_PERC) {
+
+ memset(eff_map, 1, EFF_ALEN(len));
+
+ afl->blocks_eff_select += EFF_ALEN(len);
+
+ } else {
+
+ afl->blocks_eff_select += eff_cnt;
+
+ }
+
+ afl->blocks_eff_total += EFF_ALEN(len);
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_FLIP8] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_FLIP8] += afl->stage_max;
+
+ /* Two walking bytes. */
+
+ if (len < 2) { goto skip_bitflip; }
+
+ afl->stage_name = "bitflip 16/8";
+ afl->stage_short = "flip16";
+ afl->stage_cur = 0;
+ afl->stage_max = len - 1;
+
+ orig_hit_cnt = new_hit_cnt;
+
+ for (i = 0; i < len - 1; ++i) {
+
+ /* Let's consult the effector map... */
+
+ if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)]) {
+
+ --afl->stage_max;
+ continue;
+
+ }
+
+ afl->stage_cur_byte = i;
+
+ *(u16 *)(out_buf + i) ^= 0xFFFF;
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s FLIP_BIT16-%u",
+ afl->queue_cur->fname, afl->stage_cur);
+#endif
+
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ *(u16 *)(out_buf + i) ^= 0xFFFF;
+
+ }
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_FLIP16] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_FLIP16] += afl->stage_max;
+
+ if (len < 4) { goto skip_bitflip; }
+
+ /* Four walking bytes. */
+
+ afl->stage_name = "bitflip 32/8";
+ afl->stage_short = "flip32";
+ afl->stage_cur = 0;
+ afl->stage_max = len - 3;
+
+ orig_hit_cnt = new_hit_cnt;
+
+ for (i = 0; i < len - 3; ++i) {
+
+ /* Let's consult the effector map... */
+ if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)] &&
+ !eff_map[EFF_APOS(i + 2)] && !eff_map[EFF_APOS(i + 3)]) {
+
+ --afl->stage_max;
+ continue;
+
+ }
+
+ afl->stage_cur_byte = i;
+
+ *(u32 *)(out_buf + i) ^= 0xFFFFFFFF;
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s FLIP_BIT32-%u",
+ afl->queue_cur->fname, afl->stage_cur);
+#endif
+
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ *(u32 *)(out_buf + i) ^= 0xFFFFFFFF;
+
+ }
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_FLIP32] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_FLIP32] += afl->stage_max;
+
+skip_bitflip:
+
+ if (afl->no_arith) { goto skip_arith; }
+
+ /**********************
+ * ARITHMETIC INC/DEC *
+ **********************/
+
+ /* 8-bit arithmetics. */
+
+ afl->stage_name = "arith 8/8";
+ afl->stage_short = "arith8";
+ afl->stage_cur = 0;
+ afl->stage_max = 2 * len * ARITH_MAX;
+
+ afl->stage_val_type = STAGE_VAL_LE;
+
+ orig_hit_cnt = new_hit_cnt;
+
+ for (i = 0; i < (u32)len; ++i) {
+
+ u8 orig = out_buf[i];
+
+ /* Let's consult the effector map... */
+
+ if (!eff_map[EFF_APOS(i)]) {
+
+ afl->stage_max -= 2 * ARITH_MAX;
+ continue;
+
+ }
+
+ afl->stage_cur_byte = i;
+
+ for (j = 1; j <= ARITH_MAX; ++j) {
+
+ u8 r = orig ^ (orig + j);
+
+ /* Do arithmetic operations only if the result couldn't be a product
+ of a bitflip. */
+
+ if (!could_be_bitflip(r)) {
+
+ afl->stage_cur_val = j;
+ out_buf[i] = orig + j;
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH8+-%u-%u",
+ afl->queue_cur->fname, i, j);
+#endif
+
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ } else {
+
+ --afl->stage_max;
+
+ }
+
+ r = orig ^ (orig - j);
+
+ if (!could_be_bitflip(r)) {
+
+ afl->stage_cur_val = -j;
+ out_buf[i] = orig - j;
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH8--%u-%u",
+ afl->queue_cur->fname, i, j);
+#endif
+
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ } else {
+
+ --afl->stage_max;
+
+ }
+
+ out_buf[i] = orig;
+
+ }
+
+ }
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_ARITH8] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_ARITH8] += afl->stage_max;
+
+ /* 16-bit arithmetics, both endians. */
+
+ if (len < 2) { goto skip_arith; }
+
+ afl->stage_name = "arith 16/8";
+ afl->stage_short = "arith16";
+ afl->stage_cur = 0;
+ afl->stage_max = 4 * (len - 1) * ARITH_MAX;
+
+ orig_hit_cnt = new_hit_cnt;
+
+ for (i = 0; i < (u32)len - 1; ++i) {
+
+ u16 orig = *(u16 *)(out_buf + i);
+
+ /* Let's consult the effector map... */
+
+ if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)]) {
+
+ afl->stage_max -= 4 * ARITH_MAX;
+ continue;
+
+ }
+
+ afl->stage_cur_byte = i;
+
+ for (j = 1; j <= ARITH_MAX; ++j) {
+
+ u16 r1 = orig ^ (orig + j), r2 = orig ^ (orig - j),
+ r3 = orig ^ SWAP16(SWAP16(orig) + j),
+ r4 = orig ^ SWAP16(SWAP16(orig) - j);
+
+ /* Try little endian addition and subtraction first. Do it only
+ if the operation would affect more than one byte (hence the
+ & 0xff overflow checks) and if it couldn't be a product of
+ a bitflip. */
+
+ afl->stage_val_type = STAGE_VAL_LE;
+
+ if ((orig & 0xff) + j > 0xff && !could_be_bitflip(r1)) {
+
+ afl->stage_cur_val = j;
+ *(u16 *)(out_buf + i) = orig + j;
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH16+-%u-%u",
+ afl->queue_cur->fname, i, j);
+#endif
+
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ } else {
+
+ --afl->stage_max;
+
+ }
+
+ if ((orig & 0xff) < j && !could_be_bitflip(r2)) {
+
+ afl->stage_cur_val = -j;
+ *(u16 *)(out_buf + i) = orig - j;
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH16--%u-%u",
+ afl->queue_cur->fname, i, j);
+#endif
+
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ } else {
+
+ --afl->stage_max;
+
+ }
+
+ /* Big endian comes next. Same deal. */
+
+ afl->stage_val_type = STAGE_VAL_BE;
+
+ if ((orig >> 8) + j > 0xff && !could_be_bitflip(r3)) {
+
+ afl->stage_cur_val = j;
+ *(u16 *)(out_buf + i) = SWAP16(SWAP16(orig) + j);
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH16+BE-%u-%u",
+ afl->queue_cur->fname, i, j);
+#endif
+
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ } else {
+
+ --afl->stage_max;
+
+ }
+
+ if ((orig >> 8) < j && !could_be_bitflip(r4)) {
+
+ afl->stage_cur_val = -j;
+ *(u16 *)(out_buf + i) = SWAP16(SWAP16(orig) - j);
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH16_BE-%u-%u",
+ afl->queue_cur->fname, i, j);
+#endif
+
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ } else {
+
+ --afl->stage_max;
+
+ }
+
+ *(u16 *)(out_buf + i) = orig;
+
+ }
+
+ }
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_ARITH16] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_ARITH16] += afl->stage_max;
+
+ /* 32-bit arithmetics, both endians. */
+
+ if (len < 4) { goto skip_arith; }
+
+ afl->stage_name = "arith 32/8";
+ afl->stage_short = "arith32";
+ afl->stage_cur = 0;
+ afl->stage_max = 4 * (len - 3) * ARITH_MAX;
+
+ orig_hit_cnt = new_hit_cnt;
+
+ for (i = 0; i < (u32)len - 3; ++i) {
+
+ u32 orig = *(u32 *)(out_buf + i);
+
+ /* Let's consult the effector map... */
+
+ if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)] &&
+ !eff_map[EFF_APOS(i + 2)] && !eff_map[EFF_APOS(i + 3)]) {
+
+ afl->stage_max -= 4 * ARITH_MAX;
+ continue;
+
+ }
+
+ afl->stage_cur_byte = i;
+
+ for (j = 1; j <= ARITH_MAX; ++j) {
+
+ u32 r1 = orig ^ (orig + j), r2 = orig ^ (orig - j),
+ r3 = orig ^ SWAP32(SWAP32(orig) + j),
+ r4 = orig ^ SWAP32(SWAP32(orig) - j);
+
+ /* Little endian first. Same deal as with 16-bit: we only want to
+ try if the operation would have effect on more than two bytes. */
+
+ afl->stage_val_type = STAGE_VAL_LE;
+
+ if ((orig & 0xffff) + j > 0xffff && !could_be_bitflip(r1)) {
+
+ afl->stage_cur_val = j;
+ *(u32 *)(out_buf + i) = orig + j;
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH32+-%u-%u",
+ afl->queue_cur->fname, i, j);
+#endif
+
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ } else {
+
+ --afl->stage_max;
+
+ }
+
+ if ((orig & 0xffff) < (u32)j && !could_be_bitflip(r2)) {
+
+ afl->stage_cur_val = -j;
+ *(u32 *)(out_buf + i) = orig - j;
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH32_-%u-%u",
+ afl->queue_cur->fname, i, j);
+#endif
+
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ } else {
+
+ --afl->stage_max;
+
+ }
+
+ /* Big endian next. */
+
+ afl->stage_val_type = STAGE_VAL_BE;
+
+ if ((SWAP32(orig) & 0xffff) + j > 0xffff && !could_be_bitflip(r3)) {
+
+ afl->stage_cur_val = j;
+ *(u32 *)(out_buf + i) = SWAP32(SWAP32(orig) + j);
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH32+BE-%u-%u",
+ afl->queue_cur->fname, i, j);
+#endif
+
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ } else {
+
+ --afl->stage_max;
+
+ }
+
+ if ((SWAP32(orig) & 0xffff) < (u32)j && !could_be_bitflip(r4)) {
+
+ afl->stage_cur_val = -j;
+ *(u32 *)(out_buf + i) = SWAP32(SWAP32(orig) - j);
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH32_BE-%u-%u",
+ afl->queue_cur->fname, i, j);
+#endif
+
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ } else {
+
+ --afl->stage_max;
+
+ }
+
+ *(u32 *)(out_buf + i) = orig;
+
+ }
+
+ }
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_ARITH32] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_ARITH32] += afl->stage_max;
+
+skip_arith:
+
+ /**********************
+ * INTERESTING VALUES *
+ **********************/
+
+ afl->stage_name = "interest 8/8";
+ afl->stage_short = "int8";
+ afl->stage_cur = 0;
+ afl->stage_max = len * sizeof(interesting_8);
+
+ afl->stage_val_type = STAGE_VAL_LE;
+
+ orig_hit_cnt = new_hit_cnt;
+
+ /* Setting 8-bit integers. */
+
+ for (i = 0; i < (u32)len; ++i) {
+
+ u8 orig = out_buf[i];
+
+ /* Let's consult the effector map... */
+
+ if (!eff_map[EFF_APOS(i)]) {
+
+ afl->stage_max -= sizeof(interesting_8);
+ continue;
+
+ }
+
+ afl->stage_cur_byte = i;
+
+ for (j = 0; j < (u32)sizeof(interesting_8); ++j) {
+
+ /* Skip if the value could be a product of bitflips or arithmetics. */
+
+ if (could_be_bitflip(orig ^ (u8)interesting_8[j]) ||
+ could_be_arith(orig, (u8)interesting_8[j], 1)) {
+
+ --afl->stage_max;
+ continue;
+
+ }
+
+ afl->stage_cur_val = interesting_8[j];
+ out_buf[i] = interesting_8[j];
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s INTERESTING8_%u_%u",
+ afl->queue_cur->fname, i, j);
+#endif
+
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+
+ out_buf[i] = orig;
+ ++afl->stage_cur;
+
+ }
+
+ }
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_INTEREST8] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_INTEREST8] += afl->stage_max;
+
+ /* Setting 16-bit integers, both endians. */
+
+ if (afl->no_arith || len < 2) { goto skip_interest; }
+
+ afl->stage_name = "interest 16/8";
+ afl->stage_short = "int16";
+ afl->stage_cur = 0;
+ afl->stage_max = 2 * (len - 1) * (sizeof(interesting_16) >> 1);
+
+ orig_hit_cnt = new_hit_cnt;
+
+ for (i = 0; i < len - 1; ++i) {
+
+ u16 orig = *(u16 *)(out_buf + i);
+
+ /* Let's consult the effector map... */
+
+ if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)]) {
+
+ afl->stage_max -= sizeof(interesting_16);
+ continue;
+
+ }
+
+ afl->stage_cur_byte = i;
+
+ for (j = 0; j < sizeof(interesting_16) / 2; ++j) {
+
+ afl->stage_cur_val = interesting_16[j];
+
+ /* Skip if this could be a product of a bitflip, arithmetics,
+ or single-byte interesting value insertion. */
+
+ if (!could_be_bitflip(orig ^ (u16)interesting_16[j]) &&
+ !could_be_arith(orig, (u16)interesting_16[j], 2) &&
+ !could_be_interest(orig, (u16)interesting_16[j], 2, 0)) {
+
+ afl->stage_val_type = STAGE_VAL_LE;
+
+ *(u16 *)(out_buf + i) = interesting_16[j];
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s INTERESTING16_%u_%u",
+ afl->queue_cur->fname, i, j);
+#endif
+
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ } else {
+
+ --afl->stage_max;
+
+ }
+
+ if ((u16)interesting_16[j] != SWAP16(interesting_16[j]) &&
+ !could_be_bitflip(orig ^ SWAP16(interesting_16[j])) &&
+ !could_be_arith(orig, SWAP16(interesting_16[j]), 2) &&
+ !could_be_interest(orig, SWAP16(interesting_16[j]), 2, 1)) {
+
+ afl->stage_val_type = STAGE_VAL_BE;
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation),
+ "%s INTERESTING16BE_%u_%u", afl->queue_cur->fname, i, j);
+#endif
+
+ *(u16 *)(out_buf + i) = SWAP16(interesting_16[j]);
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ } else {
+
+ --afl->stage_max;
+
+ }
+
+ }
+
+ *(u16 *)(out_buf + i) = orig;
+
+ }
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_INTEREST16] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_INTEREST16] += afl->stage_max;
+
+ if (len < 4) { goto skip_interest; }
+
+ /* Setting 32-bit integers, both endians. */
+
+ afl->stage_name = "interest 32/8";
+ afl->stage_short = "int32";
+ afl->stage_cur = 0;
+ afl->stage_max = 2 * (len - 3) * (sizeof(interesting_32) >> 2);
+
+ orig_hit_cnt = new_hit_cnt;
+
+ for (i = 0; i < len - 3; i++) {
+
+ u32 orig = *(u32 *)(out_buf + i);
+
+ /* Let's consult the effector map... */
+
+ if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)] &&
+ !eff_map[EFF_APOS(i + 2)] && !eff_map[EFF_APOS(i + 3)]) {
+
+ afl->stage_max -= sizeof(interesting_32) >> 1;
+ continue;
+
+ }
+
+ afl->stage_cur_byte = i;
+
+ for (j = 0; j < sizeof(interesting_32) / 4; ++j) {
+
+ afl->stage_cur_val = interesting_32[j];
+
+ /* Skip if this could be a product of a bitflip, arithmetics,
+ or word interesting value insertion. */
+
+ if (!could_be_bitflip(orig ^ (u32)interesting_32[j]) &&
+ !could_be_arith(orig, interesting_32[j], 4) &&
+ !could_be_interest(orig, interesting_32[j], 4, 0)) {
+
+ afl->stage_val_type = STAGE_VAL_LE;
+
+ *(u32 *)(out_buf + i) = interesting_32[j];
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s INTERESTING32_%u_%u",
+ afl->queue_cur->fname, i, j);
+#endif
+
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ } else {
+
+ --afl->stage_max;
+
+ }
+
+ if ((u32)interesting_32[j] != SWAP32(interesting_32[j]) &&
+ !could_be_bitflip(orig ^ SWAP32(interesting_32[j])) &&
+ !could_be_arith(orig, SWAP32(interesting_32[j]), 4) &&
+ !could_be_interest(orig, SWAP32(interesting_32[j]), 4, 1)) {
+
+ afl->stage_val_type = STAGE_VAL_BE;
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation),
+ "%s INTERESTING32BE_%u_%u", afl->queue_cur->fname, i, j);
+#endif
+
+ *(u32 *)(out_buf + i) = SWAP32(interesting_32[j]);
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ } else {
+
+ --afl->stage_max;
+
+ }
+
+ }
+
+ *(u32 *)(out_buf + i) = orig;
+
+ }
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_INTEREST32] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_INTEREST32] += afl->stage_max;
+
+skip_interest:
+
+ /********************
+ * DICTIONARY STUFF *
+ ********************/
+
+ if (!afl->extras_cnt) { goto skip_user_extras; }
+
+ /* Overwrite with user-supplied extras. */
+
+ afl->stage_name = "user extras (over)";
+ afl->stage_short = "ext_UO";
+ afl->stage_cur = 0;
+ afl->stage_max = afl->extras_cnt * len;
+
+ afl->stage_val_type = STAGE_VAL_NONE;
+
+ orig_hit_cnt = new_hit_cnt;
+
+ for (i = 0; i < (u32)len; ++i) {
+
+ u32 last_len = 0;
+
+ afl->stage_cur_byte = i;
+
+ /* Extras are sorted by size, from smallest to largest. This means
+ that we don't have to worry about restoring the buffer in
+ between writes at a particular offset determined by the outer
+ loop. */
+
+ for (j = 0; j < afl->extras_cnt; ++j) {
+
+ /* Skip extras probabilistically if afl->extras_cnt > AFL_MAX_DET_EXTRAS.
+ Also skip them if there's no room to insert the payload, if the token
+ is redundant, or if its entire span has no bytes set in the effector
+ map. */
+
+ if ((afl->extras_cnt > afl->max_det_extras &&
+ rand_below(afl, afl->extras_cnt) >= afl->max_det_extras) ||
+ afl->extras[j].len > len - i ||
+ !memcmp(afl->extras[j].data, out_buf + i, afl->extras[j].len) ||
+ !memchr(eff_map + EFF_APOS(i), 1,
+ EFF_SPAN_ALEN(i, afl->extras[j].len))) {
+
+ --afl->stage_max;
+ continue;
+
+ }
+
+ last_len = afl->extras[j].len;
+ memcpy(out_buf + i, afl->extras[j].data, last_len);
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation),
+ "%s EXTRAS_overwrite-%u-%u", afl->queue_cur->fname, i, j);
+#endif
+
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+
+ ++afl->stage_cur;
+
+ }
+
+ /* Restore all the clobbered memory. */
+ memcpy(out_buf + i, in_buf + i, last_len);
+
+ }
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_EXTRAS_UO] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_EXTRAS_UO] += afl->stage_max;
+
+ /* Insertion of user-supplied extras. */
+
+ afl->stage_name = "user extras (insert)";
+ afl->stage_short = "ext_UI";
+ afl->stage_cur = 0;
+ afl->stage_max = afl->extras_cnt * (len + 1);
+
+ orig_hit_cnt = new_hit_cnt;
+
+ ex_tmp = afl_realloc(AFL_BUF_PARAM(ex), len + MAX_DICT_FILE);
+ if (unlikely(!ex_tmp)) { PFATAL("alloc"); }
+
+ for (i = 0; i <= (u32)len; ++i) {
+
+ afl->stage_cur_byte = i;
+
+ for (j = 0; j < afl->extras_cnt; ++j) {
+
+ if (len + afl->extras[j].len > MAX_FILE) {
+
+ --afl->stage_max;
+ continue;
+
+ }
+
+ /* Insert token */
+ memcpy(ex_tmp + i, afl->extras[j].data, afl->extras[j].len);
+
+ /* Copy tail */
+ memcpy(ex_tmp + i + afl->extras[j].len, out_buf + i, len - i);
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s EXTRAS_insert-%u-%u",
+ afl->queue_cur->fname, i, j);
+#endif
+
+ if (common_fuzz_stuff(afl, ex_tmp, len + afl->extras[j].len)) {
+
+ goto abandon_entry;
+
+ }
+
+ ++afl->stage_cur;
+
+ }
+
+ /* Copy head */
+ ex_tmp[i] = out_buf[i];
+
+ }
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_EXTRAS_UI] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_EXTRAS_UI] += afl->stage_max;
+
+skip_user_extras:
+
+ if (!afl->a_extras_cnt) { goto skip_extras; }
+
+ afl->stage_name = "auto extras (over)";
+ afl->stage_short = "ext_AO";
+ afl->stage_cur = 0;
+ afl->stage_max = MIN(afl->a_extras_cnt, (u32)USE_AUTO_EXTRAS) * len;
+
+ afl->stage_val_type = STAGE_VAL_NONE;
+
+ orig_hit_cnt = new_hit_cnt;
+
+ for (i = 0; i < (u32)len; ++i) {
+
+ u32 last_len = 0;
+
+ afl->stage_cur_byte = i;
+
+ u32 min_extra_len = MIN(afl->a_extras_cnt, (u32)USE_AUTO_EXTRAS);
+ for (j = 0; j < min_extra_len; ++j) {
+
+ /* See the comment in the earlier code; extras are sorted by size. */
+
+ if (afl->a_extras[j].len > len - i ||
+ !memcmp(afl->a_extras[j].data, out_buf + i, afl->a_extras[j].len) ||
+ !memchr(eff_map + EFF_APOS(i), 1,
+ EFF_SPAN_ALEN(i, afl->a_extras[j].len))) {
+
+ --afl->stage_max;
+ continue;
+
+ }
+
+ last_len = afl->a_extras[j].len;
+ memcpy(out_buf + i, afl->a_extras[j].data, last_len);
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation),
+ "%s AUTO_EXTRAS_overwrite-%u-%u", afl->queue_cur->fname, i, j);
+#endif
+
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+
+ ++afl->stage_cur;
+
+ }
+
+ /* Restore all the clobbered memory. */
+ memcpy(out_buf + i, in_buf + i, last_len);
+
+ }
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_EXTRAS_AO] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_EXTRAS_AO] += afl->stage_max;
+
+ /* Insertion of auto extras. */
+
+ afl->stage_name = "auto extras (insert)";
+ afl->stage_short = "ext_AI";
+ afl->stage_cur = 0;
+ afl->stage_max = afl->a_extras_cnt * (len + 1);
+
+ orig_hit_cnt = new_hit_cnt;
+
+ ex_tmp = afl_realloc(AFL_BUF_PARAM(ex), len + MAX_DICT_FILE);
+ if (unlikely(!ex_tmp)) { PFATAL("alloc"); }
+
+ for (i = 0; i <= (u32)len; ++i) {
+
+ afl->stage_cur_byte = i;
+
+ for (j = 0; j < afl->a_extras_cnt; ++j) {
+
+ if (len + afl->a_extras[j].len > MAX_FILE) {
+
+ --afl->stage_max;
+ continue;
+
+ }
+
+ /* Insert token */
+ memcpy(ex_tmp + i, afl->a_extras[j].data, afl->a_extras[j].len);
+
+ /* Copy tail */
+ memcpy(ex_tmp + i + afl->a_extras[j].len, out_buf + i, len - i);
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation),
+ "%s AUTO_EXTRAS_insert-%u-%u", afl->queue_cur->fname, i, j);
+#endif
+
+ if (common_fuzz_stuff(afl, ex_tmp, len + afl->a_extras[j].len)) {
+
+ goto abandon_entry;
+
+ }
+
+ ++afl->stage_cur;
+
+ }
+
+ /* Copy head */
+ ex_tmp[i] = out_buf[i];
+
+ }
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_EXTRAS_AI] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_EXTRAS_AI] += afl->stage_max;
+
+skip_extras:
+
+ /* If we made this to here without jumping to havoc_stage or abandon_entry,
+ we're properly done with deterministic steps and can mark it as such
+ in the .state/ directory. */
+
+ if (!afl->queue_cur->passed_det) { mark_as_det_done(afl, afl->queue_cur); }
+
+custom_mutator_stage:
+ /*******************
+ * CUSTOM MUTATORS *
+ *******************/
+
+ if (likely(!afl->custom_mutators_count)) { goto havoc_stage; }
+
+ afl->stage_name = "custom mutator";
+ afl->stage_short = "custom";
+ afl->stage_max = HAVOC_CYCLES * perf_score / afl->havoc_div / 100;
+ afl->stage_val_type = STAGE_VAL_NONE;
+ bool has_custom_fuzz = false;
+
+ if (afl->stage_max < HAVOC_MIN) { afl->stage_max = HAVOC_MIN; }
+
+ const u32 max_seed_size = MAX_FILE, saved_max = afl->stage_max;
+
+ orig_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+#ifdef INTROSPECTION
+ afl->mutation[0] = 0;
+#endif
+
+ LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+ if (el->afl_custom_fuzz) {
+
+ afl->current_custom_fuzz = el;
+
+ if (el->afl_custom_fuzz_count) {
+
+ afl->stage_max = el->afl_custom_fuzz_count(el->data, out_buf, len);
+
+ } else {
+
+ afl->stage_max = saved_max;
+
+ }
+
+ has_custom_fuzz = true;
+
+ afl->stage_short = el->name_short;
+
+ if (afl->stage_max) {
+
+ for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max;
+ ++afl->stage_cur) {
+
+ struct queue_entry *target = NULL;
+ u32 tid;
+ u8 * new_buf = NULL;
+ u32 target_len = 0;
+
+ /* check if splicing makes sense yet (enough entries) */
+ if (likely(afl->ready_for_splicing_count > 1)) {
+
+ /* Pick a random other queue entry for passing to external API
+ that has the necessary length */
+
+ do {
+
+ tid = rand_below(afl, afl->queued_items);
+
+ } while (unlikely(tid == afl->current_entry ||
+
+ afl->queue_buf[tid]->len < 4));
+
+ target = afl->queue_buf[tid];
+ afl->splicing_with = tid;
+
+ /* Read the additional testcase into a new buffer. */
+ new_buf = queue_testcase_get(afl, target);
+ target_len = target->len;
+
+ }
+
+ u8 *mutated_buf = NULL;
+
+ size_t mutated_size =
+ el->afl_custom_fuzz(el->data, out_buf, len, &mutated_buf, new_buf,
+ target_len, max_seed_size);
+
+ if (unlikely(!mutated_buf)) {
+
+ FATAL("Error in custom_fuzz. Size returned: %zu", mutated_size);
+
+ }
+
+ if (mutated_size > 0) {
+
+ if (common_fuzz_stuff(afl, mutated_buf, (u32)mutated_size)) {
+
+ goto abandon_entry;
+
+ }
+
+ if (!el->afl_custom_fuzz_count) {
+
+ /* If we're finding new stuff, let's run for a bit longer, limits
+ permitting. */
+
+ if (afl->queued_items != havoc_queued) {
+
+ if (perf_score <= afl->havoc_max_mult * 100) {
+
+ afl->stage_max *= 2;
+ perf_score *= 2;
+
+ }
+
+ havoc_queued = afl->queued_items;
+
+ }
+
+ }
+
+ }
+
+ /* out_buf may have been changed by the call to custom_fuzz */
+ memcpy(out_buf, in_buf, len);
+
+ }
+
+ }
+
+ }
+
+ });
+
+ afl->current_custom_fuzz = NULL;
+
+ if (!has_custom_fuzz) goto havoc_stage;
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_CUSTOM_MUTATOR] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_CUSTOM_MUTATOR] += afl->stage_max;
+
+ if (likely(afl->custom_only)) {
+
+ /* Skip other stages */
+ ret_val = 0;
+ goto abandon_entry;
+
+ }
+
+ /****************
+ * RANDOM HAVOC *
+ ****************/
+
+havoc_stage:
+
+ afl->stage_cur_byte = -1;
+
+ /* The havoc stage mutation code is also invoked when splicing files; if the
+ splice_cycle variable is set, generate different descriptions and such. */
+
+ if (!splice_cycle) {
+
+ afl->stage_name = "havoc";
+ afl->stage_short = "havoc";
+ afl->stage_max = (doing_det ? HAVOC_CYCLES_INIT : HAVOC_CYCLES) *
+ perf_score / afl->havoc_div / 100;
+
+ } else {
+
+ perf_score = orig_perf;
+
+ snprintf(afl->stage_name_buf, STAGE_BUF_SIZE, "splice %u", splice_cycle);
+ afl->stage_name = afl->stage_name_buf;
+ afl->stage_short = "splice";
+ afl->stage_max = SPLICE_HAVOC * perf_score / afl->havoc_div / 100;
+
+ }
+
+ if (afl->stage_max < HAVOC_MIN) { afl->stage_max = HAVOC_MIN; }
+
+ temp_len = len;
+
+ orig_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ havoc_queued = afl->queued_items;
+
+ if (afl->custom_mutators_count) {
+
+ LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+ if (el->stacked_custom && el->afl_custom_havoc_mutation_probability) {
+
+ el->stacked_custom_prob =
+ el->afl_custom_havoc_mutation_probability(el->data);
+ if (el->stacked_custom_prob > 100) {
+
+ FATAL(
+ "The probability returned by "
+ "afl_custom_havoc_mutation_propability "
+ "has to be in the range 0-100.");
+
+ }
+
+ }
+
+ });
+
+ }
+
+ /* We essentially just do several thousand runs (depending on perf_score)
+ where we take the input file and make random stacked tweaks. */
+
+#define MAX_HAVOC_ENTRY 64
+#define MUTATE_ASCII_DICT 64
+
+ u32 r_max, r;
+
+ r_max = (MAX_HAVOC_ENTRY + 1) + (afl->extras_cnt ? 4 : 0) +
+ (afl->a_extras_cnt
+ ? (unlikely(afl->cmplog_binary && afl->queue_cur->is_ascii)
+ ? MUTATE_ASCII_DICT
+ : 4)
+ : 0);
+
+ if (unlikely(afl->expand_havoc && afl->ready_for_splicing_count > 1)) {
+
+ /* add expensive havoc cases here, they are activated after a full
+ cycle without finds happened */
+
+ r_max += 4;
+
+ }
+
+ if (unlikely(get_cur_time() - afl->last_find_time > 5000 /* 5 seconds */ &&
+ afl->ready_for_splicing_count > 1)) {
+
+ /* add expensive havoc cases here if there is no findings in the last 5s */
+
+ r_max += 4;
+
+ }
+
+ for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) {
+
+ u32 use_stacking = 1 << (1 + rand_below(afl, afl->havoc_stack_pow2));
+
+ afl->stage_cur_val = use_stacking;
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s HAVOC-%u",
+ afl->queue_cur->fname, use_stacking);
+#endif
+
+ for (i = 0; i < use_stacking; ++i) {
+
+ if (afl->custom_mutators_count) {
+
+ LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+ if (el->stacked_custom &&
+ rand_below(afl, 100) < el->stacked_custom_prob) {
+
+ u8 * custom_havoc_buf = NULL;
+ size_t new_len = el->afl_custom_havoc_mutation(
+ el->data, out_buf, temp_len, &custom_havoc_buf, MAX_FILE);
+ if (unlikely(!custom_havoc_buf)) {
+
+ FATAL("Error in custom_havoc (return %zu)", new_len);
+
+ }
+
+ if (likely(new_len > 0 && custom_havoc_buf)) {
+
+ temp_len = new_len;
+ if (out_buf != custom_havoc_buf) {
+
+ out_buf = afl_realloc(AFL_BUF_PARAM(out), temp_len);
+ if (unlikely(!afl->out_buf)) { PFATAL("alloc"); }
+ memcpy(out_buf, custom_havoc_buf, temp_len);
+
+ }
+
+ }
+
+ }
+
+ });
+
+ }
+
+ switch ((r = rand_below(afl, r_max))) {
+
+ case 0 ... 3: {
+
+ /* Flip a single bit somewhere. Spooky! */
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " FLIP_BIT1");
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ FLIP_BIT(out_buf, rand_below(afl, temp_len << 3));
+ break;
+
+ }
+
+ case 4 ... 7: {
+
+ /* Set byte to interesting value. */
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING8");
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ out_buf[rand_below(afl, temp_len)] =
+ interesting_8[rand_below(afl, sizeof(interesting_8))];
+ break;
+
+ }
+
+ case 8 ... 9: {
+
+ /* Set word to interesting value, little endian. */
+
+ if (temp_len < 2) { break; }
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING16");
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) =
+ interesting_16[rand_below(afl, sizeof(interesting_16) >> 1)];
+
+ break;
+
+ }
+
+ case 10 ... 11: {
+
+ /* Set word to interesting value, big endian. */
+
+ if (temp_len < 2) { break; }
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING16BE");
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) = SWAP16(
+ interesting_16[rand_below(afl, sizeof(interesting_16) >> 1)]);
+
+ break;
+
+ }
+
+ case 12 ... 13: {
+
+ /* Set dword to interesting value, little endian. */
+
+ if (temp_len < 4) { break; }
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING32");
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) =
+ interesting_32[rand_below(afl, sizeof(interesting_32) >> 2)];
+
+ break;
+
+ }
+
+ case 14 ... 15: {
+
+ /* Set dword to interesting value, big endian. */
+
+ if (temp_len < 4) { break; }
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING32BE");
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) = SWAP32(
+ interesting_32[rand_below(afl, sizeof(interesting_32) >> 2)]);
+
+ break;
+
+ }
+
+ case 16 ... 19: {
+
+ /* Randomly subtract from byte. */
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH8_");
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ out_buf[rand_below(afl, temp_len)] -= 1 + rand_below(afl, ARITH_MAX);
+ break;
+
+ }
+
+ case 20 ... 23: {
+
+ /* Randomly add to byte. */
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH8+");
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ out_buf[rand_below(afl, temp_len)] += 1 + rand_below(afl, ARITH_MAX);
+ break;
+
+ }
+
+ case 24 ... 25: {
+
+ /* Randomly subtract from word, little endian. */
+
+ if (temp_len < 2) { break; }
+
+ u32 pos = rand_below(afl, temp_len - 1);
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16_-%u", pos);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ *(u16 *)(out_buf + pos) -= 1 + rand_below(afl, ARITH_MAX);
+
+ break;
+
+ }
+
+ case 26 ... 27: {
+
+ /* Randomly subtract from word, big endian. */
+
+ if (temp_len < 2) { break; }
+
+ u32 pos = rand_below(afl, temp_len - 1);
+ u16 num = 1 + rand_below(afl, ARITH_MAX);
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16_BE-%u_%u", pos,
+ num);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ *(u16 *)(out_buf + pos) =
+ SWAP16(SWAP16(*(u16 *)(out_buf + pos)) - num);
+
+ break;
+
+ }
+
+ case 28 ... 29: {
+
+ /* Randomly add to word, little endian. */
+
+ if (temp_len < 2) { break; }
+
+ u32 pos = rand_below(afl, temp_len - 1);
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16+-%u", pos);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ *(u16 *)(out_buf + pos) += 1 + rand_below(afl, ARITH_MAX);
+
+ break;
+
+ }
+
+ case 30 ... 31: {
+
+ /* Randomly add to word, big endian. */
+
+ if (temp_len < 2) { break; }
+
+ u32 pos = rand_below(afl, temp_len - 1);
+ u16 num = 1 + rand_below(afl, ARITH_MAX);
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16+BE-%u_%u", pos,
+ num);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ *(u16 *)(out_buf + pos) =
+ SWAP16(SWAP16(*(u16 *)(out_buf + pos)) + num);
+
+ break;
+
+ }
+
+ case 32 ... 33: {
+
+ /* Randomly subtract from dword, little endian. */
+
+ if (temp_len < 4) { break; }
+
+ u32 pos = rand_below(afl, temp_len - 3);
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32_-%u", pos);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ *(u32 *)(out_buf + pos) -= 1 + rand_below(afl, ARITH_MAX);
+
+ break;
+
+ }
+
+ case 34 ... 35: {
+
+ /* Randomly subtract from dword, big endian. */
+
+ if (temp_len < 4) { break; }
+
+ u32 pos = rand_below(afl, temp_len - 3);
+ u32 num = 1 + rand_below(afl, ARITH_MAX);
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32_BE-%u-%u", pos,
+ num);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ *(u32 *)(out_buf + pos) =
+ SWAP32(SWAP32(*(u32 *)(out_buf + pos)) - num);
+
+ break;
+
+ }
+
+ case 36 ... 37: {
+
+ /* Randomly add to dword, little endian. */
+
+ if (temp_len < 4) { break; }
+
+ u32 pos = rand_below(afl, temp_len - 3);
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32+-%u", pos);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ *(u32 *)(out_buf + pos) += 1 + rand_below(afl, ARITH_MAX);
+
+ break;
+
+ }
+
+ case 38 ... 39: {
+
+ /* Randomly add to dword, big endian. */
+
+ if (temp_len < 4) { break; }
+
+ u32 pos = rand_below(afl, temp_len - 3);
+ u32 num = 1 + rand_below(afl, ARITH_MAX);
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32+BE-%u-%u", pos,
+ num);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ *(u32 *)(out_buf + pos) =
+ SWAP32(SWAP32(*(u32 *)(out_buf + pos)) + num);
+
+ break;
+
+ }
+
+ case 40 ... 43: {
+
+ /* Just set a random byte to a random value. Because,
+ why not. We use XOR with 1-255 to eliminate the
+ possibility of a no-op. */
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " RAND8");
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ out_buf[rand_below(afl, temp_len)] ^= 1 + rand_below(afl, 255);
+ break;
+
+ }
+
+ case 44 ... 46: {
+
+ if (temp_len + HAVOC_BLK_XL < MAX_FILE) {
+
+ /* Clone bytes. */
+
+ u32 clone_len = choose_block_len(afl, temp_len);
+ u32 clone_from = rand_below(afl, temp_len - clone_len + 1);
+ u32 clone_to = rand_below(afl, temp_len);
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " CLONE-%s-%u-%u-%u",
+ "clone", clone_from, clone_to, clone_len);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ u8 *new_buf =
+ afl_realloc(AFL_BUF_PARAM(out_scratch), temp_len + clone_len);
+ if (unlikely(!new_buf)) { PFATAL("alloc"); }
+
+ /* Head */
+
+ memcpy(new_buf, out_buf, clone_to);
+
+ /* Inserted part */
+
+ memcpy(new_buf + clone_to, out_buf + clone_from, clone_len);
+
+ /* Tail */
+ memcpy(new_buf + clone_to + clone_len, out_buf + clone_to,
+ temp_len - clone_to);
+
+ out_buf = new_buf;
+ afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
+ temp_len += clone_len;
+
+ }
+
+ break;
+
+ }
+
+ case 47: {
+
+ if (temp_len + HAVOC_BLK_XL < MAX_FILE) {
+
+ /* Insert a block of constant bytes (25%). */
+
+ u32 clone_len = choose_block_len(afl, HAVOC_BLK_XL);
+ u32 clone_to = rand_below(afl, temp_len);
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " CLONE-%s-%u-%u",
+ "insert", clone_to, clone_len);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ u8 *new_buf =
+ afl_realloc(AFL_BUF_PARAM(out_scratch), temp_len + clone_len);
+ if (unlikely(!new_buf)) { PFATAL("alloc"); }
+
+ /* Head */
+
+ memcpy(new_buf, out_buf, clone_to);
+
+ /* Inserted part */
+
+ memset(new_buf + clone_to,
+ rand_below(afl, 2) ? rand_below(afl, 256)
+ : out_buf[rand_below(afl, temp_len)],
+ clone_len);
+
+ /* Tail */
+ memcpy(new_buf + clone_to + clone_len, out_buf + clone_to,
+ temp_len - clone_to);
+
+ out_buf = new_buf;
+ afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
+ temp_len += clone_len;
+
+ }
+
+ break;
+
+ }
+
+ case 48 ... 50: {
+
+ /* Overwrite bytes with a randomly selected chunk bytes. */
+
+ if (temp_len < 2) { break; }
+
+ u32 copy_len = choose_block_len(afl, temp_len - 1);
+ u32 copy_from = rand_below(afl, temp_len - copy_len + 1);
+ u32 copy_to = rand_below(afl, temp_len - copy_len + 1);
+
+ if (likely(copy_from != copy_to)) {
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " OVERWRITE_COPY-%u-%u-%u",
+ copy_from, copy_to, copy_len);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ memmove(out_buf + copy_to, out_buf + copy_from, copy_len);
+
+ }
+
+ break;
+
+ }
+
+ case 51: {
+
+ /* Overwrite bytes with fixed bytes. */
+
+ if (temp_len < 2) { break; }
+
+ u32 copy_len = choose_block_len(afl, temp_len - 1);
+ u32 copy_to = rand_below(afl, temp_len - copy_len + 1);
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " OVERWRITE_FIXED-%u-%u",
+ copy_to, copy_len);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ memset(out_buf + copy_to,
+ rand_below(afl, 2) ? rand_below(afl, 256)
+ : out_buf[rand_below(afl, temp_len)],
+ copy_len);
+
+ break;
+
+ }
+
+ case 52: {
+
+ /* Increase byte by 1. */
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ADDBYTE_");
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ out_buf[rand_below(afl, temp_len)]++;
+ break;
+
+ }
+
+ case 53: {
+
+ /* Decrease byte by 1. */
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " SUBBYTE_");
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ out_buf[rand_below(afl, temp_len)]++;
+ break;
+
+ }
+
+ case 54: {
+
+ /* Flip byte. */
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " FLIP8_");
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ out_buf[rand_below(afl, temp_len)] ^= 0xff;
+ break;
+
+ }
+
+ case 55 ... 56: {
+
+ if (temp_len < 4) { break; }
+
+ /* Switch bytes. */
+
+ u32 to_end, switch_to, switch_len, switch_from;
+ switch_from = rand_below(afl, temp_len);
+ do {
+
+ switch_to = rand_below(afl, temp_len);
+
+ } while (switch_from == switch_to);
+
+ if (switch_from < switch_to) {
+
+ switch_len = switch_to - switch_from;
+ to_end = temp_len - switch_to;
+
+ } else {
+
+ switch_len = switch_from - switch_to;
+ to_end = temp_len - switch_from;
+
+ }
+
+ switch_len = choose_block_len(afl, MIN(switch_len, to_end));
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " SWITCH-%s-%u-%u-%u",
+ "switch", switch_from, switch_to, switch_len);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ u8 *new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), switch_len);
+ if (unlikely(!new_buf)) { PFATAL("alloc"); }
+
+ /* Backup */
+
+ memcpy(new_buf, out_buf + switch_from, switch_len);
+
+ /* Switch 1 */
+
+ memcpy(out_buf + switch_from, out_buf + switch_to, switch_len);
+
+ /* Switch 2 */
+
+ memcpy(out_buf + switch_to, new_buf, switch_len);
+
+ break;
+
+ }
+
+ // MAX_HAVOC_ENTRY = 64
+ case 57 ... MAX_HAVOC_ENTRY: {
+
+ /* Delete bytes. */
+
+ if (temp_len < 2) { break; }
+
+ /* Don't delete too much. */
+
+ u32 del_len = choose_block_len(afl, temp_len - 1);
+ u32 del_from = rand_below(afl, temp_len - del_len + 1);
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " DEL-%u-%u", del_from,
+ del_len);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ memmove(out_buf + del_from, out_buf + del_from + del_len,
+ temp_len - del_from - del_len);
+
+ temp_len -= del_len;
+
+ break;
+
+ }
+
+ default:
+
+ r -= (MAX_HAVOC_ENTRY + 1);
+
+ if (afl->extras_cnt) {
+
+ if (r < 2) {
+
+ /* Use the dictionary. */
+
+ u32 use_extra = rand_below(afl, afl->extras_cnt);
+ u32 extra_len = afl->extras[use_extra].len;
+
+ if (extra_len > temp_len) { break; }
+
+ u32 insert_at = rand_below(afl, temp_len - extra_len + 1);
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " EXTRA_OVERWRITE-%u-%u",
+ insert_at, extra_len);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ memcpy(out_buf + insert_at, afl->extras[use_extra].data,
+ extra_len);
+
+ break;
+
+ } else if (r < 4) {
+
+ u32 use_extra = rand_below(afl, afl->extras_cnt);
+ u32 extra_len = afl->extras[use_extra].len;
+ if (temp_len + extra_len >= MAX_FILE) { break; }
+
+ u8 *ptr = afl->extras[use_extra].data;
+ u32 insert_at = rand_below(afl, temp_len + 1);
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " EXTRA_INSERT-%u-%u",
+ insert_at, extra_len);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+
+ out_buf = afl_realloc(AFL_BUF_PARAM(out), temp_len + extra_len);
+ if (unlikely(!out_buf)) { PFATAL("alloc"); }
+
+ /* Tail */
+ memmove(out_buf + insert_at + extra_len, out_buf + insert_at,
+ temp_len - insert_at);
+
+ /* Inserted part */
+ memcpy(out_buf + insert_at, ptr, extra_len);
+ temp_len += extra_len;
+
+ break;
+
+ } else {
+
+ r -= 4;
+
+ }
+
+ }
+
+ if (afl->a_extras_cnt) {
+
+ u32 r_cmp = 2;
+
+ if (unlikely(afl->cmplog_binary && afl->queue_cur->is_ascii)) {
+
+ r_cmp = MUTATE_ASCII_DICT >> 1;
+
+ }
+
+ if (r < r_cmp) {
+
+ /* Use the dictionary. */
+
+ u32 use_extra = rand_below(afl, afl->a_extras_cnt);
+ u32 extra_len = afl->a_extras[use_extra].len;
+
+ if (extra_len > temp_len) { break; }
+
+ u32 insert_at = rand_below(afl, temp_len - extra_len + 1);
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp),
+ " AUTO_EXTRA_OVERWRITE-%u-%u", insert_at, extra_len);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ memcpy(out_buf + insert_at, afl->a_extras[use_extra].data,
+ extra_len);
+
+ break;
+
+ } else if (r < (r_cmp << 1)) {
+
+ u32 use_extra = rand_below(afl, afl->a_extras_cnt);
+ u32 extra_len = afl->a_extras[use_extra].len;
+ if (temp_len + extra_len >= MAX_FILE) { break; }
+
+ u8 *ptr = afl->a_extras[use_extra].data;
+ u32 insert_at = rand_below(afl, temp_len + 1);
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp),
+ " AUTO_EXTRA_INSERT-%u-%u", insert_at, extra_len);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+
+ out_buf = afl_realloc(AFL_BUF_PARAM(out), temp_len + extra_len);
+ if (unlikely(!out_buf)) { PFATAL("alloc"); }
+
+ /* Tail */
+ memmove(out_buf + insert_at + extra_len, out_buf + insert_at,
+ temp_len - insert_at);
+
+ /* Inserted part */
+ memcpy(out_buf + insert_at, ptr, extra_len);
+ temp_len += extra_len;
+
+ break;
+
+ } else {
+
+ r -= (r_cmp << 1);
+
+ }
+
+ }
+
+ /* Splicing otherwise if we are still here.
+ Overwrite bytes with a randomly selected chunk from another
+ testcase or insert that chunk. */
+
+ /* Pick a random queue entry and seek to it. */
+
+ u32 tid;
+ do {
+
+ tid = rand_below(afl, afl->queued_items);
+
+ } while (tid == afl->current_entry || afl->queue_buf[tid]->len < 4);
+
+ /* Get the testcase for splicing. */
+ struct queue_entry *target = afl->queue_buf[tid];
+ u32 new_len = target->len;
+ u8 * new_buf = queue_testcase_get(afl, target);
+
+ if ((temp_len >= 2 && r % 2) || temp_len + HAVOC_BLK_XL >= MAX_FILE) {
+
+ /* overwrite mode */
+
+ u32 copy_from, copy_to, copy_len;
+
+ copy_len = choose_block_len(afl, new_len - 1);
+ if (copy_len > temp_len) copy_len = temp_len;
+
+ copy_from = rand_below(afl, new_len - copy_len + 1);
+ copy_to = rand_below(afl, temp_len - copy_len + 1);
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp),
+ " SPLICE_OVERWRITE-%u-%u-%u-%s", copy_from, copy_to,
+ copy_len, target->fname);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ memmove(out_buf + copy_to, new_buf + copy_from, copy_len);
+
+ } else {
+
+ /* insert mode */
+
+ u32 clone_from, clone_to, clone_len;
+
+ clone_len = choose_block_len(afl, new_len);
+ clone_from = rand_below(afl, new_len - clone_len + 1);
+ clone_to = rand_below(afl, temp_len + 1);
+
+ u8 *temp_buf = afl_realloc(AFL_BUF_PARAM(out_scratch),
+ temp_len + clone_len + 1);
+ if (unlikely(!temp_buf)) { PFATAL("alloc"); }
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp),
+ " SPLICE_INSERT-%u-%u-%u-%s", clone_from, clone_to,
+ clone_len, target->fname);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ /* Head */
+
+ memcpy(temp_buf, out_buf, clone_to);
+
+ /* Inserted part */
+
+ memcpy(temp_buf + clone_to, new_buf + clone_from, clone_len);
+
+ /* Tail */
+ memcpy(temp_buf + clone_to + clone_len, out_buf + clone_to,
+ temp_len - clone_to);
+
+ out_buf = temp_buf;
+ afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
+ temp_len += clone_len;
+
+ }
+
+ break;
+
+ // end of default
+
+ }
+
+ }
+
+ if (common_fuzz_stuff(afl, out_buf, temp_len)) { goto abandon_entry; }
+
+ /* out_buf might have been mangled a bit, so let's restore it to its
+ original size and shape. */
+
+ out_buf = afl_realloc(AFL_BUF_PARAM(out), len);
+ if (unlikely(!out_buf)) { PFATAL("alloc"); }
+ temp_len = len;
+ memcpy(out_buf, in_buf, len);
+
+ /* If we're finding new stuff, let's run for a bit longer, limits
+ permitting. */
+
+ if (afl->queued_items != havoc_queued) {
+
+ if (perf_score <= afl->havoc_max_mult * 100) {
+
+ afl->stage_max *= 2;
+ perf_score *= 2;
+
+ }
+
+ havoc_queued = afl->queued_items;
+
+ }
+
+ }
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ if (!splice_cycle) {
+
+ afl->stage_finds[STAGE_HAVOC] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_HAVOC] += afl->stage_max;
+
+ } else {
+
+ afl->stage_finds[STAGE_SPLICE] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_SPLICE] += afl->stage_max;
+
+ }
+
+#ifndef IGNORE_FINDS
+
+ /************
+ * SPLICING *
+ ************/
+
+ /* This is a last-resort strategy triggered by a full round with no findings.
+ It takes the current input file, randomly selects another input, and
+ splices them together at some offset, then relies on the havoc
+ code to mutate that blob. */
+
+retry_splicing:
+
+ if (afl->use_splicing && splice_cycle++ < SPLICE_CYCLES &&
+ afl->ready_for_splicing_count > 1 && afl->queue_cur->len >= 4) {
+
+ struct queue_entry *target;
+ u32 tid, split_at;
+ u8 * new_buf;
+ s32 f_diff, l_diff;
+
+ /* First of all, if we've modified in_buf for havoc, let's clean that
+ up... */
+
+ if (in_buf != orig_in) {
+
+ in_buf = orig_in;
+ len = afl->queue_cur->len;
+
+ }
+
+ /* Pick a random queue entry and seek to it. Don't splice with yourself. */
+
+ do {
+
+ tid = rand_below(afl, afl->queued_items);
+
+ } while (tid == afl->current_entry || afl->queue_buf[tid]->len < 4);
+
+ /* Get the testcase */
+ afl->splicing_with = tid;
+ target = afl->queue_buf[tid];
+ new_buf = queue_testcase_get(afl, target);
+
+ /* Find a suitable splicing location, somewhere between the first and
+ the last differing byte. Bail out if the difference is just a single
+ byte or so. */
+
+ locate_diffs(in_buf, new_buf, MIN(len, (s64)target->len), &f_diff, &l_diff);
+
+ if (f_diff < 0 || l_diff < 2 || f_diff == l_diff) { goto retry_splicing; }
+
+ /* Split somewhere between the first and last differing byte. */
+
+ split_at = f_diff + rand_below(afl, l_diff - f_diff);
+
+ /* Do the thing. */
+
+ len = target->len;
+ afl->in_scratch_buf = afl_realloc(AFL_BUF_PARAM(in_scratch), len);
+ memcpy(afl->in_scratch_buf, in_buf, split_at);
+ memcpy(afl->in_scratch_buf + split_at, new_buf, len - split_at);
+ in_buf = afl->in_scratch_buf;
+ afl_swap_bufs(AFL_BUF_PARAM(in), AFL_BUF_PARAM(in_scratch));
+
+ out_buf = afl_realloc(AFL_BUF_PARAM(out), len);
+ if (unlikely(!out_buf)) { PFATAL("alloc"); }
+ memcpy(out_buf, in_buf, len);
+
+ goto custom_mutator_stage;
+
+ }
+
+#endif /* !IGNORE_FINDS */
+
+ ret_val = 0;
+
+/* we are through with this queue entry - for this iteration */
+abandon_entry:
+
+ afl->splicing_with = -1;
+
+ /* Update afl->pending_not_fuzzed count if we made it through the calibration
+ cycle and have not seen this entry before. */
+
+ if (!afl->stop_soon && !afl->queue_cur->cal_failed &&
+ !afl->queue_cur->was_fuzzed && !afl->queue_cur->disabled) {
+
+ --afl->pending_not_fuzzed;
+ afl->queue_cur->was_fuzzed = 1;
+ afl->reinit_table = 1;
+ if (afl->queue_cur->favored) { --afl->pending_favored; }
+
+ }
+
+ ++afl->queue_cur->fuzz_level;
+ orig_in = NULL;
+ return ret_val;
+
+#undef FLIP_BIT
+
+}
+
+/* MOpt mode */
+static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
+
+ if (!MOpt_globals.is_pilot_mode) {
+
+ if (swarm_num == 1) {
+
+ afl->key_module = 2;
+ return 0;
+
+ }
+
+ }
+
+ u32 len, temp_len;
+ u32 i;
+ u32 j;
+ u8 *in_buf, *out_buf, *orig_in, *ex_tmp, *eff_map = 0;
+ u64 havoc_queued = 0, orig_hit_cnt, new_hit_cnt = 0, cur_ms_lv, prev_cksum,
+ _prev_cksum;
+ u32 splice_cycle = 0, perf_score = 100, orig_perf, eff_cnt = 1;
+
+ u8 ret_val = 1, doing_det = 0;
+
+ u8 a_collect[MAX_AUTO_EXTRA];
+ u32 a_len = 0;
+
+#ifdef IGNORE_FINDS
+
+ /* In IGNORE_FINDS mode, skip any entries that weren't in the
+ initial data set. */
+
+ if (afl->queue_cur->depth > 1) return 1;
+
+#else
+
+ if (likely(afl->pending_favored)) {
+
+ /* If we have any favored, non-fuzzed new arrivals in the queue,
+ possibly skip to them at the expense of already-fuzzed or non-favored
+ cases. */
+
+ if ((afl->queue_cur->fuzz_level || !afl->queue_cur->favored) &&
+ rand_below(afl, 100) < SKIP_TO_NEW_PROB) {
+
+ return 1;
+
+ }
+
+ } else if (!afl->non_instrumented_mode && !afl->queue_cur->favored &&
+
+ afl->queued_items > 10) {
+
+ /* Otherwise, still possibly skip non-favored cases, albeit less often.
+ The odds of skipping stuff are higher for already-fuzzed inputs and
+ lower for never-fuzzed entries. */
+
+ if (afl->queue_cycle > 1 && !afl->queue_cur->fuzz_level) {
+
+ if (likely(rand_below(afl, 100) < SKIP_NFAV_NEW_PROB)) { return 1; }
+
+ } else {
+
+ if (likely(rand_below(afl, 100) < SKIP_NFAV_OLD_PROB)) { return 1; }
+
+ }
+
+ }
+
+#endif /* ^IGNORE_FINDS */
+
+ if (afl->not_on_tty) {
+
+ ACTF("Fuzzing test case #%u (%u total, %llu crashes saved)...",
+ afl->current_entry, afl->queued_items, afl->saved_crashes);
+ fflush(stdout);
+
+ }
+
+ /* Map the test case into memory. */
+ orig_in = in_buf = queue_testcase_get(afl, afl->queue_cur);
+ len = afl->queue_cur->len;
+
+ out_buf = afl_realloc(AFL_BUF_PARAM(out), len);
+ if (unlikely(!out_buf)) { PFATAL("alloc"); }
+
+ afl->subseq_tmouts = 0;
+
+ afl->cur_depth = afl->queue_cur->depth;
+
+ /*******************************************
+ * CALIBRATION (only if failed earlier on) *
+ *******************************************/
+
+ if (unlikely(afl->queue_cur->cal_failed)) {
+
+ u8 res = FSRV_RUN_TMOUT;
+
+ if (afl->queue_cur->cal_failed < CAL_CHANCES) {
+
+ afl->queue_cur->exec_cksum = 0;
+
+ res =
+ calibrate_case(afl, afl->queue_cur, in_buf, afl->queue_cycle - 1, 0);
+
+ if (res == FSRV_RUN_ERROR) {
+
+ FATAL("Unable to execute target application");
+
+ }
+
+ }
+
+ if (afl->stop_soon || res != afl->crash_mode) {
+
+ ++afl->cur_skipped_items;
+ goto abandon_entry;
+
+ }
+
+ }
+
+ /************
+ * TRIMMING *
+ ************/
+
+ if (unlikely(!afl->non_instrumented_mode && !afl->queue_cur->trim_done &&
+ !afl->disable_trim)) {
+
+ u32 old_len = afl->queue_cur->len;
+
+ u8 res = trim_case(afl, afl->queue_cur, in_buf);
+ orig_in = in_buf = queue_testcase_get(afl, afl->queue_cur);
+
+ if (unlikely(res == FSRV_RUN_ERROR)) {
+
+ FATAL("Unable to execute target application");
+
+ }
+
+ if (unlikely(afl->stop_soon)) {
+
+ ++afl->cur_skipped_items;
+ goto abandon_entry;
+
+ }
+
+ /* Don't retry trimming, even if it failed. */
+
+ afl->queue_cur->trim_done = 1;
+
+ len = afl->queue_cur->len;
+
+ /* maybe current entry is not ready for splicing anymore */
+ if (unlikely(len <= 4 && old_len > 4)) --afl->ready_for_splicing_count;
+
+ }
+
+ memcpy(out_buf, in_buf, len);
+
+ /*********************
+ * PERFORMANCE SCORE *
+ *********************/
+
+ if (likely(!afl->old_seed_selection))
+ orig_perf = perf_score = afl->queue_cur->perf_score;
+ else
+ orig_perf = perf_score = calculate_score(afl, afl->queue_cur);
+
+ if (unlikely(perf_score <= 0 && afl->active_items > 1)) {
+
+ goto abandon_entry;
+
+ }
+
+ if (unlikely(afl->shm.cmplog_mode &&
+ afl->queue_cur->colorized < afl->cmplog_lvl &&
+ (u32)len <= afl->cmplog_max_filesize)) {
+
+ if (unlikely(len < 4)) {
+
+ afl->queue_cur->colorized = CMPLOG_LVL_MAX;
+
+ } else {
+
+ if (afl->cmplog_lvl == 3 ||
+ (afl->cmplog_lvl == 2 && afl->queue_cur->tc_ref) ||
+ !(afl->fsrv.total_execs % afl->queued_items) ||
+ get_cur_time() - afl->last_find_time > 300000) { // 300 seconds
+
+ if (input_to_state_stage(afl, in_buf, out_buf, len)) {
+
+ goto abandon_entry;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ /* Go to pacemker fuzzing if MOpt is doing well */
+
+ cur_ms_lv = get_cur_time();
+ if (!(afl->key_puppet == 0 &&
+ ((cur_ms_lv - afl->last_find_time < (u32)afl->limit_time_puppet) ||
+ (afl->last_crash_time != 0 &&
+ cur_ms_lv - afl->last_crash_time < (u32)afl->limit_time_puppet) ||
+ afl->last_find_time == 0))) {
+
+ afl->key_puppet = 1;
+ goto pacemaker_fuzzing;
+
+ }
+
+ /* Skip right away if -d is given, if we have done deterministic fuzzing on
+ this entry ourselves (was_fuzzed), or if it has gone through deterministic
+ testing in earlier, resumed runs (passed_det). */
+
+ if (likely(afl->skip_deterministic || afl->queue_cur->was_fuzzed ||
+ afl->queue_cur->passed_det)) {
+
+ goto havoc_stage;
+
+ }
+
+ /* Skip deterministic fuzzing if exec path checksum puts this out of scope
+ for this main instance. */
+
+ if (unlikely(afl->main_node_max &&
+ (afl->queue_cur->exec_cksum % afl->main_node_max) !=
+ afl->main_node_id - 1)) {
+
+ goto havoc_stage;
+
+ }
+
+ doing_det = 1;
+
+ /*********************************************
+ * SIMPLE BITFLIP (+dictionary construction) *
+ *********************************************/
+
+#define FLIP_BIT(_ar, _b) \
+ do { \
+ \
+ u8 *_arf = (u8 *)(_ar); \
+ u32 _bf = (_b); \
+ _arf[(_bf) >> 3] ^= (128 >> ((_bf)&7)); \
+ \
+ } while (0)
+
+ /* Single walking bit. */
+
+ afl->stage_short = "flip1";
+ afl->stage_max = len << 3;
+ afl->stage_name = "bitflip 1/1";
+
+ afl->stage_val_type = STAGE_VAL_NONE;
+
+ orig_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ /* Get a clean cksum. */
+
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+
+ prev_cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
+ _prev_cksum = prev_cksum;
+
+ /* Now flip bits. */
+
+ for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) {
+
+ afl->stage_cur_byte = afl->stage_cur >> 3;
+
+ FLIP_BIT(out_buf, afl->stage_cur);
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s MOPT_FLIP_BIT1-%u",
+ afl->queue_cur->fname, afl->stage_cur);
+#endif
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+
+ FLIP_BIT(out_buf, afl->stage_cur);
+
+ /* While flipping the least significant bit in every byte, pull of an extra
+ trick to detect possible syntax tokens. In essence, the idea is that if
+ you have a binary blob like this:
+
+ xxxxxxxxIHDRxxxxxxxx
+
+ ...and changing the leading and trailing bytes causes variable or no
+ changes in program flow, but touching any character in the "IHDR" string
+ always produces the same, distinctive path, it's highly likely that
+ "IHDR" is an atomically-checked magic value of special significance to
+ the fuzzed format.
+
+ We do this here, rather than as a separate stage, because it's a nice
+ way to keep the operation approximately "free" (i.e., no extra execs).
+
+ Empirically, performing the check when flipping the least significant bit
+ is advantageous, compared to doing it at the time of more disruptive
+ changes, where the program flow may be affected in more violent ways.
+
+ The caveat is that we won't generate dictionaries in the -d mode or -S
+ mode - but that's probably a fair trade-off.
+
+ This won't work particularly well with paths that exhibit variable
+ behavior, but fails gracefully, so we'll carry out the checks anyway.
+
+ */
+
+ if (!afl->non_instrumented_mode && (afl->stage_cur & 7) == 7) {
+
+ u64 cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
+
+ if (afl->stage_cur == afl->stage_max - 1 && cksum == prev_cksum) {
+
+ /* If at end of file and we are still collecting a string, grab the
+ final character and force output. */
+
+ if (a_len < MAX_AUTO_EXTRA) {
+
+ a_collect[a_len] = out_buf[afl->stage_cur >> 3];
+
+ }
+
+ ++a_len;
+
+ if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA) {
+
+ maybe_add_auto(afl, a_collect, a_len);
+
+ }
+
+ } else if (cksum != prev_cksum) {
+
+ /* Otherwise, if the checksum has changed, see if we have something
+ worthwhile queued up, and collect that if the answer is yes. */
+
+ if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA) {
+
+ maybe_add_auto(afl, a_collect, a_len);
+
+ }
+
+ a_len = 0;
+ prev_cksum = cksum;
+
+ }
+
+ /* Continue collecting string, but only if the bit flip actually made
+ any difference - we don't want no-op tokens. */
+
+ if (cksum != _prev_cksum) {
+
+ if (a_len < MAX_AUTO_EXTRA) {
+
+ a_collect[a_len] = out_buf[afl->stage_cur >> 3];
+
+ }
+
+ ++a_len;
+
+ }
+
+ } /* if (afl->stage_cur & 7) == 7 */
+
+ } /* for afl->stage_cur */
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_FLIP1] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_FLIP1] += afl->stage_max;
+
+ /* Two walking bits. */
+
+ afl->stage_name = "bitflip 2/1";
+ afl->stage_short = "flip2";
+ afl->stage_max = (len << 3) - 1;
+
+ orig_hit_cnt = new_hit_cnt;
+
+ for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) {
+
+ afl->stage_cur_byte = afl->stage_cur >> 3;
+
+ FLIP_BIT(out_buf, afl->stage_cur);
+ FLIP_BIT(out_buf, afl->stage_cur + 1);
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s MOPT_FLIP_BIT2-%u",
+ afl->queue_cur->fname, afl->stage_cur);
+#endif
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+
+ FLIP_BIT(out_buf, afl->stage_cur);
+ FLIP_BIT(out_buf, afl->stage_cur + 1);
+
+ } /* for afl->stage_cur */
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_FLIP2] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_FLIP2] += afl->stage_max;
+
+ /* Four walking bits. */
+
+ afl->stage_name = "bitflip 4/1";
+ afl->stage_short = "flip4";
+ afl->stage_max = (len << 3) - 3;
+
+ orig_hit_cnt = new_hit_cnt;
+
+ for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) {
+
+ afl->stage_cur_byte = afl->stage_cur >> 3;
+
+ FLIP_BIT(out_buf, afl->stage_cur);
+ FLIP_BIT(out_buf, afl->stage_cur + 1);
+ FLIP_BIT(out_buf, afl->stage_cur + 2);
+ FLIP_BIT(out_buf, afl->stage_cur + 3);
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s MOPT_FLIP_BIT4-%u",
+ afl->queue_cur->fname, afl->stage_cur);
+#endif
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+
+ FLIP_BIT(out_buf, afl->stage_cur);
+ FLIP_BIT(out_buf, afl->stage_cur + 1);
+ FLIP_BIT(out_buf, afl->stage_cur + 2);
+ FLIP_BIT(out_buf, afl->stage_cur + 3);
+
+ } /* for afl->stage_cur */
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_FLIP4] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_FLIP4] += afl->stage_max;
+
+ /* Effector map setup. These macros calculate:
+
+ EFF_APOS - position of a particular file offset in the map.
+ EFF_ALEN - length of a map with a particular number of bytes.
+ EFF_SPAN_ALEN - map span for a sequence of bytes.
+
+ */
+
+#define EFF_APOS(_p) ((_p) >> EFF_MAP_SCALE2)
+#define EFF_REM(_x) ((_x) & ((1 << EFF_MAP_SCALE2) - 1))
+#define EFF_ALEN(_l) (EFF_APOS(_l) + !!EFF_REM(_l))
+#define EFF_SPAN_ALEN(_p, _l) (EFF_APOS((_p) + (_l)-1) - EFF_APOS(_p) + 1)
+
+ /* Initialize effector map for the next step (see comments below). Always
+ flag first and last byte as doing something. */
+
+ eff_map = afl_realloc(AFL_BUF_PARAM(eff), EFF_ALEN(len));
+ if (unlikely(!eff_map)) { PFATAL("alloc"); }
+ eff_map[0] = 1;
+
+ if (EFF_APOS(len - 1) != 0) {
+
+ eff_map[EFF_APOS(len - 1)] = 1;
+ ++eff_cnt;
+
+ }
+
+ /* Walking byte. */
+
+ afl->stage_name = "bitflip 8/8";
+ afl->stage_short = "flip8";
+ afl->stage_max = len;
+
+ orig_hit_cnt = new_hit_cnt;
+ prev_cksum = _prev_cksum;
+
+ for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) {
+
+ afl->stage_cur_byte = afl->stage_cur;
+
+ out_buf[afl->stage_cur] ^= 0xFF;
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s MOPT_FLIP_BIT8-%u",
+ afl->queue_cur->fname, afl->stage_cur);
+#endif
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+
+ /* We also use this stage to pull off a simple trick: we identify
+ bytes that seem to have no effect on the current execution path
+ even when fully flipped - and we skip them during more expensive
+ deterministic stages, such as arithmetics or known ints. */
+
+ if (!eff_map[EFF_APOS(afl->stage_cur)]) {
+
+ u64 cksum;
+
+ /* If in non-instrumented mode or if the file is very short, just flag
+ everything without wasting time on checksums. */
+
+ if (!afl->non_instrumented_mode && len >= EFF_MIN_LEN) {
+
+ cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
+
+ } else {
+
+ cksum = ~prev_cksum;
+
+ }
+
+ if (cksum != prev_cksum) {
+
+ eff_map[EFF_APOS(afl->stage_cur)] = 1;
+ ++eff_cnt;
+
+ }
+
+ }
+
+ out_buf[afl->stage_cur] ^= 0xFF;
+
+ } /* for afl->stage_cur */
+
+ /* If the effector map is more than EFF_MAX_PERC dense, just flag the
+ whole thing as worth fuzzing, since we wouldn't be saving much time
+ anyway. */
+
+ if (eff_cnt != (u32)EFF_ALEN(len) &&
+ eff_cnt * 100 / EFF_ALEN(len) > EFF_MAX_PERC) {
+
+ memset(eff_map, 1, EFF_ALEN(len));
+
+ afl->blocks_eff_select += EFF_ALEN(len);
+
+ } else {
+
+ afl->blocks_eff_select += eff_cnt;
+
+ }
+
+ afl->blocks_eff_total += EFF_ALEN(len);
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_FLIP8] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_FLIP8] += afl->stage_max;
+
+ /* Two walking bytes. */
+
+ if (len < 2) { goto skip_bitflip; }
+
+ afl->stage_name = "bitflip 16/8";
+ afl->stage_short = "flip16";
+ afl->stage_cur = 0;
+ afl->stage_max = len - 1;
+
+ orig_hit_cnt = new_hit_cnt;
+
+ for (i = 0; i < len - 1; ++i) {
+
+ /* Let's consult the effector map... */
+
+ if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)]) {
+
+ --afl->stage_max;
+ continue;
+
+ }
+
+ afl->stage_cur_byte = i;
+
+ *(u16 *)(out_buf + i) ^= 0xFFFF;
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s MOPT_FLIP_BIT16-%u",
+ afl->queue_cur->fname, afl->stage_cur);
+#endif
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ *(u16 *)(out_buf + i) ^= 0xFFFF;
+
+ } /* for i = 0; i < len */
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_FLIP16] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_FLIP16] += afl->stage_max;
+
+ if (len < 4) { goto skip_bitflip; }
+
+ /* Four walking bytes. */
+
+ afl->stage_name = "bitflip 32/8";
+ afl->stage_short = "flip32";
+ afl->stage_cur = 0;
+ afl->stage_max = len - 3;
+
+ orig_hit_cnt = new_hit_cnt;
+
+ for (i = 0; i < len - 3; ++i) {
+
+ /* Let's consult the effector map... */
+ if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)] &&
+ !eff_map[EFF_APOS(i + 2)] && !eff_map[EFF_APOS(i + 3)]) {
+
+ --afl->stage_max;
+ continue;
+
+ }
+
+ afl->stage_cur_byte = i;
+
+ *(u32 *)(out_buf + i) ^= 0xFFFFFFFF;
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s MOPT_FLIP_BIT32-%u",
+ afl->queue_cur->fname, afl->stage_cur);
+#endif
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ *(u32 *)(out_buf + i) ^= 0xFFFFFFFF;
+
+ } /* for i = 0; i < len - 3 */
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_FLIP32] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_FLIP32] += afl->stage_max;
+
+skip_bitflip:
+
+ if (afl->no_arith) { goto skip_arith; }
+
+ /**********************
+ * ARITHMETIC INC/DEC *
+ **********************/
+
+ /* 8-bit arithmetics. */
+
+ afl->stage_name = "arith 8/8";
+ afl->stage_short = "arith8";
+ afl->stage_cur = 0;
+ afl->stage_max = 2 * len * ARITH_MAX;
+
+ afl->stage_val_type = STAGE_VAL_LE;
+
+ orig_hit_cnt = new_hit_cnt;
+
+ for (i = 0; i < (u32)len; ++i) {
+
+ u8 orig = out_buf[i];
+
+ /* Let's consult the effector map... */
+
+ if (!eff_map[EFF_APOS(i)]) {
+
+ afl->stage_max -= 2 * ARITH_MAX;
+ continue;
+
+ }
+
+ afl->stage_cur_byte = i;
+
+ for (j = 1; j <= ARITH_MAX; ++j) {
+
+ u8 r = orig ^ (orig + j);
+
+ /* Do arithmetic operations only if the result couldn't be a product
+ of a bitflip. */
+
+ if (!could_be_bitflip(r)) {
+
+ afl->stage_cur_val = j;
+ out_buf[i] = orig + j;
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s MOPT_ARITH8+-%u-%u",
+ afl->queue_cur->fname, i, j);
+#endif
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ } else {
+
+ --afl->stage_max;
+
+ }
+
+ r = orig ^ (orig - j);
+
+ if (!could_be_bitflip(r)) {
+
+ afl->stage_cur_val = -j;
+ out_buf[i] = orig - j;
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s MOPT_ARITH8_-%u-%u",
+ afl->queue_cur->fname, i, j);
+#endif
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ } else {
+
+ --afl->stage_max;
+
+ }
+
+ out_buf[i] = orig;
+
+ }
+
+ } /* for i = 0; i < len */
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_ARITH8] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_ARITH8] += afl->stage_max;
+
+ /* 16-bit arithmetics, both endians. */
+
+ if (len < 2) { goto skip_arith; }
+
+ afl->stage_name = "arith 16/8";
+ afl->stage_short = "arith16";
+ afl->stage_cur = 0;
+ afl->stage_max = 4 * (len - 1) * ARITH_MAX;
+
+ orig_hit_cnt = new_hit_cnt;
+
+ for (i = 0; i < len - 1; ++i) {
+
+ u16 orig = *(u16 *)(out_buf + i);
+
+ /* Let's consult the effector map... */
+
+ if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)]) {
+
+ afl->stage_max -= 4 * ARITH_MAX;
+ continue;
+
+ }
+
+ afl->stage_cur_byte = i;
+
+ for (j = 1; j <= ARITH_MAX; ++j) {
+
+ u16 r1 = orig ^ (orig + j), r2 = orig ^ (orig - j),
+ r3 = orig ^ SWAP16(SWAP16(orig) + j),
+ r4 = orig ^ SWAP16(SWAP16(orig) - j);
+
+ /* Try little endian addition and subtraction first. Do it only
+ if the operation would affect more than one byte (hence the
+ & 0xff overflow checks) and if it couldn't be a product of
+ a bitflip. */
+
+ afl->stage_val_type = STAGE_VAL_LE;
+
+ if ((orig & 0xff) + j > 0xff && !could_be_bitflip(r1)) {
+
+ afl->stage_cur_val = j;
+ *(u16 *)(out_buf + i) = orig + j;
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s MOPT_ARITH16+-%u-%u",
+ afl->queue_cur->fname, i, j);
+#endif
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ } else {
+
+ --afl->stage_max;
+
+ }
+
+ if ((orig & 0xff) < j && !could_be_bitflip(r2)) {
+
+ afl->stage_cur_val = -j;
+ *(u16 *)(out_buf + i) = orig - j;
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s MOPT_ARITH16_-%u-%u",
+ afl->queue_cur->fname, i, j);
+#endif
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ } else {
+
+ --afl->stage_max;
+
+ }
+
+ /* Big endian comes next. Same deal. */
+
+ afl->stage_val_type = STAGE_VAL_BE;
+
+ if ((orig >> 8) + j > 0xff && !could_be_bitflip(r3)) {
+
+ afl->stage_cur_val = j;
+ *(u16 *)(out_buf + i) = SWAP16(SWAP16(orig) + j);
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation),
+ "%s MOPT_ARITH16+BE-%u-%u", afl->queue_cur->fname, i, j);
+#endif
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ } else {
+
+ --afl->stage_max;
+
+ }
+
+ if ((orig >> 8) < j && !could_be_bitflip(r4)) {
+
+ afl->stage_cur_val = -j;
+ *(u16 *)(out_buf + i) = SWAP16(SWAP16(orig) - j);
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation),
+ "%s MOPT_ARITH16_BE+%u+%u", afl->queue_cur->fname, i, j);
+#endif
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ } else {
+
+ --afl->stage_max;
+
+ }
+
+ *(u16 *)(out_buf + i) = orig;
+
+ }
+
+ } /* for i = 0; i < len - 1 */
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_ARITH16] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_ARITH16] += afl->stage_max;
+
+ /* 32-bit arithmetics, both endians. */
+
+ if (len < 4) { goto skip_arith; }
+
+ afl->stage_name = "arith 32/8";
+ afl->stage_short = "arith32";
+ afl->stage_cur = 0;
+ afl->stage_max = 4 * (len - 3) * ARITH_MAX;
+
+ orig_hit_cnt = new_hit_cnt;
+
+ for (i = 0; i < len - 3; ++i) {
+
+ u32 orig = *(u32 *)(out_buf + i);
+
+ /* Let's consult the effector map... */
+
+ if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)] &&
+ !eff_map[EFF_APOS(i + 2)] && !eff_map[EFF_APOS(i + 3)]) {
+
+ afl->stage_max -= 4 * ARITH_MAX;
+ continue;
+
+ }
+
+ afl->stage_cur_byte = i;
+
+ for (j = 1; j <= ARITH_MAX; ++j) {
+
+ u32 r1 = orig ^ (orig + j), r2 = orig ^ (orig - j),
+ r3 = orig ^ SWAP32(SWAP32(orig) + j),
+ r4 = orig ^ SWAP32(SWAP32(orig) - j);
+
+ /* Little endian first. Same deal as with 16-bit: we only want to
+ try if the operation would have effect on more than two bytes. */
+
+ afl->stage_val_type = STAGE_VAL_LE;
+
+ if ((orig & 0xffff) + j > 0xffff && !could_be_bitflip(r1)) {
+
+ afl->stage_cur_val = j;
+ *(u32 *)(out_buf + i) = orig + j;
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s MOPT_ARITH32+-%u-%u",
+ afl->queue_cur->fname, i, j);
+#endif
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ } else {
+
+ --afl->stage_max;
+
+ }
+
+ if ((orig & 0xffff) < j && !could_be_bitflip(r2)) {
+
+ afl->stage_cur_val = -j;
+ *(u32 *)(out_buf + i) = orig - j;
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s MOPT_ARITH32_-%u-%u",
+ afl->queue_cur->fname, i, j);
+#endif
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ } else {
+
+ --afl->stage_max;
+
+ }
+
+ /* Big endian next. */
+
+ afl->stage_val_type = STAGE_VAL_BE;
+
+ if ((SWAP32(orig) & 0xffff) + j > 0xffff && !could_be_bitflip(r3)) {
+
+ afl->stage_cur_val = j;
+ *(u32 *)(out_buf + i) = SWAP32(SWAP32(orig) + j);
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation),
+ "%s MOPT_ARITH32+BE-%u-%u", afl->queue_cur->fname, i, j);
+#endif
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ } else {
+
+ --afl->stage_max;
+
+ }
+
+ if ((SWAP32(orig) & 0xffff) < j && !could_be_bitflip(r4)) {
+
+ afl->stage_cur_val = -j;
+ *(u32 *)(out_buf + i) = SWAP32(SWAP32(orig) - j);
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation),
+ "%s MOPT_ARITH32_BE-%u-%u", afl->queue_cur->fname, i, j);
+#endif
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ } else {
+
+ --afl->stage_max;
+
+ }
+
+ *(u32 *)(out_buf + i) = orig;
+
+ }
+
+ } /* for i = 0; i < len - 3 */
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_ARITH32] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_ARITH32] += afl->stage_max;
+
+skip_arith:
+
+ /**********************
+ * INTERESTING VALUES *
+ **********************/
+
+ afl->stage_name = "interest 8/8";
+ afl->stage_short = "int8";
+ afl->stage_cur = 0;
+ afl->stage_max = len * sizeof(interesting_8);
+
+ afl->stage_val_type = STAGE_VAL_LE;
+
+ orig_hit_cnt = new_hit_cnt;
+
+ /* Setting 8-bit integers. */
+
+ for (i = 0; i < (u32)len; ++i) {
+
+ u8 orig = out_buf[i];
+
+ /* Let's consult the effector map... */
+
+ if (!eff_map[EFF_APOS(i)]) {
+
+ afl->stage_max -= sizeof(interesting_8);
+ continue;
+
+ }
+
+ afl->stage_cur_byte = i;
+
+ for (j = 0; j < sizeof(interesting_8); ++j) {
+
+ /* Skip if the value could be a product of bitflips or arithmetics. */
+
+ if (could_be_bitflip(orig ^ (u8)interesting_8[j]) ||
+ could_be_arith(orig, (u8)interesting_8[j], 1)) {
+
+ --afl->stage_max;
+ continue;
+
+ }
+
+ afl->stage_cur_val = interesting_8[j];
+ out_buf[i] = interesting_8[j];
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation),
+ "%s MOPT_INTERESTING8-%u-%u", afl->queue_cur->fname, i, j);
+#endif
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+
+ out_buf[i] = orig;
+ ++afl->stage_cur;
+
+ }
+
+ } /* for i = 0; i < len */
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_INTEREST8] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_INTEREST8] += afl->stage_max;
+
+ /* Setting 16-bit integers, both endians. */
+
+ if (afl->no_arith || len < 2) { goto skip_interest; }
+
+ afl->stage_name = "interest 16/8";
+ afl->stage_short = "int16";
+ afl->stage_cur = 0;
+ afl->stage_max = 2 * (len - 1) * (sizeof(interesting_16) >> 1);
+
+ orig_hit_cnt = new_hit_cnt;
+
+ for (i = 0; i < len - 1; ++i) {
+
+ u16 orig = *(u16 *)(out_buf + i);
+
+ /* Let's consult the effector map... */
+
+ if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)]) {
+
+ afl->stage_max -= sizeof(interesting_16);
+ continue;
+
+ }
+
+ afl->stage_cur_byte = i;
+
+ for (j = 0; j < sizeof(interesting_16) / 2; ++j) {
+
+ afl->stage_cur_val = interesting_16[j];
+
+ /* Skip if this could be a product of a bitflip, arithmetics,
+ or single-byte interesting value insertion. */
+
+ if (!could_be_bitflip(orig ^ (u16)interesting_16[j]) &&
+ !could_be_arith(orig, (u16)interesting_16[j], 2) &&
+ !could_be_interest(orig, (u16)interesting_16[j], 2, 0)) {
+
+ afl->stage_val_type = STAGE_VAL_LE;
+
+ *(u16 *)(out_buf + i) = interesting_16[j];
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation),
+ "%s MOPT_INTERESTING16-%u-%u", afl->queue_cur->fname, i, j);
+#endif
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ } else {
+
+ --afl->stage_max;
+
+ }
+
+ if ((u16)interesting_16[j] != SWAP16(interesting_16[j]) &&
+ !could_be_bitflip(orig ^ SWAP16(interesting_16[j])) &&
+ !could_be_arith(orig, SWAP16(interesting_16[j]), 2) &&
+ !could_be_interest(orig, SWAP16(interesting_16[j]), 2, 1)) {
+
+ afl->stage_val_type = STAGE_VAL_BE;
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation),
+ "%s MOPT_INTERESTING16BE-%u-%u", afl->queue_cur->fname, i, j);
+#endif
+ *(u16 *)(out_buf + i) = SWAP16(interesting_16[j]);
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ } else {
+
+ --afl->stage_max;
+
+ }
+
+ }
+
+ *(u16 *)(out_buf + i) = orig;
+
+ } /* for i = 0; i < len - 1 */
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_INTEREST16] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_INTEREST16] += afl->stage_max;
+
+ if (len < 4) { goto skip_interest; }
+
+ /* Setting 32-bit integers, both endians. */
+
+ afl->stage_name = "interest 32/8";
+ afl->stage_short = "int32";
+ afl->stage_cur = 0;
+ afl->stage_max = 2 * (len - 3) * (sizeof(interesting_32) >> 2);
+
+ orig_hit_cnt = new_hit_cnt;
+
+ for (i = 0; i < len - 3; ++i) {
+
+ u32 orig = *(u32 *)(out_buf + i);
+
+ /* Let's consult the effector map... */
+
+ if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)] &&
+ !eff_map[EFF_APOS(i + 2)] && !eff_map[EFF_APOS(i + 3)]) {
+
+ afl->stage_max -= sizeof(interesting_32) >> 1;
+ continue;
+
+ }
+
+ afl->stage_cur_byte = i;
+
+ for (j = 0; j < sizeof(interesting_32) / 4; ++j) {
+
+ afl->stage_cur_val = interesting_32[j];
+
+ /* Skip if this could be a product of a bitflip, arithmetics,
+ or word interesting value insertion. */
+
+ if (!could_be_bitflip(orig ^ (u32)interesting_32[j]) &&
+ !could_be_arith(orig, interesting_32[j], 4) &&
+ !could_be_interest(orig, interesting_32[j], 4, 0)) {
+
+ afl->stage_val_type = STAGE_VAL_LE;
+
+ *(u32 *)(out_buf + i) = interesting_32[j];
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation),
+ "%s MOPT_INTERESTING32-%u-%u", afl->queue_cur->fname, i, j);
+#endif
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ } else {
+
+ --afl->stage_max;
+
+ }
+
+ if ((u32)interesting_32[j] != SWAP32(interesting_32[j]) &&
+ !could_be_bitflip(orig ^ SWAP32(interesting_32[j])) &&
+ !could_be_arith(orig, SWAP32(interesting_32[j]), 4) &&
+ !could_be_interest(orig, SWAP32(interesting_32[j]), 4, 1)) {
+
+ afl->stage_val_type = STAGE_VAL_BE;
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation),
+ "%s MOPT_INTERESTING32BE-%u-%u", afl->queue_cur->fname, i, j);
+#endif
+ *(u32 *)(out_buf + i) = SWAP32(interesting_32[j]);
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+ ++afl->stage_cur;
+
+ } else {
+
+ --afl->stage_max;
+
+ }
+
+ }
+
+ *(u32 *)(out_buf + i) = orig;
+
+ } /* for i = 0; i < len - 3 */
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_INTEREST32] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_INTEREST32] += afl->stage_max;
+
+skip_interest:
+
+ /********************
+ * DICTIONARY STUFF *
+ ********************/
+
+ if (!afl->extras_cnt) { goto skip_user_extras; }
+
+ /* Overwrite with user-supplied extras. */
+
+ afl->stage_name = "user extras (over)";
+ afl->stage_short = "ext_UO";
+ afl->stage_cur = 0;
+ afl->stage_max = afl->extras_cnt * len;
+
+ afl->stage_val_type = STAGE_VAL_NONE;
+
+ orig_hit_cnt = new_hit_cnt;
+
+ for (i = 0; i < (u32)len; ++i) {
+
+ u32 last_len = 0;
+
+ afl->stage_cur_byte = i;
+
+ /* Extras are sorted by size, from smallest to largest. This means
+ that we don't have to worry about restoring the buffer in
+ between writes at a particular offset determined by the outer
+ loop. */
+
+ for (j = 0; j < afl->extras_cnt; ++j) {
+
+ /* Skip extras probabilistically if afl->extras_cnt > AFL_MAX_DET_EXTRAS.
+ Also skip them if there's no room to insert the payload, if the token
+ is redundant, or if its entire span has no bytes set in the effector
+ map. */
+
+ if ((afl->extras_cnt > afl->max_det_extras &&
+ rand_below(afl, afl->extras_cnt) >= afl->max_det_extras) ||
+ afl->extras[j].len > len - i ||
+ !memcmp(afl->extras[j].data, out_buf + i, afl->extras[j].len) ||
+ !memchr(eff_map + EFF_APOS(i), 1,
+ EFF_SPAN_ALEN(i, afl->extras[j].len))) {
+
+ --afl->stage_max;
+ continue;
+
+ }
+
+ last_len = afl->extras[j].len;
+ memcpy(out_buf + i, afl->extras[j].data, last_len);
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation),
+ "%s MOPT_EXTRAS_overwrite-%u-%u", afl->queue_cur->fname, i, j);
+#endif
+
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+
+ ++afl->stage_cur;
+
+ }
+
+ /* Restore all the clobbered memory. */
+ memcpy(out_buf + i, in_buf + i, last_len);
+
+ } /* for i = 0; i < len */
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_EXTRAS_UO] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_EXTRAS_UO] += afl->stage_max;
+
+ /* Insertion of user-supplied extras. */
+
+ afl->stage_name = "user extras (insert)";
+ afl->stage_short = "ext_UI";
+ afl->stage_cur = 0;
+ afl->stage_max = afl->extras_cnt * (len + 1);
+
+ orig_hit_cnt = new_hit_cnt;
+
+ ex_tmp = afl_realloc(AFL_BUF_PARAM(ex), len + MAX_DICT_FILE);
+ if (unlikely(!ex_tmp)) { PFATAL("alloc"); }
+
+ for (i = 0; i <= (u32)len; ++i) {
+
+ afl->stage_cur_byte = i;
+
+ for (j = 0; j < afl->extras_cnt; ++j) {
+
+ if (len + afl->extras[j].len > MAX_FILE) {
+
+ --afl->stage_max;
+ continue;
+
+ }
+
+ /* Insert token */
+ memcpy(ex_tmp + i, afl->extras[j].data, afl->extras[j].len);
+
+ /* Copy tail */
+ memcpy(ex_tmp + i + afl->extras[j].len, out_buf + i, len - i);
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation),
+ "%s MOPT_EXTRAS_insert-%u-%u", afl->queue_cur->fname, i, j);
+#endif
+
+ if (common_fuzz_stuff(afl, ex_tmp, len + afl->extras[j].len)) {
+
+ goto abandon_entry;
+
+ }
+
+ ++afl->stage_cur;
+
+ }
+
+ /* Copy head */
+ ex_tmp[i] = out_buf[i];
+
+ } /* for i = 0; i <= len */
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_EXTRAS_UI] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_EXTRAS_UI] += afl->stage_max;
+
+skip_user_extras:
+
+ if (!afl->a_extras_cnt) { goto skip_extras; }
+
+ afl->stage_name = "auto extras (over)";
+ afl->stage_short = "ext_AO";
+ afl->stage_cur = 0;
+ afl->stage_max = MIN(afl->a_extras_cnt, (u32)USE_AUTO_EXTRAS) * len;
+
+ afl->stage_val_type = STAGE_VAL_NONE;
+
+ orig_hit_cnt = new_hit_cnt;
+
+ for (i = 0; i < (u32)len; ++i) {
+
+ u32 last_len = 0;
+
+ afl->stage_cur_byte = i;
+
+ u32 min_extra_len = MIN(afl->a_extras_cnt, (u32)USE_AUTO_EXTRAS);
+ for (j = 0; j < min_extra_len; ++j) {
+
+ /* See the comment in the earlier code; extras are sorted by size. */
+
+ if ((afl->a_extras[j].len) > (len - i) ||
+ !memcmp(afl->a_extras[j].data, out_buf + i, afl->a_extras[j].len) ||
+ !memchr(eff_map + EFF_APOS(i), 1,
+ EFF_SPAN_ALEN(i, afl->a_extras[j].len))) {
+
+ --afl->stage_max;
+ continue;
+
+ }
+
+ last_len = afl->a_extras[j].len;
+ memcpy(out_buf + i, afl->a_extras[j].data, last_len);
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation),
+ "%s MOPT_AUTO_EXTRAS_overwrite-%u-%u", afl->queue_cur->fname, i,
+ j);
+#endif
+
+ if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+
+ ++afl->stage_cur;
+
+ }
+
+ /* Restore all the clobbered memory. */
+ memcpy(out_buf + i, in_buf + i, last_len);
+
+ } /* for i = 0; i < len */
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_EXTRAS_AO] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_EXTRAS_AO] += afl->stage_max;
+
+ /* Insertion of auto extras. */
+
+ afl->stage_name = "auto extras (insert)";
+ afl->stage_short = "ext_AI";
+ afl->stage_cur = 0;
+ afl->stage_max = afl->a_extras_cnt * (len + 1);
+
+ orig_hit_cnt = new_hit_cnt;
+
+ ex_tmp = afl_realloc(AFL_BUF_PARAM(ex), len + MAX_DICT_FILE);
+ if (unlikely(!ex_tmp)) { PFATAL("alloc"); }
+
+ for (i = 0; i <= (u32)len; ++i) {
+
+ afl->stage_cur_byte = i;
+
+ for (j = 0; j < afl->a_extras_cnt; ++j) {
+
+ if (len + afl->a_extras[j].len > MAX_FILE) {
+
+ --afl->stage_max;
+ continue;
+
+ }
+
+ /* Insert token */
+ memcpy(ex_tmp + i, afl->a_extras[j].data, afl->a_extras[j].len);
+
+ /* Copy tail */
+ memcpy(ex_tmp + i + afl->a_extras[j].len, out_buf + i, len - i);
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation),
+ "%s MOPT_AUTO_EXTRAS_insert-%u-%u", afl->queue_cur->fname, i, j);
+#endif
+
+ if (common_fuzz_stuff(afl, ex_tmp, len + afl->a_extras[j].len)) {
+
+ goto abandon_entry;
+
+ }
+
+ ++afl->stage_cur;
+
+ }
+
+ /* Copy head */
+ ex_tmp[i] = out_buf[i];
+
+ } /* for i = 0; i <= len */
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_EXTRAS_AI] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_EXTRAS_AI] += afl->stage_max;
+
+skip_extras:
+
+ /* If we made this to here without jumping to havoc_stage or abandon_entry,
+ we're properly done with deterministic steps and can mark it as such
+ in the .state/ directory. */
+
+ if (!afl->queue_cur->passed_det) { mark_as_det_done(afl, afl->queue_cur); }
+
+ /****************
+ * RANDOM HAVOC *
+ ****************/
+
+havoc_stage:
+pacemaker_fuzzing:
+
+ afl->stage_cur_byte = -1;
+
+ /* The havoc stage mutation code is also invoked when splicing files; if the
+ splice_cycle variable is set, generate different descriptions and such. */
+
+ if (!splice_cycle) {
+
+ afl->stage_name = MOpt_globals.havoc_stagename;
+ afl->stage_short = MOpt_globals.havoc_stagenameshort;
+ afl->stage_max = (doing_det ? HAVOC_CYCLES_INIT : HAVOC_CYCLES) *
+ perf_score / afl->havoc_div / 100;
+
+ } else {
+
+ perf_score = orig_perf;
+
+ snprintf(afl->stage_name_buf, STAGE_BUF_SIZE,
+ MOpt_globals.splice_stageformat, splice_cycle);
+ afl->stage_name = afl->stage_name_buf;
+ afl->stage_short = MOpt_globals.splice_stagenameshort;
+ afl->stage_max = SPLICE_HAVOC * perf_score / afl->havoc_div / 100;
+
+ }
+
+ s32 temp_len_puppet;
+
+ // for (; afl->swarm_now < swarm_num; ++afl->swarm_now)
+ {
+
+ if (afl->key_puppet == 1) {
+
+ if (unlikely(afl->orig_hit_cnt_puppet == 0)) {
+
+ afl->orig_hit_cnt_puppet = afl->queued_items + afl->saved_crashes;
+ afl->last_limit_time_start = get_cur_time();
+ afl->SPLICE_CYCLES_puppet =
+ (rand_below(
+ afl, SPLICE_CYCLES_puppet_up - SPLICE_CYCLES_puppet_low + 1) +
+ SPLICE_CYCLES_puppet_low);
+
+ }
+
+ } /* if afl->key_puppet == 1 */
+
+ {
+
+#ifndef IGNORE_FINDS
+ havoc_stage_puppet:
+#endif
+
+ afl->stage_cur_byte = -1;
+
+ /* The havoc stage mutation code is also invoked when splicing files; if
+ the splice_cycle variable is set, generate different descriptions and
+ such. */
+
+ if (!splice_cycle) {
+
+ afl->stage_name = MOpt_globals.havoc_stagename;
+ afl->stage_short = MOpt_globals.havoc_stagenameshort;
+ afl->stage_max = (doing_det ? HAVOC_CYCLES_INIT : HAVOC_CYCLES) *
+ perf_score / afl->havoc_div / 100;
+
+ } else {
+
+ perf_score = orig_perf;
+ snprintf(afl->stage_name_buf, STAGE_BUF_SIZE,
+ MOpt_globals.splice_stageformat, splice_cycle);
+ afl->stage_name = afl->stage_name_buf;
+ afl->stage_short = MOpt_globals.splice_stagenameshort;
+ afl->stage_max = SPLICE_HAVOC * perf_score / afl->havoc_div / 100;
+
+ }
+
+ if (afl->stage_max < HAVOC_MIN) { afl->stage_max = HAVOC_MIN; }
+
+ temp_len = len;
+
+ orig_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ havoc_queued = afl->queued_items;
+
+ u32 r_max, r;
+
+ r_max = 16 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0);
+
+ if (unlikely(afl->expand_havoc && afl->ready_for_splicing_count > 1)) {
+
+ /* add expensive havoc cases here, they are activated after a full
+ cycle without any finds happened */
+
+ ++r_max;
+
+ }
+
+ for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max;
+ ++afl->stage_cur) {
+
+ u32 use_stacking = 1 << (1 + rand_below(afl, afl->havoc_stack_pow2));
+
+ afl->stage_cur_val = use_stacking;
+
+ for (i = 0; i < operator_num; ++i) {
+
+ MOpt_globals.cycles_v3[i] = MOpt_globals.cycles_v2[i];
+
+ }
+
+#ifdef INTROSPECTION
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s MOPT_HAVOC-%u",
+ afl->queue_cur->fname, use_stacking);
+#endif
+
+ for (i = 0; i < use_stacking; ++i) {
+
+ switch (r = (select_algorithm(afl, r_max))) {
+
+ case 0:
+ /* Flip a single bit somewhere. Spooky! */
+ FLIP_BIT(out_buf, rand_below(afl, temp_len << 3));
+ MOpt_globals.cycles_v2[STAGE_FLIP1]++;
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " FLIP_BIT1");
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ break;
+
+ case 1:
+ if (temp_len < 2) { break; }
+ temp_len_puppet = rand_below(afl, (temp_len << 3) - 1);
+ FLIP_BIT(out_buf, temp_len_puppet);
+ FLIP_BIT(out_buf, temp_len_puppet + 1);
+ MOpt_globals.cycles_v2[STAGE_FLIP2]++;
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " FLIP_BIT2");
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ break;
+
+ case 2:
+ if (temp_len < 2) { break; }
+ temp_len_puppet = rand_below(afl, (temp_len << 3) - 3);
+ FLIP_BIT(out_buf, temp_len_puppet);
+ FLIP_BIT(out_buf, temp_len_puppet + 1);
+ FLIP_BIT(out_buf, temp_len_puppet + 2);
+ FLIP_BIT(out_buf, temp_len_puppet + 3);
+ MOpt_globals.cycles_v2[STAGE_FLIP4]++;
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " FLIP_BIT4");
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ break;
+
+ case 3:
+ if (temp_len < 4) { break; }
+ out_buf[rand_below(afl, temp_len)] ^= 0xFF;
+ MOpt_globals.cycles_v2[STAGE_FLIP8]++;
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " FLIP_BIT8");
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ break;
+
+ case 4:
+ if (temp_len < 8) { break; }
+ *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) ^= 0xFFFF;
+ MOpt_globals.cycles_v2[STAGE_FLIP16]++;
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " FLIP_BIT16");
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ break;
+
+ case 5:
+ if (temp_len < 8) { break; }
+ *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) ^= 0xFFFFFFFF;
+ MOpt_globals.cycles_v2[STAGE_FLIP32]++;
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " FLIP_BIT32");
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ break;
+
+ case 6:
+ out_buf[rand_below(afl, temp_len)] -=
+ 1 + rand_below(afl, ARITH_MAX);
+ out_buf[rand_below(afl, temp_len)] +=
+ 1 + rand_below(afl, ARITH_MAX);
+ MOpt_globals.cycles_v2[STAGE_ARITH8]++;
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH8");
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ break;
+
+ case 7:
+ /* Randomly subtract from word, random endian. */
+ if (temp_len < 8) { break; }
+ if (rand_below(afl, 2)) {
+
+ u32 pos = rand_below(afl, temp_len - 1);
+ *(u16 *)(out_buf + pos) -= 1 + rand_below(afl, ARITH_MAX);
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16-%u", pos);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+
+ } else {
+
+ u32 pos = rand_below(afl, temp_len - 1);
+ u16 num = 1 + rand_below(afl, ARITH_MAX);
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16BE-%u-%u",
+ pos, num);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ *(u16 *)(out_buf + pos) =
+ SWAP16(SWAP16(*(u16 *)(out_buf + pos)) - num);
+
+ }
+
+ /* Randomly add to word, random endian. */
+ if (rand_below(afl, 2)) {
+
+ u32 pos = rand_below(afl, temp_len - 1);
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16+-%u", pos);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ *(u16 *)(out_buf + pos) += 1 + rand_below(afl, ARITH_MAX);
+
+ } else {
+
+ u32 pos = rand_below(afl, temp_len - 1);
+ u16 num = 1 + rand_below(afl, ARITH_MAX);
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16BE+-%u-%u",
+ pos, num);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ *(u16 *)(out_buf + pos) =
+ SWAP16(SWAP16(*(u16 *)(out_buf + pos)) + num);
+
+ }
+
+ MOpt_globals.cycles_v2[STAGE_ARITH16]++;
+ break;
+
+ case 8:
+ /* Randomly subtract from dword, random endian. */
+ if (temp_len < 8) { break; }
+ if (rand_below(afl, 2)) {
+
+ u32 pos = rand_below(afl, temp_len - 3);
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32_-%u", pos);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ *(u32 *)(out_buf + pos) -= 1 + rand_below(afl, ARITH_MAX);
+
+ } else {
+
+ u32 pos = rand_below(afl, temp_len - 3);
+ u32 num = 1 + rand_below(afl, ARITH_MAX);
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32BE_-%u-%u",
+ pos, num);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ *(u32 *)(out_buf + pos) =
+ SWAP32(SWAP32(*(u32 *)(out_buf + pos)) - num);
+
+ }
+
+ /* Randomly add to dword, random endian. */
+ // if (temp_len < 4) break;
+ if (rand_below(afl, 2)) {
+
+ u32 pos = rand_below(afl, temp_len - 3);
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32+-%u", pos);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ *(u32 *)(out_buf + pos) += 1 + rand_below(afl, ARITH_MAX);
+
+ } else {
+
+ u32 pos = rand_below(afl, temp_len - 3);
+ u32 num = 1 + rand_below(afl, ARITH_MAX);
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32BE+-%u-%u",
+ pos, num);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ *(u32 *)(out_buf + pos) =
+ SWAP32(SWAP32(*(u32 *)(out_buf + pos)) + num);
+
+ }
+
+ MOpt_globals.cycles_v2[STAGE_ARITH32]++;
+ break;
+
+ case 9:
+ /* Set byte to interesting value. */
+ if (temp_len < 4) { break; }
+ out_buf[rand_below(afl, temp_len)] =
+ interesting_8[rand_below(afl, sizeof(interesting_8))];
+ MOpt_globals.cycles_v2[STAGE_INTEREST8]++;
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING8");
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ break;
+
+ case 10:
+ /* Set word to interesting value, randomly choosing endian. */
+ if (temp_len < 8) { break; }
+ if (rand_below(afl, 2)) {
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING16");
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) =
+ interesting_16[rand_below(afl,
+ sizeof(interesting_16) >> 1)];
+
+ } else {
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING16BE");
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) =
+ SWAP16(interesting_16[rand_below(
+ afl, sizeof(interesting_16) >> 1)]);
+
+ }
+
+ MOpt_globals.cycles_v2[STAGE_INTEREST16]++;
+ break;
+
+ case 11:
+ /* Set dword to interesting value, randomly choosing endian. */
+
+ if (temp_len < 8) { break; }
+
+ if (rand_below(afl, 2)) {
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING32");
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) =
+ interesting_32[rand_below(afl,
+ sizeof(interesting_32) >> 2)];
+
+ } else {
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING32BE");
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) =
+ SWAP32(interesting_32[rand_below(
+ afl, sizeof(interesting_32) >> 2)]);
+
+ }
+
+ MOpt_globals.cycles_v2[STAGE_INTEREST32]++;
+ break;
+
+ case 12:
+
+ /* Just set a random byte to a random value. Because,
+ why not. We use XOR with 1-255 to eliminate the
+ possibility of a no-op. */
+
+ out_buf[rand_below(afl, temp_len)] ^= 1 + rand_below(afl, 255);
+ MOpt_globals.cycles_v2[STAGE_RANDOMBYTE]++;
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " RAND8");
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ break;
+
+ case 13: {
+
+ /* Delete bytes. We're making this a bit more likely
+ than insertion (the next option) in hopes of keeping
+ files reasonably small. */
+
+ u32 del_from, del_len;
+
+ if (temp_len < 2) { break; }
+
+ /* Don't delete too much. */
+
+ del_len = choose_block_len(afl, temp_len - 1);
+
+ del_from = rand_below(afl, temp_len - del_len + 1);
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " DEL-%u%u", del_from,
+ del_len);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ memmove(out_buf + del_from, out_buf + del_from + del_len,
+ temp_len - del_from - del_len);
+
+ temp_len -= del_len;
+ MOpt_globals.cycles_v2[STAGE_DELETEBYTE]++;
+ break;
+
+ }
+
+ case 14:
+
+ if (temp_len + HAVOC_BLK_XL < MAX_FILE) {
+
+ /* Clone bytes (75%) or insert a block of constant bytes (25%).
+ */
+
+ u8 actually_clone = rand_below(afl, 4);
+ u32 clone_from, clone_to, clone_len;
+ u8 *new_buf;
+
+ if (likely(actually_clone)) {
+
+ clone_len = choose_block_len(afl, temp_len);
+ clone_from = rand_below(afl, temp_len - clone_len + 1);
+
+ } else {
+
+ clone_len = choose_block_len(afl, HAVOC_BLK_XL);
+ clone_from = 0;
+
+ }
+
+ clone_to = rand_below(afl, temp_len);
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " CLONE_%s-%u-%u-%u",
+ actually_clone ? "clone" : "insert", clone_from,
+ clone_to, clone_len);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch),
+ temp_len + clone_len);
+ if (unlikely(!new_buf)) { PFATAL("alloc"); }
+
+ /* Head */
+
+ memcpy(new_buf, out_buf, clone_to);
+
+ /* Inserted part */
+
+ if (actually_clone) {
+
+ memcpy(new_buf + clone_to, out_buf + clone_from, clone_len);
+
+ } else {
+
+ memset(new_buf + clone_to,
+ rand_below(afl, 2)
+ ? rand_below(afl, 256)
+ : out_buf[rand_below(afl, temp_len)],
+ clone_len);
+
+ }
+
+ /* Tail */
+ memcpy(new_buf + clone_to + clone_len, out_buf + clone_to,
+ temp_len - clone_to);
+
+ out_buf = new_buf;
+ afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
+ temp_len += clone_len;
+ MOpt_globals.cycles_v2[STAGE_Clone75]++;
+
+ }
+
+ break;
+
+ case 15: {
+
+ /* Overwrite bytes with a randomly selected chunk (75%) or fixed
+ bytes (25%). */
+
+ u32 copy_from, copy_to, copy_len;
+
+ if (temp_len < 2) { break; }
+
+ copy_len = choose_block_len(afl, temp_len - 1);
+
+ copy_from = rand_below(afl, temp_len - copy_len + 1);
+ copy_to = rand_below(afl, temp_len - copy_len + 1);
+
+ if (likely(rand_below(afl, 4))) {
+
+ if (likely(copy_from != copy_to)) {
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp),
+ " OVERWRITE_COPY-%u-%u-%u", copy_from, copy_to,
+ copy_len);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ memmove(out_buf + copy_to, out_buf + copy_from, copy_len);
+
+ }
+
+ } else {
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp),
+ " OVERWRITE_FIXED-%u-%u-%u", copy_from, copy_to,
+ copy_len);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ memset(out_buf + copy_to,
+ rand_below(afl, 2) ? rand_below(afl, 256)
+ : out_buf[rand_below(afl, temp_len)],
+ copy_len);
+
+ }
+
+ MOpt_globals.cycles_v2[STAGE_OverWrite75]++;
+ break;
+
+ } /* case 15 */
+
+ default: {
+
+ /* Values 16 and 17 can be selected only if there are any extras
+ present in the dictionaries. */
+
+ r -= 16;
+
+ if (r == 0 && (afl->extras_cnt || afl->a_extras_cnt)) {
+
+ /* Overwrite bytes with an extra. */
+
+ if (!afl->extras_cnt ||
+ (afl->a_extras_cnt && rand_below(afl, 2))) {
+
+ /* No user-specified extras or odds in our favor. Let's use an
+ auto-detected one. */
+
+ u32 use_extra = rand_below(afl, afl->a_extras_cnt);
+ u32 extra_len = afl->a_extras[use_extra].len;
+
+ if (extra_len > (u32)temp_len) break;
+
+ u32 insert_at = rand_below(afl, temp_len - extra_len + 1);
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp),
+ " AUTO_EXTRA_OVERWRITE-%u-%u", insert_at, extra_len);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ memcpy(out_buf + insert_at, afl->a_extras[use_extra].data,
+ extra_len);
+
+ } else {
+
+ /* No auto extras or odds in our favor. Use the dictionary. */
+
+ u32 use_extra = rand_below(afl, afl->extras_cnt);
+ u32 extra_len = afl->extras[use_extra].len;
+
+ if (extra_len > (u32)temp_len) break;
+
+ u32 insert_at = rand_below(afl, temp_len - extra_len + 1);
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp),
+ " EXTRA_OVERWRITE-%u-%u", insert_at, extra_len);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ memcpy(out_buf + insert_at, afl->extras[use_extra].data,
+ extra_len);
+
+ }
+
+ MOpt_globals.cycles_v2[STAGE_OverWriteExtra]++;
+
+ break;
+
+ }
+
+ /* Insert an extra. */
+
+ else if (r == 1 && (afl->extras_cnt || afl->a_extras_cnt)) {
+
+ u32 use_extra, extra_len,
+ insert_at = rand_below(afl, temp_len + 1);
+ u8 *ptr;
+
+ /* Insert an extra. Do the same dice-rolling stuff as for the
+ previous case. */
+
+ if (!afl->extras_cnt ||
+ (afl->a_extras_cnt && rand_below(afl, 2))) {
+
+ use_extra = rand_below(afl, afl->a_extras_cnt);
+ extra_len = afl->a_extras[use_extra].len;
+ ptr = afl->a_extras[use_extra].data;
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp),
+ " AUTO_EXTRA_INSERT-%u-%u", insert_at, extra_len);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+
+ } else {
+
+ use_extra = rand_below(afl, afl->extras_cnt);
+ extra_len = afl->extras[use_extra].len;
+ ptr = afl->extras[use_extra].data;
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp),
+ " EXTRA_INSERT-%u-%u", insert_at, extra_len);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+
+ }
+
+ if (temp_len + extra_len >= MAX_FILE) break;
+
+ out_buf = afl_realloc(AFL_BUF_PARAM(out), temp_len + extra_len);
+ if (unlikely(!out_buf)) { PFATAL("alloc"); }
+
+ /* Tail */
+ memmove(out_buf + insert_at + extra_len, out_buf + insert_at,
+ temp_len - insert_at);
+
+ /* Inserted part */
+ memcpy(out_buf + insert_at, ptr, extra_len);
+
+ temp_len += extra_len;
+ MOpt_globals.cycles_v2[STAGE_InsertExtra]++;
+ break;
+
+ } else {
+
+ if (unlikely(afl->ready_for_splicing_count < 2)) break;
+
+ u32 tid;
+ do {
+
+ tid = rand_below(afl, afl->queued_items);
+
+ } while (tid == afl->current_entry ||
+
+ afl->queue_buf[tid]->len < 4);
+
+ /* Get the testcase for splicing. */
+ struct queue_entry *target = afl->queue_buf[tid];
+ u32 new_len = target->len;
+ u8 * new_buf = queue_testcase_get(afl, target);
+
+ if ((temp_len >= 2 && rand_below(afl, 2)) ||
+ temp_len + HAVOC_BLK_XL >= MAX_FILE) {
+
+ /* overwrite mode */
+
+ u32 copy_from, copy_to, copy_len;
+
+ copy_len = choose_block_len(afl, new_len - 1);
+ if (copy_len > temp_len) copy_len = temp_len;
+
+ copy_from = rand_below(afl, new_len - copy_len + 1);
+ copy_to = rand_below(afl, temp_len - copy_len + 1);
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp),
+ " SPLICE_OVERWRITE-%u-%u-%u-%s", copy_from, copy_to,
+ copy_len, target->fname);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ memmove(out_buf + copy_to, new_buf + copy_from, copy_len);
+
+ } else {
+
+ /* insert mode */
+
+ u32 clone_from, clone_to, clone_len;
+
+ clone_len = choose_block_len(afl, new_len);
+ clone_from = rand_below(afl, new_len - clone_len + 1);
+ clone_to = rand_below(afl, temp_len + 1);
+
+ u8 *temp_buf = afl_realloc(AFL_BUF_PARAM(out_scratch),
+ temp_len + clone_len + 1);
+ if (unlikely(!temp_buf)) { PFATAL("alloc"); }
+
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp),
+ " SPLICE_INSERT-%u-%u-%u-%s", clone_from, clone_to,
+ clone_len, target->fname);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ /* Head */
+
+ memcpy(temp_buf, out_buf, clone_to);
+
+ /* Inserted part */
+
+ memcpy(temp_buf + clone_to, new_buf + clone_from, clone_len);
+
+ /* Tail */
+ memcpy(temp_buf + clone_to + clone_len, out_buf + clone_to,
+ temp_len - clone_to);
+
+ out_buf = temp_buf;
+ afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
+ temp_len += clone_len;
+
+ }
+
+ MOpt_globals.cycles_v2[STAGE_Splice]++;
+ break;
+
+ }
+
+ } // end of default:
+
+ } /* switch select_algorithm() */
+
+ } /* for i=0; i < use_stacking */
+
+ ++*MOpt_globals.pTime;
+
+ u64 temp_total_found = afl->queued_items + afl->saved_crashes;
+
+ if (common_fuzz_stuff(afl, out_buf, temp_len)) {
+
+ goto abandon_entry_puppet;
+
+ }
+
+ /* out_buf might have been mangled a bit, so let's restore it to its
+ original size and shape. */
+
+ out_buf = afl_realloc(AFL_BUF_PARAM(out), len);
+ if (unlikely(!out_buf)) { PFATAL("alloc"); }
+ temp_len = len;
+ memcpy(out_buf, in_buf, len);
+
+ /* If we're finding new stuff, let's run for a bit longer, limits
+ permitting. */
+
+ if (afl->queued_items != havoc_queued) {
+
+ if (perf_score <= afl->havoc_max_mult * 100) {
+
+ afl->stage_max *= 2;
+ perf_score *= 2;
+
+ }
+
+ havoc_queued = afl->queued_items;
+
+ }
+
+ if (unlikely(afl->queued_items + afl->saved_crashes >
+ temp_total_found)) {
+
+ u64 temp_temp_puppet =
+ afl->queued_items + afl->saved_crashes - temp_total_found;
+ afl->total_puppet_find = afl->total_puppet_find + temp_temp_puppet;
+
+ if (MOpt_globals.is_pilot_mode) {
+
+ for (i = 0; i < operator_num; ++i) {
+
+ if (MOpt_globals.cycles_v2[i] > MOpt_globals.cycles_v3[i]) {
+
+ MOpt_globals.finds_v2[i] += temp_temp_puppet;
+
+ }
+
+ }
+
+ } else {
+
+ for (i = 0; i < operator_num; i++) {
+
+ if (afl->core_operator_cycles_puppet_v2[i] >
+ afl->core_operator_cycles_puppet_v3[i])
+
+ afl->core_operator_finds_puppet_v2[i] += temp_temp_puppet;
+
+ }
+
+ }
+
+ } /* if */
+
+ } /* for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max;
+
+ ++afl->stage_cur) { */
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ if (MOpt_globals.is_pilot_mode) {
+
+ if (!splice_cycle) {
+
+ afl->stage_finds[STAGE_HAVOC] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_HAVOC] += afl->stage_max;
+
+ } else {
+
+ afl->stage_finds[STAGE_SPLICE] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_SPLICE] += afl->stage_max;
+
+ }
+
+ }
+
+#ifndef IGNORE_FINDS
+
+ /************
+ * SPLICING *
+ ************/
+
+ retry_splicing_puppet:
+
+ if (afl->use_splicing &&
+ splice_cycle++ < (u32)afl->SPLICE_CYCLES_puppet &&
+ afl->ready_for_splicing_count > 1 && afl->queue_cur->len >= 4) {
+
+ struct queue_entry *target;
+ u32 tid, split_at;
+ u8 * new_buf;
+ s32 f_diff, l_diff;
+
+ /* First of all, if we've modified in_buf for havoc, let's clean that
+ up... */
+
+ if (in_buf != orig_in) {
+
+ in_buf = orig_in;
+ len = afl->queue_cur->len;
+
+ }
+
+ /* Pick a random queue entry and seek to it. Don't splice with yourself.
+ */
+
+ do {
+
+ tid = rand_below(afl, afl->queued_items);
+
+ } while (tid == afl->current_entry || afl->queue_buf[tid]->len < 4);
+
+ afl->splicing_with = tid;
+ target = afl->queue_buf[tid];
+
+ /* Read the testcase into a new buffer. */
+ new_buf = queue_testcase_get(afl, target);
+
+ /* Find a suitable splicin g location, somewhere between the first and
+ the last differing byte. Bail out if the difference is just a single
+ byte or so. */
+
+ locate_diffs(in_buf, new_buf, MIN(len, target->len), &f_diff, &l_diff);
+
+ if (f_diff < 0 || l_diff < 2 || f_diff == l_diff) {
+
+ goto retry_splicing_puppet;
+
+ }
+
+ /* Split somewhere between the first and last differing byte. */
+
+ split_at = f_diff + rand_below(afl, l_diff - f_diff);
+
+ /* Do the thing. */
+
+ len = target->len;
+ afl->in_scratch_buf = afl_realloc(AFL_BUF_PARAM(in_scratch), len);
+ memcpy(afl->in_scratch_buf, in_buf, split_at);
+ memcpy(afl->in_scratch_buf + split_at, new_buf, len - split_at);
+ in_buf = afl->in_scratch_buf;
+ afl_swap_bufs(AFL_BUF_PARAM(in), AFL_BUF_PARAM(in_scratch));
+
+ out_buf = afl_realloc(AFL_BUF_PARAM(out), len);
+ if (unlikely(!out_buf)) { PFATAL("alloc"); }
+ memcpy(out_buf, in_buf, len);
+
+ goto havoc_stage_puppet;
+
+ } /* if splice_cycle */
+
+#endif /* !IGNORE_FINDS */
+
+ ret_val = 0;
+
+ abandon_entry:
+ abandon_entry_puppet:
+
+ if ((s64)splice_cycle >= afl->SPLICE_CYCLES_puppet) {
+
+ afl->SPLICE_CYCLES_puppet =
+ (rand_below(
+ afl, SPLICE_CYCLES_puppet_up - SPLICE_CYCLES_puppet_low + 1) +
+ SPLICE_CYCLES_puppet_low);
+
+ }
+
+ afl->splicing_with = -1;
+
+ /* Update afl->pending_not_fuzzed count if we made it through the
+ calibration cycle and have not seen this entry before. */
+ /*
+ // TODO FIXME: I think we need this plus need an -L -1 check
+ if (!afl->stop_soon && !afl->queue_cur->cal_failed &&
+ (afl->queue_cur->was_fuzzed == 0 || afl->queue_cur->fuzz_level == 0)
+ && !afl->queue_cur->disabled) {
+
+ if (!afl->queue_cur->was_fuzzed) {
+
+ --afl->pending_not_fuzzed;
+ afl->queue_cur->was_fuzzed = 1;
+ if (afl->queue_cur->favored) { --afl->pending_favored; }
+
+ }
+
+ }
+
+ */
+
+ orig_in = NULL;
+
+ if (afl->key_puppet == 1) {
+
+ if (unlikely(
+ afl->queued_items + afl->saved_crashes >
+ ((afl->queued_items + afl->saved_crashes) * limit_time_bound +
+ afl->orig_hit_cnt_puppet))) {
+
+ afl->key_puppet = 0;
+ afl->orig_hit_cnt_puppet = 0;
+ afl->last_limit_time_start = 0;
+
+ }
+
+ }
+
+ if (unlikely(*MOpt_globals.pTime > MOpt_globals.period)) {
+
+ afl->total_pacemaker_time += *MOpt_globals.pTime;
+ *MOpt_globals.pTime = 0;
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ if (MOpt_globals.is_pilot_mode) {
+
+ afl->swarm_fitness[afl->swarm_now] =
+ (double)(afl->total_puppet_find - afl->temp_puppet_find) /
+ ((double)(afl->tmp_pilot_time) / afl->period_pilot_tmp);
+
+ }
+
+ afl->temp_puppet_find = afl->total_puppet_find;
+ for (i = 0; i < operator_num; ++i) {
+
+ if (MOpt_globals.is_pilot_mode) {
+
+ double temp_eff = 0.0;
+
+ if (MOpt_globals.cycles_v2[i] > MOpt_globals.cycles[i]) {
+
+ temp_eff =
+ (double)(MOpt_globals.finds_v2[i] - MOpt_globals.finds[i]) /
+ (double)(MOpt_globals.cycles_v2[i] - MOpt_globals.cycles[i]);
+
+ }
+
+ if (afl->eff_best[afl->swarm_now][i] < temp_eff) {
+
+ afl->eff_best[afl->swarm_now][i] = temp_eff;
+ afl->L_best[afl->swarm_now][i] = afl->x_now[afl->swarm_now][i];
+
+ }
+
+ }
+
+ MOpt_globals.finds[i] = MOpt_globals.finds_v2[i];
+ MOpt_globals.cycles[i] = MOpt_globals.cycles_v2[i];
+
+ } /* for i = 0; i < operator_num */
+
+ if (MOpt_globals.is_pilot_mode) {
+
+ afl->swarm_now = afl->swarm_now + 1;
+ if (afl->swarm_now == swarm_num) {
+
+ afl->key_module = 1;
+ for (i = 0; i < operator_num; ++i) {
+
+ afl->core_operator_cycles_puppet_v2[i] =
+ afl->core_operator_cycles_puppet[i];
+ afl->core_operator_cycles_puppet_v3[i] =
+ afl->core_operator_cycles_puppet[i];
+ afl->core_operator_finds_puppet_v2[i] =
+ afl->core_operator_finds_puppet[i];
+
+ }
+
+ double swarm_eff = 0.0;
+ afl->swarm_now = 0;
+ for (i = 0; i < swarm_num; ++i) {
+
+ if (afl->swarm_fitness[i] > swarm_eff) {
+
+ swarm_eff = afl->swarm_fitness[i];
+ afl->swarm_now = i;
+
+ }
+
+ }
+
+ if (afl->swarm_now < 0 || afl->swarm_now > swarm_num - 1) {
+
+ PFATAL("swarm_now error number %d", afl->swarm_now);
+
+ }
+
+ } /* if afl->swarm_now == swarm_num */
+
+ /* adjust pointers dependent on 'afl->swarm_now' */
+ afl->mopt_globals_pilot.finds =
+ afl->stage_finds_puppet[afl->swarm_now];
+ afl->mopt_globals_pilot.finds_v2 =
+ afl->stage_finds_puppet_v2[afl->swarm_now];
+ afl->mopt_globals_pilot.cycles =
+ afl->stage_cycles_puppet[afl->swarm_now];
+ afl->mopt_globals_pilot.cycles_v2 =
+ afl->stage_cycles_puppet_v2[afl->swarm_now];
+ afl->mopt_globals_pilot.cycles_v3 =
+ afl->stage_cycles_puppet_v3[afl->swarm_now];
+
+ } else {
+
+ for (i = 0; i < operator_num; i++) {
+
+ afl->core_operator_finds_puppet[i] =
+ afl->core_operator_finds_puppet_v2[i];
+ afl->core_operator_cycles_puppet[i] =
+ afl->core_operator_cycles_puppet_v2[i];
+
+ }
+
+ afl->key_module = 2;
+
+ afl->old_hit_count = new_hit_cnt;
+
+ } /* if pilot_mode */
+
+ } /* if (unlikely(*MOpt_globals.pTime > MOpt_globals.period)) */
+
+ } /* block */
+
+ } /* block */
+
+ return ret_val;
+
+}
+
+#undef FLIP_BIT
+
+u8 core_fuzzing(afl_state_t *afl) {
+
+ return mopt_common_fuzzing(afl, afl->mopt_globals_core);
+
+}
+
+u8 pilot_fuzzing(afl_state_t *afl) {
+
+ return mopt_common_fuzzing(afl, afl->mopt_globals_pilot);
+
+}
+
+void pso_updating(afl_state_t *afl) {
+
+ afl->g_now++;
+ if (afl->g_now > afl->g_max) { afl->g_now = 0; }
+ afl->w_now =
+ (afl->w_init - afl->w_end) * (afl->g_max - afl->g_now) / (afl->g_max) +
+ afl->w_end;
+ int tmp_swarm, i, j;
+ u64 temp_operator_finds_puppet = 0;
+ for (i = 0; i < operator_num; ++i) {
+
+ afl->operator_finds_puppet[i] = afl->core_operator_finds_puppet[i];
+
+ for (j = 0; j < swarm_num; ++j) {
+
+ afl->operator_finds_puppet[i] =
+ afl->operator_finds_puppet[i] + afl->stage_finds_puppet[j][i];
+
+ }
+
+ temp_operator_finds_puppet =
+ temp_operator_finds_puppet + afl->operator_finds_puppet[i];
+
+ }
+
+ for (i = 0; i < operator_num; ++i) {
+
+ if (afl->operator_finds_puppet[i]) {
+
+ afl->G_best[i] = (double)((double)(afl->operator_finds_puppet[i]) /
+ (double)(temp_operator_finds_puppet));
+
+ }
+
+ }
+
+ for (tmp_swarm = 0; tmp_swarm < swarm_num; ++tmp_swarm) {
+
+ double x_temp = 0.0;
+ for (i = 0; i < operator_num; ++i) {
+
+ afl->probability_now[tmp_swarm][i] = 0.0;
+ afl->v_now[tmp_swarm][i] =
+ afl->w_now * afl->v_now[tmp_swarm][i] +
+ RAND_C * (afl->L_best[tmp_swarm][i] - afl->x_now[tmp_swarm][i]) +
+ RAND_C * (afl->G_best[i] - afl->x_now[tmp_swarm][i]);
+ afl->x_now[tmp_swarm][i] += afl->v_now[tmp_swarm][i];
+ if (afl->x_now[tmp_swarm][i] > v_max) {
+
+ afl->x_now[tmp_swarm][i] = v_max;
+
+ } else if (afl->x_now[tmp_swarm][i] < v_min) {
+
+ afl->x_now[tmp_swarm][i] = v_min;
+
+ }
+
+ x_temp += afl->x_now[tmp_swarm][i];
+
+ }
+
+ for (i = 0; i < operator_num; ++i) {
+
+ afl->x_now[tmp_swarm][i] = afl->x_now[tmp_swarm][i] / x_temp;
+ if (likely(i != 0)) {
+
+ afl->probability_now[tmp_swarm][i] =
+ afl->probability_now[tmp_swarm][i - 1] + afl->x_now[tmp_swarm][i];
+
+ } else {
+
+ afl->probability_now[tmp_swarm][i] = afl->x_now[tmp_swarm][i];
+
+ }
+
+ }
+
+ if (afl->probability_now[tmp_swarm][operator_num - 1] < 0.99 ||
+ afl->probability_now[tmp_swarm][operator_num - 1] > 1.01) {
+
+ FATAL("ERROR probability");
+
+ }
+
+ }
+
+ afl->swarm_now = 0;
+ afl->key_module = 0;
+
+}
+
+/* larger change for MOpt implementation: the original fuzz_one was renamed
+ to fuzz_one_original. All documentation references to fuzz_one therefore
+ mean fuzz_one_original */
+
+u8 fuzz_one(afl_state_t *afl) {
+
+ int key_val_lv_1 = 0, key_val_lv_2 = 0;
+
+#ifdef _AFL_DOCUMENT_MUTATIONS
+
+ u8 path_buf[PATH_MAX];
+ if (afl->do_document == 0) {
+
+ snprintf(path_buf, PATH_MAX, "%s/mutations", afl->out_dir);
+ afl->do_document = mkdir(path_buf, 0700); // if it exists we do not care
+ afl->do_document = 1;
+
+ } else {
+
+ afl->do_document = 2;
+ afl->stop_soon = 2;
+
+ }
+
+#endif
+
+ // if limit_time_sig == -1 then both are run after each other
+
+ if (afl->limit_time_sig <= 0) { key_val_lv_1 = fuzz_one_original(afl); }
+
+ if (afl->limit_time_sig != 0) {
+
+ if (afl->key_module == 0) {
+
+ key_val_lv_2 = pilot_fuzzing(afl);
+
+ } else if (afl->key_module == 1) {
+
+ key_val_lv_2 = core_fuzzing(afl);
+
+ } else if (afl->key_module == 2) {
+
+ pso_updating(afl);
+
+ }
+
+ }
+
+ return (key_val_lv_1 | key_val_lv_2);
+
+}
+
diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c
new file mode 100644
index 00000000..65501c8c
--- /dev/null
+++ b/src/afl-fuzz-python.c
@@ -0,0 +1,894 @@
+/*
+ american fuzzy lop++ - python extension routines
+ ------------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Andrea Fioraldi <andreafioraldi@gmail.com>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ This is the real deal: the program takes an instrumented binary and
+ attempts a variety of basic fuzzing tricks, paying close attention to
+ how they affect the execution path.
+
+ */
+
+#include "afl-fuzz.h"
+
+/* Python stuff */
+#ifdef USE_PYTHON
+
+static void *unsupported(afl_state_t *afl, unsigned int seed) {
+
+ (void)afl;
+ (void)seed;
+
+ FATAL("Python Mutator cannot be called twice yet");
+ return NULL;
+
+}
+
+ /* sorry for this makro...
+ it just fills in `&py_mutator->something_buf, &py_mutator->something_size`. */
+ #define BUF_PARAMS(name) (void **)&((py_mutator_t *)py_mutator)->name##_buf
+
+static size_t fuzz_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf,
+ u8 *add_buf, size_t add_buf_size, size_t max_size) {
+
+ size_t mutated_size;
+ PyObject *py_args, *py_value;
+ py_args = PyTuple_New(3);
+ py_mutator_t *py = (py_mutator_t *)py_mutator;
+
+ /* buf */
+ py_value = PyByteArray_FromStringAndSize(buf, buf_size);
+ if (!py_value) {
+
+ Py_DECREF(py_args);
+ FATAL("Failed to convert arguments");
+
+ }
+
+ PyTuple_SetItem(py_args, 0, py_value);
+
+ /* add_buf */
+ py_value = PyByteArray_FromStringAndSize(add_buf, add_buf_size);
+ if (!py_value) {
+
+ Py_DECREF(py_args);
+ FATAL("Failed to convert arguments");
+
+ }
+
+ PyTuple_SetItem(py_args, 1, py_value);
+
+ /* max_size */
+ #if PY_MAJOR_VERSION >= 3
+ py_value = PyLong_FromLong(max_size);
+ #else
+ py_value = PyInt_FromLong(max_size);
+ #endif
+ if (!py_value) {
+
+ Py_DECREF(py_args);
+ FATAL("Failed to convert arguments");
+
+ }
+
+ PyTuple_SetItem(py_args, 2, py_value);
+
+ py_value = PyObject_CallObject(py->py_functions[PY_FUNC_FUZZ], py_args);
+
+ Py_DECREF(py_args);
+
+ if (py_value != NULL) {
+
+ mutated_size = PyByteArray_Size(py_value);
+
+ *out_buf = afl_realloc(BUF_PARAMS(fuzz), mutated_size);
+ if (unlikely(!*out_buf)) { PFATAL("alloc"); }
+
+ memcpy(*out_buf, PyByteArray_AsString(py_value), mutated_size);
+ Py_DECREF(py_value);
+ return mutated_size;
+
+ } else {
+
+ PyErr_Print();
+ FATAL("python custom fuzz: call failed");
+
+ }
+
+}
+
+static const char *custom_describe_py(void * py_mutator,
+ size_t max_description_len) {
+
+ PyObject *py_args, *py_value;
+
+ py_args = PyTuple_New(1);
+
+ PyLong_FromSize_t(max_description_len);
+
+ /* add_buf */
+ py_value = PyLong_FromSize_t(max_description_len);
+ if (!py_value) {
+
+ Py_DECREF(py_args);
+ FATAL("Failed to convert arguments");
+
+ }
+
+ PyTuple_SetItem(py_args, 0, py_value);
+
+ py_value = PyObject_CallObject(
+ ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_DESCRIBE], py_args);
+
+ Py_DECREF(py_args);
+
+ if (py_value != NULL) { return PyBytes_AsString(py_value); }
+
+ return NULL;
+
+}
+
+static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) {
+
+ (void)afl;
+
+ if (!module_name) { return NULL; }
+
+ py_mutator_t *py = calloc(1, sizeof(py_mutator_t));
+ if (!py) { PFATAL("Could not allocate memory for python mutator!"); }
+
+ Py_Initialize();
+
+ #if PY_MAJOR_VERSION >= 3
+ PyObject *py_name = PyUnicode_FromString(module_name);
+ #else
+ PyObject *py_name = PyString_FromString(module_name);
+ #endif
+
+ py->py_module = PyImport_Import(py_name);
+ Py_DECREF(py_name);
+
+ PyObject * py_module = py->py_module;
+ PyObject **py_functions = py->py_functions;
+
+ // initialize the post process buffer; ensures it's always valid
+ PyObject *unused_bytes = PyByteArray_FromStringAndSize("OHAI", 4);
+ if (!unused_bytes) { FATAL("allocation failed!"); }
+ if (PyObject_GetBuffer(unused_bytes, &py->post_process_buf, PyBUF_SIMPLE) ==
+ -1) {
+
+ FATAL("buffer initialization failed");
+
+ }
+
+ Py_DECREF(unused_bytes);
+
+ if (py_module != NULL) {
+
+ u8 py_notrim = 0, py_idx;
+ /* init, required */
+ py_functions[PY_FUNC_INIT] = PyObject_GetAttrString(py_module, "init");
+ if (!py_functions[PY_FUNC_INIT])
+ FATAL("init function not found in python module");
+ py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "fuzz");
+ if (!py_functions[PY_FUNC_FUZZ])
+ py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "mutate");
+ py_functions[PY_FUNC_DESCRIBE] =
+ PyObject_GetAttrString(py_module, "describe");
+ py_functions[PY_FUNC_FUZZ_COUNT] =
+ PyObject_GetAttrString(py_module, "fuzz_count");
+ if (!py_functions[PY_FUNC_FUZZ])
+ WARNF("fuzz function not found in python module");
+ py_functions[PY_FUNC_POST_PROCESS] =
+ PyObject_GetAttrString(py_module, "post_process");
+ py_functions[PY_FUNC_INIT_TRIM] =
+ PyObject_GetAttrString(py_module, "init_trim");
+ py_functions[PY_FUNC_POST_TRIM] =
+ PyObject_GetAttrString(py_module, "post_trim");
+ py_functions[PY_FUNC_TRIM] = PyObject_GetAttrString(py_module, "trim");
+ py_functions[PY_FUNC_HAVOC_MUTATION] =
+ PyObject_GetAttrString(py_module, "havoc_mutation");
+ py_functions[PY_FUNC_HAVOC_MUTATION_PROBABILITY] =
+ PyObject_GetAttrString(py_module, "havoc_mutation_probability");
+ py_functions[PY_FUNC_QUEUE_GET] =
+ PyObject_GetAttrString(py_module, "queue_get");
+ py_functions[PY_FUNC_QUEUE_NEW_ENTRY] =
+ PyObject_GetAttrString(py_module, "queue_new_entry");
+ py_functions[PY_FUNC_INTROSPECTION] =
+ PyObject_GetAttrString(py_module, "introspection");
+ py_functions[PY_FUNC_DEINIT] = PyObject_GetAttrString(py_module, "deinit");
+ if (!py_functions[PY_FUNC_DEINIT])
+ WARNF("deinit function not found in python module");
+
+ for (py_idx = 0; py_idx < PY_FUNC_COUNT; ++py_idx) {
+
+ if (!py_functions[py_idx] || !PyCallable_Check(py_functions[py_idx])) {
+
+ if (py_idx >= PY_FUNC_INIT_TRIM && py_idx <= PY_FUNC_TRIM) {
+
+ // Implementing the trim API is optional for now
+ if (PyErr_Occurred()) { PyErr_Print(); }
+ py_notrim = 1;
+
+ } else if (py_idx >= PY_OPTIONAL) {
+
+ // Only _init and _deinit are not optional currently
+
+ if (PyErr_Occurred()) { PyErr_Print(); }
+
+ } else {
+
+ fprintf(stderr,
+ "Cannot find/call function with index %d in external "
+ "Python module.\n",
+ py_idx);
+ return NULL;
+
+ }
+
+ }
+
+ }
+
+ if (py_notrim) {
+
+ py_functions[PY_FUNC_INIT_TRIM] = NULL;
+ py_functions[PY_FUNC_POST_TRIM] = NULL;
+ py_functions[PY_FUNC_TRIM] = NULL;
+ WARNF(
+ "Python module does not implement trim API, standard trimming will "
+ "be used.");
+
+ }
+
+ } else {
+
+ PyErr_Print();
+ fprintf(stderr, "Failed to load \"%s\"\n", module_name);
+ free(py);
+ return NULL;
+
+ }
+
+ return py;
+
+}
+
+void finalize_py_module(void *py_mutator) {
+
+ py_mutator_t *py = (py_mutator_t *)py_mutator;
+
+ if (py->py_module != NULL) {
+
+ deinit_py(py_mutator);
+
+ u32 i;
+ for (i = 0; i < PY_FUNC_COUNT; ++i) {
+
+ Py_XDECREF(py->py_functions[i]);
+
+ }
+
+ Py_DECREF(py->py_module);
+
+ }
+
+ Py_Finalize();
+
+}
+
+static void init_py(afl_state_t *afl, py_mutator_t *py_mutator,
+ unsigned int seed) {
+
+ (void)afl;
+
+ PyObject *py_args, *py_value;
+
+ /* Provide the init function a seed for the Python RNG */
+ py_args = PyTuple_New(1);
+ #if PY_MAJOR_VERSION >= 3
+ py_value = PyLong_FromLong(seed);
+ #else
+ py_value = PyInt_FromLong(seed);
+ #endif
+
+ if (!py_value) {
+
+ Py_DECREF(py_args);
+ FATAL("Cannot convert argument in python init.");
+
+ }
+
+ PyTuple_SetItem(py_args, 0, py_value);
+
+ py_value =
+ PyObject_CallObject(py_mutator->py_functions[PY_FUNC_INIT], py_args);
+
+ Py_DECREF(py_args);
+
+ if (py_value == NULL) {
+
+ PyErr_Print();
+ fprintf(stderr, "Call failed\n");
+ FATAL("Custom py mutator INIT failed.");
+
+ }
+
+}
+
+void deinit_py(void *py_mutator) {
+
+ PyObject *py_args, *py_value;
+
+ py_args = PyTuple_New(0);
+ py_value = PyObject_CallObject(
+ ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_DEINIT], py_args);
+ Py_DECREF(py_args);
+
+ if (py_value != NULL) {
+
+ Py_DECREF(py_value);
+
+ } else {
+
+ PyErr_Print();
+ FATAL("Call failed");
+
+ }
+
+}
+
+struct custom_mutator *load_custom_mutator_py(afl_state_t *afl,
+ char * module_name) {
+
+ struct custom_mutator *mutator;
+
+ mutator = ck_alloc(sizeof(struct custom_mutator));
+
+ mutator->name = module_name;
+ ACTF("Loading Python mutator library from '%s'...", module_name);
+
+ py_mutator_t *py_mutator;
+ py_mutator = init_py_module(afl, module_name);
+ mutator->data = py_mutator;
+ if (!py_mutator) { FATAL("Failed to load python mutator."); }
+
+ PyObject **py_functions = py_mutator->py_functions;
+
+ if (py_functions[PY_FUNC_INIT]) { mutator->afl_custom_init = unsupported; }
+
+ if (py_functions[PY_FUNC_DEINIT]) { mutator->afl_custom_deinit = deinit_py; }
+
+ if (py_functions[PY_FUNC_FUZZ]) { mutator->afl_custom_fuzz = fuzz_py; }
+
+ if (py_functions[PY_FUNC_DESCRIBE]) {
+
+ mutator->afl_custom_describe = custom_describe_py;
+
+ }
+
+ if (py_functions[PY_FUNC_POST_PROCESS]) {
+
+ mutator->afl_custom_post_process = post_process_py;
+
+ }
+
+ if (py_functions[PY_FUNC_INIT_TRIM]) {
+
+ mutator->afl_custom_init_trim = init_trim_py;
+
+ }
+
+ if (py_functions[PY_FUNC_FUZZ_COUNT]) {
+
+ mutator->afl_custom_fuzz_count = fuzz_count_py;
+
+ }
+
+ if (py_functions[PY_FUNC_POST_TRIM]) {
+
+ mutator->afl_custom_post_trim = post_trim_py;
+
+ }
+
+ if (py_functions[PY_FUNC_TRIM]) { mutator->afl_custom_trim = trim_py; }
+
+ if (py_functions[PY_FUNC_HAVOC_MUTATION]) {
+
+ mutator->afl_custom_havoc_mutation = havoc_mutation_py;
+
+ }
+
+ if (py_functions[PY_FUNC_HAVOC_MUTATION_PROBABILITY]) {
+
+ mutator->afl_custom_havoc_mutation_probability =
+ havoc_mutation_probability_py;
+
+ }
+
+ if (py_functions[PY_FUNC_QUEUE_GET]) {
+
+ mutator->afl_custom_queue_get = queue_get_py;
+
+ }
+
+ if (py_functions[PY_FUNC_QUEUE_NEW_ENTRY]) {
+
+ mutator->afl_custom_queue_new_entry = queue_new_entry_py;
+
+ }
+
+ #ifdef INTROSPECTION
+ if (py_functions[PY_FUNC_INTROSPECTION]) {
+
+ mutator->afl_custom_introspection = introspection_py;
+
+ }
+
+ #endif
+
+ OKF("Python mutator '%s' installed successfully.", module_name);
+
+ /* Initialize the custom mutator */
+ init_py(afl, py_mutator, rand_below(afl, 0xFFFFFFFF));
+
+ mutator->stacked_custom = (mutator && mutator->afl_custom_havoc_mutation);
+ mutator->stacked_custom_prob =
+ 6; // like one of the default mutations in havoc
+
+ return mutator;
+
+}
+
+size_t post_process_py(void *py_mutator, u8 *buf, size_t buf_size,
+ u8 **out_buf) {
+
+ PyObject * py_args, *py_value;
+ py_mutator_t *py = (py_mutator_t *)py_mutator;
+
+ // buffer returned previously must be released; initialized during init
+ // so we don't need to do comparisons
+ PyBuffer_Release(&py->post_process_buf);
+
+ py_args = PyTuple_New(1);
+ py_value = PyByteArray_FromStringAndSize(buf, buf_size);
+ if (!py_value) {
+
+ Py_DECREF(py_args);
+ FATAL("Failed to convert arguments in custom post_process");
+
+ }
+
+ PyTuple_SetItem(py_args, 0, py_value);
+
+ py_value = PyObject_CallObject(
+ ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_POST_PROCESS],
+ py_args);
+
+ Py_DECREF(py_args);
+
+ if (py_value != NULL) {
+
+ if (PyObject_GetBuffer(py_value, &py->post_process_buf, PyBUF_SIMPLE) ==
+ -1) {
+
+ PyErr_Print();
+ FATAL(
+ "Python custom mutator: post_process call return value not a "
+ "bytes-like object");
+
+ }
+
+ Py_DECREF(py_value);
+
+ *out_buf = (u8 *)py->post_process_buf.buf;
+ return py->post_process_buf.len;
+
+ } else {
+
+ PyErr_Print();
+ FATAL("Python custom mutator: post_process call failed.");
+
+ }
+
+}
+
+s32 init_trim_py(void *py_mutator, u8 *buf, size_t buf_size) {
+
+ PyObject *py_args, *py_value;
+
+ py_args = PyTuple_New(1);
+ py_value = PyByteArray_FromStringAndSize(buf, buf_size);
+ if (!py_value) {
+
+ Py_DECREF(py_args);
+ FATAL("Failed to convert arguments");
+
+ }
+
+ PyTuple_SetItem(py_args, 0, py_value);
+
+ py_value = PyObject_CallObject(
+ ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_INIT_TRIM], py_args);
+ Py_DECREF(py_args);
+
+ if (py_value != NULL) {
+
+ #if PY_MAJOR_VERSION >= 3
+ u32 retcnt = (u32)PyLong_AsLong(py_value);
+ #else
+ u32 retcnt = PyInt_AsLong(py_value);
+ #endif
+ Py_DECREF(py_value);
+ return retcnt;
+
+ } else {
+
+ PyErr_Print();
+ FATAL("Call failed");
+
+ }
+
+}
+
+u32 fuzz_count_py(void *py_mutator, const u8 *buf, size_t buf_size) {
+
+ PyObject *py_args, *py_value;
+
+ py_args = PyTuple_New(1);
+ py_value = PyByteArray_FromStringAndSize(buf, buf_size);
+ if (!py_value) {
+
+ Py_DECREF(py_args);
+ FATAL("Failed to convert arguments");
+
+ }
+
+ PyTuple_SetItem(py_args, 0, py_value);
+
+ py_value = PyObject_CallObject(
+ ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_FUZZ_COUNT], py_args);
+ Py_DECREF(py_args);
+
+ if (py_value != NULL) {
+
+ #if PY_MAJOR_VERSION >= 3
+ u32 retcnt = (u32)PyLong_AsLong(py_value);
+ #else
+ u32 retcnt = PyInt_AsLong(py_value);
+ #endif
+ Py_DECREF(py_value);
+ return retcnt;
+
+ } else {
+
+ PyErr_Print();
+ FATAL("Call failed");
+
+ }
+
+}
+
+s32 post_trim_py(void *py_mutator, u8 success) {
+
+ PyObject *py_args, *py_value;
+
+ py_args = PyTuple_New(1);
+
+ py_value = PyBool_FromLong(success);
+ if (!py_value) {
+
+ Py_DECREF(py_args);
+ FATAL("Failed to convert arguments");
+
+ }
+
+ PyTuple_SetItem(py_args, 0, py_value);
+
+ py_value = PyObject_CallObject(
+ ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_POST_TRIM], py_args);
+ Py_DECREF(py_args);
+
+ if (py_value != NULL) {
+
+ #if PY_MAJOR_VERSION >= 3
+ u32 retcnt = (u32)PyLong_AsLong(py_value);
+ #else
+ u32 retcnt = PyInt_AsLong(py_value);
+ #endif
+ Py_DECREF(py_value);
+ return retcnt;
+
+ } else {
+
+ PyErr_Print();
+ FATAL("Call failed");
+
+ }
+
+}
+
+size_t trim_py(void *py_mutator, u8 **out_buf) {
+
+ PyObject *py_args, *py_value;
+ size_t ret;
+
+ py_args = PyTuple_New(0);
+ py_value = PyObject_CallObject(
+ ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_TRIM], py_args);
+ Py_DECREF(py_args);
+
+ if (py_value != NULL) {
+
+ ret = PyByteArray_Size(py_value);
+ *out_buf = afl_realloc(BUF_PARAMS(trim), ret);
+ if (unlikely(!*out_buf)) { PFATAL("alloc"); }
+ memcpy(*out_buf, PyByteArray_AsString(py_value), ret);
+ Py_DECREF(py_value);
+
+ } else {
+
+ PyErr_Print();
+ FATAL("Call failed");
+
+ }
+
+ return ret;
+
+}
+
+size_t havoc_mutation_py(void *py_mutator, u8 *buf, size_t buf_size,
+ u8 **out_buf, size_t max_size) {
+
+ size_t mutated_size;
+ PyObject *py_args, *py_value;
+ py_args = PyTuple_New(2);
+
+ /* buf */
+ py_value = PyByteArray_FromStringAndSize(buf, buf_size);
+ if (!py_value) {
+
+ Py_DECREF(py_args);
+ FATAL("Failed to convert arguments");
+
+ }
+
+ PyTuple_SetItem(py_args, 0, py_value);
+
+ /* max_size */
+ #if PY_MAJOR_VERSION >= 3
+ py_value = PyLong_FromLong(max_size);
+ #else
+ py_value = PyInt_FromLong(max_size);
+ #endif
+ if (!py_value) {
+
+ Py_DECREF(py_args);
+ FATAL("Failed to convert arguments");
+
+ }
+
+ PyTuple_SetItem(py_args, 1, py_value);
+
+ py_value = PyObject_CallObject(
+ ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_HAVOC_MUTATION],
+ py_args);
+
+ Py_DECREF(py_args);
+
+ if (py_value != NULL) {
+
+ mutated_size = PyByteArray_Size(py_value);
+ if (mutated_size <= buf_size) {
+
+ /* We reuse the input buf here. */
+ *out_buf = buf;
+
+ } else {
+
+ /* A new buf is needed... */
+ *out_buf = afl_realloc(BUF_PARAMS(havoc), mutated_size);
+ if (unlikely(!*out_buf)) { PFATAL("alloc"); }
+
+ }
+
+ memcpy(*out_buf, PyByteArray_AsString(py_value), mutated_size);
+
+ Py_DECREF(py_value);
+ return mutated_size;
+
+ } else {
+
+ PyErr_Print();
+ FATAL("Call failed");
+
+ }
+
+}
+
+u8 havoc_mutation_probability_py(void *py_mutator) {
+
+ PyObject *py_args, *py_value;
+
+ py_args = PyTuple_New(0);
+ py_value = PyObject_CallObject(
+ ((py_mutator_t *)py_mutator)
+ ->py_functions[PY_FUNC_HAVOC_MUTATION_PROBABILITY],
+ py_args);
+ Py_DECREF(py_args);
+
+ if (py_value != NULL) {
+
+ long prob = PyLong_AsLong(py_value);
+ Py_DECREF(py_value);
+ return (u8)prob;
+
+ } else {
+
+ PyErr_Print();
+ FATAL("Call failed");
+
+ }
+
+}
+
+const char *introspection_py(void *py_mutator) {
+
+ PyObject *py_args, *py_value;
+
+ py_args = PyTuple_New(0);
+ py_value = PyObject_CallObject(
+ ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_INTROSPECTION],
+ py_args);
+ Py_DECREF(py_args);
+
+ if (py_value == NULL) {
+
+ return NULL;
+
+ } else {
+
+ return PyByteArray_AsString(py_value);
+
+ }
+
+}
+
+u8 queue_get_py(void *py_mutator, const u8 *filename) {
+
+ PyObject *py_args, *py_value;
+
+ py_args = PyTuple_New(1);
+
+ // File name
+ #if PY_MAJOR_VERSION >= 3
+ py_value = PyUnicode_FromString(filename);
+ #else
+ py_value = PyString_FromString(filename);
+ #endif
+ if (!py_value) {
+
+ Py_DECREF(py_args);
+ FATAL("Failed to convert arguments");
+
+ }
+
+ PyTuple_SetItem(py_args, 0, py_value);
+
+ // Call Python function
+ py_value = PyObject_CallObject(
+ ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_QUEUE_GET], py_args);
+ Py_DECREF(py_args);
+
+ if (py_value != NULL) {
+
+ int ret = PyObject_IsTrue(py_value);
+ Py_DECREF(py_value);
+
+ if (ret == -1) {
+
+ PyErr_Print();
+ FATAL("Failed to convert return value");
+
+ }
+
+ return (u8)ret & 0xFF;
+
+ } else {
+
+ PyErr_Print();
+ FATAL("Call failed");
+
+ }
+
+}
+
+u8 queue_new_entry_py(void *py_mutator, const u8 *filename_new_queue,
+ const u8 *filename_orig_queue) {
+
+ PyObject *py_args, *py_value;
+
+ py_args = PyTuple_New(2);
+
+ // New queue
+ #if PY_MAJOR_VERSION >= 3
+ py_value = PyUnicode_FromString(filename_new_queue);
+ #else
+ py_value = PyString_FromString(filename_new_queue);
+ #endif
+ if (!py_value) {
+
+ Py_DECREF(py_args);
+ FATAL("Failed to convert arguments");
+
+ }
+
+ PyTuple_SetItem(py_args, 0, py_value);
+
+ // Orig queue
+ py_value = Py_None;
+ if (filename_orig_queue) {
+
+ #if PY_MAJOR_VERSION >= 3
+ py_value = PyUnicode_FromString(filename_orig_queue);
+ #else
+ py_value = PyString_FromString(filename_orig_queue);
+ #endif
+ if (!py_value) {
+
+ Py_DECREF(py_args);
+ FATAL("Failed to convert arguments");
+
+ }
+
+ }
+
+ PyTuple_SetItem(py_args, 1, py_value);
+
+ // Call
+ py_value = PyObject_CallObject(
+ ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_QUEUE_NEW_ENTRY],
+ py_args);
+ Py_DECREF(py_args);
+
+ if (py_value != NULL) {
+
+ int ret = PyObject_IsTrue(py_value);
+ Py_DECREF(py_value);
+
+ if (ret == -1) {
+
+ PyErr_Print();
+ FATAL("Failed to convert return value");
+
+ }
+
+ return (u8)ret & 0xFF;
+
+ } else {
+
+ PyErr_Print();
+ FATAL("Call failed");
+
+ }
+
+}
+
+ #undef BUF_PARAMS
+
+#endif /* USE_PYTHON */
+
diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c
new file mode 100644
index 00000000..713c7447
--- /dev/null
+++ b/src/afl-fuzz-queue.c
@@ -0,0 +1,1354 @@
+/*
+ american fuzzy lop++ - queue relates routines
+ ---------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Andrea Fioraldi <andreafioraldi@gmail.com>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ This is the real deal: the program takes an instrumented binary and
+ attempts a variety of basic fuzzing tricks, paying close attention to
+ how they affect the execution path.
+
+ */
+
+#include "afl-fuzz.h"
+#include <limits.h>
+#include <ctype.h>
+#include <math.h>
+
+/* select next queue entry based on alias algo - fast! */
+
+inline u32 select_next_queue_entry(afl_state_t *afl) {
+
+ u32 s = rand_below(afl, afl->queued_items);
+ double p = rand_next_percent(afl);
+ /*
+ fprintf(stderr, "select: p=%f s=%u ... p < prob[s]=%f ? s=%u : alias[%u]=%u"
+ " ==> %u\n", p, s, afl->alias_probability[s], s, s, afl->alias_table[s], p <
+ afl->alias_probability[s] ? s : afl->alias_table[s]);
+ */
+ return (p < afl->alias_probability[s] ? s : afl->alias_table[s]);
+
+}
+
+double compute_weight(afl_state_t *afl, struct queue_entry *q,
+ double avg_exec_us, double avg_bitmap_size,
+ double avg_top_size) {
+
+ double weight = 1.0;
+
+ if (likely(afl->schedule >= FAST && afl->schedule <= RARE)) {
+
+ u32 hits = afl->n_fuzz[q->n_fuzz_entry];
+ if (likely(hits)) { weight *= log10(hits) + 1; }
+
+ }
+
+ if (likely(afl->schedule < RARE)) { weight *= (avg_exec_us / q->exec_us); }
+ weight *= (log(q->bitmap_size) / avg_bitmap_size);
+ weight *= (1 + (q->tc_ref / avg_top_size));
+ if (unlikely(q->favored)) { weight *= 5; }
+ if (unlikely(!q->was_fuzzed)) { weight *= 2; }
+
+ return weight;
+
+}
+
+/* create the alias table that allows weighted random selection - expensive */
+
+void create_alias_table(afl_state_t *afl) {
+
+ u32 n = afl->queued_items, i = 0, a, g;
+ double sum = 0;
+
+ afl->alias_table =
+ (u32 *)afl_realloc((void **)&afl->alias_table, n * sizeof(u32));
+ afl->alias_probability = (double *)afl_realloc(
+ (void **)&afl->alias_probability, n * sizeof(double));
+ double *P = (double *)afl_realloc(AFL_BUF_PARAM(out), n * sizeof(double));
+ int * S = (u32 *)afl_realloc(AFL_BUF_PARAM(out_scratch), n * sizeof(u32));
+ int * L = (u32 *)afl_realloc(AFL_BUF_PARAM(in_scratch), n * sizeof(u32));
+
+ if (!P || !S || !L || !afl->alias_table || !afl->alias_probability) {
+
+ FATAL("could not acquire memory for alias table");
+
+ }
+
+ memset((void *)afl->alias_table, 0, n * sizeof(u32));
+ memset((void *)afl->alias_probability, 0, n * sizeof(double));
+
+ if (likely(afl->schedule < RARE)) {
+
+ double avg_exec_us = 0.0;
+ double avg_bitmap_size = 0.0;
+ double avg_top_size = 0.0;
+ u32 active = 0;
+
+ for (i = 0; i < n; i++) {
+
+ struct queue_entry *q = afl->queue_buf[i];
+
+ // disabled entries might have timings and bitmap values
+ if (likely(!q->disabled)) {
+
+ avg_exec_us += q->exec_us;
+ avg_bitmap_size += log(q->bitmap_size);
+ avg_top_size += q->tc_ref;
+ ++active;
+
+ }
+
+ }
+
+ avg_exec_us /= active;
+ avg_bitmap_size /= active;
+ avg_top_size /= active;
+
+ for (i = 0; i < n; i++) {
+
+ struct queue_entry *q = afl->queue_buf[i];
+
+ if (likely(!q->disabled)) {
+
+ q->weight =
+ compute_weight(afl, q, avg_exec_us, avg_bitmap_size, avg_top_size);
+ q->perf_score = calculate_score(afl, q);
+ sum += q->weight;
+
+ }
+
+ }
+
+ for (i = 0; i < n; i++) {
+
+ // weight is always 0 for disabled entries
+ P[i] = (afl->queue_buf[i]->weight * n) / sum;
+
+ }
+
+ } else {
+
+ for (i = 0; i < n; i++) {
+
+ struct queue_entry *q = afl->queue_buf[i];
+
+ if (likely(!q->disabled)) { q->perf_score = calculate_score(afl, q); }
+
+ sum += q->perf_score;
+
+ }
+
+ for (i = 0; i < n; i++) {
+
+ // perf_score is always 0 for disabled entries
+ P[i] = (afl->queue_buf[i]->perf_score * n) / sum;
+
+ }
+
+ }
+
+ int nS = 0, nL = 0, s;
+ for (s = (s32)n - 1; s >= 0; --s) {
+
+ if (P[s] < 1) {
+
+ S[nS++] = s;
+
+ } else {
+
+ L[nL++] = s;
+
+ }
+
+ }
+
+ while (nS && nL) {
+
+ a = S[--nS];
+ g = L[--nL];
+ afl->alias_probability[a] = P[a];
+ afl->alias_table[a] = g;
+ P[g] = P[g] + P[a] - 1;
+ if (P[g] < 1) {
+
+ S[nS++] = g;
+
+ } else {
+
+ L[nL++] = g;
+
+ }
+
+ }
+
+ while (nL)
+ afl->alias_probability[L[--nL]] = 1;
+
+ while (nS)
+ afl->alias_probability[S[--nS]] = 1;
+
+ afl->reinit_table = 0;
+
+ /*
+ #ifdef INTROSPECTION
+ u8 fn[PATH_MAX];
+ snprintf(fn, PATH_MAX, "%s/introspection_corpus.txt", afl->out_dir);
+ FILE *f = fopen(fn, "a");
+ if (f) {
+
+ for (i = 0; i < n; i++) {
+
+ struct queue_entry *q = afl->queue_buf[i];
+ fprintf(
+ f,
+ "entry=%u name=%s favored=%s variable=%s disabled=%s len=%u "
+ "exec_us=%u "
+ "bitmap_size=%u bitsmap_size=%u tops=%u weight=%f perf_score=%f\n",
+ i, q->fname, q->favored ? "true" : "false",
+ q->var_behavior ? "true" : "false", q->disabled ? "true" : "false",
+ q->len, (u32)q->exec_us, q->bitmap_size, q->bitsmap_size, q->tc_ref,
+ q->weight, q->perf_score);
+
+ }
+
+ fprintf(f, "\n");
+ fclose(f);
+
+ }
+
+ #endif
+ */
+ /*
+ fprintf(stderr, " entry alias probability perf_score weight
+ filename\n"); for (u32 i = 0; i < n; ++i) fprintf(stderr, " %5u %5u %11u
+ %0.9f %0.9f %s\n", i, afl->alias_table[i], afl->alias_probability[i],
+ afl->queue_buf[i]->perf_score, afl->queue_buf[i]->weight,
+ afl->queue_buf[i]->fname);
+ */
+
+}
+
+/* Mark deterministic checks as done for a particular queue entry. We use the
+ .state file to avoid repeating deterministic fuzzing when resuming aborted
+ scans. */
+
+void mark_as_det_done(afl_state_t *afl, struct queue_entry *q) {
+
+ u8 fn[PATH_MAX];
+ s32 fd;
+
+ snprintf(fn, PATH_MAX, "%s/queue/.state/deterministic_done/%s", afl->out_dir,
+ strrchr(q->fname, '/') + 1);
+
+ fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
+ if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
+ close(fd);
+
+ q->passed_det = 1;
+
+}
+
+/* Mark as variable. Create symlinks if possible to make it easier to examine
+ the files. */
+
+void mark_as_variable(afl_state_t *afl, struct queue_entry *q) {
+
+ u8 fn[PATH_MAX];
+ u8 ldest[PATH_MAX];
+
+ u8 *fn_name = strrchr(q->fname, '/') + 1;
+
+ sprintf(ldest, "../../%s", fn_name);
+ sprintf(fn, "%s/queue/.state/variable_behavior/%s", afl->out_dir, fn_name);
+
+ if (symlink(ldest, fn)) {
+
+ s32 fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
+ if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
+ close(fd);
+
+ }
+
+ q->var_behavior = 1;
+
+}
+
+/* Mark / unmark as redundant (edge-only). This is not used for restoring state,
+ but may be useful for post-processing datasets. */
+
+void mark_as_redundant(afl_state_t *afl, struct queue_entry *q, u8 state) {
+
+ if (likely(state == q->fs_redundant)) { return; }
+
+ u8 fn[PATH_MAX];
+
+ q->fs_redundant = state;
+
+ sprintf(fn, "%s/queue/.state/redundant_edges/%s", afl->out_dir,
+ strrchr(q->fname, '/') + 1);
+
+ if (state) {
+
+ s32 fd;
+
+ fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
+ if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
+ close(fd);
+
+ } else {
+
+ if (unlink(fn)) { PFATAL("Unable to remove '%s'", fn); }
+
+ }
+
+}
+
+/* check if pointer is ascii or UTF-8 */
+
+u8 check_if_text_buf(u8 *buf, u32 len) {
+
+ u32 offset = 0, ascii = 0, utf8 = 0;
+
+ while (offset < len) {
+
+ // ASCII: <= 0x7F to allow ASCII control characters
+ if ((buf[offset + 0] == 0x09 || buf[offset + 0] == 0x0A ||
+ buf[offset + 0] == 0x0D ||
+ (0x20 <= buf[offset + 0] && buf[offset + 0] <= 0x7E))) {
+
+ offset++;
+ utf8++;
+ ascii++;
+ continue;
+
+ }
+
+ if (isascii((int)buf[offset]) || isprint((int)buf[offset])) {
+
+ ascii++;
+ // we continue though as it can also be a valid utf8
+
+ }
+
+ // non-overlong 2-byte
+ if (len - offset > 1 &&
+ ((0xC2 <= buf[offset + 0] && buf[offset + 0] <= 0xDF) &&
+ (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0xBF))) {
+
+ offset += 2;
+ utf8++;
+ continue;
+
+ }
+
+ // excluding overlongs
+ if ((len - offset > 2) &&
+ ((buf[offset + 0] == 0xE0 &&
+ (0xA0 <= buf[offset + 1] && buf[offset + 1] <= 0xBF) &&
+ (0x80 <= buf[offset + 2] &&
+ buf[offset + 2] <= 0xBF)) || // straight 3-byte
+ (((0xE1 <= buf[offset + 0] && buf[offset + 0] <= 0xEC) ||
+ buf[offset + 0] == 0xEE || buf[offset + 0] == 0xEF) &&
+ (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0xBF) &&
+ (0x80 <= buf[offset + 2] &&
+ buf[offset + 2] <= 0xBF)) || // excluding surrogates
+ (buf[offset + 0] == 0xED &&
+ (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0x9F) &&
+ (0x80 <= buf[offset + 2] && buf[offset + 2] <= 0xBF)))) {
+
+ offset += 3;
+ utf8++;
+ continue;
+
+ }
+
+ // planes 1-3
+ if ((len - offset > 3) &&
+ ((buf[offset + 0] == 0xF0 &&
+ (0x90 <= buf[offset + 1] && buf[offset + 1] <= 0xBF) &&
+ (0x80 <= buf[offset + 2] && buf[offset + 2] <= 0xBF) &&
+ (0x80 <= buf[offset + 3] &&
+ buf[offset + 3] <= 0xBF)) || // planes 4-15
+ ((0xF1 <= buf[offset + 0] && buf[offset + 0] <= 0xF3) &&
+ (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0xBF) &&
+ (0x80 <= buf[offset + 2] && buf[offset + 2] <= 0xBF) &&
+ (0x80 <= buf[offset + 3] && buf[offset + 3] <= 0xBF)) || // plane 16
+ (buf[offset + 0] == 0xF4 &&
+ (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0x8F) &&
+ (0x80 <= buf[offset + 2] && buf[offset + 2] <= 0xBF) &&
+ (0x80 <= buf[offset + 3] && buf[offset + 3] <= 0xBF)))) {
+
+ offset += 4;
+ utf8++;
+ continue;
+
+ }
+
+ offset++;
+
+ }
+
+ return (utf8 > ascii ? utf8 : ascii);
+
+}
+
+/* check if queue entry is ascii or UTF-8 */
+
+static u8 check_if_text(afl_state_t *afl, struct queue_entry *q) {
+
+ if (q->len < AFL_TXT_MIN_LEN) return 0;
+
+ u8 * buf;
+ int fd;
+ u32 len = q->len, offset = 0, ascii = 0, utf8 = 0;
+ ssize_t comp;
+
+ if (len >= MAX_FILE) len = MAX_FILE - 1;
+ if ((fd = open(q->fname, O_RDONLY)) < 0) return 0;
+ buf = afl_realloc(AFL_BUF_PARAM(in_scratch), len + 1);
+ comp = read(fd, buf, len);
+ close(fd);
+ if (comp != (ssize_t)len) return 0;
+ buf[len] = 0;
+
+ while (offset < len) {
+
+ // ASCII: <= 0x7F to allow ASCII control characters
+ if ((buf[offset + 0] == 0x09 || buf[offset + 0] == 0x0A ||
+ buf[offset + 0] == 0x0D ||
+ (0x20 <= buf[offset + 0] && buf[offset + 0] <= 0x7E))) {
+
+ offset++;
+ utf8++;
+ ascii++;
+ continue;
+
+ }
+
+ if (isascii((int)buf[offset]) || isprint((int)buf[offset])) {
+
+ ascii++;
+ // we continue though as it can also be a valid utf8
+
+ }
+
+ // non-overlong 2-byte
+ if (len - offset > 1 &&
+ ((0xC2 <= buf[offset + 0] && buf[offset + 0] <= 0xDF) &&
+ (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0xBF))) {
+
+ offset += 2;
+ utf8++;
+ comp--;
+ continue;
+
+ }
+
+ // excluding overlongs
+ if ((len - offset > 2) &&
+ ((buf[offset + 0] == 0xE0 &&
+ (0xA0 <= buf[offset + 1] && buf[offset + 1] <= 0xBF) &&
+ (0x80 <= buf[offset + 2] &&
+ buf[offset + 2] <= 0xBF)) || // straight 3-byte
+ (((0xE1 <= buf[offset + 0] && buf[offset + 0] <= 0xEC) ||
+ buf[offset + 0] == 0xEE || buf[offset + 0] == 0xEF) &&
+ (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0xBF) &&
+ (0x80 <= buf[offset + 2] &&
+ buf[offset + 2] <= 0xBF)) || // excluding surrogates
+ (buf[offset + 0] == 0xED &&
+ (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0x9F) &&
+ (0x80 <= buf[offset + 2] && buf[offset + 2] <= 0xBF)))) {
+
+ offset += 3;
+ utf8++;
+ comp -= 2;
+ continue;
+
+ }
+
+ // planes 1-3
+ if ((len - offset > 3) &&
+ ((buf[offset + 0] == 0xF0 &&
+ (0x90 <= buf[offset + 1] && buf[offset + 1] <= 0xBF) &&
+ (0x80 <= buf[offset + 2] && buf[offset + 2] <= 0xBF) &&
+ (0x80 <= buf[offset + 3] &&
+ buf[offset + 3] <= 0xBF)) || // planes 4-15
+ ((0xF1 <= buf[offset + 0] && buf[offset + 0] <= 0xF3) &&
+ (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0xBF) &&
+ (0x80 <= buf[offset + 2] && buf[offset + 2] <= 0xBF) &&
+ (0x80 <= buf[offset + 3] && buf[offset + 3] <= 0xBF)) || // plane 16
+ (buf[offset + 0] == 0xF4 &&
+ (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0x8F) &&
+ (0x80 <= buf[offset + 2] && buf[offset + 2] <= 0xBF) &&
+ (0x80 <= buf[offset + 3] && buf[offset + 3] <= 0xBF)))) {
+
+ offset += 4;
+ utf8++;
+ comp -= 3;
+ continue;
+
+ }
+
+ offset++;
+
+ }
+
+ u32 percent_utf8 = (utf8 * 100) / comp;
+ u32 percent_ascii = (ascii * 100) / len;
+
+ if (percent_utf8 >= percent_ascii && percent_utf8 >= AFL_TXT_MIN_PERCENT)
+ return 2;
+ if (percent_ascii >= AFL_TXT_MIN_PERCENT) return 1;
+ return 0;
+
+}
+
+/* Append new test case to the queue. */
+
+void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
+
+ struct queue_entry *q = ck_alloc(sizeof(struct queue_entry));
+
+ q->fname = fname;
+ q->len = len;
+ q->depth = afl->cur_depth + 1;
+ q->passed_det = passed_det;
+ q->trace_mini = NULL;
+ q->testcase_buf = NULL;
+ q->mother = afl->queue_cur;
+
+#ifdef INTROSPECTION
+ q->bitsmap_size = afl->bitsmap_size;
+#endif
+
+ if (q->depth > afl->max_depth) { afl->max_depth = q->depth; }
+
+ if (afl->queue_top) {
+
+ afl->queue_top = q;
+
+ } else {
+
+ afl->queue = afl->queue_top = q;
+
+ }
+
+ if (likely(q->len > 4)) afl->ready_for_splicing_count++;
+
+ ++afl->queued_items;
+ ++afl->active_items;
+ ++afl->pending_not_fuzzed;
+
+ afl->cycles_wo_finds = 0;
+
+ struct queue_entry **queue_buf = afl_realloc(
+ AFL_BUF_PARAM(queue), afl->queued_items * sizeof(struct queue_entry *));
+ if (unlikely(!queue_buf)) { PFATAL("alloc"); }
+ queue_buf[afl->queued_items - 1] = q;
+ q->id = afl->queued_items - 1;
+
+ afl->last_find_time = get_cur_time();
+
+ if (afl->custom_mutators_count) {
+
+ /* At the initialization stage, queue_cur is NULL */
+ if (afl->queue_cur && !afl->syncing_party) {
+
+ run_afl_custom_queue_new_entry(afl, q, fname, afl->queue_cur->fname);
+
+ }
+
+ }
+
+ /* only redqueen currently uses is_ascii */
+ if (afl->shm.cmplog_mode) q->is_ascii = check_if_text(afl, q);
+
+}
+
+/* Destroy the entire queue. */
+
+void destroy_queue(afl_state_t *afl) {
+
+ u32 i;
+
+ for (i = 0; i < afl->queued_items; i++) {
+
+ struct queue_entry *q;
+
+ q = afl->queue_buf[i];
+ ck_free(q->fname);
+ ck_free(q->trace_mini);
+ ck_free(q);
+
+ }
+
+}
+
+/* When we bump into a new path, we call this to see if the path appears
+ more "favorable" than any of the existing ones. The purpose of the
+ "favorables" is to have a minimal set of paths that trigger all the bits
+ seen in the bitmap so far, and focus on fuzzing them at the expense of
+ the rest.
+
+ The first step of the process is to maintain a list of afl->top_rated[]
+ entries for every byte in the bitmap. We win that slot if there is no
+ previous contender, or if the contender has a more favorable speed x size
+ factor. */
+
+void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) {
+
+ u32 i;
+ u64 fav_factor;
+ u64 fuzz_p2;
+
+ if (unlikely(afl->schedule >= FAST && afl->schedule < RARE))
+ fuzz_p2 = 0; // Skip the fuzz_p2 comparison
+ else if (unlikely(afl->schedule == RARE))
+ fuzz_p2 = next_pow2(afl->n_fuzz[q->n_fuzz_entry]);
+ else
+ fuzz_p2 = q->fuzz_level;
+
+ if (unlikely(afl->schedule >= RARE) || unlikely(afl->fixed_seed)) {
+
+ fav_factor = q->len << 2;
+
+ } else {
+
+ fav_factor = q->exec_us * q->len;
+
+ }
+
+ /* For every byte set in afl->fsrv.trace_bits[], see if there is a previous
+ winner, and how it compares to us. */
+ for (i = 0; i < afl->fsrv.map_size; ++i) {
+
+ if (afl->fsrv.trace_bits[i]) {
+
+ if (afl->top_rated[i]) {
+
+ /* Faster-executing or smaller test cases are favored. */
+ u64 top_rated_fav_factor;
+ u64 top_rated_fuzz_p2;
+ if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE))
+ top_rated_fuzz_p2 =
+ next_pow2(afl->n_fuzz[afl->top_rated[i]->n_fuzz_entry]);
+ else
+ top_rated_fuzz_p2 = afl->top_rated[i]->fuzz_level;
+
+ if (unlikely(afl->schedule >= RARE) || unlikely(afl->fixed_seed)) {
+
+ top_rated_fav_factor = afl->top_rated[i]->len << 2;
+
+ } else {
+
+ top_rated_fav_factor =
+ afl->top_rated[i]->exec_us * afl->top_rated[i]->len;
+
+ }
+
+ if (fuzz_p2 > top_rated_fuzz_p2) {
+
+ continue;
+
+ } else if (fuzz_p2 == top_rated_fuzz_p2) {
+
+ if (fav_factor > top_rated_fav_factor) { continue; }
+
+ }
+
+ if (unlikely(afl->schedule >= RARE) || unlikely(afl->fixed_seed)) {
+
+ if (fav_factor > afl->top_rated[i]->len << 2) { continue; }
+
+ } else {
+
+ if (fav_factor >
+ afl->top_rated[i]->exec_us * afl->top_rated[i]->len) {
+
+ continue;
+
+ }
+
+ }
+
+ /* Looks like we're going to win. Decrease ref count for the
+ previous winner, discard its afl->fsrv.trace_bits[] if necessary. */
+
+ if (!--afl->top_rated[i]->tc_ref) {
+
+ ck_free(afl->top_rated[i]->trace_mini);
+ afl->top_rated[i]->trace_mini = 0;
+
+ }
+
+ }
+
+ /* Insert ourselves as the new winner. */
+
+ afl->top_rated[i] = q;
+ ++q->tc_ref;
+
+ if (!q->trace_mini) {
+
+ u32 len = (afl->fsrv.map_size >> 3);
+ q->trace_mini = ck_alloc(len);
+ minimize_bits(afl, q->trace_mini, afl->fsrv.trace_bits);
+
+ }
+
+ afl->score_changed = 1;
+
+ }
+
+ }
+
+}
+
+/* The second part of the mechanism discussed above is a routine that
+ goes over afl->top_rated[] entries, and then sequentially grabs winners for
+ previously-unseen bytes (temp_v) and marks them as favored, at least
+ until the next run. The favored entries are given more air time during
+ all fuzzing steps. */
+
+void cull_queue(afl_state_t *afl) {
+
+ if (likely(!afl->score_changed || afl->non_instrumented_mode)) { return; }
+
+ u32 len = (afl->fsrv.map_size >> 3);
+ u32 i;
+ u8 *temp_v = afl->map_tmp_buf;
+
+ afl->score_changed = 0;
+
+ memset(temp_v, 255, len);
+
+ afl->queued_favored = 0;
+ afl->pending_favored = 0;
+
+ for (i = 0; i < afl->queued_items; i++) {
+
+ afl->queue_buf[i]->favored = 0;
+
+ }
+
+ /* Let's see if anything in the bitmap isn't captured in temp_v.
+ If yes, and if it has a afl->top_rated[] contender, let's use it. */
+
+ for (i = 0; i < afl->fsrv.map_size; ++i) {
+
+ if (afl->top_rated[i] && (temp_v[i >> 3] & (1 << (i & 7)))) {
+
+ u32 j = len;
+
+ /* Remove all bits belonging to the current entry from temp_v. */
+
+ while (j--) {
+
+ if (afl->top_rated[i]->trace_mini[j]) {
+
+ temp_v[j] &= ~afl->top_rated[i]->trace_mini[j];
+
+ }
+
+ }
+
+ if (!afl->top_rated[i]->favored) {
+
+ afl->top_rated[i]->favored = 1;
+ ++afl->queued_favored;
+
+ if (!afl->top_rated[i]->was_fuzzed) { ++afl->pending_favored; }
+
+ }
+
+ }
+
+ }
+
+ for (i = 0; i < afl->queued_items; i++) {
+
+ if (likely(!afl->queue_buf[i]->disabled)) {
+
+ mark_as_redundant(afl, afl->queue_buf[i], !afl->queue_buf[i]->favored);
+
+ }
+
+ }
+
+}
+
+/* Calculate case desirability score to adjust the length of havoc fuzzing.
+ A helper function for fuzz_one(). Maybe some of these constants should
+ go into config.h. */
+
+u32 calculate_score(afl_state_t *afl, struct queue_entry *q) {
+
+ u32 avg_exec_us = afl->total_cal_us / afl->total_cal_cycles;
+ u32 avg_bitmap_size = afl->total_bitmap_size / afl->total_bitmap_entries;
+ u32 perf_score = 100;
+
+ /* Adjust score based on execution speed of this path, compared to the
+ global average. Multiplier ranges from 0.1x to 3x. Fast inputs are
+ less expensive to fuzz, so we're giving them more air time. */
+
+ // TODO BUG FIXME: is this really a good idea?
+ // This sounds like looking for lost keys under a street light just because
+ // the light is better there.
+ // Longer execution time means longer work on the input, the deeper in
+ // coverage, the better the fuzzing, right? -mh
+
+ if (likely(afl->schedule < RARE) && likely(!afl->fixed_seed)) {
+
+ if (q->exec_us * 0.1 > avg_exec_us) {
+
+ perf_score = 10;
+
+ } else if (q->exec_us * 0.25 > avg_exec_us) {
+
+ perf_score = 25;
+
+ } else if (q->exec_us * 0.5 > avg_exec_us) {
+
+ perf_score = 50;
+
+ } else if (q->exec_us * 0.75 > avg_exec_us) {
+
+ perf_score = 75;
+
+ } else if (q->exec_us * 4 < avg_exec_us) {
+
+ perf_score = 300;
+
+ } else if (q->exec_us * 3 < avg_exec_us) {
+
+ perf_score = 200;
+
+ } else if (q->exec_us * 2 < avg_exec_us) {
+
+ perf_score = 150;
+
+ }
+
+ }
+
+ /* Adjust score based on bitmap size. The working theory is that better
+ coverage translates to better targets. Multiplier from 0.25x to 3x. */
+
+ if (q->bitmap_size * 0.3 > avg_bitmap_size) {
+
+ perf_score *= 3;
+
+ } else if (q->bitmap_size * 0.5 > avg_bitmap_size) {
+
+ perf_score *= 2;
+
+ } else if (q->bitmap_size * 0.75 > avg_bitmap_size) {
+
+ perf_score *= 1.5;
+
+ } else if (q->bitmap_size * 3 < avg_bitmap_size) {
+
+ perf_score *= 0.25;
+
+ } else if (q->bitmap_size * 2 < avg_bitmap_size) {
+
+ perf_score *= 0.5;
+
+ } else if (q->bitmap_size * 1.5 < avg_bitmap_size) {
+
+ perf_score *= 0.75;
+
+ }
+
+ /* Adjust score based on handicap. Handicap is proportional to how late
+ in the game we learned about this path. Latecomers are allowed to run
+ for a bit longer until they catch up with the rest. */
+
+ if (q->handicap >= 4) {
+
+ perf_score *= 4;
+ q->handicap -= 4;
+
+ } else if (q->handicap) {
+
+ perf_score *= 2;
+ --q->handicap;
+
+ }
+
+ /* Final adjustment based on input depth, under the assumption that fuzzing
+ deeper test cases is more likely to reveal stuff that can't be
+ discovered with traditional fuzzers. */
+
+ switch (q->depth) {
+
+ case 0 ... 3:
+ break;
+ case 4 ... 7:
+ perf_score *= 2;
+ break;
+ case 8 ... 13:
+ perf_score *= 3;
+ break;
+ case 14 ... 25:
+ perf_score *= 4;
+ break;
+ default:
+ perf_score *= 5;
+
+ }
+
+ u32 n_items;
+ double factor = 1.0;
+ long double fuzz_mu;
+
+ switch (afl->schedule) {
+
+ case EXPLORE:
+ break;
+
+ case SEEK:
+ break;
+
+ case EXPLOIT:
+ factor = MAX_FACTOR;
+ break;
+
+ case COE:
+ fuzz_mu = 0.0;
+ n_items = 0;
+
+ // Don't modify perf_score for unfuzzed seeds
+ if (!q->fuzz_level) break;
+
+ u32 i;
+ for (i = 0; i < afl->queued_items; i++) {
+
+ if (likely(!afl->queue_buf[i]->disabled)) {
+
+ fuzz_mu += log2(afl->n_fuzz[afl->queue_buf[i]->n_fuzz_entry]);
+ n_items++;
+
+ }
+
+ }
+
+ if (unlikely(!n_items)) { FATAL("Queue state corrupt"); }
+
+ fuzz_mu = fuzz_mu / n_items;
+
+ if (log2(afl->n_fuzz[q->n_fuzz_entry]) > fuzz_mu) {
+
+ /* Never skip favourites */
+ if (!q->favored) factor = 0;
+
+ break;
+
+ }
+
+ // Fall through
+ case FAST:
+
+ // Don't modify unfuzzed seeds
+ if (!q->fuzz_level) break;
+
+ switch ((u32)log2(afl->n_fuzz[q->n_fuzz_entry])) {
+
+ case 0 ... 1:
+ factor = 4;
+ break;
+
+ case 2 ... 3:
+ factor = 3;
+ break;
+
+ case 4:
+ factor = 2;
+ break;
+
+ case 5:
+ break;
+
+ case 6:
+ if (!q->favored) factor = 0.8;
+ break;
+
+ case 7:
+ if (!q->favored) factor = 0.6;
+ break;
+
+ default:
+ if (!q->favored) factor = 0.4;
+ break;
+
+ }
+
+ if (q->favored) factor *= 1.15;
+
+ break;
+
+ case LIN:
+ factor = q->fuzz_level / (afl->n_fuzz[q->n_fuzz_entry] + 1);
+ break;
+
+ case QUAD:
+ factor =
+ q->fuzz_level * q->fuzz_level / (afl->n_fuzz[q->n_fuzz_entry] + 1);
+ break;
+
+ case MMOPT:
+ /* -- this was a more complex setup, which is good, but competed with
+ -- rare. the simpler algo however is good when rare is not.
+ // the newer the entry, the higher the pref_score
+ perf_score *= (1 + (double)((double)q->depth /
+ (double)afl->queued_items));
+ // with special focus on the last 8 entries
+ if (afl->max_depth - q->depth < 8) perf_score *= (1 + ((8 -
+ (afl->max_depth - q->depth)) / 5));
+ */
+ // put focus on the last 5 entries
+ if (afl->max_depth - q->depth < 5) { perf_score *= 2; }
+
+ break;
+
+ case RARE:
+
+ // increase the score for every bitmap byte for which this entry
+ // is the top contender
+ perf_score += (q->tc_ref * 10);
+ // the more often fuzz result paths are equal to this queue entry,
+ // reduce its value
+ perf_score *= (1 - (double)((double)afl->n_fuzz[q->n_fuzz_entry] /
+ (double)afl->fsrv.total_execs));
+
+ break;
+
+ default:
+ PFATAL("Unknown Power Schedule");
+
+ }
+
+ if (unlikely(afl->schedule >= EXPLOIT && afl->schedule <= QUAD)) {
+
+ if (factor > MAX_FACTOR) { factor = MAX_FACTOR; }
+ perf_score *= factor / POWER_BETA;
+
+ }
+
+ // MOpt mode
+ if (afl->limit_time_sig != 0 && afl->max_depth - q->depth < 3) {
+
+ perf_score *= 2;
+
+ } else if (afl->schedule != COE && perf_score < 1) {
+
+ // Add a lower bound to AFLFast's energy assignment strategies
+ perf_score = 1;
+
+ }
+
+ /* Make sure that we don't go over limit. */
+
+ if (perf_score > afl->havoc_max_mult * 100) {
+
+ perf_score = afl->havoc_max_mult * 100;
+
+ }
+
+ return perf_score;
+
+}
+
+/* after a custom trim we need to reload the testcase from disk */
+
+inline void queue_testcase_retake(afl_state_t *afl, struct queue_entry *q,
+ u32 old_len) {
+
+ if (likely(q->testcase_buf)) {
+
+ u32 len = q->len;
+
+ if (len != old_len) {
+
+ afl->q_testcase_cache_size = afl->q_testcase_cache_size + len - old_len;
+ q->testcase_buf = realloc(q->testcase_buf, len);
+
+ if (unlikely(!q->testcase_buf)) {
+
+ PFATAL("Unable to malloc '%s' with len %u", q->fname, len);
+
+ }
+
+ }
+
+ int fd = open(q->fname, O_RDONLY);
+
+ if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", q->fname); }
+
+ ck_read(fd, q->testcase_buf, len, q->fname);
+ close(fd);
+
+ }
+
+}
+
+/* after a normal trim we need to replace the testcase with the new data */
+
+inline void queue_testcase_retake_mem(afl_state_t *afl, struct queue_entry *q,
+ u8 *in, u32 len, u32 old_len) {
+
+ if (likely(q->testcase_buf)) {
+
+ u32 is_same = in == q->testcase_buf;
+
+ if (likely(len != old_len)) {
+
+ u8 *ptr = realloc(q->testcase_buf, len);
+
+ if (likely(ptr)) {
+
+ q->testcase_buf = ptr;
+ afl->q_testcase_cache_size = afl->q_testcase_cache_size + len - old_len;
+
+ }
+
+ }
+
+ if (unlikely(!is_same)) { memcpy(q->testcase_buf, in, len); }
+
+ }
+
+}
+
+/* Returns the testcase buf from the file behind this queue entry.
+ Increases the refcount. */
+
+inline u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q) {
+
+ u32 len = q->len;
+
+ /* first handle if no testcase cache is configured */
+
+ if (unlikely(!afl->q_testcase_max_cache_size)) {
+
+ u8 *buf;
+
+ if (unlikely(q == afl->queue_cur)) {
+
+ buf = afl_realloc((void **)&afl->testcase_buf, len);
+
+ } else {
+
+ buf = afl_realloc((void **)&afl->splicecase_buf, len);
+
+ }
+
+ if (unlikely(!buf)) {
+
+ PFATAL("Unable to malloc '%s' with len %u", q->fname, len);
+
+ }
+
+ int fd = open(q->fname, O_RDONLY);
+
+ if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", q->fname); }
+
+ ck_read(fd, buf, len, q->fname);
+ close(fd);
+ return buf;
+
+ }
+
+ /* now handle the testcase cache */
+
+ if (unlikely(!q->testcase_buf)) {
+
+ /* Buf not cached, let's load it */
+ u32 tid = afl->q_testcase_max_cache_count;
+ static u32 do_once = 0; // because even threaded we would want this. WIP
+
+ while (unlikely(
+ afl->q_testcase_cache_size + len >= afl->q_testcase_max_cache_size ||
+ afl->q_testcase_cache_count >= afl->q_testcase_max_cache_entries - 1)) {
+
+ /* We want a max number of entries to the cache that we learn.
+ Very simple: once the cache is filled by size - that is the max. */
+
+ if (unlikely(afl->q_testcase_cache_size + len >=
+ afl->q_testcase_max_cache_size &&
+ (afl->q_testcase_cache_count <
+ afl->q_testcase_max_cache_entries &&
+ afl->q_testcase_max_cache_count <
+ afl->q_testcase_max_cache_entries) &&
+ !do_once)) {
+
+ if (afl->q_testcase_max_cache_count > afl->q_testcase_cache_count) {
+
+ afl->q_testcase_max_cache_entries =
+ afl->q_testcase_max_cache_count + 1;
+
+ } else {
+
+ afl->q_testcase_max_cache_entries = afl->q_testcase_cache_count + 1;
+
+ }
+
+ do_once = 1;
+ // release unneeded memory
+ afl->q_testcase_cache = ck_realloc(
+ afl->q_testcase_cache,
+ (afl->q_testcase_max_cache_entries + 1) * sizeof(size_t));
+
+ }
+
+ /* Cache full. We neet to evict one or more to map one.
+ Get a random one which is not in use */
+
+ do {
+
+ // if the cache (MB) is not enough for the queue then this gets
+ // undesirable because q_testcase_max_cache_count grows sometimes
+ // although the number of items in the cache will not change hence
+ // more and more loops
+ tid = rand_below(afl, afl->q_testcase_max_cache_count);
+
+ } while (afl->q_testcase_cache[tid] == NULL ||
+
+ afl->q_testcase_cache[tid] == afl->queue_cur);
+
+ struct queue_entry *old_cached = afl->q_testcase_cache[tid];
+ free(old_cached->testcase_buf);
+ old_cached->testcase_buf = NULL;
+ afl->q_testcase_cache_size -= old_cached->len;
+ afl->q_testcase_cache[tid] = NULL;
+ --afl->q_testcase_cache_count;
+ ++afl->q_testcase_evictions;
+ if (tid < afl->q_testcase_smallest_free)
+ afl->q_testcase_smallest_free = tid;
+
+ }
+
+ if (unlikely(tid >= afl->q_testcase_max_cache_entries)) {
+
+ // uh we were full, so now we have to search from start
+ tid = afl->q_testcase_smallest_free;
+
+ }
+
+ // we need this while loop in case there were ever previous evictions but
+ // not in this call.
+ while (unlikely(afl->q_testcase_cache[tid] != NULL))
+ ++tid;
+
+ /* Map the test case into memory. */
+
+ int fd = open(q->fname, O_RDONLY);
+
+ if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", q->fname); }
+
+ q->testcase_buf = malloc(len);
+
+ if (unlikely(!q->testcase_buf)) {
+
+ PFATAL("Unable to malloc '%s' with len %u", q->fname, len);
+
+ }
+
+ ck_read(fd, q->testcase_buf, len, q->fname);
+ close(fd);
+
+ /* Register testcase as cached */
+ afl->q_testcase_cache[tid] = q;
+ afl->q_testcase_cache_size += len;
+ ++afl->q_testcase_cache_count;
+ if (likely(tid >= afl->q_testcase_max_cache_count)) {
+
+ afl->q_testcase_max_cache_count = tid + 1;
+
+ } else if (unlikely(tid == afl->q_testcase_smallest_free)) {
+
+ afl->q_testcase_smallest_free = tid + 1;
+
+ }
+
+ }
+
+ return q->testcase_buf;
+
+}
+
+/* Adds the new queue entry to the cache. */
+
+inline void queue_testcase_store_mem(afl_state_t *afl, struct queue_entry *q,
+ u8 *mem) {
+
+ u32 len = q->len;
+
+ if (unlikely(afl->q_testcase_cache_size + len >=
+ afl->q_testcase_max_cache_size ||
+ afl->q_testcase_cache_count >=
+ afl->q_testcase_max_cache_entries - 1)) {
+
+ // no space? will be loaded regularly later.
+ return;
+
+ }
+
+ u32 tid;
+
+ if (unlikely(afl->q_testcase_max_cache_count >=
+ afl->q_testcase_max_cache_entries)) {
+
+ // uh we were full, so now we have to search from start
+ tid = afl->q_testcase_smallest_free;
+
+ } else {
+
+ tid = afl->q_testcase_max_cache_count;
+
+ }
+
+ while (unlikely(afl->q_testcase_cache[tid] != NULL))
+ ++tid;
+
+ /* Map the test case into memory. */
+
+ q->testcase_buf = malloc(len);
+
+ if (unlikely(!q->testcase_buf)) {
+
+ PFATAL("Unable to malloc '%s' with len %u", q->fname, len);
+
+ }
+
+ memcpy(q->testcase_buf, mem, len);
+
+ /* Register testcase as cached */
+ afl->q_testcase_cache[tid] = q;
+ afl->q_testcase_cache_size += len;
+ ++afl->q_testcase_cache_count;
+
+ if (likely(tid >= afl->q_testcase_max_cache_count)) {
+
+ afl->q_testcase_max_cache_count = tid + 1;
+
+ } else if (unlikely(tid == afl->q_testcase_smallest_free)) {
+
+ afl->q_testcase_smallest_free = tid + 1;
+
+ }
+
+}
+
diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c
new file mode 100644
index 00000000..2dbad5cf
--- /dev/null
+++ b/src/afl-fuzz-redqueen.c
@@ -0,0 +1,2936 @@
+/*
+ american fuzzy lop++ - redqueen implementation on top of cmplog
+ ---------------------------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Forkserver design by Jann Horn <jannhorn@googlemail.com>
+
+ Now maintained by by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Andrea Fioraldi <andreafioraldi@gmail.com>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ Shared code to handle the shared memory. This is used by the fuzzer
+ as well the other components like afl-tmin, afl-showmap, etc...
+
+ */
+
+#include <limits.h>
+#include "afl-fuzz.h"
+#include "cmplog.h"
+
+//#define _DEBUG
+//#define CMPLOG_INTROSPECTION
+
+// CMP attribute enum
+enum {
+
+ IS_EQUAL = 1, // arithemtic equal comparison
+ IS_GREATER = 2, // arithmetic greater comparison
+ IS_LESSER = 4, // arithmetic lesser comparison
+ IS_FP = 8, // is a floating point, not an integer
+ /* --- below are internal settings, not from target cmplog */
+ IS_FP_MOD = 16, // arithemtic changed floating point
+ IS_INT_MOD = 32, // arithmetic changed interger
+ IS_TRANSFORM = 64 // transformed integer
+
+};
+
+// add to dictionary enum
+// DEFAULT = 1, notTXT = 2, FOUND = 4, notSAME = 8
+enum {
+
+ DICT_ADD_NEVER = 0,
+ DICT_ADD_NOTFOUND_SAME_TXT = 1,
+ DICT_ADD_NOTFOUND_SAME = 3,
+ DICT_ADD_FOUND_SAME_TXT = 5,
+ DICT_ADD_FOUND_SAME = 7,
+ DICT_ADD_NOTFOUND_TXT = 9,
+ DICT_ADD_NOTFOUND = 11,
+ DICT_ADD_FOUND_TXT = 13,
+ DICT_ADD_FOUND = 15,
+ DICT_ADD_ANY = DICT_ADD_FOUND
+
+};
+
+// CMPLOG LVL
+enum {
+
+ LVL1 = 1, // Integer solving
+ LVL2 = 2, // unused except for setting the queue entry
+ LVL3 = 4 // expensive tranformations
+
+};
+
+#define DICT_ADD_STRATEGY DICT_ADD_FOUND_SAME
+
+struct range {
+
+ u32 start;
+ u32 end;
+ struct range *next;
+ struct range *prev;
+ u8 ok;
+
+};
+
+static u32 hshape;
+static u64 screen_update;
+static u64 last_update;
+
+static struct range *add_range(struct range *ranges, u32 start, u32 end) {
+
+ struct range *r = ck_alloc_nozero(sizeof(struct range));
+ r->start = start;
+ r->end = end;
+ r->next = ranges;
+ r->ok = 0;
+ if (likely(ranges)) ranges->prev = r;
+ return r;
+
+}
+
+static struct range *pop_biggest_range(struct range **ranges) {
+
+ struct range *r = *ranges;
+ struct range *rmax = NULL;
+ u32 max_size = 0;
+
+ while (r) {
+
+ if (!r->ok) {
+
+ u32 s = 1 + r->end - r->start;
+
+ if (s >= max_size) {
+
+ max_size = s;
+ rmax = r;
+
+ }
+
+ }
+
+ r = r->next;
+
+ }
+
+ return rmax;
+
+}
+
+#ifdef _DEBUG
+// static int logging = 0;
+static void dump(char *txt, u8 *buf, u32 len) {
+
+ u32 i;
+ fprintf(stderr, "DUMP %s %016llx ", txt, hash64(buf, len, HASH_CONST));
+ for (i = 0; i < len; i++)
+ fprintf(stderr, "%02x", buf[i]);
+ fprintf(stderr, "\n");
+
+}
+
+static void dump_file(char *path, char *name, u32 counter, u8 *buf, u32 len) {
+
+ char fn[4096];
+ if (!path) path = ".";
+ snprintf(fn, sizeof(fn), "%s/%s%d", path, name, counter);
+ int fd = open(fn, O_RDWR | O_CREAT | O_TRUNC, 0644);
+ if (fd >= 0) {
+
+ write(fd, buf, len);
+ close(fd);
+
+ }
+
+}
+
+#endif
+
+static u8 get_exec_checksum(afl_state_t *afl, u8 *buf, u32 len, u64 *cksum) {
+
+ if (unlikely(common_fuzz_stuff(afl, buf, len))) { return 1; }
+
+ *cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
+
+ return 0;
+
+}
+
+/* replace everything with different values but stay in the same type */
+static void type_replace(afl_state_t *afl, u8 *buf, u32 len) {
+
+ u32 i;
+ u8 c;
+ for (i = 0; i < len; ++i) {
+
+ // wont help for UTF or non-latin charsets
+ do {
+
+ switch (buf[i]) {
+
+ case 'A' ... 'F':
+ c = 'A' + rand_below(afl, 1 + 'F' - 'A');
+ break;
+ case 'a' ... 'f':
+ c = 'a' + rand_below(afl, 1 + 'f' - 'a');
+ break;
+ case '0':
+ c = '1';
+ break;
+ case '1':
+ c = '0';
+ break;
+ case '2' ... '9':
+ c = '2' + rand_below(afl, 1 + '9' - '2');
+ break;
+ case 'G' ... 'Z':
+ c = 'G' + rand_below(afl, 1 + 'Z' - 'G');
+ break;
+ case 'g' ... 'z':
+ c = 'g' + rand_below(afl, 1 + 'z' - 'g');
+ break;
+ case '!' ... '*':
+ c = '!' + rand_below(afl, 1 + '*' - '!');
+ break;
+ case ',' ... '.':
+ c = ',' + rand_below(afl, 1 + '.' - ',');
+ break;
+ case ':' ... '@':
+ c = ':' + rand_below(afl, 1 + '@' - ':');
+ break;
+ case '[' ... '`':
+ c = '[' + rand_below(afl, 1 + '`' - '[');
+ break;
+ case '{' ... '~':
+ c = '{' + rand_below(afl, 1 + '~' - '{');
+ break;
+ case '+':
+ c = '/';
+ break;
+ case '/':
+ c = '+';
+ break;
+ case ' ':
+ c = '\t';
+ break;
+ case '\t':
+ c = ' ';
+ break;
+ case '\r':
+ c = '\n';
+ break;
+ case '\n':
+ c = '\r';
+ break;
+ case 0:
+ c = 1;
+ break;
+ case 1:
+ c = 0;
+ break;
+ case 0xff:
+ c = 0;
+ break;
+ default:
+ if (buf[i] < 32) {
+
+ c = (buf[i] ^ 0x1f);
+
+ } else {
+
+ c = (buf[i] ^ 0x7f); // we keep the highest bit
+
+ }
+
+ }
+
+ } while (c == buf[i]);
+
+ buf[i] = c;
+
+ }
+
+}
+
+static u8 colorization(afl_state_t *afl, u8 *buf, u32 len,
+ struct tainted **taints) {
+
+ struct range * ranges = add_range(NULL, 0, len - 1), *rng;
+ struct tainted *taint = NULL;
+ u8 * backup = ck_alloc_nozero(len);
+ u8 * changed = ck_alloc_nozero(len);
+
+#if defined(_DEBUG) || defined(CMPLOG_INTROSPECTION)
+ u64 start_time = get_cur_time();
+#endif
+
+ u64 orig_hit_cnt, new_hit_cnt, exec_cksum;
+ orig_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_name = "colorization";
+ afl->stage_short = "colorization";
+ afl->stage_max = (len << 1);
+ afl->stage_cur = 0;
+
+ // in colorization we do not classify counts, hence we have to calculate
+ // the original checksum.
+ if (unlikely(get_exec_checksum(afl, buf, len, &exec_cksum))) {
+
+ goto checksum_fail;
+
+ }
+
+ memcpy(backup, buf, len);
+ memcpy(changed, buf, len);
+ type_replace(afl, changed, len);
+
+ while ((rng = pop_biggest_range(&ranges)) != NULL &&
+ afl->stage_cur < afl->stage_max) {
+
+ u32 s = 1 + rng->end - rng->start;
+
+ memcpy(buf + rng->start, changed + rng->start, s);
+
+ u64 cksum = 0;
+ u64 start_us = get_cur_time_us();
+ if (unlikely(get_exec_checksum(afl, buf, len, &cksum))) {
+
+ goto checksum_fail;
+
+ }
+
+ u64 stop_us = get_cur_time_us();
+
+ /* Discard if the mutations change the path or if it is too decremental
+ in speed - how could the same path have a much different speed
+ though ...*/
+ if (cksum != exec_cksum ||
+ (unlikely(stop_us - start_us > 3 * afl->queue_cur->exec_us) &&
+ likely(!afl->fixed_seed))) {
+
+ memcpy(buf + rng->start, backup + rng->start, s);
+
+ if (s > 1) { // to not add 0 size ranges
+
+ ranges = add_range(ranges, rng->start, rng->start - 1 + s / 2);
+ ranges = add_range(ranges, rng->start + s / 2, rng->end);
+
+ }
+
+ if (ranges == rng) {
+
+ ranges = rng->next;
+ if (ranges) { ranges->prev = NULL; }
+
+ } else if (rng->next) {
+
+ rng->prev->next = rng->next;
+ rng->next->prev = rng->prev;
+
+ } else {
+
+ if (rng->prev) { rng->prev->next = NULL; }
+
+ }
+
+ free(rng);
+
+ } else {
+
+ rng->ok = 1;
+
+ }
+
+ if (++afl->stage_cur % screen_update == 0) { show_stats(afl); };
+
+ }
+
+ rng = ranges;
+ while (rng) {
+
+ rng = rng->next;
+
+ }
+
+ u32 i = 1;
+ u32 positions = 0;
+ while (i) {
+
+ restart:
+ i = 0;
+ struct range *r = NULL;
+ u32 pos = (u32)-1;
+ rng = ranges;
+
+ while (rng) {
+
+ if (rng->ok == 1 && rng->start < pos) {
+
+ if (taint && taint->pos + taint->len == rng->start) {
+
+ taint->len += (1 + rng->end - rng->start);
+ positions += (1 + rng->end - rng->start);
+ rng->ok = 2;
+ goto restart;
+
+ } else {
+
+ r = rng;
+ pos = rng->start;
+
+ }
+
+ }
+
+ rng = rng->next;
+
+ }
+
+ if (r) {
+
+ struct tainted *t = ck_alloc_nozero(sizeof(struct tainted));
+ t->pos = r->start;
+ t->len = 1 + r->end - r->start;
+ positions += (1 + r->end - r->start);
+ if (likely(taint)) { taint->prev = t; }
+ t->next = taint;
+ t->prev = NULL;
+ taint = t;
+ r->ok = 2;
+ i = 1;
+
+ }
+
+ }
+
+ /* temporary: clean ranges */
+ while (ranges) {
+
+ rng = ranges;
+ ranges = rng->next;
+ ck_free(rng);
+ rng = NULL;
+
+ }
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+#if defined(_DEBUG) || defined(CMPLOG_INTROSPECTION)
+ FILE *f = stderr;
+ #ifndef _DEBUG
+ if (afl->not_on_tty) {
+
+ char fn[4096];
+ snprintf(fn, sizeof(fn), "%s/introspection_cmplog.txt", afl->out_dir);
+ f = fopen(fn, "a");
+
+ }
+
+ #endif
+
+ if (f) {
+
+ fprintf(
+ f,
+ "Colorization: fname=%s len=%u ms=%llu result=%u execs=%u found=%llu "
+ "taint=%u ascii=%u auto_extra_before=%u\n",
+ afl->queue_cur->fname, len, get_cur_time() - start_time,
+ afl->queue_cur->colorized, afl->stage_cur, new_hit_cnt - orig_hit_cnt,
+ positions, afl->queue_cur->is_ascii ? 1 : 0, afl->a_extras_cnt);
+
+ #ifndef _DEBUG
+ if (afl->not_on_tty) { fclose(f); }
+ #endif
+
+ }
+
+#endif
+
+ if (taint) {
+
+ if (afl->colorize_success && afl->cmplog_lvl < 3 &&
+ (positions > CMPLOG_POSITIONS_MAX && len / positions == 1 &&
+ afl->active_items / afl->colorize_success > CMPLOG_CORPUS_PERCENT)) {
+
+#ifdef _DEBUG
+ fprintf(stderr, "Colorization unsatisfactory\n");
+#endif
+
+ *taints = NULL;
+
+ struct tainted *t;
+ while (taint) {
+
+ t = taint->next;
+ ck_free(taint);
+ taint = t;
+
+ }
+
+ } else {
+
+ *taints = taint;
+ ++afl->colorize_success;
+
+ }
+
+ }
+
+ afl->stage_finds[STAGE_COLORIZATION] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_COLORIZATION] += afl->stage_cur;
+ ck_free(backup);
+ ck_free(changed);
+
+ return 0;
+
+checksum_fail:
+ while (ranges) {
+
+ rng = ranges;
+ ranges = rng->next;
+ ck_free(rng);
+ rng = NULL;
+
+ }
+
+ ck_free(backup);
+ ck_free(changed);
+
+ return 1;
+
+}
+
+///// Input to State replacement
+
+static u8 its_fuzz(afl_state_t *afl, u8 *buf, u32 len, u8 *status) {
+
+ u64 orig_hit_cnt, new_hit_cnt;
+
+ orig_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+#ifdef _DEBUG
+ dump("DATA", buf, len);
+#endif
+
+ if (unlikely(common_fuzz_stuff(afl, buf, len))) { return 1; }
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ if (unlikely(new_hit_cnt != orig_hit_cnt)) {
+
+#ifdef _DEBUG
+ fprintf(stderr, "NEW FIND\n");
+#endif
+ *status = 1;
+
+ } else {
+
+ *status = 2;
+
+ }
+
+ return 0;
+
+}
+
+//#ifdef CMPLOG_SOLVE_TRANSFORM
+static int strntoll(const char *str, size_t sz, char **end, int base,
+ long long *out) {
+
+ char buf[64];
+ long long ret;
+ const char *beg = str;
+
+ if (!str || !sz) { return 1; }
+
+ for (; beg && sz && *beg == ' '; beg++, sz--) {};
+
+ if (!sz) return 1;
+ if (sz >= sizeof(buf)) sz = sizeof(buf) - 1;
+
+ memcpy(buf, beg, sz);
+ buf[sz] = '\0';
+ ret = strtoll(buf, end, base);
+ if ((ret == LLONG_MIN || ret == LLONG_MAX) && errno == ERANGE) return 1;
+ if (end) *end = (char *)beg + (*end - buf);
+ *out = ret;
+
+ return 0;
+
+}
+
+static int strntoull(const char *str, size_t sz, char **end, int base,
+ unsigned long long *out) {
+
+ char buf[64];
+ unsigned long long ret;
+ const char * beg = str;
+
+ if (!str || !sz) { return 1; }
+
+ for (; beg && sz && *beg == ' '; beg++, sz--)
+ ;
+
+ if (!sz) return 1;
+ if (sz >= sizeof(buf)) sz = sizeof(buf) - 1;
+
+ memcpy(buf, beg, sz);
+ buf[sz] = '\0';
+ ret = strtoull(buf, end, base);
+ if (ret == ULLONG_MAX && errno == ERANGE) return 1;
+ if (end) *end = (char *)beg + (*end - buf);
+ *out = ret;
+
+ return 0;
+
+}
+
+static u8 hex_table_up[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+static u8 hex_table_low[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+static u8 hex_table[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0,
+ 0, 0, 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15};
+
+// tests 2 bytes at location
+static int is_hex(const char *str) {
+
+ u32 i;
+
+ for (i = 0; i < 2; i++) {
+
+ switch (str[i]) {
+
+ case '0' ... '9':
+ case 'A' ... 'F':
+ case 'a' ... 'f':
+ break;
+ default:
+ return 0;
+
+ }
+
+ }
+
+ return 1;
+
+}
+
+#ifdef CMPLOG_SOLVE_TRANSFORM_BASE64
+// tests 4 bytes at location
+static int is_base64(const char *str) {
+
+ u32 i;
+
+ for (i = 0; i < 4; i++) {
+
+ switch (str[i]) {
+
+ case '0' ... '9':
+ case 'A' ... 'Z':
+ case 'a' ... 'z':
+ case '+':
+ case '/':
+ case '=':
+ break;
+ default:
+ return 0;
+
+ }
+
+ }
+
+ return 1;
+
+}
+
+static u8 base64_encode_table[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static u8 base64_decode_table[] = {
+
+ 62, 0, 0, 0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51};
+
+static u32 from_base64(u8 *src, u8 *dst, u32 dst_len) {
+
+ u32 i, j, v;
+ u32 len = ((dst_len / 3) << 2);
+ u32 ret = 0;
+
+ for (i = 0, j = 0; i < len; i += 4, j += 3) {
+
+ v = base64_decode_table[src[i] - 43];
+ v = (v << 6) | base64_decode_table[src[i + 1] - 43];
+ v = src[i + 2] == '=' ? v << 6
+ : (v << 6) | base64_decode_table[src[i + 2] - 43];
+ v = src[i + 3] == '=' ? v << 6
+ : (v << 6) | base64_decode_table[src[i + 3] - 43];
+
+ dst[j] = (v >> 16) & 0xFF;
+ ++ret;
+
+ if (src[i + 2] != '=') {
+
+ dst[j + 1] = (v >> 8) & 0xFF;
+ ++ret;
+
+ }
+
+ if (src[i + 3] != '=') {
+
+ dst[j + 2] = v & 0xFF;
+ ++ret;
+
+ }
+
+ }
+
+ return ret;
+
+}
+
+static void to_base64(u8 *src, u8 *dst, u32 dst_len) {
+
+ u32 i, j, v;
+ u32 len = (dst_len >> 2) * 3;
+
+ for (i = 0, j = 0; i < len; i += 3, j += 4) {
+
+ v = src[i];
+ v = i + 1 < len ? v << 8 | src[i + 1] : v << 8;
+ v = i + 2 < len ? v << 8 | src[i + 2] : v << 8;
+
+ dst[j] = base64_encode_table[(v >> 18) & 0x3F];
+ dst[j + 1] = base64_encode_table[(v >> 12) & 0x3F];
+ if (i + 1 < len) {
+
+ dst[j + 2] = base64_encode_table[(v >> 6) & 0x3F];
+
+ } else {
+
+ dst[j + 2] = '=';
+
+ }
+
+ if (i + 2 < len) {
+
+ dst[j + 3] = base64_encode_table[v & 0x3F];
+
+ } else {
+
+ dst[j + 3] = '=';
+
+ }
+
+ }
+
+}
+
+#endif
+
+//#endif
+
+static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
+ u64 pattern, u64 repl, u64 o_pattern,
+ u64 changed_val, u8 attr, u32 idx, u32 taint_len,
+ u8 *orig_buf, u8 *buf, u8 *cbuf, u32 len,
+ u8 do_reverse, u8 lvl, u8 *status) {
+
+ u64 *buf_64 = (u64 *)&buf[idx];
+ u32 *buf_32 = (u32 *)&buf[idx];
+ u16 *buf_16 = (u16 *)&buf[idx];
+ u8 * buf_8 = &buf[idx];
+ u64 *o_buf_64 = (u64 *)&orig_buf[idx];
+ u32 *o_buf_32 = (u32 *)&orig_buf[idx];
+ u16 *o_buf_16 = (u16 *)&orig_buf[idx];
+ u8 * o_buf_8 = &orig_buf[idx];
+
+ u32 its_len = MIN(len - idx, taint_len);
+
+ if (afl->fsrv.total_execs - last_update > screen_update) {
+
+ show_stats(afl);
+ last_update = afl->fsrv.total_execs;
+
+ }
+
+ // fprintf(stderr,
+ // "Encode: %llx->%llx into %llx(<-%llx) at idx=%u "
+ // "taint_len=%u shape=%u attr=%u\n",
+ // o_pattern, pattern, repl, changed_val, idx, taint_len,
+ // hshape, attr);
+
+ //#ifdef CMPLOG_SOLVE_TRANSFORM
+ // reverse atoi()/strnu?toll() is expensive, so we only to it in lvl 3
+ if (afl->cmplog_enable_transform && (lvl & LVL3)) {
+
+ u8 * endptr;
+ u8 use_num = 0, use_unum = 0;
+ unsigned long long unum;
+ long long num;
+
+ if (afl->queue_cur->is_ascii) {
+
+ endptr = buf_8;
+ if (strntoll(buf_8, len - idx, (char **)&endptr, 0, &num)) {
+
+ if (!strntoull(buf_8, len - idx, (char **)&endptr, 0, &unum))
+ use_unum = 1;
+
+ } else
+
+ use_num = 1;
+
+ }
+
+#ifdef _DEBUG
+ if (idx == 0)
+ fprintf(stderr, "ASCII is=%u use_num=%u use_unum=%u idx=%u %llx==%llx\n",
+ afl->queue_cur->is_ascii, use_num, use_unum, idx, num, pattern);
+#endif
+
+ // num is likely not pattern as atoi("AAA") will be zero...
+ if (use_num && ((u64)num == pattern || !num)) {
+
+ u8 tmp_buf[32];
+ size_t num_len = snprintf(tmp_buf, sizeof(tmp_buf), "%lld", repl);
+ size_t old_len = endptr - buf_8;
+
+ u8 *new_buf = afl_realloc((void **)&afl->out_scratch_buf, len + num_len);
+ if (unlikely(!new_buf)) { PFATAL("alloc"); }
+
+ memcpy(new_buf, buf, idx);
+ memcpy(new_buf + idx, tmp_buf, num_len);
+ memcpy(new_buf + idx + num_len, buf_8 + old_len, len - idx - old_len);
+
+ if (new_buf[idx + num_len] >= '0' && new_buf[idx + num_len] <= '9') {
+
+ new_buf[idx + num_len] = ' ';
+
+ }
+
+ if (unlikely(its_fuzz(afl, new_buf, len, status))) { return 1; }
+
+ } else if (use_unum && (unum == pattern || !unum)) {
+
+ u8 tmp_buf[32];
+ size_t num_len = snprintf(tmp_buf, sizeof(tmp_buf), "%llu", repl);
+ size_t old_len = endptr - buf_8;
+
+ u8 *new_buf = afl_realloc((void **)&afl->out_scratch_buf, len + num_len);
+ if (unlikely(!new_buf)) { PFATAL("alloc"); }
+
+ memcpy(new_buf, buf, idx);
+ memcpy(new_buf + idx, tmp_buf, num_len);
+ memcpy(new_buf + idx + num_len, buf_8 + old_len, len - idx - old_len);
+
+ if (new_buf[idx + num_len] >= '0' && new_buf[idx + num_len] <= '9') {
+
+ new_buf[idx + num_len] = ' ';
+
+ }
+
+ if (unlikely(its_fuzz(afl, new_buf, len, status))) { return 1; }
+
+ }
+
+ // Try to identify transform magic
+ if (pattern != o_pattern && repl == changed_val && attr <= IS_EQUAL) {
+
+ u64 b_val, o_b_val, mask;
+ u8 bytes;
+
+ switch (hshape) {
+
+ case 0:
+ case 1:
+ bytes = 1;
+ break;
+ case 2:
+ bytes = 2;
+ break;
+ case 3:
+ case 4:
+ bytes = 4;
+ break;
+ default:
+ bytes = 8;
+
+ }
+
+ // necessary for preventing heap access overflow
+ bytes = MIN(bytes, len - idx);
+
+ switch (bytes) {
+
+ case 0: // cannot happen
+ b_val = o_b_val = mask = 0; // keep the linters happy
+ break;
+ case 1: {
+
+ u8 *ptr = (u8 *)&buf[idx];
+ u8 *o_ptr = (u8 *)&orig_buf[idx];
+ b_val = (u64)(*ptr);
+ o_b_val = (u64)(*o_ptr % 0x100);
+ mask = 0xff;
+ break;
+
+ }
+
+ case 2:
+ case 3: {
+
+ u16 *ptr = (u16 *)&buf[idx];
+ u16 *o_ptr = (u16 *)&orig_buf[idx];
+ b_val = (u64)(*ptr);
+ o_b_val = (u64)(*o_ptr);
+ mask = 0xffff;
+ break;
+
+ }
+
+ case 4:
+ case 5:
+ case 6:
+ case 7: {
+
+ u32 *ptr = (u32 *)&buf[idx];
+ u32 *o_ptr = (u32 *)&orig_buf[idx];
+ b_val = (u64)(*ptr);
+ o_b_val = (u64)(*o_ptr);
+ mask = 0xffffffff;
+ break;
+
+ }
+
+ default: {
+
+ u64 *ptr = (u64 *)&buf[idx];
+ u64 *o_ptr = (u64 *)&orig_buf[idx];
+ b_val = (u64)(*ptr);
+ o_b_val = (u64)(*o_ptr);
+ mask = 0xffffffffffffffff;
+
+ }
+
+ }
+
+ // test for arithmetic, eg. "if ((user_val - 0x1111) == 0x1234) ..."
+ s64 diff = pattern - b_val;
+ s64 o_diff = o_pattern - o_b_val;
+ /* fprintf(stderr, "DIFF1 idx=%03u shape=%02u %llx-%llx=%lx\n", idx,
+ hshape, o_pattern, o_b_val, o_diff);
+ fprintf(stderr, "DIFF1 %016llx %llx-%llx=%lx\n", repl, pattern,
+ b_val, diff); */
+ if (diff == o_diff && diff) {
+
+ // this could be an arithmetic transformation
+
+ u64 new_repl = (u64)((s64)repl - diff);
+ // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl);
+
+ if (unlikely(cmp_extend_encoding(
+ afl, h, pattern, new_repl, o_pattern, repl, IS_TRANSFORM, idx,
+ taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) {
+
+ return 1;
+
+ }
+
+ // if (*status == 1) { fprintf(stderr, "FOUND!\n"); }
+
+ }
+
+ // test for XOR, eg. "if ((user_val ^ 0xabcd) == 0x1234) ..."
+ if (*status != 1) {
+
+ diff = pattern ^ b_val;
+ s64 o_diff = o_pattern ^ o_b_val;
+
+ /* fprintf(stderr, "DIFF2 idx=%03u shape=%02u %llx-%llx=%lx\n",
+ idx, hshape, o_pattern, o_b_val, o_diff);
+ fprintf(stderr,
+ "DIFF2 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff);
+ */
+ if (diff == o_diff && diff) {
+
+ // this could be a XOR transformation
+
+ u64 new_repl = (u64)((s64)repl ^ diff);
+ // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl);
+
+ if (unlikely(cmp_extend_encoding(
+ afl, h, pattern, new_repl, o_pattern, repl, IS_TRANSFORM, idx,
+ taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) {
+
+ return 1;
+
+ }
+
+ // if (*status == 1) { fprintf(stderr, "FOUND!\n"); }
+
+ }
+
+ }
+
+ // test for to lowercase, eg. "new_val = (user_val | 0x2020) ..."
+ if (*status != 1) {
+
+ if ((b_val | (0x2020202020202020 & mask)) == (pattern & mask)) {
+
+ diff = 1;
+
+ } else {
+
+ diff = 0;
+
+ }
+
+ if ((o_b_val | (0x2020202020202020 & mask)) == (o_pattern & mask)) {
+
+ o_diff = 1;
+
+ } else {
+
+ diff = 0;
+
+ }
+
+ /* fprintf(stderr, "DIFF3 idx=%03u shape=%02u %llx-%llx=%lx\n",
+ idx, hshape, o_pattern, o_b_val, o_diff);
+ fprintf(stderr,
+ "DIFF3 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff);
+ */
+ if (o_diff && diff) {
+
+ // this could be a lower to upper
+
+ u64 new_repl = (repl & (0x5f5f5f5f5f5f5f5f & mask));
+ // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl);
+
+ if (unlikely(cmp_extend_encoding(
+ afl, h, pattern, new_repl, o_pattern, repl, IS_TRANSFORM, idx,
+ taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) {
+
+ return 1;
+
+ }
+
+ // if (*status == 1) { fprintf(stderr, "FOUND!\n"); }
+
+ }
+
+ }
+
+ // test for to uppercase, eg. "new_val = (user_val | 0x5f5f) ..."
+ if (*status != 1) {
+
+ if ((b_val & (0x5f5f5f5f5f5f5f5f & mask)) == (pattern & mask)) {
+
+ diff = 1;
+
+ } else {
+
+ diff = 0;
+
+ }
+
+ if ((o_b_val & (0x5f5f5f5f5f5f5f5f & mask)) == (o_pattern & mask)) {
+
+ o_diff = 1;
+
+ } else {
+
+ o_diff = 0;
+
+ }
+
+ /* fprintf(stderr, "DIFF4 idx=%03u shape=%02u %llx-%llx=%lx\n",
+ idx, hshape, o_pattern, o_b_val, o_diff);
+ fprintf(stderr,
+ "DIFF4 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff);
+ */
+ if (o_diff && diff) {
+
+ // this could be a lower to upper
+
+ u64 new_repl = (repl | (0x2020202020202020 & mask));
+ // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl);
+
+ if (unlikely(cmp_extend_encoding(
+ afl, h, pattern, new_repl, o_pattern, repl, IS_TRANSFORM, idx,
+ taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) {
+
+ return 1;
+
+ }
+
+ // if (*status == 1) { fprintf(stderr, "FOUND!\n"); }
+
+ }
+
+ }
+
+ *status = 0;
+
+ }
+
+ }
+
+ //#endif
+
+ // we only allow this for ascii2integer (above) so leave if this is the case
+ if (unlikely(pattern == o_pattern)) { return 0; }
+
+ if ((lvl & LVL1) || attr >= IS_FP_MOD) {
+
+ if (hshape >= 8 && *status != 1) {
+
+ // if (its_len >= 8)
+ // fprintf(stderr,
+ // "TestU64: %u>=8 (idx=%u attr=%u) %llx==%llx"
+ // " %llx==%llx <= %llx<-%llx\n",
+ // its_len, idx, attr, *buf_64, pattern, *o_buf_64, o_pattern,
+ // repl, changed_val);
+
+ // if this is an fcmp (attr & 8 == 8) then do not compare the patterns -
+ // due to a bug in llvm dynamic float bitcasts do not work :(
+ // the value 16 means this is a +- 1.0 test case
+ if (its_len >= 8 && ((*buf_64 == pattern && *o_buf_64 == o_pattern) ||
+ attr >= IS_FP_MOD)) {
+
+ u64 tmp_64 = *buf_64;
+ *buf_64 = repl;
+ if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
+#ifdef CMPLOG_COMBINE
+ if (*status == 1) { memcpy(cbuf + idx, buf_64, 8); }
+#endif
+ *buf_64 = tmp_64;
+
+ // fprintf(stderr, "Status=%u\n", *status);
+
+ }
+
+ // reverse encoding
+ if (do_reverse && *status != 1) {
+
+ if (unlikely(cmp_extend_encoding(afl, h, SWAP64(pattern), SWAP64(repl),
+ SWAP64(o_pattern), SWAP64(changed_val),
+ attr, idx, taint_len, orig_buf, buf,
+ cbuf, len, 0, lvl, status))) {
+
+ return 1;
+
+ }
+
+ }
+
+ }
+
+ if (hshape >= 4 && *status != 1) {
+
+ // if (its_len >= 4 && (attr <= 1 || attr >= 8))
+ // fprintf(stderr,
+ // "TestU32: %u>=4 (idx=%u attr=%u) %x==%x"
+ // " %x==%x <= %x<-%x\n",
+ // its_len, idx, attr, *buf_32, (u32)pattern, *o_buf_32,
+ // (u32)o_pattern, (u32)repl, (u32)changed_val);
+
+ if (its_len >= 4 &&
+ ((*buf_32 == (u32)pattern && *o_buf_32 == (u32)o_pattern) ||
+ attr >= IS_FP_MOD)) {
+
+ u32 tmp_32 = *buf_32;
+ *buf_32 = (u32)repl;
+ if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
+#ifdef CMPLOG_COMBINE
+ if (*status == 1) { memcpy(cbuf + idx, buf_32, 4); }
+#endif
+ *buf_32 = tmp_32;
+
+ // fprintf(stderr, "Status=%u\n", *status);
+
+ }
+
+ // reverse encoding
+ if (do_reverse && *status != 1) {
+
+ if (unlikely(cmp_extend_encoding(afl, h, SWAP32(pattern), SWAP32(repl),
+ SWAP32(o_pattern), SWAP32(changed_val),
+ attr, idx, taint_len, orig_buf, buf,
+ cbuf, len, 0, lvl, status))) {
+
+ return 1;
+
+ }
+
+ }
+
+ }
+
+ if (hshape >= 2 && *status != 1) {
+
+ if (its_len >= 2 &&
+ ((*buf_16 == (u16)pattern && *o_buf_16 == (u16)o_pattern) ||
+ attr >= IS_FP_MOD)) {
+
+ u16 tmp_16 = *buf_16;
+ *buf_16 = (u16)repl;
+ if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
+#ifdef CMPLOG_COMBINE
+ if (*status == 1) { memcpy(cbuf + idx, buf_16, 2); }
+#endif
+ *buf_16 = tmp_16;
+
+ }
+
+ // reverse encoding
+ if (do_reverse && *status != 1) {
+
+ if (unlikely(cmp_extend_encoding(afl, h, SWAP16(pattern), SWAP16(repl),
+ SWAP16(o_pattern), SWAP16(changed_val),
+ attr, idx, taint_len, orig_buf, buf,
+ cbuf, len, 0, lvl, status))) {
+
+ return 1;
+
+ }
+
+ }
+
+ }
+
+ if (*status != 1) { // u8
+
+ // if (its_len >= 1)
+ // fprintf(stderr,
+ // "TestU8: %u>=1 (idx=%u attr=%u) %x==%x %x==%x <= %x<-%x\n",
+ // its_len, idx, attr, *buf_8, (u8)pattern, *o_buf_8,
+ // (u8)o_pattern, (u8)repl, (u8)changed_val);
+
+ if (its_len >= 1 &&
+ ((*buf_8 == (u8)pattern && *o_buf_8 == (u8)o_pattern) ||
+ attr >= IS_FP_MOD)) {
+
+ u8 tmp_8 = *buf_8;
+ *buf_8 = (u8)repl;
+ if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
+#ifdef CMPLOG_COMBINE
+ if (*status == 1) { cbuf[idx] = *buf_8; }
+#endif
+ *buf_8 = tmp_8;
+
+ }
+
+ }
+
+ }
+
+ // here we add and subract 1 from the value, but only if it is not an
+ // == or != comparison
+ // Bits: 1 = Equal, 2 = Greater, 4 = Lesser, 8 = Float
+ // 16 = modified float, 32 = modified integer (modified = wont match
+ // in original buffer)
+
+ //#ifdef CMPLOG_SOLVE_ARITHMETIC
+ if (!afl->cmplog_enable_arith || lvl < LVL3 || attr == IS_TRANSFORM) {
+
+ return 0;
+
+ }
+
+ if (!(attr & (IS_GREATER | IS_LESSER)) || hshape < 4) { return 0; }
+
+ // transform >= to < and <= to >
+ if ((attr & IS_EQUAL) && (attr & (IS_GREATER | IS_LESSER))) {
+
+ if (attr & 2) {
+
+ attr += 2;
+
+ } else {
+
+ attr -= 2;
+
+ }
+
+ }
+
+ // lesser/greater FP comparison
+ if (attr >= IS_FP && attr < IS_FP_MOD) {
+
+ u64 repl_new;
+
+ if (attr & IS_GREATER) {
+
+ if (hshape == 4 && its_len >= 4) {
+
+ float *f = (float *)&repl;
+ float g = *f;
+ g += 1.0;
+ u32 *r = (u32 *)&g;
+ repl_new = (u32)*r;
+
+ } else if (hshape == 8 && its_len >= 8) {
+
+ double *f = (double *)&repl;
+ double g = *f;
+ g += 1.0;
+
+ u64 *r = (u64 *)&g;
+ repl_new = *r;
+
+ } else {
+
+ return 0;
+
+ }
+
+ changed_val = repl_new;
+
+ if (unlikely(cmp_extend_encoding(
+ afl, h, pattern, repl_new, o_pattern, changed_val, 16, idx,
+ taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) {
+
+ return 1;
+
+ }
+
+ } else {
+
+ if (hshape == 4) {
+
+ float *f = (float *)&repl;
+ float g = *f;
+ g -= 1.0;
+ u32 *r = (u32 *)&g;
+ repl_new = (u32)*r;
+
+ } else if (hshape == 8) {
+
+ double *f = (double *)&repl;
+ double g = *f;
+ g -= 1.0;
+ u64 *r = (u64 *)&g;
+ repl_new = *r;
+
+ } else {
+
+ return 0;
+
+ }
+
+ changed_val = repl_new;
+
+ if (unlikely(cmp_extend_encoding(
+ afl, h, pattern, repl_new, o_pattern, changed_val, 16, idx,
+ taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) {
+
+ return 1;
+
+ }
+
+ }
+
+ // transform double to float, llvm likes to do that internally ...
+ if (hshape == 8 && its_len >= 4) {
+
+ double *f = (double *)&repl;
+ float g = (float)*f;
+ repl_new = 0;
+#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+ memcpy((char *)&repl_new, (char *)&g, 4);
+#else
+ memcpy(((char *)&repl_new) + 4, (char *)&g, 4);
+#endif
+ changed_val = repl_new;
+ hshape = 4; // modify shape
+
+ // fprintf(stderr, "DOUBLE2FLOAT %llx\n", repl_new);
+
+ if (unlikely(cmp_extend_encoding(
+ afl, h, pattern, repl_new, o_pattern, changed_val, 16, idx,
+ taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) {
+
+ hshape = 8; // recover shape
+ return 1;
+
+ }
+
+ hshape = 8; // recover shape
+
+ }
+
+ }
+
+ else if (attr < IS_FP) {
+
+ // lesser/greater integer comparison
+
+ u64 repl_new;
+
+ if (attr & IS_GREATER) {
+
+ repl_new = repl + 1;
+ changed_val = repl_new;
+ if (unlikely(cmp_extend_encoding(
+ afl, h, pattern, repl_new, o_pattern, changed_val, 32, idx,
+ taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) {
+
+ return 1;
+
+ }
+
+ } else {
+
+ repl_new = repl - 1;
+ changed_val = repl_new;
+ if (unlikely(cmp_extend_encoding(
+ afl, h, pattern, repl_new, o_pattern, changed_val, 32, idx,
+ taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) {
+
+ return 1;
+
+ }
+
+ }
+
+ }
+
+ //#endif /*
+ // CMPLOG_SOLVE_ARITHMETIC
+
+ return 0;
+
+}
+
+#ifdef WORD_SIZE_64
+
+static u8 cmp_extend_encodingN(afl_state_t *afl, struct cmp_header *h,
+ u128 pattern, u128 repl, u128 o_pattern,
+ u128 changed_val, u8 attr, u32 idx,
+ u32 taint_len, u8 *orig_buf, u8 *buf, u8 *cbuf,
+ u32 len, u8 do_reverse, u8 lvl, u8 *status) {
+
+ if (afl->fsrv.total_execs - last_update > screen_update) {
+
+ show_stats(afl);
+ last_update = afl->fsrv.total_execs;
+
+ }
+
+ u8 *ptr = (u8 *)&buf[idx];
+ u8 *o_ptr = (u8 *)&orig_buf[idx];
+ u8 *p = (u8 *)&pattern;
+ u8 *o_p = (u8 *)&o_pattern;
+ u8 *r = (u8 *)&repl;
+ u8 backup[16];
+ u32 its_len = MIN(len - idx, taint_len);
+ #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+ size_t off = 0;
+ #else
+ size_t off = 16 - hshape;
+ #endif
+
+ if (its_len >= hshape) {
+
+ #ifdef _DEBUG
+ fprintf(stderr, "TestUN: %u>=%u (len=%u idx=%u attr=%u off=%lu) (%u) ",
+ its_len, hshape, len, idx, attr, off, do_reverse);
+ u32 i;
+ u8 *o_r = (u8 *)&changed_val;
+ for (i = 0; i < hshape; i++)
+ fprintf(stderr, "%02x", ptr[i]);
+ fprintf(stderr, "==");
+ for (i = 0; i < hshape; i++)
+ fprintf(stderr, "%02x", p[off + i]);
+ fprintf(stderr, " ");
+ for (i = 0; i < hshape; i++)
+ fprintf(stderr, "%02x", o_ptr[i]);
+ fprintf(stderr, "==");
+ for (i = 0; i < hshape; i++)
+ fprintf(stderr, "%02x", o_p[off + i]);
+ fprintf(stderr, " <= ");
+ for (i = 0; i < hshape; i++)
+ fprintf(stderr, "%02x", r[off + i]);
+ fprintf(stderr, "<-");
+ for (i = 0; i < hshape; i++)
+ fprintf(stderr, "%02x", o_r[off + i]);
+ fprintf(stderr, "\n");
+ #endif
+
+ if (!memcmp(ptr, p + off, hshape) && !memcmp(o_ptr, o_p + off, hshape)) {
+
+ memcpy(backup, ptr, hshape);
+ memcpy(ptr, r + off, hshape);
+
+ if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
+
+ #ifdef CMPLOG_COMBINE
+ if (*status == 1) { memcpy(cbuf + idx, r, hshape); }
+ #endif
+
+ memcpy(ptr, backup, hshape);
+
+ #ifdef _DEBUG
+ fprintf(stderr, "Status=%u\n", *status);
+ #endif
+
+ }
+
+ // reverse encoding
+ if (do_reverse && *status != 1) {
+
+ if (unlikely(cmp_extend_encodingN(
+ afl, h, SWAPN(pattern, (hshape << 3)), SWAPN(repl, (hshape << 3)),
+ SWAPN(o_pattern, (hshape << 3)),
+ SWAPN(changed_val, (hshape << 3)), attr, idx, taint_len, orig_buf,
+ buf, cbuf, len, 0, lvl, status))) {
+
+ return 1;
+
+ }
+
+ }
+
+ }
+
+ return 0;
+
+}
+
+#endif
+
+static void try_to_add_to_dict(afl_state_t *afl, u64 v, u8 shape) {
+
+ u8 *b = (u8 *)&v;
+
+ u32 k;
+ u8 cons_ff = 0, cons_0 = 0;
+ for (k = 0; k < shape; ++k) {
+
+ if (b[k] == 0) {
+
+ ++cons_0;
+
+ } else if (b[k] == 0xff) {
+
+ ++cons_ff;
+
+ } else {
+
+ cons_0 = cons_ff = 0;
+
+ }
+
+ if (cons_0 > 1 || cons_ff > 1) { return; }
+
+ }
+
+ maybe_add_auto(afl, (u8 *)&v, shape);
+
+ u64 rev;
+ switch (shape) {
+
+ case 1:
+ break;
+ case 2:
+ rev = SWAP16((u16)v);
+ maybe_add_auto(afl, (u8 *)&rev, shape);
+ break;
+ case 4:
+ rev = SWAP32((u32)v);
+ maybe_add_auto(afl, (u8 *)&rev, shape);
+ break;
+ case 8:
+ rev = SWAP64(v);
+ maybe_add_auto(afl, (u8 *)&rev, shape);
+ break;
+
+ }
+
+}
+
+#ifdef WORD_SIZE_64
+static void try_to_add_to_dictN(afl_state_t *afl, u128 v, u8 size) {
+
+ u8 *b = (u8 *)&v;
+
+ u32 k;
+ u8 cons_ff = 0, cons_0 = 0;
+ #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+ u32 off = 0;
+ for (k = 0; k < size; ++k) {
+
+ #else
+ u32 off = 16 - size;
+ for (k = 16 - size; k < 16; ++k) {
+
+ #endif
+ if (b[k] == 0) {
+
+ ++cons_0;
+
+ } else if (b[k] == 0xff) {
+
+ ++cons_ff;
+
+ } else {
+
+ cons_0 = cons_ff = 0;
+
+ }
+
+ }
+
+ maybe_add_auto(afl, (u8 *)&v + off, size);
+ u128 rev = SWAPN(v, size);
+ maybe_add_auto(afl, (u8 *)&rev + off, size);
+
+}
+
+#endif
+
+#define SWAPA(_x) ((_x & 0xf8) + ((_x & 7) ^ 0x07))
+
+static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
+ u32 len, u32 lvl, struct tainted *taint) {
+
+ struct cmp_header *h = &afl->shm.cmp_map->headers[key];
+ struct tainted * t;
+ u32 i, j, idx, taint_len, loggeds;
+ u32 have_taint = 1;
+ u8 status = 0, found_one = 0;
+
+ /* loop cmps are useless, detect and ignore them */
+#ifdef WORD_SIZE_64
+ u32 is_n = 0;
+ u128 s128_v0 = 0, s128_v1 = 0, orig_s128_v0 = 0, orig_s128_v1 = 0;
+#endif
+ u64 s_v0, s_v1;
+ u8 s_v0_fixed = 1, s_v1_fixed = 1;
+ u8 s_v0_inc = 1, s_v1_inc = 1;
+ u8 s_v0_dec = 1, s_v1_dec = 1;
+
+ hshape = SHAPE_BYTES(h->shape);
+
+ if (h->hits > CMP_MAP_H) {
+
+ loggeds = CMP_MAP_H;
+
+ } else {
+
+ loggeds = h->hits;
+
+ }
+
+#ifdef WORD_SIZE_64
+ switch (hshape) {
+
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ break;
+ default:
+ is_n = 1;
+
+ }
+
+#endif
+
+ for (i = 0; i < loggeds; ++i) {
+
+ struct cmp_operands *o = &afl->shm.cmp_map->log[key][i];
+
+ // loop detection code
+ if (i == 0) {
+
+ s_v0 = o->v0;
+ s_v1 = o->v1;
+
+ } else {
+
+ if (s_v0 != o->v0) { s_v0_fixed = 0; }
+ if (s_v1 != o->v1) { s_v1_fixed = 0; }
+ if (s_v0 + 1 != o->v0) { s_v0_inc = 0; }
+ if (s_v1 + 1 != o->v1) { s_v1_inc = 0; }
+ if (s_v0 - 1 != o->v0) { s_v0_dec = 0; }
+ if (s_v1 - 1 != o->v1) { s_v1_dec = 0; }
+ s_v0 = o->v0;
+ s_v1 = o->v1;
+
+ }
+
+ struct cmp_operands *orig_o = &afl->orig_cmp_map->log[key][i];
+
+ // opt not in the paper
+ for (j = 0; j < i; ++j) {
+
+ if (afl->shm.cmp_map->log[key][j].v0 == o->v0 &&
+ afl->shm.cmp_map->log[key][j].v1 == o->v1) {
+
+ goto cmp_fuzz_next_iter;
+
+ }
+
+ }
+
+#ifdef _DEBUG
+ fprintf(stderr, "Handling: %llx->%llx vs %llx->%llx attr=%u shape=%u\n",
+ orig_o->v0, o->v0, orig_o->v1, o->v1, h->attribute, hshape);
+#endif
+
+ t = taint;
+ while (t->next) {
+
+ t = t->next;
+
+ }
+
+#ifdef WORD_SIZE_64
+ if (unlikely(is_n)) {
+
+ s128_v0 = ((u128)o->v0) + (((u128)o->v0_128) << 64);
+ s128_v1 = ((u128)o->v1) + (((u128)o->v1_128) << 64);
+ orig_s128_v0 = ((u128)orig_o->v0) + (((u128)orig_o->v0_128) << 64);
+ orig_s128_v1 = ((u128)orig_o->v1) + (((u128)orig_o->v1_128) << 64);
+
+ }
+
+#endif
+
+ for (idx = 0; idx < len; ++idx) {
+
+ if (have_taint) {
+
+ if (!t || idx < t->pos) {
+
+ continue;
+
+ } else {
+
+ taint_len = t->pos + t->len - idx;
+
+ if (idx == t->pos + t->len - 1) { t = t->prev; }
+
+ }
+
+ } else {
+
+ taint_len = len - idx;
+
+ }
+
+ status = 0;
+
+#ifdef WORD_SIZE_64
+ if (is_n) { // _ExtInt special case including u128
+
+ if (s128_v0 != orig_s128_v0 && orig_s128_v0 != orig_s128_v1) {
+
+ if (unlikely(cmp_extend_encodingN(
+ afl, h, s128_v0, s128_v1, orig_s128_v0, orig_s128_v1,
+ h->attribute, idx, taint_len, orig_buf, buf, cbuf, len, 1,
+ lvl, &status))) {
+
+ return 1;
+
+ }
+
+ }
+
+ if (status == 1) {
+
+ found_one = 1;
+ break;
+
+ }
+
+ if (s128_v1 != orig_s128_v1 && orig_s128_v1 != orig_s128_v0) {
+
+ if (unlikely(cmp_extend_encodingN(
+ afl, h, s128_v1, s128_v0, orig_s128_v1, orig_s128_v0,
+ SWAPA(h->attribute), idx, taint_len, orig_buf, buf, cbuf, len,
+ 1, lvl, &status))) {
+
+ return 1;
+
+ }
+
+ }
+
+ if (status == 1) {
+
+ found_one = 1;
+ break;
+
+ }
+
+ }
+
+#endif
+
+#ifdef _DEBUG
+ if (o->v0 != orig_o->v0 || o->v1 != orig_o->v1)
+ fprintf(stderr, "key=%u idx=%u o0=%llu v0=%llu o1=%llu v1=%llu\n", key,
+ idx, orig_o->v0, o->v0, orig_o->v1, o->v1);
+#endif
+
+ // even for u128 and _ExtInt we do cmp_extend_encoding() because
+ // if we got here their own special trials failed and it might just be
+ // a cast from e.g. u64 to u128 from the input data.
+
+ if ((o->v0 != orig_o->v0 || lvl >= LVL3) && orig_o->v0 != orig_o->v1) {
+
+ if (unlikely(cmp_extend_encoding(
+ afl, h, o->v0, o->v1, orig_o->v0, orig_o->v1, h->attribute, idx,
+ taint_len, orig_buf, buf, cbuf, len, 1, lvl, &status))) {
+
+ return 1;
+
+ }
+
+ }
+
+ if (status == 1) {
+
+ found_one = 1;
+ break;
+
+ }
+
+ status = 0;
+ if ((o->v1 != orig_o->v1 || lvl >= LVL3) && orig_o->v0 != orig_o->v1) {
+
+ if (unlikely(cmp_extend_encoding(afl, h, o->v1, o->v0, orig_o->v1,
+ orig_o->v0, SWAPA(h->attribute), idx,
+ taint_len, orig_buf, buf, cbuf, len, 1,
+ lvl, &status))) {
+
+ return 1;
+
+ }
+
+ }
+
+ if (status == 1) {
+
+ found_one = 1;
+ break;
+
+ }
+
+ }
+
+#ifdef _DEBUG
+ fprintf(stderr,
+ "END: %llx->%llx vs %llx->%llx attr=%u i=%u found=%u "
+ "isN=%u size=%u\n",
+ orig_o->v0, o->v0, orig_o->v1, o->v1, h->attribute, i, found_one,
+ is_n, hshape);
+#endif
+
+ // we only learn 16 bit +
+ if (hshape > 1) {
+
+ if (!found_one || afl->queue_cur->is_ascii) {
+
+#ifdef WORD_SIZE_64
+ if (unlikely(is_n)) {
+
+ if (!found_one ||
+ check_if_text_buf((u8 *)&s128_v0, SHAPE_BYTES(h->shape)) ==
+ SHAPE_BYTES(h->shape))
+ try_to_add_to_dictN(afl, s128_v0, SHAPE_BYTES(h->shape));
+ if (!found_one ||
+ check_if_text_buf((u8 *)&s128_v1, SHAPE_BYTES(h->shape)) ==
+ SHAPE_BYTES(h->shape))
+ try_to_add_to_dictN(afl, s128_v1, SHAPE_BYTES(h->shape));
+
+ } else
+
+#endif
+ {
+
+ if (!memcmp((u8 *)&o->v0, (u8 *)&orig_o->v0, SHAPE_BYTES(h->shape)) &&
+ (!found_one ||
+ check_if_text_buf((u8 *)&o->v0, SHAPE_BYTES(h->shape)) ==
+ SHAPE_BYTES(h->shape)))
+ try_to_add_to_dict(afl, o->v0, SHAPE_BYTES(h->shape));
+ if (!memcmp((u8 *)&o->v1, (u8 *)&orig_o->v1, SHAPE_BYTES(h->shape)) &&
+ (!found_one ||
+ check_if_text_buf((u8 *)&o->v1, SHAPE_BYTES(h->shape)) ==
+ SHAPE_BYTES(h->shape)))
+ try_to_add_to_dict(afl, o->v1, SHAPE_BYTES(h->shape));
+
+ }
+
+ }
+
+ }
+
+ cmp_fuzz_next_iter:
+ afl->stage_cur++;
+
+ }
+
+ if (loggeds > 3 && ((s_v0_fixed && s_v1_inc) || (s_v1_fixed && s_v0_inc) ||
+ (s_v0_fixed && s_v1_dec) || (s_v1_fixed && s_v0_dec))) {
+
+ afl->pass_stats[key].total = afl->pass_stats[key].faileds = 0xff;
+
+ }
+
+ if (!found_one && afl->pass_stats[key].faileds < 0xff) {
+
+ afl->pass_stats[key].faileds++;
+
+ }
+
+ if (afl->pass_stats[key].total < 0xff) { afl->pass_stats[key].total++; }
+
+ return 0;
+
+}
+
+static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
+ struct cmpfn_operands *o,
+ struct cmpfn_operands *orig_o, u32 idx,
+ u32 taint_len, u8 *orig_buf, u8 *buf, u8 *cbuf,
+ u32 len, u8 lvl, u8 *status) {
+
+#ifndef CMPLOG_COMBINE
+ (void)(cbuf);
+#endif
+ //#ifndef CMPLOG_SOLVE_TRANSFORM
+ // (void)(changed_val);
+ //#endif
+
+ if (afl->fsrv.total_execs - last_update > screen_update) {
+
+ show_stats(afl);
+ last_update = afl->fsrv.total_execs;
+
+ }
+
+ u8 *pattern, *repl, *o_pattern, *changed_val;
+ u8 l0, l1, ol0, ol1;
+
+ if (entry == 0) {
+
+ pattern = o->v0;
+ repl = o->v1;
+ o_pattern = orig_o->v0;
+ changed_val = orig_o->v1;
+ l0 = o->v0_len;
+ ol0 = orig_o->v0_len;
+ l1 = o->v1_len;
+ ol1 = orig_o->v1_len;
+
+ } else {
+
+ pattern = o->v1;
+ repl = o->v0;
+ o_pattern = orig_o->v1;
+ changed_val = orig_o->v0;
+ l0 = o->v1_len;
+ ol0 = orig_o->v1_len;
+ l1 = o->v0_len;
+ ol1 = orig_o->v0_len;
+
+ }
+
+ if (l0 >= 0x80 || ol0 >= 0x80) {
+
+ l0 -= 0x80;
+ l1 -= 0x80;
+ ol0 -= 0x80;
+ ol1 -= 0x80;
+
+ }
+
+ if (l0 == 0 || l1 == 0 || ol0 == 0 || ol1 == 0 || l0 > 31 || l1 > 31 ||
+ ol0 > 31 || ol1 > 31) {
+
+ l0 = ol0 = hshape;
+
+ }
+
+ u8 lmax = MAX(l0, ol0);
+ u8 save[40];
+ u32 saved_idx = idx, pre, from = 0, to = 0, i, j;
+ u32 its_len = MIN(MIN(lmax, hshape), len - idx);
+ its_len = MIN(its_len, taint_len);
+ u32 saved_its_len = its_len;
+
+ if (lvl & LVL3) {
+
+ u32 max_to = MIN(4U, idx);
+ if (!(lvl & LVL1) && max_to) { from = 1; }
+ to = max_to;
+
+ }
+
+ memcpy(save, &buf[saved_idx - to], its_len + to);
+ (void)(j);
+
+#ifdef _DEBUG
+ fprintf(stderr, "RTN T idx=%u lvl=%02x is_txt=%u shape=%u/%u ", idx, lvl,
+ o->v0_len >= 0x80 ? 1 : 0, hshape, l0);
+ for (j = 0; j < 8; j++)
+ fprintf(stderr, "%02x", orig_buf[idx + j]);
+ fprintf(stderr, " -> ");
+ for (j = 0; j < 8; j++)
+ fprintf(stderr, "%02x", o_pattern[j]);
+ fprintf(stderr, " <= ");
+ for (j = 0; j < 8; j++)
+ fprintf(stderr, "%02x", repl[j]);
+ fprintf(stderr, "\n");
+ fprintf(stderr, " ");
+ for (j = 0; j < 8; j++)
+ fprintf(stderr, "%02x", buf[idx + j]);
+ fprintf(stderr, " -> ");
+ for (j = 0; j < 8; j++)
+ fprintf(stderr, "%02x", pattern[j]);
+ fprintf(stderr, " <= ");
+ for (j = 0; j < 8; j++)
+ fprintf(stderr, "%02x", changed_val[j]);
+ fprintf(stderr, "\n");
+#endif
+
+ // Try to match the replace value up to 4 bytes before the current idx.
+ // This allows matching of eg.:
+ // if (memcmp(user_val, "TEST") == 0)
+ // if (memcmp(user_val, "TEST-VALUE") == 0) ...
+ // We only do this in lvl 3, otherwise we only do direct matching
+
+ for (pre = from; pre <= to; pre++) {
+
+ if (*status != 1 && (!pre || !memcmp(buf + saved_idx - pre, repl, pre))) {
+
+ idx = saved_idx - pre;
+ its_len = saved_its_len + pre;
+
+ for (i = 0; i < its_len; ++i) {
+
+ if ((pattern[i] != buf[idx + i] && o_pattern[i] != orig_buf[idx + i]) ||
+ *status == 1) {
+
+ break;
+
+ }
+
+ buf[idx + i] = repl[i];
+
+ if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
+
+#ifdef CMPLOG_COMBINE
+ if (*status == 1) { memcpy(cbuf + idx, &buf[idx], i); }
+#endif
+
+ }
+
+ memcpy(&buf[idx], save + to - pre, i);
+
+ }
+
+ }
+
+ if (*status == 1) return 0;
+
+ // transform solving
+
+ if (afl->cmplog_enable_transform && (lvl & LVL3)) {
+
+ u32 toupper = 0, tolower = 0, xor = 0, arith = 0, tohex = 0, fromhex = 0;
+#ifdef CMPLOG_SOLVE_TRANSFORM_BASE64
+ u32 tob64 = 0, fromb64 = 0;
+#endif
+ u32 from_0 = 0, from_x = 0, from_X = 0, from_slash = 0, from_up = 0;
+ u32 to_0 = 0, to_x = 0, to_slash = 0, to_up = 0;
+ u8 xor_val[32], arith_val[32], tmp[48];
+
+ idx = saved_idx;
+ its_len = saved_its_len;
+
+ memcpy(save, &buf[idx], its_len);
+
+ for (i = 0; i < its_len; ++i) {
+
+ xor_val[i] = pattern[i] ^ buf[idx + i];
+ arith_val[i] = pattern[i] - buf[idx + i];
+
+ if (i == 0) {
+
+ if (orig_buf[idx] == '0') {
+
+ from_0 = 1;
+
+ } else if (orig_buf[idx] == '\\') {
+
+ from_slash = 1;
+
+ }
+
+ if (repl[0] == '0') {
+
+ to_0 = 1;
+
+ } else if (repl[0] == '\\') {
+
+ to_slash = 1;
+
+ }
+
+ } else if (i == 1) {
+
+ if (orig_buf[idx + 1] == 'x') {
+
+ from_x = 1;
+
+ } else if (orig_buf[idx + 1] == 'X') {
+
+ from_X = from_x = 1;
+
+ }
+
+ if (repl[1] == 'x' || repl[1] == 'X') { to_x = 1; }
+
+ }
+
+ if (i < 16 && is_hex(repl + (i << 1))) {
+
+ ++tohex;
+
+ if (!to_up) {
+
+ if (repl[i << 1] >= 'A' && repl[i << 1] <= 'F')
+ to_up = 1;
+ else if (repl[i << 1] >= 'a' && repl[i << 1] <= 'f')
+ to_up = 2;
+ if (repl[(i << 1) + 1] >= 'A' && repl[(i << 1) + 1] <= 'F')
+ to_up = 1;
+ else if (repl[(i << 1) + 1] >= 'a' && repl[(i << 1) + 1] <= 'f')
+ to_up = 2;
+
+ }
+
+ }
+
+ if ((i % 2)) {
+
+ if (len > idx + i + 1 && is_hex(orig_buf + idx + i)) {
+
+ fromhex += 2;
+
+ if (!from_up) {
+
+ if (orig_buf[idx + i] >= 'A' && orig_buf[idx + i] <= 'F')
+ from_up = 1;
+ else if (orig_buf[idx + i] >= 'a' && orig_buf[idx + i] <= 'f')
+ from_up = 2;
+ if (orig_buf[idx + i - 1] >= 'A' && orig_buf[idx + i - 1] <= 'F')
+ from_up = 1;
+ else if (orig_buf[idx + i - 1] >= 'a' &&
+ orig_buf[idx + i - 1] <= 'f')
+ from_up = 2;
+
+ }
+
+ }
+
+ }
+
+#ifdef CMPLOG_SOLVE_TRANSFORM_BASE64
+ if (i % 3 == 2 && i < 24) {
+
+ if (is_base64(repl + ((i / 3) << 2))) tob64 += 3;
+
+ }
+
+ if (i % 4 == 3 && i < 24) {
+
+ if (is_base64(orig_buf + idx + i - 3)) fromb64 += 4;
+
+ }
+
+#endif
+
+ if ((o_pattern[i] ^ orig_buf[idx + i]) == xor_val[i] && xor_val[i]) {
+
+ ++xor;
+
+ }
+
+ if ((o_pattern[i] - orig_buf[idx + i]) == arith_val[i] && arith_val[i]) {
+
+ ++arith;
+
+ }
+
+ if ((buf[idx + i] | 0x20) == pattern[i] &&
+ (orig_buf[idx + i] | 0x20) == o_pattern[i]) {
+
+ ++tolower;
+
+ }
+
+ if ((buf[idx + i] & 0x5a) == pattern[i] &&
+ (orig_buf[idx + i] & 0x5a) == o_pattern[i]) {
+
+ ++toupper;
+
+ }
+
+#ifdef _DEBUG
+ fprintf(stderr,
+ "RTN idx=%u loop=%u xor=%u arith=%u tolower=%u toupper=%u "
+ "tohex=%u fromhex=%u to_0=%u to_slash=%u to_x=%u "
+ "from_0=%u from_slash=%u from_x=%u\n",
+ idx, i, xor, arith, tolower, toupper, tohex, fromhex, to_0,
+ to_slash, to_x, from_0, from_slash, from_x);
+ #ifdef CMPLOG_SOLVE_TRANSFORM_BASE64
+ fprintf(stderr, "RTN idx=%u loop=%u tob64=%u from64=%u\n", tob64,
+ fromb64);
+ #endif
+#endif
+
+#ifdef CMPLOG_SOLVE_TRANSFORM_BASE64
+ // input is base64 and converted to binary? convert repl to base64!
+ if ((i % 4) == 3 && i < 24 && fromb64 > i) {
+
+ to_base64(repl, tmp, i + 1);
+ memcpy(buf + idx, tmp, i + 1);
+ if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
+ // fprintf(stderr, "RTN ATTEMPT fromb64 %u result %u\n", fromb64,
+ // *status);
+
+ }
+
+ // input is converted to base64? decode repl with base64!
+ if ((i % 3) == 2 && i < 24 && tob64 > i) {
+
+ u32 olen = from_base64(repl, tmp, i + 1);
+ memcpy(buf + idx, tmp, olen);
+ if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
+ // fprintf(stderr, "RTN ATTEMPT tob64 %u idx=%u result %u\n", tob64,
+ // idx, *status);
+
+ }
+
+#endif
+
+ // input is converted to hex? convert repl to binary!
+ if (i < 16 && tohex > i) {
+
+ u32 off;
+ if (to_slash + to_x + to_0 == 2) {
+
+ off = 2;
+
+ } else {
+
+ off = 0;
+
+ }
+
+ for (j = 0; j <= i; j++)
+ tmp[j] = (hex_table[repl[off + (j << 1)] - '0'] << 4) +
+ hex_table[repl[off + (j << 1) + 1] - '0'];
+
+ memcpy(buf + idx, tmp, i + 1);
+ if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
+ // fprintf(stderr, "RTN ATTEMPT tohex %u result %u\n", tohex,
+ // *status);
+
+ }
+
+ // input is hex and converted to binary? convert repl to hex!
+ if (i && (i % 2) && i < 16 && fromhex &&
+ fromhex + from_slash + from_x + from_0 > i) {
+
+ u8 off = 0;
+ if (from_slash && from_x) {
+
+ tmp[0] = '\\';
+ if (from_X) {
+
+ tmp[1] = 'X';
+
+ } else {
+
+ tmp[1] = 'x';
+
+ }
+
+ off = 2;
+
+ } else if (from_0 && from_x) {
+
+ tmp[0] = '0';
+ if (from_X) {
+
+ tmp[1] = 'X';
+
+ } else {
+
+ tmp[1] = 'x';
+
+ }
+
+ off = 2;
+
+ }
+
+ if (to_up == 1) {
+
+ for (j = 0; j <= (i >> 1); j++) {
+
+ tmp[off + (j << 1)] = hex_table_up[repl[j] >> 4];
+ tmp[off + (j << 1) + 1] = hex_table_up[repl[j] % 16];
+
+ }
+
+ } else {
+
+ for (j = 0; j <= (i >> 1); j++) {
+
+ tmp[off + (j << 1)] = hex_table_low[repl[j] >> 4];
+ tmp[off + (j << 1) + 1] = hex_table_low[repl[j] % 16];
+
+ }
+
+ }
+
+ memcpy(buf + idx, tmp, i + 1 + off);
+ if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
+ // fprintf(stderr, "RTN ATTEMPT fromhex %u result %u\n", fromhex,
+ // *status);
+ memcpy(buf + idx, save, i + 1 + off);
+
+ }
+
+ if (xor > i) {
+
+ for (j = 0; j <= i; j++)
+ buf[idx + j] = repl[j] ^ xor_val[j];
+ if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
+ // fprintf(stderr, "RTN ATTEMPT xor %u result %u\n", xor, *status);
+
+ }
+
+ if (arith > i && *status != 1) {
+
+ for (j = 0; j <= i; j++)
+ buf[idx + j] = repl[j] - arith_val[j];
+ if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
+ // fprintf(stderr, "RTN ATTEMPT arith %u result %u\n", arith,
+ // *status);
+
+ }
+
+ if (toupper > i && *status != 1) {
+
+ for (j = 0; j <= i; j++)
+ buf[idx + j] = repl[j] | 0x20;
+ if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
+ // fprintf(stderr, "RTN ATTEMPT toupper %u result %u\n", toupper,
+ // *status);
+
+ }
+
+ if (tolower > i && *status != 1) {
+
+ for (j = 0; j <= i; j++)
+ buf[idx + j] = repl[j] & 0x5f;
+ if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
+ // fprintf(stderr, "RTN ATTEMPT tolower %u result %u\n", tolower,
+ // *status);
+
+ }
+
+#ifdef CMPLOG_COMBINE
+ if (*status == 1) { memcpy(cbuf + idx, &buf[idx], i + 1); }
+#endif
+
+ if ((i >= 7 &&
+ (i >= xor&&i >= arith &&i >= tolower &&i >= toupper &&i > tohex &&i >
+ (fromhex + from_0 + from_x + from_slash + 1)
+#ifdef CMPLOG_SOLVE_TRANSFORM_BASE64
+ && i > tob64 + 3 && i > fromb64 + 4
+#endif
+ )) ||
+ repl[i] != changed_val[i] || *status == 1) {
+
+ break;
+
+ }
+
+ }
+
+ memcpy(&buf[idx], save, i);
+
+ }
+
+ //#endif
+
+ return 0;
+
+}
+
+static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
+ u32 len, u8 lvl, struct tainted *taint) {
+
+ struct tainted * t;
+ struct cmp_header *h = &afl->shm.cmp_map->headers[key];
+ u32 i, j, idx, have_taint = 1, taint_len, loggeds;
+ u8 status = 0, found_one = 0;
+
+ hshape = SHAPE_BYTES(h->shape);
+
+ if (h->hits > CMP_MAP_RTN_H) {
+
+ loggeds = CMP_MAP_RTN_H;
+
+ } else {
+
+ loggeds = h->hits;
+
+ }
+
+ for (i = 0; i < loggeds; ++i) {
+
+ struct cmpfn_operands *o =
+ &((struct cmpfn_operands *)afl->shm.cmp_map->log[key])[i];
+
+ struct cmpfn_operands *orig_o =
+ &((struct cmpfn_operands *)afl->orig_cmp_map->log[key])[i];
+
+ // opt not in the paper
+ for (j = 0; j < i; ++j) {
+
+ if (!memcmp(&((struct cmpfn_operands *)afl->shm.cmp_map->log[key])[j], o,
+ sizeof(struct cmpfn_operands))) {
+
+ goto rtn_fuzz_next_iter;
+
+ }
+
+ }
+
+ /*
+ struct cmp_header *hh = &afl->orig_cmp_map->headers[key];
+ fprintf(stderr, "RTN N hits=%u id=%u shape=%u attr=%u v0=", h->hits, h->id,
+ hshape, h->attribute);
+ for (j = 0; j < 8; j++)
+ fprintf(stderr, "%02x", o->v0[j]);
+ fprintf(stderr, " v1=");
+ for (j = 0; j < 8; j++)
+ fprintf(stderr, "%02x", o->v1[j]);
+ fprintf(stderr, "\nRTN O hits=%u id=%u shape=%u attr=%u o0=", hh->hits,
+ hh->id, hshape, hh->attribute);
+ for (j = 0; j < 8; j++)
+ fprintf(stderr, "%02x", orig_o->v0[j]);
+ fprintf(stderr, " o1=");
+ for (j = 0; j < 8; j++)
+ fprintf(stderr, "%02x", orig_o->v1[j]);
+ fprintf(stderr, "\n");
+ */
+
+ t = taint;
+ while (t->next) {
+
+ t = t->next;
+
+ }
+
+ for (idx = 0; idx < len; ++idx) {
+
+ if (have_taint) {
+
+ if (!t || idx < t->pos) {
+
+ continue;
+
+ } else {
+
+ taint_len = t->pos + t->len - idx;
+
+ if (idx == t->pos + t->len - 1) { t = t->prev; }
+
+ }
+
+ } else {
+
+ taint_len = len - idx;
+
+ }
+
+ status = 0;
+
+#ifdef _DEBUG
+ int w;
+ fprintf(stderr, "key=%u idx=%u len=%u o0=", key, idx, hshape);
+ for (w = 0; w < hshape; ++w)
+ fprintf(stderr, "%02x", orig_o->v0[w]);
+ fprintf(stderr, " v0=");
+ for (w = 0; w < hshape; ++w)
+ fprintf(stderr, "%02x", o->v0[w]);
+ fprintf(stderr, " o1=");
+ for (w = 0; w < hshape; ++w)
+ fprintf(stderr, "%02x", orig_o->v1[w]);
+ fprintf(stderr, " v1=");
+ for (w = 0; w < hshape; ++w)
+ fprintf(stderr, "%02x", o->v1[w]);
+ fprintf(stderr, "\n");
+#endif
+
+ if (unlikely(rtn_extend_encoding(afl, 0, o, orig_o, idx, taint_len,
+ orig_buf, buf, cbuf, len, lvl,
+ &status))) {
+
+ return 1;
+
+ }
+
+ if (status == 1) {
+
+ found_one = 1;
+ break;
+
+ }
+
+ status = 0;
+
+ if (unlikely(rtn_extend_encoding(afl, 1, o, orig_o, idx, taint_len,
+ orig_buf, buf, cbuf, len, lvl,
+ &status))) {
+
+ return 1;
+
+ }
+
+ if (status == 1) {
+
+ found_one = 1;
+ break;
+
+ }
+
+ }
+
+ // if (unlikely(!afl->pass_stats[key].total)) {
+
+ if ((!found_one && (lvl & LVL1)) || afl->queue_cur->is_ascii) {
+
+ // if (unlikely(!afl->pass_stats[key].total)) {
+
+ u32 shape_len = SHAPE_BYTES(h->shape);
+ u32 v0_len = shape_len, v1_len = shape_len;
+ if (afl->queue_cur->is_ascii ||
+ check_if_text_buf((u8 *)&o->v0, shape_len) == shape_len) {
+
+ if (strlen(o->v0)) v0_len = strlen(o->v0);
+
+ }
+
+ if (afl->queue_cur->is_ascii ||
+ check_if_text_buf((u8 *)&o->v1, shape_len) == shape_len) {
+
+ if (strlen(o->v1)) v1_len = strlen(o->v1);
+
+ }
+
+ // fprintf(stderr, "SHOULD: found:%u ascii:%u text?%u:%u %u:%s %u:%s \n",
+ // found_one, afl->queue_cur->is_ascii, check_if_text_buf((u8 *)&o->v0,
+ // shape_len), check_if_text_buf((u8 *)&o->v1, shape_len), v0_len,
+ // o->v0, v1_len, o->v1);
+
+ if (!memcmp(o->v0, orig_o->v0, v0_len) ||
+ (!found_one || check_if_text_buf((u8 *)&o->v0, v0_len) == v0_len))
+ maybe_add_auto(afl, o->v0, v0_len);
+ if (!memcmp(o->v1, orig_o->v1, v1_len) ||
+ (!found_one || check_if_text_buf((u8 *)&o->v1, v1_len) == v1_len))
+ maybe_add_auto(afl, o->v1, v1_len);
+
+ //}
+
+ }
+
+ rtn_fuzz_next_iter:
+ afl->stage_cur++;
+
+ }
+
+ if (!found_one && afl->pass_stats[key].faileds < 0xff) {
+
+ afl->pass_stats[key].faileds++;
+
+ }
+
+ if (afl->pass_stats[key].total < 0xff) { afl->pass_stats[key].total++; }
+
+ return 0;
+
+}
+
+///// Input to State stage
+
+// afl->queue_cur->exec_cksum
+u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len) {
+
+ u8 r = 1;
+ if (unlikely(!afl->pass_stats)) {
+
+ afl->pass_stats = ck_alloc(sizeof(struct afl_pass_stat) * CMP_MAP_W);
+
+ }
+
+ struct tainted *taint = NULL;
+ if (likely(afl->queue_cur->exec_us)) {
+
+ if (likely((100000 / 2) >= afl->queue_cur->exec_us)) {
+
+ screen_update = 100000 / afl->queue_cur->exec_us;
+
+ } else {
+
+ screen_update = 1;
+
+ }
+
+ } else {
+
+ screen_update = 100000;
+
+ }
+
+ if (!afl->queue_cur->taint || !afl->queue_cur->cmplog_colorinput) {
+
+ if (unlikely(colorization(afl, buf, len, &taint))) { return 1; }
+
+ // no taint? still try, create a dummy to prevent again colorization
+ if (!taint) {
+
+#ifdef _DEBUG
+ fprintf(stderr, "TAINT FAILED\n");
+#endif
+ afl->queue_cur->colorized = CMPLOG_LVL_MAX;
+ return 0;
+
+ }
+
+#ifdef _DEBUG
+ else if (taint->pos == 0 && taint->len == len) {
+
+ fprintf(stderr, "TAINT FULL\n");
+
+ }
+
+#endif
+
+ } else {
+
+ buf = afl->queue_cur->cmplog_colorinput;
+ taint = afl->queue_cur->taint;
+
+ }
+
+ struct tainted *t = taint;
+
+ while (t) {
+
+#ifdef _DEBUG
+ fprintf(stderr, "T: idx=%u len=%u\n", t->pos, t->len);
+#endif
+ t = t->next;
+
+ }
+
+#if defined(_DEBUG) || defined(CMPLOG_INTROSPECTION)
+ u64 start_time = get_cur_time();
+ u32 cmp_locations = 0;
+#endif
+
+ // Generate the cmplog data
+
+ // manually clear the full cmp_map
+ memset(afl->shm.cmp_map, 0, sizeof(struct cmp_map));
+ if (unlikely(common_fuzz_cmplog_stuff(afl, orig_buf, len))) {
+
+ afl->queue_cur->colorized = CMPLOG_LVL_MAX;
+ while (taint) {
+
+ t = taint->next;
+ ck_free(taint);
+ taint = t;
+
+ }
+
+ return 1;
+
+ }
+
+ if (unlikely(!afl->orig_cmp_map)) {
+
+ afl->orig_cmp_map = ck_alloc_nozero(sizeof(struct cmp_map));
+
+ }
+
+ memcpy(afl->orig_cmp_map, afl->shm.cmp_map, sizeof(struct cmp_map));
+ memset(afl->shm.cmp_map->headers, 0, sizeof(struct cmp_header) * CMP_MAP_W);
+ if (unlikely(common_fuzz_cmplog_stuff(afl, buf, len))) {
+
+ afl->queue_cur->colorized = CMPLOG_LVL_MAX;
+ while (taint) {
+
+ t = taint->next;
+ ck_free(taint);
+ taint = t;
+
+ }
+
+ return 1;
+
+ }
+
+#ifdef _DEBUG
+ dump("ORIG", orig_buf, len);
+ dump("NEW ", buf, len);
+#endif
+
+ // Start insertion loop
+
+ u64 orig_hit_cnt, new_hit_cnt;
+ u64 orig_execs = afl->fsrv.total_execs;
+ orig_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_name = "input-to-state";
+ afl->stage_short = "its";
+ afl->stage_max = 0;
+ afl->stage_cur = 0;
+
+ u32 lvl = (afl->queue_cur->colorized ? 0 : LVL1) +
+ (afl->cmplog_lvl == CMPLOG_LVL_MAX ? LVL3 : 0);
+
+#ifdef CMPLOG_COMBINE
+ u8 *cbuf = afl_realloc((void **)&afl->in_scratch_buf, len + 128);
+ memcpy(cbuf, orig_buf, len);
+ u8 *virgin_backup = afl_realloc((void **)&afl->ex_buf, afl->shm.map_size);
+ memcpy(virgin_backup, afl->virgin_bits, afl->shm.map_size);
+#else
+ u8 *cbuf = NULL;
+#endif
+
+ u32 k;
+ for (k = 0; k < CMP_MAP_W; ++k) {
+
+ if (!afl->shm.cmp_map->headers[k].hits) { continue; }
+
+ if (afl->pass_stats[k].faileds >= CMPLOG_FAIL_MAX ||
+ afl->pass_stats[k].total >= CMPLOG_FAIL_MAX) {
+
+#ifdef _DEBUG
+ fprintf(stderr, "DISABLED %u\n", k);
+#endif
+
+ afl->shm.cmp_map->headers[k].hits = 0; // ignore this cmp
+
+ }
+
+ if (afl->shm.cmp_map->headers[k].type == CMP_TYPE_INS) {
+
+ // fprintf(stderr, "INS %u\n", k);
+ afl->stage_max +=
+ MIN((u32)(afl->shm.cmp_map->headers[k].hits), (u32)CMP_MAP_H);
+
+ } else {
+
+ // fprintf(stderr, "RTN %u\n", k);
+ afl->stage_max +=
+ MIN((u32)(afl->shm.cmp_map->headers[k].hits), (u32)CMP_MAP_RTN_H);
+
+ }
+
+ }
+
+ for (k = 0; k < CMP_MAP_W; ++k) {
+
+ if (!afl->shm.cmp_map->headers[k].hits) { continue; }
+
+#if defined(_DEBUG) || defined(CMPLOG_INTROSPECTION)
+ ++cmp_locations;
+#endif
+
+ if (afl->shm.cmp_map->headers[k].type == CMP_TYPE_INS) {
+
+ if (unlikely(cmp_fuzz(afl, k, orig_buf, buf, cbuf, len, lvl, taint))) {
+
+ goto exit_its;
+
+ }
+
+ } else if ((lvl & LVL1)
+
+ //#ifdef CMPLOG_SOLVE_TRANSFORM
+ || ((lvl & LVL3) && afl->cmplog_enable_transform)
+ //#endif
+ ) {
+
+ if (unlikely(rtn_fuzz(afl, k, orig_buf, buf, cbuf, len, lvl, taint))) {
+
+ goto exit_its;
+
+ }
+
+ }
+
+ }
+
+ r = 0;
+
+exit_its:
+
+ if (afl->cmplog_lvl == CMPLOG_LVL_MAX) {
+
+ afl->queue_cur->colorized = CMPLOG_LVL_MAX;
+
+ if (afl->queue_cur->cmplog_colorinput) {
+
+ ck_free(afl->queue_cur->cmplog_colorinput);
+
+ }
+
+ while (taint) {
+
+ t = taint->next;
+ ck_free(taint);
+ taint = t;
+
+ }
+
+ afl->queue_cur->taint = NULL;
+
+ } else {
+
+ afl->queue_cur->colorized = LVL2;
+
+ if (!afl->queue_cur->taint) { afl->queue_cur->taint = taint; }
+
+ if (!afl->queue_cur->cmplog_colorinput) {
+
+ afl->queue_cur->cmplog_colorinput = ck_alloc_nozero(len);
+ memcpy(afl->queue_cur->cmplog_colorinput, buf, len);
+ memcpy(buf, orig_buf, len);
+
+ }
+
+ }
+
+#ifdef CMPLOG_COMBINE
+ if (afl->queued_items + afl->saved_crashes > orig_hit_cnt + 1) {
+
+ // copy the current virgin bits so we can recover the information
+ u8 *virgin_save = afl_realloc((void **)&afl->eff_buf, afl->shm.map_size);
+ memcpy(virgin_save, afl->virgin_bits, afl->shm.map_size);
+ // reset virgin bits to the backup previous to redqueen
+ memcpy(afl->virgin_bits, virgin_backup, afl->shm.map_size);
+
+ u8 status = 0;
+ its_fuzz(afl, cbuf, len, &status);
+
+ // now combine with the saved virgin bits
+ #ifdef WORD_SIZE_64
+ u64 *v = (u64 *)afl->virgin_bits;
+ u64 *s = (u64 *)virgin_save;
+ u32 i;
+ for (i = 0; i < (afl->shm.map_size >> 3); i++) {
+
+ v[i] &= s[i];
+
+ }
+
+ #else
+ u32 *v = (u32 *)afl->virgin_bits;
+ u32 *s = (u32 *)virgin_save;
+ u32 i;
+ for (i = 0; i < (afl->shm.map_size >> 2); i++) {
+
+ v[i] &= s[i];
+
+ }
+
+ #endif
+
+ #ifdef _DEBUG
+ dump("COMB", cbuf, len);
+ if (status == 1) {
+
+ fprintf(stderr, "NEW CMPLOG_COMBINED\n");
+
+ } else {
+
+ fprintf(stderr, "NO new combined\n");
+
+ }
+
+ #endif
+
+ }
+
+#endif
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+ afl->stage_finds[STAGE_ITS] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_ITS] += afl->fsrv.total_execs - orig_execs;
+
+#if defined(_DEBUG) || defined(CMPLOG_INTROSPECTION)
+ FILE *f = stderr;
+ #ifndef _DEBUG
+ if (afl->not_on_tty) {
+
+ char fn[4096];
+ snprintf(fn, sizeof(fn), "%s/introspection_cmplog.txt", afl->out_dir);
+ f = fopen(fn, "a");
+
+ }
+
+ #endif
+
+ if (f) {
+
+ fprintf(f,
+ "Cmplog: fname=%s len=%u ms=%llu result=%u finds=%llu entries=%u "
+ "auto_extra_after=%u\n",
+ afl->queue_cur->fname, len, get_cur_time() - start_time, r,
+ new_hit_cnt - orig_hit_cnt, cmp_locations, afl->a_extras_cnt);
+
+ #ifndef _DEBUG
+ if (afl->not_on_tty) { fclose(f); }
+ #endif
+
+ }
+
+#endif
+
+ return r;
+
+}
+
diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c
new file mode 100644
index 00000000..09e773f0
--- /dev/null
+++ b/src/afl-fuzz-run.c
@@ -0,0 +1,1022 @@
+/*
+ american fuzzy lop++ - target execution related routines
+ --------------------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Andrea Fioraldi <andreafioraldi@gmail.com> and
+ Dominik Maier <mail@dmnk.co>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ This is the real deal: the program takes an instrumented binary and
+ attempts a variety of basic fuzzing tricks, paying close attention to
+ how they affect the execution path.
+
+ */
+
+#include "afl-fuzz.h"
+#include <sys/time.h>
+#include <signal.h>
+#include <limits.h>
+#if !defined NAME_MAX
+ #define NAME_MAX _XOPEN_NAME_MAX
+#endif
+
+#include "cmplog.h"
+
+#ifdef PROFILING
+u64 time_spent_working = 0;
+#endif
+
+/* 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) {
+
+#ifdef PROFILING
+ static u64 time_spent_start = 0;
+ struct timespec spec;
+ if (time_spent_start) {
+
+ u64 current;
+ clock_gettime(CLOCK_REALTIME, &spec);
+ current = (spec.tv_sec * 1000000000) + spec.tv_nsec;
+ time_spent_working += (current - time_spent_start);
+
+ }
+
+#endif
+
+ fsrv_run_result_t res = afl_fsrv_run_target(fsrv, timeout, &afl->stop_soon);
+
+#ifdef PROFILING
+ clock_gettime(CLOCK_REALTIME, &spec);
+ time_spent_start = (spec.tv_sec * 1000000000) + spec.tv_nsec;
+#endif
+
+ return res;
+
+}
+
+/* Write modified data to file for testing. If afl->fsrv.out_file is set, the
+ old file is unlinked and a new one is created. Otherwise, afl->fsrv.out_fd is
+ rewound and truncated. */
+
+u32 __attribute__((hot))
+write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) {
+
+#ifdef _AFL_DOCUMENT_MUTATIONS
+ s32 doc_fd;
+ char fn[PATH_MAX];
+ snprintf(fn, PATH_MAX, "%s/mutations/%09u:%s", afl->out_dir,
+ afl->document_counter++,
+ describe_op(afl, 0, NAME_MAX - strlen("000000000:")));
+
+ if ((doc_fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION)) >=
+ 0) {
+
+ if (write(doc_fd, *mem, len) != len)
+ PFATAL("write to mutation file failed: %s", fn);
+ close(doc_fd);
+
+ }
+
+#endif
+
+ if (unlikely(afl->custom_mutators_count)) {
+
+ ssize_t new_size = len;
+ u8 * new_mem = *mem;
+ u8 * new_buf = NULL;
+
+ LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+ if (el->afl_custom_post_process) {
+
+ new_size =
+ el->afl_custom_post_process(el->data, new_mem, new_size, &new_buf);
+
+ if (unlikely(!new_buf && new_size <= 0)) {
+
+ FATAL("Custom_post_process failed (ret: %lu)",
+ (long unsigned)new_size);
+
+ }
+
+ new_mem = new_buf;
+
+ }
+
+ });
+
+ if (unlikely(new_size < afl->min_length && !fix)) {
+
+ new_size = afl->min_length;
+
+ } else if (unlikely(new_size > afl->max_length)) {
+
+ new_size = afl->max_length;
+
+ }
+
+ if (new_mem != *mem) {
+
+ *mem = new_mem;
+
+ }
+
+ /* everything as planned. use the potentially new data. */
+ afl_fsrv_write_to_testcase(&afl->fsrv, *mem, new_size);
+ len = new_size;
+
+ } else {
+
+ if (unlikely(len < afl->min_length && !fix)) {
+
+ len = afl->min_length;
+
+ } else if (unlikely(len > afl->max_length)) {
+
+ len = afl->max_length;
+
+ }
+
+ /* boring uncustom. */
+ afl_fsrv_write_to_testcase(&afl->fsrv, *mem, len);
+
+ }
+
+ return len;
+
+}
+
+/* The same, but with an adjustable gap. Used for trimming. */
+
+static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at,
+ u32 skip_len) {
+
+ s32 fd = afl->fsrv.out_fd;
+ u32 tail_len = len - skip_at - skip_len;
+
+ /*
+ This memory is used to carry out the post_processing(if present) after copying
+ the testcase by removing the gaps. This can break though
+ */
+ u8 *mem_trimmed = afl_realloc(AFL_BUF_PARAM(out_scratch), len - skip_len + 1);
+ if (unlikely(!mem_trimmed)) { PFATAL("alloc"); }
+
+ ssize_t new_size = len - skip_len;
+ u8 * new_mem = mem;
+
+ bool post_process_skipped = true;
+
+ if (unlikely(afl->custom_mutators_count)) {
+
+ u8 *new_buf = NULL;
+ new_mem = mem_trimmed;
+
+ LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+ if (el->afl_custom_post_process) {
+
+ // We copy into the mem_trimmed only if we actually have custom mutators
+ // *with* post_processing installed
+
+ if (post_process_skipped) {
+
+ if (skip_at) { memcpy(mem_trimmed, (u8 *)mem, skip_at); }
+
+ if (tail_len) {
+
+ memcpy(mem_trimmed + skip_at, (u8 *)mem + skip_at + skip_len,
+ tail_len);
+
+ }
+
+ post_process_skipped = false;
+
+ }
+
+ new_size =
+ el->afl_custom_post_process(el->data, new_mem, new_size, &new_buf);
+
+ if (unlikely(!new_buf || new_size <= 0)) {
+
+ FATAL("Custom_post_process failed (ret: %lu)",
+ (long unsigned)new_size);
+
+ }
+
+ new_mem = new_buf;
+
+ }
+
+ });
+
+ }
+
+ if (likely(afl->fsrv.use_shmem_fuzz)) {
+
+ if (!post_process_skipped) {
+
+ // If we did post_processing, copy directly from the new_mem buffer
+
+ memcpy(afl->fsrv.shmem_fuzz, new_mem, new_size);
+
+ } else {
+
+ memcpy(afl->fsrv.shmem_fuzz, mem, skip_at);
+
+ memcpy(afl->fsrv.shmem_fuzz + skip_at, mem + skip_at + skip_len,
+ tail_len);
+
+ }
+
+ *afl->fsrv.shmem_fuzz_len = new_size;
+
+#ifdef _DEBUG
+ if (afl->debug) {
+
+ fprintf(
+ stderr, "FS crc: %16llx len: %u\n",
+ hash64(afl->fsrv.shmem_fuzz, *afl->fsrv.shmem_fuzz_len, HASH_CONST),
+ *afl->fsrv.shmem_fuzz_len);
+ fprintf(stderr, "SHM :");
+ for (u32 i = 0; i < *afl->fsrv.shmem_fuzz_len; i++)
+ fprintf(stderr, "%02x", afl->fsrv.shmem_fuzz[i]);
+ fprintf(stderr, "\nORIG:");
+ for (u32 i = 0; i < *afl->fsrv.shmem_fuzz_len; i++)
+ fprintf(stderr, "%02x", (u8)((u8 *)mem)[i]);
+ fprintf(stderr, "\n");
+
+ }
+
+#endif
+
+ return;
+
+ } else if (unlikely(!afl->fsrv.use_stdin)) {
+
+ if (unlikely(afl->no_unlink)) {
+
+ fd = open(afl->fsrv.out_file, O_WRONLY | O_CREAT | O_TRUNC,
+ DEFAULT_PERMISSION);
+
+ } else {
+
+ unlink(afl->fsrv.out_file); /* Ignore errors. */
+ fd = open(afl->fsrv.out_file, O_WRONLY | O_CREAT | O_EXCL,
+ DEFAULT_PERMISSION);
+
+ }
+
+ if (fd < 0) { PFATAL("Unable to create '%s'", afl->fsrv.out_file); }
+
+ } else {
+
+ lseek(fd, 0, SEEK_SET);
+
+ }
+
+ if (!post_process_skipped) {
+
+ ck_write(fd, new_mem, new_size, afl->fsrv.out_file);
+
+ } else {
+
+ ck_write(fd, mem, skip_at, afl->fsrv.out_file);
+
+ ck_write(fd, mem + skip_at + skip_len, tail_len, afl->fsrv.out_file);
+
+ }
+
+ if (afl->fsrv.use_stdin) {
+
+ if (ftruncate(fd, new_size)) { PFATAL("ftruncate() failed"); }
+ lseek(fd, 0, SEEK_SET);
+
+ } else {
+
+ close(fd);
+
+ }
+
+}
+
+/* Calibrate a new test case. This is done when processing the input directory
+ to warn about flaky or otherwise problematic test cases early on; and when
+ new paths are discovered to detect variable behavior and so on. */
+
+u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
+ u32 handicap, u8 from_queue) {
+
+ u8 fault = 0, new_bits = 0, var_detected = 0, hnb = 0,
+ first_run = (q->exec_cksum == 0);
+ u64 start_us, stop_us, diff_us;
+ s32 old_sc = afl->stage_cur, old_sm = afl->stage_max;
+ u32 use_tmout = afl->fsrv.exec_tmout;
+ u8 *old_sn = afl->stage_name;
+
+ if (unlikely(afl->shm.cmplog_mode)) { q->exec_cksum = 0; }
+
+ /* Be a bit more generous about timeouts when resuming sessions, or when
+ trying to calibrate already-added finds. This helps avoid trouble due
+ to intermittent latency. */
+
+ if (!from_queue || afl->resuming_fuzz) {
+
+ use_tmout = MAX(afl->fsrv.exec_tmout + CAL_TMOUT_ADD,
+ afl->fsrv.exec_tmout * CAL_TMOUT_PERC / 100);
+
+ }
+
+ ++q->cal_failed;
+
+ afl->stage_name = "calibration";
+ afl->stage_max = afl->afl_env.afl_cal_fast ? 3 : CAL_CYCLES;
+
+ /* Make sure the forkserver is up before we do anything, and let's not
+ count its spin-up time toward binary calibration. */
+
+ if (!afl->fsrv.fsrv_pid) {
+
+ if (afl->fsrv.cmplog_binary &&
+ afl->fsrv.init_child_func != cmplog_exec_child) {
+
+ FATAL("BUG in afl-fuzz detected. Cmplog mode not set correctly.");
+
+ }
+
+ afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon,
+ afl->afl_env.afl_debug_child);
+
+ if (afl->fsrv.support_shmem_fuzz && !afl->fsrv.use_shmem_fuzz) {
+
+ afl_shm_deinit(afl->shm_fuzz);
+ ck_free(afl->shm_fuzz);
+ afl->shm_fuzz = NULL;
+ afl->fsrv.support_shmem_fuzz = 0;
+ afl->fsrv.shmem_fuzz = NULL;
+
+ }
+
+ }
+
+ /* we need a dummy run if this is LTO + cmplog */
+ if (unlikely(afl->shm.cmplog_mode)) {
+
+ (void)write_to_testcase(afl, (void **)&use_mem, q->len, 1);
+
+ fault = fuzz_run_target(afl, &afl->fsrv, use_tmout);
+
+ /* afl->stop_soon is set by the handler for Ctrl+C. When it's pressed,
+ we want to bail out quickly. */
+
+ if (afl->stop_soon || fault != afl->crash_mode) { goto abort_calibration; }
+
+ if (!afl->non_instrumented_mode && !afl->stage_cur &&
+ !count_bytes(afl, afl->fsrv.trace_bits)) {
+
+ fault = FSRV_RUN_NOINST;
+ goto abort_calibration;
+
+ }
+
+#ifdef INTROSPECTION
+ if (unlikely(!q->bitsmap_size)) q->bitsmap_size = afl->bitsmap_size;
+#endif
+
+ }
+
+ if (q->exec_cksum) {
+
+ memcpy(afl->first_trace, afl->fsrv.trace_bits, afl->fsrv.map_size);
+ hnb = has_new_bits(afl, afl->virgin_bits);
+ if (hnb > new_bits) { new_bits = hnb; }
+
+ }
+
+ start_us = get_cur_time_us();
+
+ for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) {
+
+ if (unlikely(afl->debug)) {
+
+ DEBUGF("calibration stage %d/%d\n", afl->stage_cur + 1, afl->stage_max);
+
+ }
+
+ u64 cksum;
+
+ (void)write_to_testcase(afl, (void **)&use_mem, q->len, 1);
+
+ fault = fuzz_run_target(afl, &afl->fsrv, use_tmout);
+
+ /* afl->stop_soon is set by the handler for Ctrl+C. When it's pressed,
+ we want to bail out quickly. */
+
+ if (afl->stop_soon || fault != afl->crash_mode) { goto abort_calibration; }
+
+ if (!afl->non_instrumented_mode && !afl->stage_cur &&
+ !count_bytes(afl, afl->fsrv.trace_bits)) {
+
+ fault = FSRV_RUN_NOINST;
+ goto abort_calibration;
+
+ }
+
+#ifdef INTROSPECTION
+ if (unlikely(!q->bitsmap_size)) q->bitsmap_size = afl->bitsmap_size;
+#endif
+
+ classify_counts(&afl->fsrv);
+ cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
+ if (q->exec_cksum != cksum) {
+
+ hnb = has_new_bits(afl, afl->virgin_bits);
+ if (hnb > new_bits) { new_bits = hnb; }
+
+ if (q->exec_cksum) {
+
+ u32 i;
+
+ for (i = 0; i < afl->fsrv.map_size; ++i) {
+
+ if (unlikely(!afl->var_bytes[i]) &&
+ unlikely(afl->first_trace[i] != afl->fsrv.trace_bits[i])) {
+
+ afl->var_bytes[i] = 1;
+ // ignore the variable edge by setting it to fully discovered
+ afl->virgin_bits[i] = 0;
+
+ }
+
+ }
+
+ if (unlikely(!var_detected)) {
+
+ // note: from_queue seems to only be set during initialization
+ if (afl->afl_env.afl_no_ui || from_queue) {
+
+ WARNF("instability detected during calibration");
+
+ } else if (afl->debug) {
+
+ DEBUGF("instability detected during calibration\n");
+
+ }
+
+ }
+
+ var_detected = 1;
+ afl->stage_max =
+ afl->afl_env.afl_cal_fast ? CAL_CYCLES : CAL_CYCLES_LONG;
+
+ } else {
+
+ q->exec_cksum = cksum;
+ memcpy(afl->first_trace, afl->fsrv.trace_bits, afl->fsrv.map_size);
+
+ }
+
+ }
+
+ }
+
+ if (unlikely(afl->fixed_seed)) {
+
+ diff_us = (u64)(afl->fsrv.exec_tmout - 1) * (u64)afl->stage_max;
+
+ } else {
+
+ stop_us = get_cur_time_us();
+ diff_us = stop_us - start_us;
+ if (unlikely(!diff_us)) { ++diff_us; }
+
+ }
+
+ afl->total_cal_us += diff_us;
+ afl->total_cal_cycles += afl->stage_max;
+
+ /* OK, let's collect some stats about the performance of this test case.
+ This is used for fuzzing air time calculations in calculate_score(). */
+
+ if (unlikely(!afl->stage_max)) {
+
+ // Pretty sure this cannot happen, yet scan-build complains.
+ FATAL("BUG: stage_max should not be 0 here! Please report this condition.");
+
+ }
+
+ q->exec_us = diff_us / afl->stage_max;
+ q->bitmap_size = count_bytes(afl, afl->fsrv.trace_bits);
+ q->handicap = handicap;
+ q->cal_failed = 0;
+
+ afl->total_bitmap_size += q->bitmap_size;
+ ++afl->total_bitmap_entries;
+
+ update_bitmap_score(afl, q);
+
+ /* If this case didn't result in new output from the instrumentation, tell
+ parent. This is a non-critical problem, but something to warn the user
+ about. */
+
+ if (!afl->non_instrumented_mode && first_run && !fault && !new_bits) {
+
+ fault = FSRV_RUN_NOBITS;
+
+ }
+
+abort_calibration:
+
+ if (new_bits == 2 && !q->has_new_cov) {
+
+ q->has_new_cov = 1;
+ ++afl->queued_with_cov;
+
+ }
+
+ /* Mark variable paths. */
+
+ if (var_detected) {
+
+ afl->var_byte_count = count_bytes(afl, afl->var_bytes);
+
+ if (!q->var_behavior) {
+
+ mark_as_variable(afl, q);
+ ++afl->queued_variable;
+
+ }
+
+ }
+
+ afl->stage_name = old_sn;
+ afl->stage_cur = old_sc;
+ afl->stage_max = old_sm;
+
+ if (!first_run) { show_stats(afl); }
+
+ return fault;
+
+}
+
+/* Grab interesting test cases from other fuzzers. */
+
+void sync_fuzzers(afl_state_t *afl) {
+
+ DIR * sd;
+ struct dirent *sd_ent;
+ u32 sync_cnt = 0, synced = 0, entries = 0;
+ u8 path[PATH_MAX + 1 + NAME_MAX];
+
+ sd = opendir(afl->sync_dir);
+ if (!sd) { PFATAL("Unable to open '%s'", afl->sync_dir); }
+
+ afl->stage_max = afl->stage_cur = 0;
+ afl->cur_depth = 0;
+
+ /* Look at the entries created for every other fuzzer in the sync directory.
+ */
+
+ while ((sd_ent = readdir(sd))) {
+
+ u8 qd_synced_path[PATH_MAX], qd_path[PATH_MAX];
+ u32 min_accept = 0, next_min_accept = 0;
+
+ s32 id_fd;
+
+ /* Skip dot files and our own output directory. */
+
+ if (sd_ent->d_name[0] == '.' || !strcmp(afl->sync_id, sd_ent->d_name)) {
+
+ continue;
+
+ }
+
+ entries++;
+
+ // secondary nodes only syncs from main, the main node syncs from everyone
+ if (likely(afl->is_secondary_node)) {
+
+ sprintf(qd_path, "%s/%s/is_main_node", afl->sync_dir, sd_ent->d_name);
+ int res = access(qd_path, F_OK);
+ if (unlikely(afl->is_main_node)) { // an elected temporary main node
+
+ if (likely(res == 0)) { // there is another main node? downgrade.
+
+ afl->is_main_node = 0;
+ sprintf(qd_path, "%s/is_main_node", afl->out_dir);
+ unlink(qd_path);
+
+ }
+
+ } else {
+
+ if (likely(res != 0)) { continue; }
+
+ }
+
+ }
+
+ synced++;
+
+ /* document the attempt to sync to this instance */
+
+ sprintf(qd_synced_path, "%s/.synced/%s.last", afl->out_dir, sd_ent->d_name);
+ id_fd =
+ open(qd_synced_path, O_RDWR | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
+ if (id_fd >= 0) close(id_fd);
+
+ /* Skip anything that doesn't have a queue/ subdirectory. */
+
+ sprintf(qd_path, "%s/%s/queue", afl->sync_dir, sd_ent->d_name);
+
+ struct dirent **namelist = NULL;
+ int m = 0, n, o;
+
+ n = scandir(qd_path, &namelist, NULL, alphasort);
+
+ if (n < 1) {
+
+ if (namelist) free(namelist);
+ continue;
+
+ }
+
+ /* Retrieve the ID of the last seen test case. */
+
+ sprintf(qd_synced_path, "%s/.synced/%s", afl->out_dir, sd_ent->d_name);
+
+ id_fd = open(qd_synced_path, O_RDWR | O_CREAT, DEFAULT_PERMISSION);
+
+ if (id_fd < 0) { PFATAL("Unable to create '%s'", qd_synced_path); }
+
+ if (read(id_fd, &min_accept, sizeof(u32)) == sizeof(u32)) {
+
+ next_min_accept = min_accept;
+ lseek(id_fd, 0, SEEK_SET);
+
+ }
+
+ /* Show stats */
+
+ snprintf(afl->stage_name_buf, STAGE_BUF_SIZE, "sync %u", ++sync_cnt);
+
+ afl->stage_name = afl->stage_name_buf;
+ afl->stage_cur = 0;
+ afl->stage_max = 0;
+
+ /* For every file queued by this fuzzer, parse ID and see if we have
+ looked at it before; exec a test case if not. */
+
+ u8 entry[12];
+ sprintf(entry, "id:%06u", next_min_accept);
+
+ while (m < n) {
+
+ if (strncmp(namelist[m]->d_name, entry, 9)) {
+
+ m++;
+
+ } else {
+
+ break;
+
+ }
+
+ }
+
+ if (m >= n) { goto close_sync; } // nothing new
+
+ for (o = m; o < n; o++) {
+
+ s32 fd;
+ struct stat st;
+
+ snprintf(path, sizeof(path), "%s/%s", qd_path, namelist[o]->d_name);
+ afl->syncing_case = next_min_accept;
+ next_min_accept++;
+
+ /* Allow this to fail in case the other fuzzer is resuming or so... */
+
+ fd = open(path, O_RDONLY);
+
+ if (fd < 0) { continue; }
+
+ if (fstat(fd, &st)) { WARNF("fstat() failed"); }
+
+ /* Ignore zero-sized or oversized files. */
+
+ if (st.st_size && st.st_size <= MAX_FILE) {
+
+ u8 fault;
+ u8 *mem = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+
+ if (mem == MAP_FAILED) { PFATAL("Unable to mmap '%s'", path); }
+
+ /* See what happens. We rely on save_if_interesting() to catch major
+ errors and save the test case. */
+
+ (void)write_to_testcase(afl, (void **)&mem, st.st_size, 1);
+
+ fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
+
+ if (afl->stop_soon) { goto close_sync; }
+
+ afl->syncing_party = sd_ent->d_name;
+ afl->queued_imported +=
+ save_if_interesting(afl, mem, st.st_size, fault);
+ afl->syncing_party = 0;
+
+ munmap(mem, st.st_size);
+
+ }
+
+ close(fd);
+
+ }
+
+ ck_write(id_fd, &next_min_accept, sizeof(u32), qd_synced_path);
+
+ close_sync:
+ close(id_fd);
+ if (n > 0)
+ for (m = 0; m < n; m++)
+ free(namelist[m]);
+ free(namelist);
+
+ }
+
+ closedir(sd);
+
+ // If we are a secondary and no main was found to sync then become the main
+ if (unlikely(synced == 0) && likely(entries) &&
+ likely(afl->is_secondary_node)) {
+
+ // there is a small race condition here that another secondary runs at the
+ // same time. If so, the first temporary main node running again will demote
+ // themselves so this is not an issue
+
+ // u8 path2[PATH_MAX];
+ afl->is_main_node = 1;
+ sprintf(path, "%s/is_main_node", afl->out_dir);
+ int fd = open(path, O_CREAT | O_RDWR, 0644);
+ if (fd >= 0) { close(fd); }
+
+ }
+
+ if (afl->foreign_sync_cnt) read_foreign_testcases(afl, 0);
+
+ afl->last_sync_time = get_cur_time();
+ afl->last_sync_cycle = afl->queue_cycle;
+
+}
+
+/* Trim all new test cases to save cycles when doing deterministic checks. The
+ trimmer uses power-of-two increments somewhere between 1/16 and 1/1024 of
+ file size, to keep the stage short and sweet. */
+
+u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
+
+ u32 orig_len = q->len;
+
+ /* Custom mutator trimmer */
+ if (afl->custom_mutators_count) {
+
+ u8 trimmed_case = 0;
+ bool custom_trimmed = false;
+
+ LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+ if (el->afl_custom_trim) {
+
+ trimmed_case = trim_case_custom(afl, q, in_buf, el);
+ custom_trimmed = true;
+
+ }
+
+ });
+
+ if (orig_len != q->len || custom_trimmed) {
+
+ queue_testcase_retake(afl, q, orig_len);
+
+ }
+
+ if (custom_trimmed) return trimmed_case;
+
+ }
+
+ u8 needs_write = 0, fault = 0;
+ u32 trim_exec = 0;
+ u32 remove_len;
+ u32 len_p2;
+
+ u8 val_bufs[2][STRINGIFY_VAL_SIZE_MAX];
+
+ /* Although the trimmer will be less useful when variable behavior is
+ detected, it will still work to some extent, so we don't check for
+ this. */
+
+ if (q->len < 5) { return 0; }
+
+ afl->stage_name = afl->stage_name_buf;
+ afl->bytes_trim_in += q->len;
+
+ /* Select initial chunk len, starting with large steps. */
+
+ len_p2 = next_pow2(q->len);
+
+ remove_len = MAX(len_p2 / TRIM_START_STEPS, (u32)TRIM_MIN_BYTES);
+
+ /* Continue until the number of steps gets too high or the stepover
+ gets too small. */
+
+ while (remove_len >= MAX(len_p2 / TRIM_END_STEPS, (u32)TRIM_MIN_BYTES)) {
+
+ u32 remove_pos = remove_len;
+
+ sprintf(afl->stage_name_buf, "trim %s/%s",
+ u_stringify_int(val_bufs[0], remove_len),
+ u_stringify_int(val_bufs[1], remove_len));
+
+ afl->stage_cur = 0;
+ afl->stage_max = q->len / remove_len;
+
+ while (remove_pos < q->len) {
+
+ u32 trim_avail = MIN(remove_len, q->len - remove_pos);
+ u64 cksum;
+
+ write_with_gap(afl, in_buf, q->len, remove_pos, trim_avail);
+
+ fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
+
+ if (afl->stop_soon || fault == FSRV_RUN_ERROR) { goto abort_trimming; }
+
+ /* Note that we don't keep track of crashes or hangs here; maybe TODO?
+ */
+
+ ++afl->trim_execs;
+ classify_counts(&afl->fsrv);
+ cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
+
+ /* If the deletion had no impact on the trace, make it permanent. This
+ isn't perfect for variable-path inputs, but we're just making a
+ best-effort pass, so it's not a big deal if we end up with false
+ negatives every now and then. */
+
+ if (cksum == q->exec_cksum) {
+
+ u32 move_tail = q->len - remove_pos - trim_avail;
+
+ q->len -= trim_avail;
+ len_p2 = next_pow2(q->len);
+
+ memmove(in_buf + remove_pos, in_buf + remove_pos + trim_avail,
+ move_tail);
+
+ /* Let's save a clean trace, which will be needed by
+ update_bitmap_score once we're done with the trimming stuff. */
+
+ if (!needs_write) {
+
+ needs_write = 1;
+ memcpy(afl->clean_trace, afl->fsrv.trace_bits, afl->fsrv.map_size);
+
+ }
+
+ } else {
+
+ remove_pos += remove_len;
+
+ }
+
+ /* Since this can be slow, update the screen every now and then. */
+
+ if (!(trim_exec++ % afl->stats_update_freq)) { show_stats(afl); }
+ ++afl->stage_cur;
+
+ }
+
+ remove_len >>= 1;
+
+ }
+
+ /* If we have made changes to in_buf, we also need to update the on-disk
+ version of the test case. */
+
+ if (needs_write) {
+
+ s32 fd;
+
+ if (unlikely(afl->no_unlink)) {
+
+ fd = open(q->fname, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
+
+ if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); }
+
+ u32 written = 0;
+ while (written < q->len) {
+
+ ssize_t result = write(fd, in_buf, q->len - written);
+ if (result > 0) written += result;
+
+ }
+
+ } else {
+
+ unlink(q->fname); /* ignore errors */
+ fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
+
+ if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); }
+
+ ck_write(fd, in_buf, q->len, q->fname);
+
+ }
+
+ close(fd);
+
+ queue_testcase_retake_mem(afl, q, in_buf, q->len, orig_len);
+
+ memcpy(afl->fsrv.trace_bits, afl->clean_trace, afl->fsrv.map_size);
+ update_bitmap_score(afl, q);
+
+ }
+
+abort_trimming:
+
+ afl->bytes_trim_out += q->len;
+ return fault;
+
+}
+
+/* Write a modified test case, run program, process results. Handle
+ 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 fault;
+
+ len = write_to_testcase(afl, (void **)&out_buf, len, 0);
+
+ fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
+
+ if (afl->stop_soon) { return 1; }
+
+ if (fault == FSRV_RUN_TMOUT) {
+
+ if (afl->subseq_tmouts++ > TMOUT_LIMIT) {
+
+ ++afl->cur_skipped_items;
+ return 1;
+
+ }
+
+ } else {
+
+ afl->subseq_tmouts = 0;
+
+ }
+
+ /* Users can hit us with SIGUSR1 to request the current input
+ to be abandoned. */
+
+ if (afl->skip_requested) {
+
+ afl->skip_requested = 0;
+ ++afl->cur_skipped_items;
+ return 1;
+
+ }
+
+ /* This handles FAULT_ERROR for us: */
+
+ afl->queued_discovered += save_if_interesting(afl, out_buf, len, fault);
+
+ if (!(afl->stage_cur % afl->stats_update_freq) ||
+ afl->stage_cur + 1 == afl->stage_max) {
+
+ show_stats(afl);
+
+ }
+
+ return 0;
+
+}
+
diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c
new file mode 100644
index 00000000..98217438
--- /dev/null
+++ b/src/afl-fuzz-state.c
@@ -0,0 +1,649 @@
+/*
+ american fuzzy lop++ - globals declarations
+ -------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Andrea Fioraldi <andreafioraldi@gmail.com>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ This is the real deal: the program takes an instrumented binary and
+ attempts a variety of basic fuzzing tricks, paying close attention to
+ how they affect the execution path.
+
+ */
+
+#include "afl-fuzz.h"
+#include "envs.h"
+
+s8 interesting_8[] = {INTERESTING_8};
+s16 interesting_16[] = {INTERESTING_8, INTERESTING_16};
+s32 interesting_32[] = {INTERESTING_8, INTERESTING_16, INTERESTING_32};
+
+char *power_names[POWER_SCHEDULES_NUM] = {"explore", "mmopt", "exploit",
+ "fast", "coe", "lin",
+ "quad", "rare", "seek"};
+
+/* Initialize MOpt "globals" for this afl state */
+
+static void init_mopt_globals(afl_state_t *afl) {
+
+ MOpt_globals_t *core = &afl->mopt_globals_core;
+ core->finds = afl->core_operator_finds_puppet;
+ core->finds_v2 = afl->core_operator_finds_puppet_v2;
+ core->cycles = afl->core_operator_cycles_puppet;
+ core->cycles_v2 = afl->core_operator_cycles_puppet_v2;
+ core->cycles_v3 = afl->core_operator_cycles_puppet_v3;
+ core->is_pilot_mode = 0;
+ core->pTime = &afl->tmp_core_time;
+ core->period = period_core;
+ core->havoc_stagename = "MOpt-core-havoc";
+ core->splice_stageformat = "MOpt-core-splice %u";
+ core->havoc_stagenameshort = "MOpt_core_havoc";
+ core->splice_stagenameshort = "MOpt_core_splice";
+
+ MOpt_globals_t *pilot = &afl->mopt_globals_pilot;
+ pilot->finds = afl->stage_finds_puppet[0];
+ pilot->finds_v2 = afl->stage_finds_puppet_v2[0];
+ pilot->cycles = afl->stage_cycles_puppet[0];
+ pilot->cycles_v2 = afl->stage_cycles_puppet_v2[0];
+ pilot->cycles_v3 = afl->stage_cycles_puppet_v3[0];
+ pilot->is_pilot_mode = 1;
+ pilot->pTime = &afl->tmp_pilot_time;
+ pilot->period = period_pilot;
+ pilot->havoc_stagename = "MOpt-havoc";
+ pilot->splice_stageformat = "MOpt-splice %u";
+ pilot->havoc_stagenameshort = "MOpt_havoc";
+ pilot->splice_stagenameshort = "MOpt_splice";
+
+}
+
+/* A global pointer to all instances is needed (for now) for signals to arrive
+ */
+
+static list_t afl_states = {.element_prealloc_count = 0};
+
+/* Initializes an afl_state_t. */
+
+void afl_state_init(afl_state_t *afl, uint32_t map_size) {
+
+ /* thanks to this memset, growing vars like out_buf
+ and out_size are NULL/0 by default. */
+ memset(afl, 0, sizeof(afl_state_t));
+
+ afl->shm.map_size = map_size ? map_size : MAP_SIZE;
+
+ afl->w_init = 0.9;
+ afl->w_end = 0.3;
+ afl->g_max = 5000;
+ afl->period_pilot_tmp = 5000.0;
+ afl->schedule = FAST; /* Power schedule (default: FAST) */
+ afl->havoc_max_mult = HAVOC_MAX_MULT;
+
+ afl->clear_screen = 1; /* Window resized? */
+ afl->havoc_div = 1; /* Cycle count divisor for havoc */
+ afl->stage_name = "init"; /* Name of the current fuzz stage */
+ afl->splicing_with = -1; /* Splicing with which test case? */
+ afl->cpu_to_bind = -1;
+ afl->havoc_stack_pow2 = HAVOC_STACK_POW2;
+ afl->hang_tmout = EXEC_TIMEOUT;
+ afl->exit_on_time = 0;
+ afl->stats_update_freq = 1;
+ afl->stats_avg_exec = 0;
+ afl->skip_deterministic = 1;
+ afl->cmplog_lvl = 2;
+ afl->min_length = 1;
+ afl->max_length = MAX_FILE;
+#ifndef NO_SPLICING
+ afl->use_splicing = 1;
+#endif
+ afl->q_testcase_max_cache_size = TESTCASE_CACHE_SIZE * 1048576UL;
+ afl->q_testcase_max_cache_entries = 64 * 1024;
+
+#ifdef HAVE_AFFINITY
+ afl->cpu_aff = -1; /* Selected CPU core */
+#endif /* HAVE_AFFINITY */
+
+ afl->virgin_bits = ck_alloc(map_size);
+ afl->virgin_tmout = ck_alloc(map_size);
+ afl->virgin_crash = ck_alloc(map_size);
+ afl->var_bytes = ck_alloc(map_size);
+ afl->top_rated = ck_alloc(map_size * sizeof(void *));
+ afl->clean_trace = ck_alloc(map_size);
+ afl->clean_trace_custom = ck_alloc(map_size);
+ afl->first_trace = ck_alloc(map_size);
+ afl->map_tmp_buf = ck_alloc(map_size);
+
+ afl->fsrv.use_stdin = 1;
+ afl->fsrv.map_size = map_size;
+ // afl_state_t is not available in forkserver.c
+ afl->fsrv.afl_ptr = (void *)afl;
+ afl->fsrv.add_extra_func = (void (*)(void *, u8 *, u32)) & add_extra;
+ afl->fsrv.exec_tmout = EXEC_TIMEOUT;
+ afl->fsrv.mem_limit = MEM_LIMIT;
+ afl->fsrv.dev_urandom_fd = -1;
+ afl->fsrv.dev_null_fd = -1;
+ afl->fsrv.child_pid = -1;
+ afl->fsrv.out_dir_fd = -1;
+
+ init_mopt_globals(afl);
+
+ list_append(&afl_states, afl);
+
+}
+
+/*This sets up the environment variables for afl-fuzz into the afl_state
+ * struct*/
+
+void read_afl_environment(afl_state_t *afl, char **envp) {
+
+ int index = 0, issue_detected = 0;
+ char *env;
+ while ((env = envp[index++]) != NULL) {
+
+ if (strncmp(env, "ALF_", 4) == 0) {
+
+ WARNF("Potentially mistyped AFL environment variable: %s", env);
+ issue_detected = 1;
+
+ } else if (strncmp(env, "USE_", 4) == 0) {
+
+ WARNF(
+ "Potentially mistyped AFL environment variable: %s, did you mean "
+ "AFL_%s?",
+ env, env);
+ issue_detected = 1;
+
+ } else if (strncmp(env, "AFL_", 4) == 0) {
+
+ int i = 0, match = 0;
+ while (match == 0 && afl_environment_variables[i] != NULL) {
+
+ size_t afl_environment_variable_len =
+ strlen(afl_environment_variables[i]);
+ if (strncmp(env, afl_environment_variables[i],
+ afl_environment_variable_len) == 0 &&
+ env[afl_environment_variable_len] == '=') {
+
+ match = 1;
+ if (!strncmp(env, "AFL_SKIP_CPUFREQ", afl_environment_variable_len)) {
+
+ afl->afl_env.afl_skip_cpufreq =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
+ } else if (!strncmp(env, "AFL_EXIT_WHEN_DONE",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_exit_when_done =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
+ } else if (!strncmp(env, "AFL_EXIT_ON_TIME",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_exit_on_time =
+ (u8 *)get_afl_env(afl_environment_variables[i]);
+
+ } else if (!strncmp(env, "AFL_NO_AFFINITY",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_no_affinity =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
+ } else if (!strncmp(env, "AFL_TRY_AFFINITY",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_try_affinity =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
+ } else if (!strncmp(env, "AFL_SKIP_CRASHES",
+
+ afl_environment_variable_len)) {
+
+ // we should mark this obsolete in a few versions
+
+ } else if (!strncmp(env, "AFL_HANG_TMOUT",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_hang_tmout =
+ (u8 *)get_afl_env(afl_environment_variables[i]);
+
+ } else if (!strncmp(env, "AFL_KEEP_TIMEOUTS",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_keep_timeouts =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
+ } else if (!strncmp(env, "AFL_SKIP_BIN_CHECK",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_skip_bin_check =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
+ } else if (!strncmp(env, "AFL_DUMB_FORKSRV",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_dumb_forksrv =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
+ } else if (!strncmp(env, "AFL_IMPORT_FIRST",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_import_first =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
+ } else if (!strncmp(env, "AFL_CUSTOM_MUTATOR_ONLY",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_custom_mutator_only =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
+ } else if (!strncmp(env, "AFL_CMPLOG_ONLY_NEW",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_cmplog_only_new =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
+ } else if (!strncmp(env, "AFL_NO_UI", afl_environment_variable_len)) {
+
+ afl->afl_env.afl_no_ui =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
+ } else if (!strncmp(env, "AFL_FORCE_UI",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_force_ui =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
+ } else if (!strncmp(env, "AFL_IGNORE_PROBLEMS",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_ignore_problems =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
+ } else if (!strncmp(env, "AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_i_dont_care_about_missing_crashes =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
+ } else if (!strncmp(env, "AFL_BENCH_JUST_ONE",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_bench_just_one =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
+ } else if (!strncmp(env, "AFL_BENCH_UNTIL_CRASH",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_bench_until_crash =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
+ } else if (!strncmp(env, "AFL_DEBUG_CHILD",
+
+ afl_environment_variable_len) ||
+ !strncmp(env, "AFL_DEBUG_CHILD_OUTPUT",
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_debug_child =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
+ } else if (!strncmp(env, "AFL_AUTORESUME",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_autoresume =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
+ } else if (!strncmp(env, "AFL_PERSISTENT_RECORD",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_persistent_record =
+ get_afl_env(afl_environment_variables[i]);
+
+ } else if (!strncmp(env, "AFL_CYCLE_SCHEDULES",
+
+ afl_environment_variable_len)) {
+
+ afl->cycle_schedules = afl->afl_env.afl_cycle_schedules =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
+ } else if (!strncmp(env, "AFL_EXIT_ON_SEED_ISSUES",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_exit_on_seed_issues =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
+ } else if (!strncmp(env, "AFL_EXPAND_HAVOC_NOW",
+
+ afl_environment_variable_len)) {
+
+ afl->expand_havoc = afl->afl_env.afl_expand_havoc =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
+ } else if (!strncmp(env, "AFL_CAL_FAST",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_cal_fast =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
+ } else if (!strncmp(env, "AFL_FAST_CAL",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_cal_fast =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
+ } else if (!strncmp(env, "AFL_STATSD",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_statsd =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
+ } else if (!strncmp(env, "AFL_TMPDIR",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_tmpdir =
+ (u8 *)get_afl_env(afl_environment_variables[i]);
+
+ } else if (!strncmp(env, "AFL_CUSTOM_MUTATOR_LIBRARY",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_custom_mutator_library =
+ (u8 *)get_afl_env(afl_environment_variables[i]);
+
+ } else if (!strncmp(env, "AFL_PYTHON_MODULE",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_python_module =
+ (u8 *)get_afl_env(afl_environment_variables[i]);
+
+ } else if (!strncmp(env, "AFL_PATH", afl_environment_variable_len)) {
+
+ afl->afl_env.afl_path =
+ (u8 *)get_afl_env(afl_environment_variables[i]);
+
+ } else if (!strncmp(env, "AFL_PRELOAD",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_preload =
+ (u8 *)get_afl_env(afl_environment_variables[i]);
+
+ } else if (!strncmp(env, "AFL_MAX_DET_EXTRAS",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_max_det_extras =
+ (u8 *)get_afl_env(afl_environment_variables[i]);
+
+ } else if (!strncmp(env, "AFL_FORKSRV_INIT_TMOUT",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_forksrv_init_tmout =
+ (u8 *)get_afl_env(afl_environment_variables[i]);
+
+ } else if (!strncmp(env, "AFL_TESTCACHE_SIZE",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_testcache_size =
+ (u8 *)get_afl_env(afl_environment_variables[i]);
+
+ } else if (!strncmp(env, "AFL_TESTCACHE_ENTRIES",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_testcache_entries =
+ (u8 *)get_afl_env(afl_environment_variables[i]);
+
+ } else if (!strncmp(env, "AFL_STATSD_HOST",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_statsd_host =
+ (u8 *)get_afl_env(afl_environment_variables[i]);
+
+ } else if (!strncmp(env, "AFL_STATSD_PORT",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_statsd_port =
+ (u8 *)get_afl_env(afl_environment_variables[i]);
+
+ } else if (!strncmp(env, "AFL_STATSD_TAGS_FLAVOR",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_statsd_tags_flavor =
+ (u8 *)get_afl_env(afl_environment_variables[i]);
+
+ } else if (!strncmp(env, "AFL_CRASH_EXITCODE",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_crash_exitcode =
+ (u8 *)get_afl_env(afl_environment_variables[i]);
+
+#if defined USE_COLOR && !defined ALWAYS_COLORED
+
+ } else if (!strncmp(env, "AFL_NO_COLOR",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_statsd_tags_flavor =
+ (u8 *)get_afl_env(afl_environment_variables[i]);
+
+ } else if (!strncmp(env, "AFL_NO_COLOUR",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_statsd_tags_flavor =
+ (u8 *)get_afl_env(afl_environment_variables[i]);
+#endif
+
+ } else if (!strncmp(env, "AFL_KILL_SIGNAL",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_kill_signal =
+ (u8 *)get_afl_env(afl_environment_variables[i]);
+
+ } else if (!strncmp(env, "AFL_TARGET_ENV",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_target_env =
+ (u8 *)get_afl_env(afl_environment_variables[i]);
+
+ } else if (!strncmp(env, "AFL_INPUT_LEN_MIN",
+
+ afl_environment_variable_len)) {
+
+ afl->min_length =
+ atoi((u8 *)get_afl_env(afl_environment_variables[i]));
+
+ } else if (!strncmp(env, "AFL_INPUT_LEN_MAX",
+
+ afl_environment_variable_len)) {
+
+ afl->max_length =
+ atoi((u8 *)get_afl_env(afl_environment_variables[i]));
+
+ } else if (!strncmp(env, "AFL_PIZZA_MODE",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_pizza_mode =
+ atoi((u8 *)get_afl_env(afl_environment_variables[i]));
+ if (afl->afl_env.afl_pizza_mode == 0) {
+
+ afl->afl_env.afl_pizza_mode = 1;
+
+ } else {
+
+ afl->pizza_is_served = 1;
+
+ }
+
+ }
+
+ } else {
+
+ i++;
+
+ }
+
+ }
+
+ i = 0;
+ while (match == 0 && afl_environment_variables[i] != NULL) {
+
+ if (strncmp(env, afl_environment_variables[i],
+ strlen(afl_environment_variables[i])) == 0 &&
+ env[strlen(afl_environment_variables[i])] == '=') {
+
+ match = 1;
+
+ } else {
+
+ i++;
+
+ }
+
+ }
+
+ i = 0;
+ while (match == 0 && afl_environment_deprecated[i] != NULL) {
+
+ if (strncmp(env, afl_environment_deprecated[i],
+ strlen(afl_environment_deprecated[i])) == 0 &&
+ env[strlen(afl_environment_deprecated[i])] == '=') {
+
+ match = 1;
+
+ WARNF("AFL environment variable %s is deprecated!",
+ afl_environment_deprecated[i]);
+ issue_detected = 1;
+
+ } else {
+
+ i++;
+
+ }
+
+ }
+
+ if (match == 0) {
+
+ WARNF("Mistyped AFL environment variable: %s", env);
+ issue_detected = 1;
+
+ print_suggested_envs(env);
+
+ }
+
+ }
+
+ }
+
+ if (issue_detected) { sleep(2); }
+
+}
+
+/* Removes this afl_state instance and frees it. */
+
+void afl_state_deinit(afl_state_t *afl) {
+
+ if (afl->in_place_resume) { ck_free(afl->in_dir); }
+ if (afl->sync_id) { ck_free(afl->out_dir); }
+ if (afl->pass_stats) { ck_free(afl->pass_stats); }
+ if (afl->orig_cmp_map) { ck_free(afl->orig_cmp_map); }
+ if (afl->cmplog_binary) { ck_free(afl->cmplog_binary); }
+
+ afl_free(afl->queue_buf);
+ afl_free(afl->out_buf);
+ afl_free(afl->out_scratch_buf);
+ afl_free(afl->eff_buf);
+ afl_free(afl->in_buf);
+ afl_free(afl->in_scratch_buf);
+ afl_free(afl->ex_buf);
+
+ ck_free(afl->virgin_bits);
+ ck_free(afl->virgin_tmout);
+ ck_free(afl->virgin_crash);
+ ck_free(afl->var_bytes);
+ ck_free(afl->top_rated);
+ ck_free(afl->clean_trace);
+ ck_free(afl->clean_trace_custom);
+ ck_free(afl->first_trace);
+ ck_free(afl->map_tmp_buf);
+
+ list_remove(&afl_states, afl);
+
+}
+
+void afl_states_stop(void) {
+
+ /* We may be inside a signal handler.
+ Set flags first, send kill signals to child proceses later. */
+ LIST_FOREACH(&afl_states, afl_state_t, {
+
+ el->stop_soon = 1;
+
+ });
+
+ LIST_FOREACH(&afl_states, afl_state_t, {
+
+ if (el->fsrv.child_pid > 0) kill(el->fsrv.child_pid, el->fsrv.kill_signal);
+ if (el->fsrv.fsrv_pid > 0) kill(el->fsrv.fsrv_pid, el->fsrv.kill_signal);
+
+ });
+
+}
+
+void afl_states_clear_screen(void) {
+
+ LIST_FOREACH(&afl_states, afl_state_t, { el->clear_screen = 1; });
+
+}
+
+void afl_states_request_skip(void) {
+
+ LIST_FOREACH(&afl_states, afl_state_t, { el->skip_requested = 1; });
+
+}
+
diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c
new file mode 100644
index 00000000..5b237748
--- /dev/null
+++ b/src/afl-fuzz-stats.c
@@ -0,0 +1,2249 @@
+/*
+ american fuzzy lop++ - stats related routines
+ ---------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Andrea Fioraldi <andreafioraldi@gmail.com>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ This is the real deal: the program takes an instrumented binary and
+ attempts a variety of basic fuzzing tricks, paying close attention to
+ how they affect the execution path.
+
+ */
+
+#include "afl-fuzz.h"
+#include "envs.h"
+#include <limits.h>
+
+/* Write fuzzer setup file */
+
+void write_setup_file(afl_state_t *afl, u32 argc, char **argv) {
+
+ u8 fn[PATH_MAX];
+ snprintf(fn, PATH_MAX, "%s/fuzzer_setup", afl->out_dir);
+ FILE *f = create_ffile(fn);
+ u32 i;
+
+ fprintf(f, "# environment variables:\n");
+ u32 s_afl_env = (u32)sizeof(afl_environment_variables) /
+ sizeof(afl_environment_variables[0]) -
+ 1U;
+
+ for (i = 0; i < s_afl_env; ++i) {
+
+ char *val;
+ if ((val = getenv(afl_environment_variables[i])) != NULL) {
+
+ fprintf(f, "%s=%s\n", afl_environment_variables[i], val);
+
+ }
+
+ }
+
+ fprintf(f, "# command line:\n");
+
+ size_t j;
+ for (i = 0; i < argc; ++i) {
+
+ if (i) fprintf(f, " ");
+#ifdef __ANDROID__
+ if (memchr(argv[i], '\'', sizeof(argv[i]))) {
+
+#else
+ if (index(argv[i], '\'')) {
+
+#endif
+
+ fprintf(f, "'");
+ for (j = 0; j < strlen(argv[i]); j++)
+ if (argv[i][j] == '\'')
+ fprintf(f, "'\"'\"'");
+ else
+ fprintf(f, "%c", argv[i][j]);
+ fprintf(f, "'");
+
+ } else {
+
+ fprintf(f, "'%s'", argv[i]);
+
+ }
+
+ }
+
+ fprintf(f, "\n");
+
+ fclose(f);
+ (void)(afl_environment_deprecated);
+
+}
+
+/* load some of the existing stats file when resuming.*/
+void load_stats_file(afl_state_t *afl) {
+
+ FILE *f;
+ u8 buf[MAX_LINE];
+ u8 * lptr;
+ u8 fn[PATH_MAX];
+ u32 lineno = 0;
+ snprintf(fn, PATH_MAX, "%s/fuzzer_stats", afl->out_dir);
+ f = fopen(fn, "r");
+ if (!f) {
+
+ WARNF("Unable to load stats file '%s'", fn);
+ return;
+
+ }
+
+ while ((lptr = fgets(buf, MAX_LINE, f))) {
+
+ lineno++;
+ u8 *lstartptr = lptr;
+ u8 *rptr = lptr + strlen(lptr) - 1;
+ u8 keystring[MAX_LINE];
+ while (*lptr != ':' && lptr < rptr) {
+
+ lptr++;
+
+ }
+
+ if (*lptr == '\n' || !*lptr) {
+
+ WARNF("Unable to read line %d of stats file", lineno);
+ continue;
+
+ }
+
+ if (*lptr == ':') {
+
+ *lptr = 0;
+ strcpy(keystring, lstartptr);
+ lptr++;
+ char *nptr;
+ switch (lineno) {
+
+ case 3:
+ if (!strcmp(keystring, "run_time "))
+ afl->prev_run_time = 1000 * strtoull(lptr, &nptr, 10);
+ break;
+ case 5:
+ if (!strcmp(keystring, "cycles_done "))
+ afl->queue_cycle =
+ strtoull(lptr, &nptr, 10) ? strtoull(lptr, &nptr, 10) + 1 : 0;
+ break;
+ case 7:
+ if (!strcmp(keystring, "execs_done "))
+ afl->fsrv.total_execs = strtoull(lptr, &nptr, 10);
+ break;
+ case 10:
+ if (!strcmp(keystring, "corpus_count ")) {
+
+ u32 corpus_count = strtoul(lptr, &nptr, 10);
+ if (corpus_count != afl->queued_items) {
+
+ WARNF(
+ "queue/ has been modified -- things might not work, you're "
+ "on your own!");
+
+ }
+
+ }
+
+ break;
+ case 12:
+ if (!strcmp(keystring, "corpus_found "))
+ afl->queued_discovered = strtoul(lptr, &nptr, 10);
+ break;
+ case 13:
+ if (!strcmp(keystring, "corpus_imported "))
+ afl->queued_imported = strtoul(lptr, &nptr, 10);
+ break;
+ case 14:
+ if (!strcmp(keystring, "max_depth "))
+ afl->max_depth = strtoul(lptr, &nptr, 10);
+ break;
+ case 21:
+ if (!strcmp(keystring, "saved_crashes "))
+ afl->saved_crashes = strtoull(lptr, &nptr, 10);
+ break;
+ case 22:
+ if (!strcmp(keystring, "saved_hangs "))
+ afl->saved_hangs = strtoull(lptr, &nptr, 10);
+ break;
+ default:
+ break;
+
+ }
+
+ }
+
+ }
+
+ if (afl->saved_crashes) { write_crash_readme(afl); }
+
+ return;
+
+}
+
+/* Update stats file for unattended monitoring. */
+
+void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
+ double stability, double eps) {
+
+#ifndef __HAIKU__
+ struct rusage rus;
+#endif
+
+ u64 cur_time = get_cur_time();
+ u8 fn[PATH_MAX];
+ FILE *f;
+
+ snprintf(fn, PATH_MAX, "%s/fuzzer_stats", afl->out_dir);
+ f = create_ffile(fn);
+
+ /* Keep last values in case we're called from another context
+ where exec/sec stats and such are not readily available. */
+
+ if (!bitmap_cvg && !stability && !eps) {
+
+ bitmap_cvg = afl->last_bitmap_cvg;
+ stability = afl->last_stability;
+
+ } else {
+
+ afl->last_bitmap_cvg = bitmap_cvg;
+ afl->last_stability = stability;
+ afl->last_eps = eps;
+
+ }
+
+ if ((unlikely(!afl->last_avg_exec_update ||
+ cur_time - afl->last_avg_exec_update >= 60000))) {
+
+ afl->last_avg_execs_saved =
+ (double)(1000 * (afl->fsrv.total_execs - afl->last_avg_execs)) /
+ (double)(cur_time - afl->last_avg_exec_update);
+ afl->last_avg_execs = afl->fsrv.total_execs;
+ afl->last_avg_exec_update = cur_time;
+
+ }
+
+#ifndef __HAIKU__
+ if (getrusage(RUSAGE_CHILDREN, &rus)) { rus.ru_maxrss = 0; }
+#endif
+
+ fprintf(
+ f,
+ "start_time : %llu\n"
+ "last_update : %llu\n"
+ "run_time : %llu\n"
+ "fuzzer_pid : %u\n"
+ "cycles_done : %llu\n"
+ "cycles_wo_finds : %llu\n"
+ "execs_done : %llu\n"
+ "execs_per_sec : %0.02f\n"
+ "execs_ps_last_min : %0.02f\n"
+ "corpus_count : %u\n"
+ "corpus_favored : %u\n"
+ "corpus_found : %u\n"
+ "corpus_imported : %u\n"
+ "corpus_variable : %u\n"
+ "max_depth : %u\n"
+ "cur_item : %u\n"
+ "pending_favs : %u\n"
+ "pending_total : %u\n"
+ "stability : %0.02f%%\n"
+ "bitmap_cvg : %0.02f%%\n"
+ "saved_crashes : %llu\n"
+ "saved_hangs : %llu\n"
+ "last_find : %llu\n"
+ "last_crash : %llu\n"
+ "last_hang : %llu\n"
+ "execs_since_crash : %llu\n"
+ "exec_timeout : %u\n"
+ "slowest_exec_ms : %u\n"
+ "peak_rss_mb : %lu\n"
+ "cpu_affinity : %d\n"
+ "edges_found : %u\n"
+ "total_edges : %u\n"
+ "var_byte_count : %u\n"
+ "havoc_expansion : %u\n"
+ "auto_dict_entries : %u\n"
+ "testcache_size : %llu\n"
+ "testcache_count : %u\n"
+ "testcache_evict : %u\n"
+ "afl_banner : %s\n"
+ "afl_version : " VERSION
+ "\n"
+ "target_mode : %s%s%s%s%s%s%s%s%s%s\n"
+ "command_line : %s\n",
+ (afl->start_time - afl->prev_run_time) / 1000, cur_time / 1000,
+ (afl->prev_run_time + cur_time - afl->start_time) / 1000, (u32)getpid(),
+ afl->queue_cycle ? (afl->queue_cycle - 1) : 0, afl->cycles_wo_finds,
+ afl->fsrv.total_execs,
+ afl->fsrv.total_execs /
+ ((double)(afl->prev_run_time + get_cur_time() - afl->start_time) /
+ 1000),
+ afl->last_avg_execs_saved, afl->queued_items, afl->queued_favored,
+ afl->queued_discovered, afl->queued_imported, afl->queued_variable,
+ afl->max_depth, afl->current_entry, afl->pending_favored,
+ afl->pending_not_fuzzed, stability, bitmap_cvg, afl->saved_crashes,
+ afl->saved_hangs, afl->last_find_time / 1000, afl->last_crash_time / 1000,
+ afl->last_hang_time / 1000, afl->fsrv.total_execs - afl->last_crash_execs,
+ afl->fsrv.exec_tmout, afl->slowest_exec_ms,
+#ifndef __HAIKU__
+ #ifdef __APPLE__
+ (unsigned long int)(rus.ru_maxrss >> 20),
+ #else
+ (unsigned long int)(rus.ru_maxrss >> 10),
+ #endif
+#else
+ -1UL,
+#endif
+#ifdef HAVE_AFFINITY
+ afl->cpu_aff,
+#else
+ -1,
+#endif
+ t_bytes, afl->fsrv.real_map_size, afl->var_byte_count, afl->expand_havoc,
+ afl->a_extras_cnt, afl->q_testcase_cache_size,
+ afl->q_testcase_cache_count, afl->q_testcase_evictions, afl->use_banner,
+ afl->unicorn_mode ? "unicorn" : "", afl->fsrv.qemu_mode ? "qemu " : "",
+ afl->fsrv.cs_mode ? "coresight" : "",
+ afl->non_instrumented_mode ? " non_instrumented " : "",
+ afl->no_forkserver ? "no_fsrv " : "", afl->crash_mode ? "crash " : "",
+ afl->persistent_mode ? "persistent " : "",
+ afl->shmem_testcase_mode ? "shmem_testcase " : "",
+ afl->deferred_mode ? "deferred " : "",
+ (afl->unicorn_mode || afl->fsrv.qemu_mode || afl->fsrv.cs_mode ||
+ afl->non_instrumented_mode || afl->no_forkserver || afl->crash_mode ||
+ afl->persistent_mode || afl->deferred_mode)
+ ? ""
+ : "default",
+ afl->orig_cmdline);
+
+ /* ignore errors */
+
+ if (afl->debug) {
+
+ u32 i = 0;
+ fprintf(f, "virgin_bytes :");
+ for (i = 0; i < afl->fsrv.real_map_size; i++) {
+
+ if (afl->virgin_bits[i] != 0xff) {
+
+ fprintf(f, " %u[%02x]", i, afl->virgin_bits[i]);
+
+ }
+
+ }
+
+ fprintf(f, "\n");
+ fprintf(f, "var_bytes :");
+ for (i = 0; i < afl->fsrv.real_map_size; i++) {
+
+ if (afl->var_bytes[i]) { fprintf(f, " %u", i); }
+
+ }
+
+ fprintf(f, "\n");
+
+ }
+
+ fclose(f);
+
+}
+
+/* Update the plot file if there is a reason to. */
+
+void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
+ double eps) {
+
+ if (unlikely(!afl->force_ui_update &&
+ (afl->stop_soon ||
+ (afl->plot_prev_qp == afl->queued_items &&
+ afl->plot_prev_pf == afl->pending_favored &&
+ afl->plot_prev_pnf == afl->pending_not_fuzzed &&
+ afl->plot_prev_ce == afl->current_entry &&
+ afl->plot_prev_qc == afl->queue_cycle &&
+ afl->plot_prev_uc == afl->saved_crashes &&
+ afl->plot_prev_uh == afl->saved_hangs &&
+ afl->plot_prev_md == afl->max_depth &&
+ afl->plot_prev_ed == afl->fsrv.total_execs) ||
+ !afl->queue_cycle ||
+ get_cur_time() - afl->start_time <= 60000))) {
+
+ return;
+
+ }
+
+ afl->plot_prev_qp = afl->queued_items;
+ afl->plot_prev_pf = afl->pending_favored;
+ afl->plot_prev_pnf = afl->pending_not_fuzzed;
+ afl->plot_prev_ce = afl->current_entry;
+ afl->plot_prev_qc = afl->queue_cycle;
+ afl->plot_prev_uc = afl->saved_crashes;
+ afl->plot_prev_uh = afl->saved_hangs;
+ afl->plot_prev_md = afl->max_depth;
+ afl->plot_prev_ed = afl->fsrv.total_execs;
+
+ /* Fields in the file:
+
+ relative_time, afl->cycles_done, cur_item, corpus_count, corpus_not_fuzzed,
+ favored_not_fuzzed, saved_crashes, saved_hangs, max_depth,
+ execs_per_sec, edges_found */
+
+ fprintf(afl->fsrv.plot_file,
+ "%llu, %llu, %u, %u, %u, %u, %0.02f%%, %llu, %llu, %u, %0.02f, %llu, "
+ "%u\n",
+ ((afl->prev_run_time + get_cur_time() - afl->start_time) / 1000),
+ afl->queue_cycle - 1, afl->current_entry, afl->queued_items,
+ afl->pending_not_fuzzed, afl->pending_favored, bitmap_cvg,
+ afl->saved_crashes, afl->saved_hangs, afl->max_depth, eps,
+ afl->plot_prev_ed, t_bytes); /* ignore errors */
+
+ fflush(afl->fsrv.plot_file);
+
+}
+
+/* Check terminal dimensions after resize. */
+
+static void check_term_size(afl_state_t *afl) {
+
+ struct winsize ws;
+
+ afl->term_too_small = 0;
+
+ if (ioctl(1, TIOCGWINSZ, &ws)) { return; }
+
+ if (ws.ws_row == 0 || ws.ws_col == 0) { return; }
+ if (ws.ws_row < 24 || ws.ws_col < 79) { afl->term_too_small = 1; }
+
+}
+
+/* A spiffy retro stats screen! This is called every afl->stats_update_freq
+ execve() calls, plus in several other circumstances. */
+
+void show_stats(afl_state_t *afl) {
+
+ if (afl->pizza_is_served) {
+
+ show_stats_pizza(afl);
+
+ } else {
+
+ show_stats_normal(afl);
+
+ }
+
+}
+
+void show_stats_normal(afl_state_t *afl) {
+
+ double t_byte_ratio, stab_ratio;
+
+ u64 cur_ms;
+ u32 t_bytes, t_bits;
+
+ static u8 banner[128];
+ u32 banner_len, banner_pad;
+ u8 tmp[256];
+ u8 time_tmp[64];
+
+ u8 val_buf[8][STRINGIFY_VAL_SIZE_MAX];
+#define IB(i) (val_buf[(i)])
+
+ cur_ms = get_cur_time();
+
+ if (afl->most_time_key) {
+
+ if (afl->most_time * 1000 < cur_ms - afl->start_time) {
+
+ afl->most_time_key = 2;
+ afl->stop_soon = 2;
+
+ }
+
+ }
+
+ if (afl->most_execs_key == 1) {
+
+ if (afl->most_execs <= afl->fsrv.total_execs) {
+
+ afl->most_execs_key = 2;
+ afl->stop_soon = 2;
+
+ }
+
+ }
+
+ /* If not enough time has passed since last UI update, bail out. */
+
+ if (cur_ms - afl->stats_last_ms < 1000 / UI_TARGET_HZ &&
+ !afl->force_ui_update) {
+
+ return;
+
+ }
+
+ /* Check if we're past the 10 minute mark. */
+
+ if (cur_ms - afl->start_time > 10 * 60 * 1000) { afl->run_over10m = 1; }
+
+ /* Calculate smoothed exec speed stats. */
+
+ if (unlikely(!afl->stats_last_execs)) {
+
+ if (likely(cur_ms != afl->start_time)) {
+
+ afl->stats_avg_exec = ((double)afl->fsrv.total_execs) * 1000 /
+ (afl->prev_run_time + cur_ms - afl->start_time);
+
+ }
+
+ } else {
+
+ if (likely(cur_ms != afl->stats_last_ms)) {
+
+ double cur_avg =
+ ((double)(afl->fsrv.total_execs - afl->stats_last_execs)) * 1000 /
+ (cur_ms - afl->stats_last_ms);
+
+ /* If there is a dramatic (5x+) jump in speed, reset the indicator
+ more quickly. */
+
+ if (cur_avg * 5 < afl->stats_avg_exec ||
+ cur_avg / 5 > afl->stats_avg_exec) {
+
+ afl->stats_avg_exec = cur_avg;
+
+ }
+
+ afl->stats_avg_exec = afl->stats_avg_exec * (1.0 - 1.0 / AVG_SMOOTHING) +
+ cur_avg * (1.0 / AVG_SMOOTHING);
+
+ }
+
+ }
+
+ afl->stats_last_ms = cur_ms;
+ afl->stats_last_execs = afl->fsrv.total_execs;
+
+ /* Tell the callers when to contact us (as measured in execs). */
+
+ afl->stats_update_freq = afl->stats_avg_exec / (UI_TARGET_HZ * 10);
+ if (!afl->stats_update_freq) { afl->stats_update_freq = 1; }
+
+ /* Do some bitmap stats. */
+
+ t_bytes = count_non_255_bytes(afl, afl->virgin_bits);
+ t_byte_ratio = ((double)t_bytes * 100) / afl->fsrv.real_map_size;
+
+ if (unlikely(t_bytes > afl->fsrv.real_map_size)) {
+
+ if (unlikely(!afl->afl_env.afl_ignore_problems)) {
+
+ FATAL(
+ "Incorrect fuzzing setup detected. Your target seems to have loaded "
+ "incorrectly instrumented shared libraries (%u of %u/%u). If you use "
+ "LTO mode "
+ "please see instrumentation/README.lto.md. To ignore this problem "
+ "and continue fuzzing just set 'AFL_IGNORE_PROBLEMS=1'.\n",
+ t_bytes, afl->fsrv.real_map_size, afl->fsrv.map_size);
+
+ }
+
+ }
+
+ if (likely(t_bytes) && unlikely(afl->var_byte_count)) {
+
+ stab_ratio = 100 - (((double)afl->var_byte_count * 100) / t_bytes);
+
+ } else {
+
+ stab_ratio = 100;
+
+ }
+
+ /* Roughly every minute, update fuzzer stats and save auto tokens. */
+
+ if (unlikely(!afl->non_instrumented_mode &&
+ (afl->force_ui_update ||
+ cur_ms - afl->stats_last_stats_ms > STATS_UPDATE_SEC * 1000))) {
+
+ afl->stats_last_stats_ms = cur_ms;
+ write_stats_file(afl, t_bytes, t_byte_ratio, stab_ratio,
+ afl->stats_avg_exec);
+ save_auto(afl);
+ write_bitmap(afl);
+
+ }
+
+ if (unlikely(afl->afl_env.afl_statsd)) {
+
+ if (unlikely(afl->force_ui_update || cur_ms - afl->statsd_last_send_ms >
+ STATSD_UPDATE_SEC * 1000)) {
+
+ /* reset counter, even if send failed. */
+ afl->statsd_last_send_ms = cur_ms;
+ if (statsd_send_metric(afl)) { WARNF("could not send statsd metric."); }
+
+ }
+
+ }
+
+ /* Every now and then, write plot data. */
+
+ if (unlikely(afl->force_ui_update ||
+ cur_ms - afl->stats_last_plot_ms > PLOT_UPDATE_SEC * 1000)) {
+
+ afl->stats_last_plot_ms = cur_ms;
+ maybe_update_plot_file(afl, t_bytes, t_byte_ratio, afl->stats_avg_exec);
+
+ }
+
+ /* Honor AFL_EXIT_WHEN_DONE and AFL_BENCH_UNTIL_CRASH. */
+
+ if (unlikely(!afl->non_instrumented_mode && afl->cycles_wo_finds > 100 &&
+ !afl->pending_not_fuzzed && afl->afl_env.afl_exit_when_done)) {
+
+ afl->stop_soon = 2;
+
+ }
+
+ /* AFL_EXIT_ON_TIME. */
+
+ if (unlikely(afl->last_find_time && !afl->non_instrumented_mode &&
+ afl->afl_env.afl_exit_on_time &&
+ (cur_ms - afl->last_find_time) > afl->exit_on_time)) {
+
+ afl->stop_soon = 2;
+
+ }
+
+ if (unlikely(afl->total_crashes && afl->afl_env.afl_bench_until_crash)) {
+
+ afl->stop_soon = 2;
+
+ }
+
+ /* If we're not on TTY, bail out. */
+
+ if (afl->not_on_tty) { return; }
+
+ /* If we haven't started doing things, bail out. */
+
+ if (unlikely(!afl->queue_cur)) { return; }
+
+ /* Compute some mildly useful bitmap stats. */
+
+ t_bits = (afl->fsrv.map_size << 3) - count_bits(afl, afl->virgin_bits);
+
+ /* Now, for the visuals... */
+
+ if (afl->clear_screen) {
+
+ SAYF(TERM_CLEAR CURSOR_HIDE);
+ afl->clear_screen = 0;
+
+ check_term_size(afl);
+
+ }
+
+ SAYF(TERM_HOME);
+
+ if (unlikely(afl->term_too_small)) {
+
+ SAYF(cBRI
+ "Your terminal is too small to display the UI.\n"
+ "Please resize terminal window to at least 79x24.\n" cRST);
+
+ return;
+
+ }
+
+ /* Let's start by drawing a centered banner. */
+ if (unlikely(!banner[0])) {
+
+ char *si = "";
+ if (afl->sync_id) { si = afl->sync_id; }
+ memset(banner, 0, sizeof(banner));
+ banner_len = (afl->crash_mode ? 20 : 18) + strlen(VERSION) + strlen(si) +
+ strlen(afl->power_name) + 4 + 6;
+
+ if (strlen(afl->use_banner) + banner_len > 75) {
+
+ afl->use_banner += (strlen(afl->use_banner) + banner_len) - 76;
+ memset(afl->use_banner, '.', 3);
+
+ }
+
+ banner_len += strlen(afl->use_banner);
+ banner_pad = (79 - banner_len) / 2;
+ memset(banner, ' ', banner_pad);
+
+#ifdef __linux__
+ if (afl->fsrv.nyx_mode) {
+
+ sprintf(banner + banner_pad,
+ "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s] - Nyx",
+ afl->crash_mode ? cPIN "peruvian were-rabbit"
+ : cYEL "american fuzzy lop",
+ si, afl->use_banner, afl->power_name);
+
+ } else {
+
+#endif
+ sprintf(banner + banner_pad,
+ "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s]",
+ afl->crash_mode ? cPIN "peruvian were-rabbit"
+ : cYEL "american fuzzy lop",
+ si, afl->use_banner, afl->power_name);
+
+#ifdef __linux__
+
+ }
+
+#endif
+
+ }
+
+ SAYF("\n%s\n", banner);
+
+ /* "Handy" shortcuts for drawing boxes... */
+
+#define bSTG bSTART cGRA
+#define bH2 bH bH
+#define bH5 bH2 bH2 bH
+#define bH10 bH5 bH5
+#define bH20 bH10 bH10
+#define bH30 bH20 bH10
+#define SP5 " "
+#define SP10 SP5 SP5
+#define SP20 SP10 SP10
+
+ /* Since `total_crashes` does not get reloaded from disk on restart,
+ it indicates if we found crashes this round already -> paint red.
+ If it's 0, but `saved_crashes` is set from a past run, paint in yellow. */
+ char *crash_color = afl->total_crashes ? cLRD
+ : afl->saved_crashes ? cYEL
+ : cRST;
+
+ /* Lord, forgive me this. */
+
+ SAYF(SET_G1 bSTG bLT bH bSTOP cCYA
+ " process timing " bSTG bH30 bH5 bH bHB bH bSTOP cCYA
+ " overall results " bSTG bH2 bH2 bRT "\n");
+
+ if (afl->non_instrumented_mode) {
+
+ strcpy(tmp, cRST);
+
+ } else {
+
+ u64 min_wo_finds = (cur_ms - afl->last_find_time) / 1000 / 60;
+
+ /* First queue cycle: don't stop now! */
+ if (afl->queue_cycle == 1 || min_wo_finds < 15) {
+
+ strcpy(tmp, cMGN);
+
+ } else
+
+ /* Subsequent cycles, but we're still making finds. */
+ if (afl->cycles_wo_finds < 25 || min_wo_finds < 30) {
+
+ strcpy(tmp, cYEL);
+
+ } else
+
+ /* No finds for a long time and no test cases to try. */
+ if (afl->cycles_wo_finds > 100 && !afl->pending_not_fuzzed &&
+ min_wo_finds > 120) {
+
+ strcpy(tmp, cLGN);
+
+ /* Default: cautiously OK to stop? */
+
+ } else {
+
+ strcpy(tmp, cLBL);
+
+ }
+
+ }
+
+ u_stringify_time_diff(time_tmp, afl->prev_run_time + cur_ms, afl->start_time);
+ SAYF(bV bSTOP " run time : " cRST "%-33s " bSTG bV bSTOP
+ " cycles done : %s%-5s " bSTG bV "\n",
+ time_tmp, tmp, u_stringify_int(IB(0), afl->queue_cycle - 1));
+
+ /* We want to warn people about not seeing new paths after a full cycle,
+ except when resuming fuzzing or running in non-instrumented mode. */
+
+ if (!afl->non_instrumented_mode &&
+ (afl->last_find_time || afl->resuming_fuzz || afl->queue_cycle == 1 ||
+ afl->in_bitmap || afl->crash_mode)) {
+
+ u_stringify_time_diff(time_tmp, cur_ms, afl->last_find_time);
+ SAYF(bV bSTOP " last new find : " cRST "%-33s ", time_tmp);
+
+ } else {
+
+ if (afl->non_instrumented_mode) {
+
+ SAYF(bV bSTOP " last new find : " cPIN "n/a" cRST
+ " (non-instrumented mode) ");
+
+ } else {
+
+ SAYF(bV bSTOP " last new find : " cRST "none yet " cLRD
+ "(odd, check syntax!) ");
+
+ }
+
+ }
+
+ SAYF(bSTG bV bSTOP " corpus count : " cRST "%-5s " bSTG bV "\n",
+ u_stringify_int(IB(0), afl->queued_items));
+
+ /* Highlight crashes in red if found, denote going over the KEEP_UNIQUE_CRASH
+ limit with a '+' appended to the count. */
+
+ sprintf(tmp, "%s%s", u_stringify_int(IB(0), afl->saved_crashes),
+ (afl->saved_crashes >= KEEP_UNIQUE_CRASH) ? "+" : "");
+
+ u_stringify_time_diff(time_tmp, cur_ms, afl->last_crash_time);
+ SAYF(bV bSTOP "last saved crash : " cRST "%-33s " bSTG bV bSTOP
+ "saved crashes : %s%-6s" bSTG bV "\n",
+ time_tmp, crash_color, tmp);
+
+ sprintf(tmp, "%s%s", u_stringify_int(IB(0), afl->saved_hangs),
+ (afl->saved_hangs >= KEEP_UNIQUE_HANG) ? "+" : "");
+
+ u_stringify_time_diff(time_tmp, cur_ms, afl->last_hang_time);
+ SAYF(bV bSTOP " last saved hang : " cRST "%-33s " bSTG bV bSTOP
+ " saved hangs : " cRST "%-6s" bSTG bV "\n",
+ time_tmp, tmp);
+
+ SAYF(bVR bH bSTOP cCYA
+ " cycle progress " bSTG bH10 bH5 bH2 bH2 bH2 bHB bH bSTOP cCYA
+ " map coverage" bSTG bHT bH20 bH2 bVL "\n");
+
+ /* This gets funny because we want to print several variable-length variables
+ together, but then cram them into a fixed-width field - so we need to
+ put them in a temporary buffer first. */
+
+ sprintf(tmp, "%s%s%u (%0.01f%%)", u_stringify_int(IB(0), afl->current_entry),
+ afl->queue_cur->favored ? "." : "*", afl->queue_cur->fuzz_level,
+ ((double)afl->current_entry * 100) / afl->queued_items);
+
+ SAYF(bV bSTOP " now processing : " cRST "%-18s " bSTG bV bSTOP, tmp);
+
+ sprintf(tmp, "%0.02f%% / %0.02f%%",
+ ((double)afl->queue_cur->bitmap_size) * 100 / afl->fsrv.real_map_size,
+ t_byte_ratio);
+
+ SAYF(" map density : %s%-19s" bSTG bV "\n",
+ t_byte_ratio > 70
+ ? cLRD
+ : ((t_bytes < 200 && !afl->non_instrumented_mode) ? cPIN : cRST),
+ tmp);
+
+ sprintf(tmp, "%s (%0.02f%%)", u_stringify_int(IB(0), afl->cur_skipped_items),
+ ((double)afl->cur_skipped_items * 100) / afl->queued_items);
+
+ SAYF(bV bSTOP " runs timed out : " cRST "%-18s " bSTG bV, tmp);
+
+ sprintf(tmp, "%0.02f bits/tuple", t_bytes ? (((double)t_bits) / t_bytes) : 0);
+
+ SAYF(bSTOP " count coverage : " cRST "%-19s" bSTG bV "\n", tmp);
+
+ SAYF(bVR bH bSTOP cCYA
+ " stage progress " bSTG bH10 bH5 bH2 bH2 bH2 bX bH bSTOP cCYA
+ " findings in depth " bSTG bH10 bH5 bH2 bVL "\n");
+
+ sprintf(tmp, "%s (%0.02f%%)", u_stringify_int(IB(0), afl->queued_favored),
+ ((double)afl->queued_favored) * 100 / afl->queued_items);
+
+ /* Yeah... it's still going on... halp? */
+
+ SAYF(bV bSTOP " now trying : " cRST "%-22s " bSTG bV bSTOP
+ " favored items : " cRST "%-20s" bSTG bV "\n",
+ afl->stage_name, tmp);
+
+ if (!afl->stage_max) {
+
+ sprintf(tmp, "%s/-", u_stringify_int(IB(0), afl->stage_cur));
+
+ } else {
+
+ sprintf(tmp, "%s/%s (%0.02f%%)", u_stringify_int(IB(0), afl->stage_cur),
+ u_stringify_int(IB(1), afl->stage_max),
+ ((double)afl->stage_cur) * 100 / afl->stage_max);
+
+ }
+
+ SAYF(bV bSTOP " stage execs : " cRST "%-23s" bSTG bV bSTOP, tmp);
+
+ sprintf(tmp, "%s (%0.02f%%)", u_stringify_int(IB(0), afl->queued_with_cov),
+ ((double)afl->queued_with_cov) * 100 / afl->queued_items);
+
+ SAYF(" new edges on : " cRST "%-20s" bSTG bV "\n", tmp);
+
+ sprintf(tmp, "%s (%s%s saved)", u_stringify_int(IB(0), afl->total_crashes),
+ u_stringify_int(IB(1), afl->saved_crashes),
+ (afl->saved_crashes >= KEEP_UNIQUE_CRASH) ? "+" : "");
+
+ if (afl->crash_mode) {
+
+ SAYF(bV bSTOP " total execs : " cRST "%-22s " bSTG bV bSTOP
+ " new crashes : %s%-20s" bSTG bV "\n",
+ u_stringify_int(IB(0), afl->fsrv.total_execs), crash_color, tmp);
+
+ } else {
+
+ SAYF(bV bSTOP " total execs : " cRST "%-22s " bSTG bV bSTOP
+ " total crashes : %s%-20s" bSTG bV "\n",
+ u_stringify_int(IB(0), afl->fsrv.total_execs), crash_color, tmp);
+
+ }
+
+ /* Show a warning about slow execution. */
+
+ if (afl->stats_avg_exec < 100) {
+
+ sprintf(tmp, "%s/sec (%s)", u_stringify_float(IB(0), afl->stats_avg_exec),
+ afl->stats_avg_exec < 20 ? "zzzz..." : "slow!");
+
+ SAYF(bV bSTOP " exec speed : " cLRD "%-22s ", tmp);
+
+ } else {
+
+ sprintf(tmp, "%s/sec", u_stringify_float(IB(0), afl->stats_avg_exec));
+ SAYF(bV bSTOP " exec speed : " cRST "%-22s ", tmp);
+
+ }
+
+ sprintf(tmp, "%s (%s%s saved)", u_stringify_int(IB(0), afl->total_tmouts),
+ u_stringify_int(IB(1), afl->saved_tmouts),
+ (afl->saved_hangs >= KEEP_UNIQUE_HANG) ? "+" : "");
+
+ SAYF(bSTG bV bSTOP " total tmouts : " cRST "%-20s" bSTG bV "\n", tmp);
+
+ /* Aaaalmost there... hold on! */
+
+ SAYF(bVR bH cCYA bSTOP " fuzzing strategy yields " bSTG bH10 bH2 bHT bH10 bH2
+ bH bHB bH bSTOP cCYA " item geometry " bSTG bH5 bH2 bVL "\n");
+
+ if (unlikely(afl->custom_only)) {
+
+ strcpy(tmp, "disabled (custom-mutator-only mode)");
+
+ } else if (likely(afl->skip_deterministic)) {
+
+ strcpy(tmp, "disabled (default, enable with -D)");
+
+ } else {
+
+ sprintf(tmp, "%s/%s, %s/%s, %s/%s",
+ u_stringify_int(IB(0), afl->stage_finds[STAGE_FLIP1]),
+ u_stringify_int(IB(1), afl->stage_cycles[STAGE_FLIP1]),
+ u_stringify_int(IB(2), afl->stage_finds[STAGE_FLIP2]),
+ u_stringify_int(IB(3), afl->stage_cycles[STAGE_FLIP2]),
+ u_stringify_int(IB(4), afl->stage_finds[STAGE_FLIP4]),
+ u_stringify_int(IB(5), afl->stage_cycles[STAGE_FLIP4]));
+
+ }
+
+ SAYF(bV bSTOP " bit flips : " cRST "%-36s " bSTG bV bSTOP
+ " levels : " cRST "%-10s" bSTG bV "\n",
+ tmp, u_stringify_int(IB(0), afl->max_depth));
+
+ if (unlikely(!afl->skip_deterministic)) {
+
+ sprintf(tmp, "%s/%s, %s/%s, %s/%s",
+ u_stringify_int(IB(0), afl->stage_finds[STAGE_FLIP8]),
+ u_stringify_int(IB(1), afl->stage_cycles[STAGE_FLIP8]),
+ u_stringify_int(IB(2), afl->stage_finds[STAGE_FLIP16]),
+ u_stringify_int(IB(3), afl->stage_cycles[STAGE_FLIP16]),
+ u_stringify_int(IB(4), afl->stage_finds[STAGE_FLIP32]),
+ u_stringify_int(IB(5), afl->stage_cycles[STAGE_FLIP32]));
+
+ }
+
+ SAYF(bV bSTOP " byte flips : " cRST "%-36s " bSTG bV bSTOP
+ " pending : " cRST "%-10s" bSTG bV "\n",
+ tmp, u_stringify_int(IB(0), afl->pending_not_fuzzed));
+
+ if (unlikely(!afl->skip_deterministic)) {
+
+ sprintf(tmp, "%s/%s, %s/%s, %s/%s",
+ u_stringify_int(IB(0), afl->stage_finds[STAGE_ARITH8]),
+ u_stringify_int(IB(1), afl->stage_cycles[STAGE_ARITH8]),
+ u_stringify_int(IB(2), afl->stage_finds[STAGE_ARITH16]),
+ u_stringify_int(IB(3), afl->stage_cycles[STAGE_ARITH16]),
+ u_stringify_int(IB(4), afl->stage_finds[STAGE_ARITH32]),
+ u_stringify_int(IB(5), afl->stage_cycles[STAGE_ARITH32]));
+
+ }
+
+ SAYF(bV bSTOP " arithmetics : " cRST "%-36s " bSTG bV bSTOP
+ " pend fav : " cRST "%-10s" bSTG bV "\n",
+ tmp, u_stringify_int(IB(0), afl->pending_favored));
+
+ if (unlikely(!afl->skip_deterministic)) {
+
+ sprintf(tmp, "%s/%s, %s/%s, %s/%s",
+ u_stringify_int(IB(0), afl->stage_finds[STAGE_INTEREST8]),
+ u_stringify_int(IB(1), afl->stage_cycles[STAGE_INTEREST8]),
+ u_stringify_int(IB(2), afl->stage_finds[STAGE_INTEREST16]),
+ u_stringify_int(IB(3), afl->stage_cycles[STAGE_INTEREST16]),
+ u_stringify_int(IB(4), afl->stage_finds[STAGE_INTEREST32]),
+ u_stringify_int(IB(5), afl->stage_cycles[STAGE_INTEREST32]));
+
+ }
+
+ SAYF(bV bSTOP " known ints : " cRST "%-36s " bSTG bV bSTOP
+ " own finds : " cRST "%-10s" bSTG bV "\n",
+ tmp, u_stringify_int(IB(0), afl->queued_discovered));
+
+ if (unlikely(!afl->skip_deterministic)) {
+
+ sprintf(tmp, "%s/%s, %s/%s, %s/%s, %s/%s",
+ u_stringify_int(IB(0), afl->stage_finds[STAGE_EXTRAS_UO]),
+ u_stringify_int(IB(1), afl->stage_cycles[STAGE_EXTRAS_UO]),
+ u_stringify_int(IB(2), afl->stage_finds[STAGE_EXTRAS_UI]),
+ u_stringify_int(IB(3), afl->stage_cycles[STAGE_EXTRAS_UI]),
+ u_stringify_int(IB(4), afl->stage_finds[STAGE_EXTRAS_AO]),
+ u_stringify_int(IB(5), afl->stage_cycles[STAGE_EXTRAS_AO]),
+ u_stringify_int(IB(6), afl->stage_finds[STAGE_EXTRAS_AI]),
+ u_stringify_int(IB(7), afl->stage_cycles[STAGE_EXTRAS_AI]));
+
+ } else if (unlikely(!afl->extras_cnt || afl->custom_only)) {
+
+ strcpy(tmp, "n/a");
+
+ } else {
+
+ strcpy(tmp, "havoc mode");
+
+ }
+
+ SAYF(bV bSTOP " dictionary : " cRST "%-36s " bSTG bV bSTOP
+ " imported : " cRST "%-10s" bSTG bV "\n",
+ tmp,
+ afl->sync_id ? u_stringify_int(IB(0), afl->queued_imported)
+ : (u8 *)"n/a");
+
+ sprintf(tmp, "%s/%s, %s/%s",
+ u_stringify_int(IB(0), afl->stage_finds[STAGE_HAVOC]),
+ u_stringify_int(IB(2), afl->stage_cycles[STAGE_HAVOC]),
+ u_stringify_int(IB(3), afl->stage_finds[STAGE_SPLICE]),
+ u_stringify_int(IB(4), afl->stage_cycles[STAGE_SPLICE]));
+
+ SAYF(bV bSTOP "havoc/splice : " cRST "%-36s " bSTG bV bSTOP, tmp);
+
+ if (t_bytes) {
+
+ sprintf(tmp, "%0.02f%%", stab_ratio);
+
+ } else {
+
+ strcpy(tmp, "n/a");
+
+ }
+
+ SAYF(" stability : %s%-10s" bSTG bV "\n",
+ (stab_ratio < 85 && afl->var_byte_count > 40)
+ ? cLRD
+ : ((afl->queued_variable &&
+ (!afl->persistent_mode || afl->var_byte_count > 20))
+ ? cMGN
+ : cRST),
+ tmp);
+
+ if (unlikely(afl->afl_env.afl_python_module)) {
+
+ sprintf(tmp, "%s/%s,",
+ u_stringify_int(IB(0), afl->stage_finds[STAGE_PYTHON]),
+ u_stringify_int(IB(1), afl->stage_cycles[STAGE_PYTHON]));
+
+ } else {
+
+ strcpy(tmp, "unused,");
+
+ }
+
+ if (unlikely(afl->afl_env.afl_custom_mutator_library)) {
+
+ strcat(tmp, " ");
+ strcat(tmp, u_stringify_int(IB(2), afl->stage_finds[STAGE_CUSTOM_MUTATOR]));
+ strcat(tmp, "/");
+ strcat(tmp,
+ u_stringify_int(IB(3), afl->stage_cycles[STAGE_CUSTOM_MUTATOR]));
+ strcat(tmp, ",");
+
+ } else {
+
+ strcat(tmp, " unused,");
+
+ }
+
+ if (unlikely(afl->shm.cmplog_mode)) {
+
+ strcat(tmp, " ");
+ strcat(tmp, u_stringify_int(IB(4), afl->stage_finds[STAGE_COLORIZATION]));
+ strcat(tmp, "/");
+ strcat(tmp, u_stringify_int(IB(5), afl->stage_cycles[STAGE_COLORIZATION]));
+ strcat(tmp, ", ");
+ strcat(tmp, u_stringify_int(IB(6), afl->stage_finds[STAGE_ITS]));
+ strcat(tmp, "/");
+ strcat(tmp, u_stringify_int(IB(7), afl->stage_cycles[STAGE_ITS]));
+
+ } else {
+
+ strcat(tmp, " unused, unused");
+
+ }
+
+ SAYF(bV bSTOP "py/custom/rq : " cRST "%-36s " bSTG bVR bH20 bH2 bH bRB "\n",
+ tmp);
+
+ if (likely(afl->disable_trim)) {
+
+ sprintf(tmp, "disabled, ");
+
+ } else if (unlikely(!afl->bytes_trim_out)) {
+
+ sprintf(tmp, "n/a, ");
+
+ } else {
+
+ sprintf(tmp, "%0.02f%%/%s, ",
+ ((double)(afl->bytes_trim_in - afl->bytes_trim_out)) * 100 /
+ afl->bytes_trim_in,
+ u_stringify_int(IB(0), afl->trim_execs));
+
+ }
+
+ if (likely(afl->skip_deterministic)) {
+
+ strcat(tmp, "disabled");
+
+ } else if (unlikely(!afl->blocks_eff_total)) {
+
+ strcat(tmp, "n/a");
+
+ } else {
+
+ u8 tmp2[128];
+
+ sprintf(tmp2, "%0.02f%%",
+ ((double)(afl->blocks_eff_total - afl->blocks_eff_select)) * 100 /
+ afl->blocks_eff_total);
+
+ strcat(tmp, tmp2);
+
+ }
+
+ // if (afl->custom_mutators_count) {
+
+ //
+ // sprintf(tmp, "%s/%s",
+ // u_stringify_int(IB(0), afl->stage_finds[STAGE_CUSTOM_MUTATOR]),
+ // u_stringify_int(IB(1), afl->stage_cycles[STAGE_CUSTOM_MUTATOR]));
+ // SAYF(bV bSTOP " custom mut. : " cRST "%-36s " bSTG bV RESET_G1, tmp);
+ //
+ //} else {
+
+ SAYF(bV bSTOP " trim/eff : " cRST "%-36s " bSTG bV RESET_G1, tmp);
+
+ //}
+
+ /* Provide some CPU utilization stats. */
+
+ if (afl->cpu_core_count) {
+
+ char *spacing = SP10, snap[24] = " " cLGN "snapshot" cRST " ";
+
+ double cur_runnable = get_runnable_processes();
+ u32 cur_utilization = cur_runnable * 100 / afl->cpu_core_count;
+
+ u8 *cpu_color = cCYA;
+
+ /* If we could still run one or more processes, use green. */
+
+ if (afl->cpu_core_count > 1 && cur_runnable + 1 <= afl->cpu_core_count) {
+
+ cpu_color = cLGN;
+
+ }
+
+ /* If we're clearly oversubscribed, use red. */
+
+ if (!afl->no_cpu_meter_red && cur_utilization >= 150) { cpu_color = cLRD; }
+
+ if (afl->fsrv.snapshot) { spacing = snap; }
+
+#ifdef HAVE_AFFINITY
+
+ if (afl->cpu_aff >= 0) {
+
+ SAYF("%s" cGRA "[cpu%03u:%s%3u%%" cGRA "]\r" cRST, spacing,
+ MIN(afl->cpu_aff, 999), cpu_color, MIN(cur_utilization, (u32)999));
+
+ } else {
+
+ SAYF("%s" cGRA " [cpu:%s%3u%%" cGRA "]\r" cRST, spacing, cpu_color,
+ MIN(cur_utilization, (u32)999));
+
+ }
+
+#else
+
+ SAYF("%s" cGRA " [cpu:%s%3u%%" cGRA "]\r" cRST, spacing, cpu_color,
+ MIN(cur_utilization, (u32)999));
+
+#endif /* ^HAVE_AFFINITY */
+
+ } else {
+
+ SAYF("\r");
+
+ }
+
+ /* Last line */
+ SAYF(SET_G1 "\n" bSTG bLB bH30 bH20 bH2 bRB bSTOP cRST RESET_G1);
+
+#undef IB
+
+ /* Hallelujah! */
+
+ fflush(0);
+
+}
+
+void show_stats_pizza(afl_state_t *afl) {
+
+ double t_byte_ratio, stab_ratio;
+
+ u64 cur_ms;
+ u32 t_bytes, t_bits;
+
+ static u8 banner[128];
+ u32 banner_len, banner_pad;
+ u8 tmp[256];
+ u8 time_tmp[64];
+
+ u8 val_buf[8][STRINGIFY_VAL_SIZE_MAX];
+#define IB(i) (val_buf[(i)])
+
+ cur_ms = get_cur_time();
+
+ if (afl->most_time_key) {
+
+ if (afl->most_time * 1000 < cur_ms - afl->start_time) {
+
+ afl->most_time_key = 2;
+ afl->stop_soon = 2;
+
+ }
+
+ }
+
+ if (afl->most_execs_key == 1) {
+
+ if (afl->most_execs <= afl->fsrv.total_execs) {
+
+ afl->most_execs_key = 2;
+ afl->stop_soon = 2;
+
+ }
+
+ }
+
+ /* If not enough time has passed since last UI update, bail out. */
+
+ if (cur_ms - afl->stats_last_ms < 1000 / UI_TARGET_HZ &&
+ !afl->force_ui_update) {
+
+ return;
+
+ }
+
+ /* Check if we're past the 10 minute mark. */
+
+ if (cur_ms - afl->start_time > 10 * 60 * 1000) { afl->run_over10m = 1; }
+
+ /* Calculate smoothed exec speed stats. */
+
+ if (unlikely(!afl->stats_last_execs)) {
+
+ if (likely(cur_ms != afl->start_time)) {
+
+ afl->stats_avg_exec = ((double)afl->fsrv.total_execs) * 1000 /
+ (afl->prev_run_time + cur_ms - afl->start_time);
+
+ }
+
+ } else {
+
+ if (likely(cur_ms != afl->stats_last_ms)) {
+
+ double cur_avg =
+ ((double)(afl->fsrv.total_execs - afl->stats_last_execs)) * 1000 /
+ (cur_ms - afl->stats_last_ms);
+
+ /* If there is a dramatic (5x+) jump in speed, reset the indicator
+ more quickly. */
+
+ if (cur_avg * 5 < afl->stats_avg_exec ||
+ cur_avg / 5 > afl->stats_avg_exec) {
+
+ afl->stats_avg_exec = cur_avg;
+
+ }
+
+ afl->stats_avg_exec = afl->stats_avg_exec * (1.0 - 1.0 / AVG_SMOOTHING) +
+ cur_avg * (1.0 / AVG_SMOOTHING);
+
+ }
+
+ }
+
+ afl->stats_last_ms = cur_ms;
+ afl->stats_last_execs = afl->fsrv.total_execs;
+
+ /* Tell the callers when to contact us (as measured in execs). */
+
+ afl->stats_update_freq = afl->stats_avg_exec / (UI_TARGET_HZ * 10);
+ if (!afl->stats_update_freq) { afl->stats_update_freq = 1; }
+
+ /* Do some bitmap stats. */
+
+ t_bytes = count_non_255_bytes(afl, afl->virgin_bits);
+ t_byte_ratio = ((double)t_bytes * 100) / afl->fsrv.real_map_size;
+
+ if (unlikely(t_bytes > afl->fsrv.real_map_size)) {
+
+ if (unlikely(!afl->afl_env.afl_ignore_problems)) {
+
+ FATAL(
+ "This is what happens when you speak italian to the rabbit "
+ "Don't speak italian to the rabbit");
+
+ }
+
+ }
+
+ if (likely(t_bytes) && unlikely(afl->var_byte_count)) {
+
+ stab_ratio = 100 - (((double)afl->var_byte_count * 100) / t_bytes);
+
+ } else {
+
+ stab_ratio = 100;
+
+ }
+
+ /* Roughly every minute, update fuzzer stats and save auto tokens. */
+
+ if (unlikely(!afl->non_instrumented_mode &&
+ (afl->force_ui_update ||
+ cur_ms - afl->stats_last_stats_ms > STATS_UPDATE_SEC * 1000))) {
+
+ afl->stats_last_stats_ms = cur_ms;
+ write_stats_file(afl, t_bytes, t_byte_ratio, stab_ratio,
+ afl->stats_avg_exec);
+ save_auto(afl);
+ write_bitmap(afl);
+
+ }
+
+ if (unlikely(afl->afl_env.afl_statsd)) {
+
+ if (unlikely(afl->force_ui_update || cur_ms - afl->statsd_last_send_ms >
+ STATSD_UPDATE_SEC * 1000)) {
+
+ /* reset counter, even if send failed. */
+ afl->statsd_last_send_ms = cur_ms;
+ if (statsd_send_metric(afl)) {
+
+ WARNF("Could not order tomato sauce from statsd.");
+
+ }
+
+ }
+
+ }
+
+ /* Every now and then, write plot data. */
+
+ if (unlikely(afl->force_ui_update ||
+ cur_ms - afl->stats_last_plot_ms > PLOT_UPDATE_SEC * 1000)) {
+
+ afl->stats_last_plot_ms = cur_ms;
+ maybe_update_plot_file(afl, t_bytes, t_byte_ratio, afl->stats_avg_exec);
+
+ }
+
+ /* Honor AFL_EXIT_WHEN_DONE and AFL_BENCH_UNTIL_CRASH. */
+
+ if (unlikely(!afl->non_instrumented_mode && afl->cycles_wo_finds > 100 &&
+ !afl->pending_not_fuzzed && afl->afl_env.afl_exit_when_done)) {
+
+ afl->stop_soon = 2;
+
+ }
+
+ /* AFL_EXIT_ON_TIME. */
+
+ if (unlikely(afl->last_find_time && !afl->non_instrumented_mode &&
+ afl->afl_env.afl_exit_on_time &&
+ (cur_ms - afl->last_find_time) > afl->exit_on_time)) {
+
+ afl->stop_soon = 2;
+
+ }
+
+ if (unlikely(afl->total_crashes && afl->afl_env.afl_bench_until_crash)) {
+
+ afl->stop_soon = 2;
+
+ }
+
+ /* If we're not on TTY, bail out. */
+
+ if (afl->not_on_tty) { return; }
+
+ /* If we haven't started doing things, bail out. */
+
+ if (unlikely(!afl->queue_cur)) { return; }
+
+ /* Compute some mildly useful bitmap stats. */
+
+ t_bits = (afl->fsrv.map_size << 3) - count_bits(afl, afl->virgin_bits);
+
+ /* Now, for the visuals... */
+
+ if (afl->clear_screen) {
+
+ SAYF(TERM_CLEAR CURSOR_HIDE);
+ afl->clear_screen = 0;
+
+ check_term_size(afl);
+
+ }
+
+ SAYF(TERM_HOME);
+
+ if (unlikely(afl->term_too_small)) {
+
+ SAYF(cBRI
+ "Our pizzeria can't host this many guests.\n"
+ "Please call Pizzeria Caravaggio. They have tables of at least "
+ "79x24.\n" cRST);
+
+ return;
+
+ }
+
+ /* Let's start by drawing a centered banner. */
+ if (unlikely(!banner[0])) {
+
+ char *si = "";
+ if (afl->sync_id) { si = afl->sync_id; }
+ memset(banner, 0, sizeof(banner));
+ banner_len = (afl->crash_mode ? 20 : 18) + strlen(VERSION) + strlen(si) +
+ strlen(afl->power_name) + 4 + 6;
+
+ if (strlen(afl->use_banner) + banner_len > 75) {
+
+ afl->use_banner += (strlen(afl->use_banner) + banner_len) - 76;
+ memset(afl->use_banner, '.', 3);
+
+ }
+
+ banner_len += strlen(afl->use_banner);
+ banner_pad = (79 - banner_len) / 2;
+ memset(banner, ' ', banner_pad);
+
+#ifdef __linux__
+ if (afl->fsrv.nyx_mode) {
+
+ sprintf(banner + banner_pad,
+ "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s] - Nyx",
+ afl->crash_mode ? cPIN "Mozzarbella Pizzeria table booking system"
+ : cYEL "Mozzarbella Pizzeria management system",
+ si, afl->use_banner, afl->power_name);
+
+ } else {
+
+#endif
+ sprintf(banner + banner_pad,
+ "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s]",
+ afl->crash_mode ? cPIN "Mozzarbella Pizzeria table booking system"
+ : cYEL "Mozzarbella Pizzeria management system",
+ si, afl->use_banner, afl->power_name);
+
+#ifdef __linux__
+
+ }
+
+#endif
+
+ }
+
+ SAYF("\n%s\n", banner);
+
+ /* "Handy" shortcuts for drawing boxes... */
+
+#define bSTG bSTART cGRA
+#define bH2 bH bH
+#define bH5 bH2 bH2 bH
+#define bH10 bH5 bH5
+#define bH20 bH10 bH10
+#define bH30 bH20 bH10
+#define SP5 " "
+#define SP10 SP5 SP5
+#define SP20 SP10 SP10
+
+ /* Since `total_crashes` does not get reloaded from disk on restart,
+ it indicates if we found crashes this round already -> paint red.
+ If it's 0, but `saved_crashes` is set from a past run, paint in yellow. */
+ char *crash_color = afl->total_crashes ? cLRD
+ : afl->saved_crashes ? cYEL
+ : cRST;
+
+ /* Lord, forgive me this. */
+
+ SAYF(SET_G1 bSTG bLT bH bSTOP cCYA
+ " Mozzarbella has been proudly serving pizzas since " bSTG bH20 bH bH bH
+ bHB bH bSTOP cCYA " In this time, we served " bSTG bH30 bRT "\n");
+
+ if (afl->non_instrumented_mode) {
+
+ strcpy(tmp, cRST);
+
+ } else {
+
+ u64 min_wo_finds = (cur_ms - afl->last_find_time) / 1000 / 60;
+
+ /* First queue cycle: don't stop now! */
+ if (afl->queue_cycle == 1 || min_wo_finds < 15) {
+
+ strcpy(tmp, cMGN);
+
+ } else
+
+ /* Subsequent cycles, but we're still making finds. */
+ if (afl->cycles_wo_finds < 25 || min_wo_finds < 30) {
+
+ strcpy(tmp, cYEL);
+
+ } else
+
+ /* No finds for a long time and no test cases to try. */
+ if (afl->cycles_wo_finds > 100 && !afl->pending_not_fuzzed &&
+ min_wo_finds > 120) {
+
+ strcpy(tmp, cLGN);
+
+ /* Default: cautiously OK to stop? */
+
+ } else {
+
+ strcpy(tmp, cLBL);
+
+ }
+
+ }
+
+ u_stringify_time_diff(time_tmp, afl->prev_run_time + cur_ms, afl->start_time);
+ SAYF(bV bSTOP
+ " open time : " cRST "%-37s " bSTG bV bSTOP
+ " seasons done : %s%-5s " bSTG bV "\n",
+ time_tmp, tmp, u_stringify_int(IB(0), afl->queue_cycle - 1));
+
+ /* We want to warn people about not seeing new paths after a full cycle,
+ except when resuming fuzzing or running in non-instrumented mode. */
+
+ if (!afl->non_instrumented_mode &&
+ (afl->last_find_time || afl->resuming_fuzz || afl->queue_cycle == 1 ||
+ afl->in_bitmap || afl->crash_mode)) {
+
+ u_stringify_time_diff(time_tmp, cur_ms, afl->last_find_time);
+ SAYF(bV bSTOP " last pizza baked : " cRST "%-37s ",
+ time_tmp);
+
+ } else {
+
+ if (afl->non_instrumented_mode) {
+
+ SAYF(bV bSTOP " last pizza baked : " cPIN "n/a" cRST
+ " (non-instrumented mode) ");
+
+ } else {
+
+ SAYF(bV bSTOP " last pizza baked : " cRST
+ "none yet " cLRD
+ "(odd, check Gennarino, he might be slacking!) ");
+
+ }
+
+ }
+
+ SAYF(bSTG bV bSTOP " pizzas on the menu : " cRST
+ "%-5s " bSTG bV "\n",
+ u_stringify_int(IB(0), afl->queued_items));
+
+ /* Highlight crashes in red if found, denote going over the KEEP_UNIQUE_CRASH
+ limit with a '+' appended to the count. */
+
+ sprintf(tmp, "%s%s", u_stringify_int(IB(0), afl->saved_crashes),
+ (afl->saved_crashes >= KEEP_UNIQUE_CRASH) ? "+" : "");
+
+ u_stringify_time_diff(time_tmp, cur_ms, afl->last_crash_time);
+ SAYF(bV bSTOP
+ " last ordered pizza : " cRST "%-33s " bSTG bV bSTOP
+ " at table : %s%-6s " bSTG bV "\n",
+ time_tmp, crash_color, tmp);
+
+ sprintf(tmp, "%s%s", u_stringify_int(IB(0), afl->saved_hangs),
+ (afl->saved_hangs >= KEEP_UNIQUE_HANG) ? "+" : "");
+
+ u_stringify_time_diff(time_tmp, cur_ms, afl->last_hang_time);
+ SAYF(bV bSTOP
+ " last conversation with customers : " cRST "%-33s " bSTG bV bSTOP
+ " number of Peroni : " cRST "%-6s " bSTG bV
+ "\n",
+ time_tmp, tmp);
+
+ SAYF(bVR bH bSTOP cCYA
+ " Baking progress " bSTG bH30 bH20 bH5 bH bX bH bSTOP cCYA
+ " Pizzeria busyness" bSTG bH30 bH5 bH bH bVL "\n");
+
+ /* This gets funny because we want to print several variable-length variables
+ together, but then cram them into a fixed-width field - so we need to
+ put them in a temporary buffer first. */
+
+ sprintf(tmp, "%s%s%u (%0.01f%%)", u_stringify_int(IB(0), afl->current_entry),
+ afl->queue_cur->favored ? "." : "*", afl->queue_cur->fuzz_level,
+ ((double)afl->current_entry * 100) / afl->queued_items);
+
+ SAYF(bV bSTOP " now baking : " cRST
+ "%-18s " bSTG bV bSTOP,
+ tmp);
+
+ sprintf(tmp, "%0.02f%% / %0.02f%%",
+ ((double)afl->queue_cur->bitmap_size) * 100 / afl->fsrv.real_map_size,
+ t_byte_ratio);
+
+ SAYF(" table full : %s%-19s " bSTG bV "\n",
+ t_byte_ratio > 70
+ ? cLRD
+ : ((t_bytes < 200 && !afl->non_instrumented_mode) ? cPIN : cRST),
+ tmp);
+
+ sprintf(tmp, "%s (%0.02f%%)", u_stringify_int(IB(0), afl->cur_skipped_items),
+ ((double)afl->cur_skipped_items * 100) / afl->queued_items);
+
+ SAYF(bV bSTOP " burned pizzas : " cRST
+ "%-18s " bSTG bV,
+ tmp);
+
+ sprintf(tmp, "%0.02f bits/tuple", t_bytes ? (((double)t_bits) / t_bytes) : 0);
+
+ SAYF(bSTOP " count coverage : " cRST "%-19s " bSTG bV "\n",
+ tmp);
+
+ SAYF(bVR bH bSTOP cCYA
+ " Pizzas almost ready " bSTG bH30 bH20 bH2 bH bX bH bSTOP cCYA
+ " Types of pizzas cooking " bSTG bH10 bH5 bH2 bH10 bH2 bH bVL "\n");
+
+ sprintf(tmp, "%s (%0.02f%%)", u_stringify_int(IB(0), afl->queued_favored),
+ ((double)afl->queued_favored) * 100 / afl->queued_items);
+
+ /* Yeah... it's still going on... halp? */
+
+ SAYF(bV bSTOP " now preparing : " cRST
+ "%-22s " bSTG bV bSTOP
+ " favourite topping : " cRST "%-20s" bSTG bV
+ "\n",
+ afl->stage_name, tmp);
+
+ if (!afl->stage_max) {
+
+ sprintf(tmp, "%s/-", u_stringify_int(IB(0), afl->stage_cur));
+
+ } else {
+
+ sprintf(tmp, "%s/%s (%0.02f%%)", u_stringify_int(IB(0), afl->stage_cur),
+ u_stringify_int(IB(1), afl->stage_max),
+ ((double)afl->stage_cur) * 100 / afl->stage_max);
+
+ }
+
+ SAYF(bV bSTOP " number of pizzas : " cRST
+ "%-23s " bSTG bV bSTOP,
+ tmp);
+
+ sprintf(tmp, "%s (%0.02f%%)", u_stringify_int(IB(0), afl->queued_with_cov),
+ ((double)afl->queued_with_cov) * 100 / afl->queued_items);
+
+ SAYF(" new pizza type seen on Instagram : " cRST "%-20s" bSTG bV "\n", tmp);
+
+ sprintf(tmp, "%s (%s%s saved)", u_stringify_int(IB(0), afl->total_crashes),
+ u_stringify_int(IB(1), afl->saved_crashes),
+ (afl->saved_crashes >= KEEP_UNIQUE_CRASH) ? "+" : "");
+
+ if (afl->crash_mode) {
+
+ SAYF(bV bSTOP " total pizzas : " cRST
+ "%-22s " bSTG bV bSTOP
+ " pizzas with pineapple : %s%-20s" bSTG bV "\n",
+ u_stringify_int(IB(0), afl->fsrv.total_execs), crash_color, tmp);
+
+ } else {
+
+ SAYF(bV bSTOP " total pizzas : " cRST
+ "%-22s " bSTG bV bSTOP
+ " total pizzas with pineapple : %s%-20s" bSTG bV "\n",
+ u_stringify_int(IB(0), afl->fsrv.total_execs), crash_color, tmp);
+
+ }
+
+ /* Show a warning about slow execution. */
+
+ if (afl->stats_avg_exec < 100) {
+
+ sprintf(tmp, "%s/sec (%s)", u_stringify_float(IB(0), afl->stats_avg_exec),
+ afl->stats_avg_exec < 20 ? "zzzz..." : "Gennarino is at it again!");
+
+ SAYF(bV bSTOP " pizza making speed : " cLRD
+ "%-22s ",
+ tmp);
+
+ } else {
+
+ sprintf(tmp, "%s/sec", u_stringify_float(IB(0), afl->stats_avg_exec));
+ SAYF(bV bSTOP " pizza making speed : " cRST
+ "%-22s ",
+ tmp);
+
+ }
+
+ sprintf(tmp, "%s (%s%s saved)", u_stringify_int(IB(0), afl->total_tmouts),
+ u_stringify_int(IB(1), afl->saved_tmouts),
+ (afl->saved_hangs >= KEEP_UNIQUE_HANG) ? "+" : "");
+
+ SAYF(bSTG bV bSTOP " burned pizzas : " cRST "%-20s" bSTG bV
+ "\n",
+ tmp);
+
+ /* Aaaalmost there... hold on! */
+
+ SAYF(bVR bH cCYA bSTOP " Promotional campaign on TikTok yields " bSTG bH30 bH2
+ bH bH2 bX bH bSTOP cCYA
+ " Customer type " bSTG bH5 bH2 bH30 bH2 bH bVL "\n");
+
+ if (unlikely(afl->custom_only)) {
+
+ strcpy(tmp, "oven off (custom-mutator-only mode)");
+
+ } else if (likely(afl->skip_deterministic)) {
+
+ strcpy(tmp, "oven off (default, enable with -D)");
+
+ } else {
+
+ sprintf(tmp, "%s/%s, %s/%s, %s/%s",
+ u_stringify_int(IB(0), afl->stage_finds[STAGE_FLIP1]),
+ u_stringify_int(IB(1), afl->stage_cycles[STAGE_FLIP1]),
+ u_stringify_int(IB(2), afl->stage_finds[STAGE_FLIP2]),
+ u_stringify_int(IB(3), afl->stage_cycles[STAGE_FLIP2]),
+ u_stringify_int(IB(4), afl->stage_finds[STAGE_FLIP4]),
+ u_stringify_int(IB(5), afl->stage_cycles[STAGE_FLIP4]));
+
+ }
+
+ SAYF(bV bSTOP
+ " pizzas for celiac : " cRST "%-36s " bSTG bV bSTOP
+ " levels : " cRST "%-10s " bSTG bV
+ "\n",
+ tmp, u_stringify_int(IB(0), afl->max_depth));
+
+ if (unlikely(!afl->skip_deterministic)) {
+
+ sprintf(tmp, "%s/%s, %s/%s, %s/%s",
+ u_stringify_int(IB(0), afl->stage_finds[STAGE_FLIP8]),
+ u_stringify_int(IB(1), afl->stage_cycles[STAGE_FLIP8]),
+ u_stringify_int(IB(2), afl->stage_finds[STAGE_FLIP16]),
+ u_stringify_int(IB(3), afl->stage_cycles[STAGE_FLIP16]),
+ u_stringify_int(IB(4), afl->stage_finds[STAGE_FLIP32]),
+ u_stringify_int(IB(5), afl->stage_cycles[STAGE_FLIP32]));
+
+ }
+
+ SAYF(bV bSTOP
+ " pizzas for kids : " cRST "%-36s " bSTG bV bSTOP
+ " pizzas to make : " cRST "%-10s " bSTG bV
+ "\n",
+ tmp, u_stringify_int(IB(0), afl->pending_not_fuzzed));
+
+ if (unlikely(!afl->skip_deterministic)) {
+
+ sprintf(tmp, "%s/%s, %s/%s, %s/%s",
+ u_stringify_int(IB(0), afl->stage_finds[STAGE_ARITH8]),
+ u_stringify_int(IB(1), afl->stage_cycles[STAGE_ARITH8]),
+ u_stringify_int(IB(2), afl->stage_finds[STAGE_ARITH16]),
+ u_stringify_int(IB(3), afl->stage_cycles[STAGE_ARITH16]),
+ u_stringify_int(IB(4), afl->stage_finds[STAGE_ARITH32]),
+ u_stringify_int(IB(5), afl->stage_cycles[STAGE_ARITH32]));
+
+ }
+
+ SAYF(bV bSTOP
+ " pizza bianca : " cRST "%-36s " bSTG bV bSTOP
+ " nice table : " cRST "%-10s " bSTG bV
+ "\n",
+ tmp, u_stringify_int(IB(0), afl->pending_favored));
+
+ if (unlikely(!afl->skip_deterministic)) {
+
+ sprintf(tmp, "%s/%s, %s/%s, %s/%s",
+ u_stringify_int(IB(0), afl->stage_finds[STAGE_INTEREST8]),
+ u_stringify_int(IB(1), afl->stage_cycles[STAGE_INTEREST8]),
+ u_stringify_int(IB(2), afl->stage_finds[STAGE_INTEREST16]),
+ u_stringify_int(IB(3), afl->stage_cycles[STAGE_INTEREST16]),
+ u_stringify_int(IB(4), afl->stage_finds[STAGE_INTEREST32]),
+ u_stringify_int(IB(5), afl->stage_cycles[STAGE_INTEREST32]));
+
+ }
+
+ SAYF(bV bSTOP
+ " recurring customers : " cRST "%-36s " bSTG bV bSTOP
+ " new customers : " cRST "%-10s " bSTG bV
+ "\n",
+ tmp, u_stringify_int(IB(0), afl->queued_discovered));
+
+ if (unlikely(!afl->skip_deterministic)) {
+
+ sprintf(tmp, "%s/%s, %s/%s, %s/%s, %s/%s",
+ u_stringify_int(IB(0), afl->stage_finds[STAGE_EXTRAS_UO]),
+ u_stringify_int(IB(1), afl->stage_cycles[STAGE_EXTRAS_UO]),
+ u_stringify_int(IB(2), afl->stage_finds[STAGE_EXTRAS_UI]),
+ u_stringify_int(IB(3), afl->stage_cycles[STAGE_EXTRAS_UI]),
+ u_stringify_int(IB(4), afl->stage_finds[STAGE_EXTRAS_AO]),
+ u_stringify_int(IB(5), afl->stage_cycles[STAGE_EXTRAS_AO]),
+ u_stringify_int(IB(6), afl->stage_finds[STAGE_EXTRAS_AI]),
+ u_stringify_int(IB(7), afl->stage_cycles[STAGE_EXTRAS_AI]));
+
+ } else if (unlikely(!afl->extras_cnt || afl->custom_only)) {
+
+ strcpy(tmp, "n/a");
+
+ } else {
+
+ strcpy(tmp, "18 year aniversary mode");
+
+ }
+
+ SAYF(bV bSTOP
+ " dictionary : " cRST "%-36s " bSTG bV bSTOP
+ " patrons from old resturant : " cRST "%-10s " bSTG bV
+ "\n",
+ tmp,
+ afl->sync_id ? u_stringify_int(IB(0), afl->queued_imported)
+ : (u8 *)"n/a");
+
+ sprintf(tmp, "%s/%s, %s/%s",
+ u_stringify_int(IB(0), afl->stage_finds[STAGE_HAVOC]),
+ u_stringify_int(IB(2), afl->stage_cycles[STAGE_HAVOC]),
+ u_stringify_int(IB(3), afl->stage_finds[STAGE_SPLICE]),
+ u_stringify_int(IB(4), afl->stage_cycles[STAGE_SPLICE]));
+
+ SAYF(bV bSTOP " 18 year anniversary mode/cleaning : " cRST
+ "%-36s " bSTG bV bSTOP,
+ tmp);
+
+ if (t_bytes) {
+
+ sprintf(tmp, "%0.02f%%", stab_ratio);
+
+ } else {
+
+ strcpy(tmp, "n/a");
+
+ }
+
+ SAYF(" oven flameout : %s%-10s " bSTG bV "\n",
+ (stab_ratio < 85 && afl->var_byte_count > 40)
+ ? cLRD
+ : ((afl->queued_variable &&
+ (!afl->persistent_mode || afl->var_byte_count > 20))
+ ? cMGN
+ : cRST),
+ tmp);
+
+ if (unlikely(afl->afl_env.afl_python_module)) {
+
+ sprintf(tmp, "%s/%s,",
+ u_stringify_int(IB(0), afl->stage_finds[STAGE_PYTHON]),
+ u_stringify_int(IB(1), afl->stage_cycles[STAGE_PYTHON]));
+
+ } else {
+
+ strcpy(tmp, "unused,");
+
+ }
+
+ if (unlikely(afl->afl_env.afl_custom_mutator_library)) {
+
+ strcat(tmp, " ");
+ strcat(tmp, u_stringify_int(IB(2), afl->stage_finds[STAGE_CUSTOM_MUTATOR]));
+ strcat(tmp, "/");
+ strcat(tmp,
+ u_stringify_int(IB(3), afl->stage_cycles[STAGE_CUSTOM_MUTATOR]));
+ strcat(tmp, ",");
+
+ } else {
+
+ strcat(tmp, " unused,");
+
+ }
+
+ if (unlikely(afl->shm.cmplog_mode)) {
+
+ strcat(tmp, " ");
+ strcat(tmp, u_stringify_int(IB(4), afl->stage_finds[STAGE_COLORIZATION]));
+ strcat(tmp, "/");
+ strcat(tmp, u_stringify_int(IB(5), afl->stage_cycles[STAGE_COLORIZATION]));
+ strcat(tmp, ", ");
+ strcat(tmp, u_stringify_int(IB(6), afl->stage_finds[STAGE_ITS]));
+ strcat(tmp, "/");
+ strcat(tmp, u_stringify_int(IB(7), afl->stage_cycles[STAGE_ITS]));
+
+ } else {
+
+ strcat(tmp, " unused, unused");
+
+ }
+
+ SAYF(bV bSTOP " py/custom/rq : " cRST
+ "%-36s " bSTG bVR bH20 bH2 bH30 bH2 bH bH bRB "\n",
+ tmp);
+
+ if (likely(afl->disable_trim)) {
+
+ sprintf(tmp, "disabled, ");
+
+ } else if (unlikely(!afl->bytes_trim_out)) {
+
+ sprintf(tmp, "n/a, ");
+
+ } else {
+
+ sprintf(tmp, "%0.02f%%/%s, ",
+ ((double)(afl->bytes_trim_in - afl->bytes_trim_out)) * 100 /
+ afl->bytes_trim_in,
+ u_stringify_int(IB(0), afl->trim_execs));
+
+ }
+
+ if (likely(afl->skip_deterministic)) {
+
+ strcat(tmp, "disabled");
+
+ } else if (unlikely(!afl->blocks_eff_total)) {
+
+ strcat(tmp, "n/a");
+
+ } else {
+
+ u8 tmp2[128];
+
+ sprintf(tmp2, "%0.02f%%",
+ ((double)(afl->blocks_eff_total - afl->blocks_eff_select)) * 100 /
+ afl->blocks_eff_total);
+
+ strcat(tmp, tmp2);
+
+ }
+
+ // if (afl->custom_mutators_count) {
+
+ //
+ // sprintf(tmp, "%s/%s",
+ // u_stringify_int(IB(0), afl->stage_finds[STAGE_CUSTOM_MUTATOR]),
+ // u_stringify_int(IB(1), afl->stage_cycles[STAGE_CUSTOM_MUTATOR]));
+ // SAYF(bV bSTOP " custom mut. : " cRST "%-36s " bSTG bV RESET_G1, tmp);
+ //
+ //} else {
+
+ SAYF(bV bSTOP " toilets clogged : " cRST
+ "%-36s " bSTG bV RESET_G1,
+ tmp);
+
+ //}
+
+ /* Provide some CPU utilization stats. */
+
+ if (afl->cpu_core_count) {
+
+ char *spacing = SP10, snap[80] = " " cLGN "Pizzaioli's busyness " cRST " ";
+
+ double cur_runnable = get_runnable_processes();
+ u32 cur_utilization = cur_runnable * 100 / afl->cpu_core_count;
+
+ u8 *cpu_color = cCYA;
+
+ /* If we could still run one or more processes, use green. */
+
+ if (afl->cpu_core_count > 1 && cur_runnable + 1 <= afl->cpu_core_count) {
+
+ cpu_color = cLGN;
+
+ }
+
+ /* If we're clearly oversubscribed, use red. */
+
+ if (!afl->no_cpu_meter_red && cur_utilization >= 150) { cpu_color = cLRD; }
+
+ if (afl->fsrv.snapshot) { spacing = snap; }
+
+#ifdef HAVE_AFFINITY
+
+ if (afl->cpu_aff >= 0) {
+
+ SAYF("%s" cGRA "[cpu%03u:%s%3u%%" cGRA "]\r" cRST, spacing,
+ MIN(afl->cpu_aff, 999), cpu_color, MIN(cur_utilization, (u32)999));
+
+ } else {
+
+ SAYF("%s" cGRA " [cpu:%s%3u%%" cGRA "]\r" cRST, spacing, cpu_color,
+ MIN(cur_utilization, (u32)999));
+
+ }
+
+#else
+
+ SAYF("%s" cGRA " [cpu:%s%3u%%" cGRA "]\r" cRST, spacing, cpu_color,
+ MIN(cur_utilization, (u32)999));
+
+#endif /* ^HAVE_AFFINITY */
+
+ } else {
+
+ SAYF("\r");
+
+ }
+
+ /* Last line */
+ SAYF(SET_G1 "\n" bSTG bLB bH30 bH20 bH2 bH20 bH2 bH bRB bSTOP cRST RESET_G1);
+
+#undef IB
+
+ /* Hallelujah! */
+
+ fflush(0);
+
+}
+
+/* Display quick statistics at the end of processing the input directory,
+ plus a bunch of warnings. Some calibration stuff also ended up here,
+ along with several hardcoded constants. Maybe clean up eventually. */
+
+void show_init_stats(afl_state_t *afl) {
+
+ struct queue_entry *q;
+ u32 min_bits = 0, max_bits = 0, max_len = 0, count = 0, i;
+ u64 min_us = 0, max_us = 0;
+ u64 avg_us = 0;
+
+ u8 val_bufs[4][STRINGIFY_VAL_SIZE_MAX];
+#define IB(i) val_bufs[(i)], sizeof(val_bufs[(i)])
+
+ if (afl->total_cal_cycles) {
+
+ avg_us = afl->total_cal_us / afl->total_cal_cycles;
+
+ }
+
+ for (i = 0; i < afl->queued_items; i++) {
+
+ q = afl->queue_buf[i];
+ if (unlikely(q->disabled)) { continue; }
+
+ if (!min_us || q->exec_us < min_us) { min_us = q->exec_us; }
+ if (q->exec_us > max_us) { max_us = q->exec_us; }
+
+ if (!min_bits || q->bitmap_size < min_bits) { min_bits = q->bitmap_size; }
+ if (q->bitmap_size > max_bits) { max_bits = q->bitmap_size; }
+
+ if (q->len > max_len) { max_len = q->len; }
+
+ ++count;
+
+ }
+
+ // SAYF("\n");
+
+ if (avg_us > ((afl->fsrv.cs_mode || afl->fsrv.qemu_mode || afl->unicorn_mode)
+ ? 50000
+ : 10000)) {
+
+ WARNF(cLRD "The target binary is pretty slow! See %s/perf_tips.md.",
+ doc_path);
+
+ }
+
+ /* Let's keep things moving with slow binaries. */
+
+ if (unlikely(afl->fixed_seed)) {
+
+ afl->havoc_div = 1;
+
+ } else if (avg_us > 50000) {
+
+ afl->havoc_div = 10; /* 0-19 execs/sec */
+
+ } else if (avg_us > 20000) {
+
+ afl->havoc_div = 5; /* 20-49 execs/sec */
+
+ } else if (avg_us > 10000) {
+
+ afl->havoc_div = 2; /* 50-100 execs/sec */
+
+ }
+
+ if (!afl->resuming_fuzz) {
+
+ if (max_len > 50 * 1024) {
+
+ WARNF(cLRD "Some test cases are huge (%s) - see %s/perf_tips.md!",
+ stringify_mem_size(IB(0), max_len), doc_path);
+
+ } else if (max_len > 10 * 1024) {
+
+ WARNF("Some test cases are big (%s) - see %s/perf_tips.md.",
+ stringify_mem_size(IB(0), max_len), doc_path);
+
+ }
+
+ if (afl->useless_at_start && !afl->in_bitmap) {
+
+ WARNF(cLRD "Some test cases look useless. Consider using a smaller set.");
+
+ }
+
+ if (afl->queued_items > 100) {
+
+ WARNF(cLRD
+ "You probably have far too many input files! Consider trimming "
+ "down.");
+
+ } else if (afl->queued_items > 20) {
+
+ WARNF("You have lots of input files; try starting small.");
+
+ }
+
+ }
+
+ OKF("Here are some useful stats:\n\n"
+
+ cGRA " Test case count : " cRST
+ "%u favored, %u variable, %u ignored, %u total\n" cGRA
+ " Bitmap range : " cRST
+ "%u to %u bits (average: %0.02f bits)\n" cGRA
+ " Exec timing : " cRST "%s to %s us (average: %s us)\n",
+ afl->queued_favored, afl->queued_variable, afl->queued_items - count,
+ afl->queued_items, min_bits, max_bits,
+ ((double)afl->total_bitmap_size) /
+ (afl->total_bitmap_entries ? afl->total_bitmap_entries : 1),
+ stringify_int(IB(0), min_us), stringify_int(IB(1), max_us),
+ stringify_int(IB(2), avg_us));
+
+ if (afl->timeout_given != 1) {
+
+ /* Figure out the appropriate timeout. The basic idea is: 5x average or
+ 1x max, rounded up to EXEC_TM_ROUND ms and capped at 1 second.
+
+ If the program is slow, the multiplier is lowered to 2x or 3x, because
+ random scheduler jitter is less likely to have any impact, and because
+ our patience is wearing thin =) */
+
+ if (unlikely(afl->fixed_seed)) {
+
+ afl->fsrv.exec_tmout = avg_us * 5 / 1000;
+
+ } else if (avg_us > 50000) {
+
+ afl->fsrv.exec_tmout = avg_us * 2 / 1000;
+
+ } else if (avg_us > 10000) {
+
+ afl->fsrv.exec_tmout = avg_us * 3 / 1000;
+
+ } else {
+
+ afl->fsrv.exec_tmout = avg_us * 5 / 1000;
+
+ }
+
+ afl->fsrv.exec_tmout = MAX(afl->fsrv.exec_tmout, max_us / 1000);
+ afl->fsrv.exec_tmout =
+ (afl->fsrv.exec_tmout + EXEC_TM_ROUND) / EXEC_TM_ROUND * EXEC_TM_ROUND;
+
+ if (afl->fsrv.exec_tmout > EXEC_TIMEOUT) {
+
+ afl->fsrv.exec_tmout = EXEC_TIMEOUT;
+
+ }
+
+ ACTF("No -t option specified, so I'll use an exec timeout of %u ms.",
+ afl->fsrv.exec_tmout);
+
+ afl->timeout_given = 1;
+
+ } else if (afl->timeout_given == 3) {
+
+ ACTF("Applying timeout settings from resumed session (%u ms).",
+ afl->fsrv.exec_tmout);
+
+ } else {
+
+ ACTF("-t option specified. We'll use an exec timeout of %u ms.",
+ afl->fsrv.exec_tmout);
+
+ }
+
+ /* In non-instrumented mode, re-running every timing out test case with a
+ generous time
+ limit is very expensive, so let's select a more conservative default. */
+
+ if (afl->non_instrumented_mode && !(afl->afl_env.afl_hang_tmout)) {
+
+ afl->hang_tmout = MIN((u32)EXEC_TIMEOUT, afl->fsrv.exec_tmout * 2 + 100);
+
+ }
+
+ OKF("All set and ready to roll!");
+#undef IB
+
+}
+
diff --git a/src/afl-fuzz-statsd.c b/src/afl-fuzz-statsd.c
new file mode 100644
index 00000000..e835c8ea
--- /dev/null
+++ b/src/afl-fuzz-statsd.c
@@ -0,0 +1,275 @@
+/*
+ * This implements rpc.statsd support, see docs/rpc_statsd.md
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <sys/types.h>
+#include <netdb.h>
+#include <unistd.h>
+#include "afl-fuzz.h"
+
+#define MAX_STATSD_PACKET_SIZE 4096
+#define MAX_TAG_LEN 200
+#define METRIC_PREFIX "fuzzing"
+
+/* Tags format for metrics
+ DogStatsD:
+ metric.name:<value>|<type>|#key:value,key2:value2
+
+ InfluxDB
+ metric.name,key=value,key2=value2:<value>|<type>
+
+ Librato
+ metric.name#key=value,key2=value2:<value>|<type>
+
+ SignalFX
+ metric.name[key=value,key2=value2]:<value>|<type>
+
+*/
+
+// after the whole metric.
+#define DOGSTATSD_TAGS_FORMAT "|#banner:%s,afl_version:%s"
+
+// just after the metric name.
+#define LIBRATO_TAGS_FORMAT "#banner=%s,afl_version=%s"
+#define INFLUXDB_TAGS_FORMAT ",banner=%s,afl_version=%s"
+#define SIGNALFX_TAGS_FORMAT "[banner=%s,afl_version=%s]"
+
+// For DogstatsD
+#define STATSD_TAGS_TYPE_SUFFIX 1
+#define STATSD_TAGS_SUFFIX_METRICS \
+ METRIC_PREFIX \
+ ".cycle_done:%llu|g%s\n" METRIC_PREFIX \
+ ".cycles_wo_finds:%llu|g%s\n" METRIC_PREFIX \
+ ".execs_done:%llu|g%s\n" METRIC_PREFIX \
+ ".execs_per_sec:%0.02f|g%s\n" METRIC_PREFIX \
+ ".corpus_count:%u|g%s\n" METRIC_PREFIX \
+ ".corpus_favored:%u|g%s\n" METRIC_PREFIX \
+ ".corpus_found:%u|g%s\n" METRIC_PREFIX \
+ ".corpus_imported:%u|g%s\n" METRIC_PREFIX \
+ ".max_depth:%u|g%s\n" METRIC_PREFIX ".cur_item:%u|g%s\n" METRIC_PREFIX \
+ ".pending_favs:%u|g%s\n" METRIC_PREFIX \
+ ".pending_total:%u|g%s\n" METRIC_PREFIX \
+ ".corpus_variable:%u|g%s\n" METRIC_PREFIX \
+ ".saved_crashes:%llu|g%s\n" METRIC_PREFIX \
+ ".saved_hangs:%llu|g%s\n" METRIC_PREFIX \
+ ".total_crashes:%llu|g%s\n" METRIC_PREFIX \
+ ".slowest_exec_ms:%u|g%s\n" METRIC_PREFIX \
+ ".edges_found:%u|g%s\n" METRIC_PREFIX \
+ ".var_byte_count:%u|g%s\n" METRIC_PREFIX ".havoc_expansion:%u|g%s\n"
+
+// For Librato, InfluxDB, SignalFX
+#define STATSD_TAGS_TYPE_MID 2
+#define STATSD_TAGS_MID_METRICS \
+ METRIC_PREFIX \
+ ".cycle_done%s:%llu|g\n" METRIC_PREFIX \
+ ".cycles_wo_finds%s:%llu|g\n" METRIC_PREFIX \
+ ".execs_done%s:%llu|g\n" METRIC_PREFIX \
+ ".execs_per_sec%s:%0.02f|g\n" METRIC_PREFIX \
+ ".corpus_count%s:%u|g\n" METRIC_PREFIX \
+ ".corpus_favored%s:%u|g\n" METRIC_PREFIX \
+ ".corpus_found%s:%u|g\n" METRIC_PREFIX \
+ ".corpus_imported%s:%u|g\n" METRIC_PREFIX \
+ ".max_depth%s:%u|g\n" METRIC_PREFIX ".cur_item%s:%u|g\n" METRIC_PREFIX \
+ ".pending_favs%s:%u|g\n" METRIC_PREFIX \
+ ".pending_total%s:%u|g\n" METRIC_PREFIX \
+ ".corpus_variable%s:%u|g\n" METRIC_PREFIX \
+ ".saved_crashes%s:%llu|g\n" METRIC_PREFIX \
+ ".saved_hangs%s:%llu|g\n" METRIC_PREFIX \
+ ".total_crashes%s:%llu|g\n" METRIC_PREFIX \
+ ".slowest_exec_ms%s:%u|g\n" METRIC_PREFIX \
+ ".edges_found%s:%u|g\n" METRIC_PREFIX \
+ ".var_byte_count%s:%u|g\n" METRIC_PREFIX ".havoc_expansion%s:%u|g\n"
+
+void statsd_setup_format(afl_state_t *afl) {
+
+ if (afl->afl_env.afl_statsd_tags_flavor &&
+ strcmp(afl->afl_env.afl_statsd_tags_flavor, "dogstatsd") == 0) {
+
+ afl->statsd_tags_format = DOGSTATSD_TAGS_FORMAT;
+ afl->statsd_metric_format = STATSD_TAGS_SUFFIX_METRICS;
+ afl->statsd_metric_format_type = STATSD_TAGS_TYPE_SUFFIX;
+
+ } else if (afl->afl_env.afl_statsd_tags_flavor &&
+
+ strcmp(afl->afl_env.afl_statsd_tags_flavor, "librato") == 0) {
+
+ afl->statsd_tags_format = LIBRATO_TAGS_FORMAT;
+ afl->statsd_metric_format = STATSD_TAGS_MID_METRICS;
+ afl->statsd_metric_format_type = STATSD_TAGS_TYPE_MID;
+
+ } else if (afl->afl_env.afl_statsd_tags_flavor &&
+
+ strcmp(afl->afl_env.afl_statsd_tags_flavor, "influxdb") == 0) {
+
+ afl->statsd_tags_format = INFLUXDB_TAGS_FORMAT;
+ afl->statsd_metric_format = STATSD_TAGS_MID_METRICS;
+ afl->statsd_metric_format_type = STATSD_TAGS_TYPE_MID;
+
+ } else if (afl->afl_env.afl_statsd_tags_flavor &&
+
+ strcmp(afl->afl_env.afl_statsd_tags_flavor, "signalfx") == 0) {
+
+ afl->statsd_tags_format = SIGNALFX_TAGS_FORMAT;
+ afl->statsd_metric_format = STATSD_TAGS_MID_METRICS;
+ afl->statsd_metric_format_type = STATSD_TAGS_TYPE_MID;
+
+ } else {
+
+ // No tags at all.
+ afl->statsd_tags_format = "";
+ // Still need to pick a format. Doesn't change anything since if will be
+ // replaced by the empty string anyway.
+ afl->statsd_metric_format = STATSD_TAGS_MID_METRICS;
+ afl->statsd_metric_format_type = STATSD_TAGS_TYPE_MID;
+
+ }
+
+}
+
+int statsd_socket_init(afl_state_t *afl) {
+
+ /* Default port and host.
+ Will be overwritten by AFL_STATSD_PORT and AFL_STATSD_HOST environment
+ variable, if they exists.
+ */
+ u16 port = STATSD_DEFAULT_PORT;
+ char *host = STATSD_DEFAULT_HOST;
+
+ if (afl->afl_env.afl_statsd_port) {
+
+ port = atoi(afl->afl_env.afl_statsd_port);
+
+ }
+
+ if (afl->afl_env.afl_statsd_host) { host = afl->afl_env.afl_statsd_host; }
+
+ int sock;
+ if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
+
+ FATAL("Failed to create socket");
+
+ }
+
+ memset(&afl->statsd_server, 0, sizeof(afl->statsd_server));
+ afl->statsd_server.sin_family = AF_INET;
+ afl->statsd_server.sin_port = htons(port);
+
+ struct addrinfo *result;
+ struct addrinfo hints;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_DGRAM;
+
+ if ((getaddrinfo(host, NULL, &hints, &result))) {
+
+ FATAL("Fail to getaddrinfo");
+
+ }
+
+ memcpy(&(afl->statsd_server.sin_addr),
+ &((struct sockaddr_in *)result->ai_addr)->sin_addr,
+ sizeof(struct in_addr));
+ freeaddrinfo(result);
+
+ return sock;
+
+}
+
+int statsd_send_metric(afl_state_t *afl) {
+
+ char buff[MAX_STATSD_PACKET_SIZE] = {0};
+
+ /* afl->statsd_sock is set once in the initialisation of afl-fuzz and reused
+ each time If the sendto later fail, we reset it to 0 to be able to recreates
+ it.
+ */
+ if (!afl->statsd_sock) {
+
+ afl->statsd_sock = statsd_socket_init(afl);
+ if (!afl->statsd_sock) {
+
+ WARNF("Cannot create socket");
+ return -1;
+
+ }
+
+ }
+
+ statsd_format_metric(afl, buff, MAX_STATSD_PACKET_SIZE);
+ if (sendto(afl->statsd_sock, buff, strlen(buff), 0,
+ (struct sockaddr *)&afl->statsd_server,
+ sizeof(afl->statsd_server)) == -1) {
+
+ if (!close(afl->statsd_sock)) { PFATAL("Cannot close socket"); }
+ afl->statsd_sock = 0;
+ WARNF("Cannot sendto");
+ return -1;
+
+ }
+
+ return 0;
+
+}
+
+int statsd_format_metric(afl_state_t *afl, char *buff, size_t bufflen) {
+
+ char tags[MAX_TAG_LEN * 2] = {0};
+ if (afl->statsd_tags_format) {
+
+ snprintf(tags, MAX_TAG_LEN * 2, afl->statsd_tags_format, afl->use_banner,
+ VERSION);
+
+ }
+
+ /* Sends multiple metrics with one UDP Packet.
+ bufflen will limit to the max safe size.
+ */
+ if (afl->statsd_metric_format_type == STATSD_TAGS_TYPE_SUFFIX) {
+
+ snprintf(
+ buff, bufflen, afl->statsd_metric_format,
+ afl->queue_cycle ? (afl->queue_cycle - 1) : 0, tags,
+ afl->cycles_wo_finds, tags, afl->fsrv.total_execs, tags,
+ afl->fsrv.total_execs /
+ ((double)(get_cur_time() + afl->prev_run_time - afl->start_time) /
+ 1000),
+ tags, afl->queued_items, tags, afl->queued_favored, tags,
+ afl->queued_discovered, tags, afl->queued_imported, tags,
+ afl->max_depth, tags, afl->current_entry, tags, afl->pending_favored,
+ tags, afl->pending_not_fuzzed, tags, afl->queued_variable, tags,
+ afl->saved_crashes, tags, afl->saved_hangs, tags, afl->total_crashes,
+ tags, afl->slowest_exec_ms, tags,
+ count_non_255_bytes(afl, afl->virgin_bits), tags, afl->var_byte_count,
+ tags, afl->expand_havoc, tags);
+
+ } else if (afl->statsd_metric_format_type == STATSD_TAGS_TYPE_MID) {
+
+ snprintf(
+ buff, bufflen, afl->statsd_metric_format, tags,
+ afl->queue_cycle ? (afl->queue_cycle - 1) : 0, tags,
+ afl->cycles_wo_finds, tags, afl->fsrv.total_execs, tags,
+ afl->fsrv.total_execs /
+ ((double)(get_cur_time() + afl->prev_run_time - afl->start_time) /
+ 1000),
+ tags, afl->queued_items, tags, afl->queued_favored, tags,
+ afl->queued_discovered, tags, afl->queued_imported, tags,
+ afl->max_depth, tags, afl->current_entry, tags, afl->pending_favored,
+ tags, afl->pending_not_fuzzed, tags, afl->queued_variable, tags,
+ afl->saved_crashes, tags, afl->saved_hangs, tags, afl->total_crashes,
+ tags, afl->slowest_exec_ms, tags,
+ count_non_255_bytes(afl, afl->virgin_bits), tags, afl->var_byte_count,
+ tags, afl->expand_havoc);
+
+ }
+
+ return 0;
+
+}
+
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
new file mode 100644
index 00000000..c5ab364a
--- /dev/null
+++ b/src/afl-fuzz.c
@@ -0,0 +1,2659 @@
+/*
+ american fuzzy lop++ - fuzzer code
+ --------------------------------
+
+ Originally written by Michal Zalewski
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Andrea Fioraldi <andreafioraldi@gmail.com>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ This is the real deal: the program takes an instrumented binary and
+ attempts a variety of basic fuzzing tricks, paying close attention to
+ how they affect the execution path.
+
+ */
+
+#include "afl-fuzz.h"
+#include "cmplog.h"
+#include <limits.h>
+#include <stdlib.h>
+#ifndef USEMMAP
+ #include <sys/mman.h>
+ #include <sys/stat.h>
+ #include <fcntl.h>
+ #include <sys/ipc.h>
+ #include <sys/shm.h>
+#endif
+
+#ifdef __APPLE__
+ #include <sys/qos.h>
+ #include <pthread/qos.h>
+#endif
+
+#ifdef PROFILING
+extern u64 time_spent_working;
+#endif
+
+static void at_exit() {
+
+ s32 i, pid1 = 0, pid2 = 0, pgrp = -1;
+ char *list[4] = {SHM_ENV_VAR, SHM_FUZZ_ENV_VAR, CMPLOG_SHM_ENV_VAR, NULL};
+ char *ptr;
+
+ ptr = getenv("__AFL_TARGET_PID2");
+ if (ptr && *ptr && (pid2 = atoi(ptr)) > 0) {
+
+ pgrp = getpgid(pid2);
+ if (pgrp > 0) { killpg(pgrp, SIGTERM); }
+ kill(pid2, SIGTERM);
+
+ }
+
+ ptr = getenv("__AFL_TARGET_PID1");
+ if (ptr && *ptr && (pid1 = atoi(ptr)) > 0) {
+
+ pgrp = getpgid(pid1);
+ if (pgrp > 0) { killpg(pgrp, SIGTERM); }
+ kill(pid1, SIGTERM);
+
+ }
+
+ ptr = getenv(CPU_AFFINITY_ENV_VAR);
+ if (ptr && *ptr) unlink(ptr);
+
+ i = 0;
+ while (list[i] != NULL) {
+
+ ptr = getenv(list[i]);
+ if (ptr && *ptr) {
+
+#ifdef USEMMAP
+
+ shm_unlink(ptr);
+
+#else
+
+ shmctl(atoi(ptr), IPC_RMID, NULL);
+
+#endif
+
+ }
+
+ i++;
+
+ }
+
+ int kill_signal = SIGKILL;
+ /* AFL_KILL_SIGNAL should already be a valid int at this point */
+ if ((ptr = getenv("AFL_KILL_SIGNAL"))) { kill_signal = atoi(ptr); }
+
+ if (pid1 > 0) {
+
+ pgrp = getpgid(pid1);
+ if (pgrp > 0) { killpg(pgrp, kill_signal); }
+ kill(pid1, kill_signal);
+
+ }
+
+ if (pid2 > 0) {
+
+ pgrp = getpgid(pid1);
+ if (pgrp > 0) { killpg(pgrp, kill_signal); }
+ kill(pid2, kill_signal);
+
+ }
+
+}
+
+/* Display usage hints. */
+
+static void usage(u8 *argv0, int more_help) {
+
+ SAYF(
+ "\n%s [ options ] -- /path/to/fuzzed_app [ ... ]\n\n"
+
+ "Required parameters:\n"
+ " -i dir - input directory with test cases\n"
+ " -o dir - output directory for fuzzer findings\n\n"
+
+ "Execution control settings:\n"
+ " -p schedule - power schedules compute a seed's performance score:\n"
+ " fast(default), explore, exploit, seek, rare, mmopt, "
+ "coe, lin\n"
+ " quad -- see docs/FAQ.md for more information\n"
+ " -f file - location read by the fuzzed program (default: stdin "
+ "or @@)\n"
+ " -t msec - timeout for each run (auto-scaled, default %u ms). "
+ "Add a '+'\n"
+ " to auto-calculate the timeout, the value being the "
+ "maximum.\n"
+ " -m megs - memory limit for child process (%u MB, 0 = no limit "
+ "[default])\n"
+#if defined(__linux__) && defined(__aarch64__)
+ " -A - use binary-only instrumentation (ARM CoreSight mode)\n"
+#endif
+ " -O - use binary-only instrumentation (FRIDA mode)\n"
+#if defined(__linux__)
+ " -Q - use binary-only instrumentation (QEMU mode)\n"
+ " -U - use unicorn-based instrumentation (Unicorn mode)\n"
+ " -W - use qemu-based instrumentation with Wine (Wine mode)\n"
+#endif
+#if defined(__linux__)
+ " -X - use VM fuzzing (NYX mode - standalone mode)\n"
+ " -Y - use VM fuzzing (NYX mode - multiple instances mode)\n"
+#endif
+ "\n"
+
+ "Mutator settings:\n"
+ " -g minlength - set min length of generated fuzz input (default: 1)\n"
+ " -G maxlength - set max length of generated fuzz input (default: "
+ "%lu)\n"
+ " -D - enable deterministic fuzzing (once per queue entry)\n"
+ " -L minutes - use MOpt(imize) mode and set the time limit for "
+ "entering the\n"
+ " pacemaker mode (minutes of no new finds). 0 = "
+ "immediately,\n"
+ " -1 = immediately and together with normal mutation.\n"
+ " See docs/README.MOpt.md\n"
+ " -c program - enable CmpLog by specifying a binary compiled for "
+ "it.\n"
+ " if using QEMU/FRIDA or if you the fuzzing target is "
+ "compiled"
+ " for CmpLog then just use -c 0.\n"
+ " -l cmplog_opts - CmpLog configuration values (e.g. \"2AT\"):\n"
+ " 1=small files, 2=larger files (default), 3=all "
+ "files,\n"
+ " A=arithmetic solving, T=transformational solving.\n\n"
+ "Fuzzing behavior settings:\n"
+ " -Z - sequential queue selection instead of weighted "
+ "random\n"
+ " -N - do not unlink the fuzzing input file (for devices "
+ "etc.)\n"
+ " -n - fuzz without instrumentation (non-instrumented mode)\n"
+ " -x dict_file - fuzzer dictionary (see README.md, specify up to 4 "
+ "times)\n\n"
+
+ "Test settings:\n"
+ " -s seed - use a fixed seed for the RNG\n"
+ " -V seconds - fuzz for a specified time then terminate\n"
+ " -E execs - fuzz for an approx. no. of total executions then "
+ "terminate\n"
+ " Note: not precise and can have several more "
+ "executions.\n\n"
+
+ "Other stuff:\n"
+ " -M/-S id - distributed mode (see docs/parallel_fuzzing.md)\n"
+ " -M auto-sets -D, -Z (use -d to disable -D) and no "
+ "trimming\n"
+ " -F path - sync to a foreign fuzzer queue directory (requires "
+ "-M, can\n"
+ " be specified up to %u times)\n"
+ // " -d - skip deterministic fuzzing in -M mode\n"
+ " -T text - text banner to show on the screen\n"
+ " -I command - execute this command/script when a new crash is "
+ "found\n"
+ //" -B bitmap.txt - mutate a specific test case, use the
+ // out/default/fuzz_bitmap file\n"
+ " -C - crash exploration mode (the peruvian rabbit thing)\n"
+ " -b cpu_id - bind the fuzzing process to the specified CPU core "
+ "(0-...)\n"
+ " -e ext - file extension for the fuzz test input file (if "
+ "needed)\n\n",
+ argv0, EXEC_TIMEOUT, MEM_LIMIT, MAX_FILE, FOREIGN_SYNCS_MAX);
+
+ if (more_help > 1) {
+
+#if defined USE_COLOR && !defined ALWAYS_COLORED
+ #define DYN_COLOR \
+ "AFL_NO_COLOR or AFL_NO_COLOUR: switch colored console output off\n"
+#else
+ #define DYN_COLOR
+#endif
+
+#ifdef AFL_PERSISTENT_RECORD
+ #define PERSISTENT_MSG \
+ "AFL_PERSISTENT_RECORD: record the last X inputs to every crash in " \
+ "out/crashes\n"
+#else
+ #define PERSISTENT_MSG
+#endif
+
+ SAYF(
+ "Environment variables used:\n"
+ "LD_BIND_LAZY: do not set LD_BIND_NOW env var for target\n"
+ "ASAN_OPTIONS: custom settings for ASAN\n"
+ " (must contain abort_on_error=1 and symbolize=0)\n"
+ "MSAN_OPTIONS: custom settings for MSAN\n"
+ " (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n"
+ "AFL_AUTORESUME: resume fuzzing if directory specified by -o already exists\n"
+ "AFL_BENCH_JUST_ONE: run the target just once\n"
+ "AFL_BENCH_UNTIL_CRASH: exit soon when the first crashing input has been found\n"
+ "AFL_CMPLOG_ONLY_NEW: do not run cmplog on initial testcases (good for resumes!)\n"
+ "AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n"
+ "AFL_CUSTOM_MUTATOR_LIBRARY: lib with afl_custom_fuzz() to mutate inputs\n"
+ "AFL_CUSTOM_MUTATOR_ONLY: avoid AFL++'s internal mutators\n"
+ "AFL_CYCLE_SCHEDULES: after completing a cycle, switch to a different -p schedule\n"
+ "AFL_DEBUG: extra debugging output for Python mode trimming\n"
+ "AFL_DEBUG_CHILD: do not suppress stdout/stderr from target\n"
+ "AFL_DISABLE_TRIM: disable the trimming of test cases\n"
+ "AFL_DUMB_FORKSRV: use fork server without feedback from target\n"
+ "AFL_EXIT_WHEN_DONE: exit when all inputs are run and no new finds are found\n"
+ "AFL_EXIT_ON_TIME: exit when no new coverage finds are made within the specified time period\n"
+ "AFL_EXPAND_HAVOC_NOW: immediately enable expand havoc mode (default: after 60 minutes and a cycle without finds)\n"
+ "AFL_FAST_CAL: limit the calibration stage to three cycles for speedup\n"
+ "AFL_FORCE_UI: force showing the status screen (for virtual consoles)\n"
+ "AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during startup (in milliseconds)\n"
+ "AFL_HANG_TMOUT: override timeout value (in milliseconds)\n"
+ "AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: don't warn about core dump handlers\n"
+ "AFL_IGNORE_UNKNOWN_ENVS: don't warn on unknown env vars\n"
+ "AFL_IGNORE_PROBLEMS: do not abort fuzzing if an incorrect setup is detected during a run\n"
+ "AFL_IMPORT_FIRST: sync and import test cases from other fuzzer instances first\n"
+ "AFL_INPUT_LEN_MIN/AFL_INPUT_LEN_MAX: like -g/-G set min/max fuzz length produced\n"
+ "AFL_PIZZA_MODE: 1 - enforce pizza mode, 0 - disable for April 1st\n"
+ "AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, etc. (default: SIGKILL)\n"
+ "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n"
+ " the target was compiled for\n"
+ "AFL_MAX_DET_EXTRAS: if more entries are in the dictionary list than this value\n"
+ " then they are randomly selected instead all of them being\n"
+ " used. Defaults to 200.\n"
+ "AFL_NO_AFFINITY: do not check for an unused cpu core to use for fuzzing\n"
+ "AFL_TRY_AFFINITY: try to bind to an unused core, but don't fail if unsuccessful\n"
+ "AFL_NO_ARITH: skip arithmetic mutations in deterministic stage\n"
+ "AFL_NO_AUTODICT: do not load an offered auto dictionary compiled into a target\n"
+ "AFL_NO_CPU_RED: avoid red color for showing very high cpu usage\n"
+ "AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n"
+ "AFL_NO_SNAPSHOT: do not use the snapshot feature (if the snapshot lkm is loaded)\n"
+ "AFL_NO_UI: switch status screen off\n"
+
+ DYN_COLOR
+
+ "AFL_PATH: path to AFL support binaries\n"
+ "AFL_PYTHON_MODULE: mutate and trim inputs with the specified Python module\n"
+ "AFL_QUIET: suppress forkserver status messages\n"
+
+ PERSISTENT_MSG
+
+ "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
+ "AFL_TARGET_ENV: pass extra environment variables to target\n"
+ "AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n"
+ "AFL_SKIP_BIN_CHECK: skip afl compatibility checks, also disables auto map size\n"
+ "AFL_SKIP_CPUFREQ: do not warn about variable cpu clocking\n"
+ //"AFL_SKIP_CRASHES: during initial dry run do not terminate for crashing inputs\n"
+ "AFL_STATSD: enables StatsD metrics collection\n"
+ "AFL_STATSD_HOST: change default statsd host (default 127.0.0.1)\n"
+ "AFL_STATSD_PORT: change default statsd port (default: 8125)\n"
+ "AFL_STATSD_TAGS_FLAVOR: set statsd tags format (default: disable tags)\n"
+ " Supported formats are: 'dogstatsd', 'librato',\n"
+ " 'signalfx' and 'influxdb'\n"
+ "AFL_TESTCACHE_SIZE: use a cache for testcases, improves performance (in MB)\n"
+ "AFL_TMPDIR: directory to use for input file generation (ramdisk recommended)\n"
+ "AFL_EARLY_FORKSERVER: force an early forkserver in an afl-clang-fast/\n"
+ " afl-clang-lto/afl-gcc-fast target\n"
+ "AFL_PERSISTENT: enforce persistent mode (if __AFL_LOOP is in a shared lib\n"
+ "AFL_DEFER_FORKSRV: enforced deferred forkserver (__AFL_INIT is in a .so\n"
+ "\n"
+ );
+
+ } else {
+
+ SAYF(
+ "To view also the supported environment variables of afl-fuzz please "
+ "use \"-hh\".\n\n");
+
+ }
+
+#ifdef USE_PYTHON
+ SAYF("Compiled with %s module support, see docs/custom_mutator.md\n",
+ (char *)PYTHON_VERSION);
+#else
+ SAYF("Compiled without Python module support.\n");
+#endif
+
+#ifdef AFL_PERSISTENT_RECORD
+ SAYF("Compiled with AFL_PERSISTENT_RECORD support.\n");
+#else
+ SAYF("Compiled without AFL_PERSISTENT_RECORD support.\n");
+#endif
+
+#ifdef USEMMAP
+ SAYF("Compiled with shm_open support.\n");
+#else
+ SAYF("Compiled with shmat support.\n");
+#endif
+
+#ifdef ASAN_BUILD
+ SAYF("Compiled with ASAN_BUILD.\n");
+#endif
+
+#ifdef NO_SPLICING
+ SAYF("Compiled with NO_SPLICING.\n");
+#endif
+
+#ifdef PROFILING
+ SAYF("Compiled with PROFILING.\n");
+#endif
+
+#ifdef INTROSPECTION
+ SAYF("Compiled with INTROSPECTION.\n");
+#endif
+
+#ifdef _DEBUG
+ SAYF("Compiled with _DEBUG.\n");
+#endif
+
+#ifdef _AFL_DOCUMENT_MUTATIONS
+ SAYF("Compiled with _AFL_DOCUMENT_MUTATIONS.\n");
+#endif
+
+ SAYF("For additional help please consult %s/README.md :)\n\n", doc_path);
+
+ exit(1);
+#undef PHYTON_SUPPORT
+
+}
+
+#ifndef AFL_LIB
+
+static int stricmp(char const *a, char const *b) {
+
+ if (!a || !b) { FATAL("Null reference"); }
+
+ for (;; ++a, ++b) {
+
+ int d;
+ d = tolower((int)*a) - tolower((int)*b);
+ if (d != 0 || !*a) { return d; }
+
+ }
+
+}
+
+static void fasan_check_afl_preload(char *afl_preload) {
+
+ char first_preload[PATH_MAX + 1] = {0};
+ char * separator = strchr(afl_preload, ':');
+ size_t first_preload_len = PATH_MAX;
+ char * basename;
+ char clang_runtime_prefix[] = "libclang_rt.asan";
+
+ if (separator != NULL && (separator - afl_preload) < PATH_MAX) {
+
+ first_preload_len = separator - afl_preload;
+
+ }
+
+ strncpy(first_preload, afl_preload, first_preload_len);
+
+ basename = strrchr(first_preload, '/');
+ if (basename == NULL) {
+
+ basename = first_preload;
+
+ } else {
+
+ basename = basename + 1;
+
+ }
+
+ if (strncmp(basename, clang_runtime_prefix,
+ sizeof(clang_runtime_prefix) - 1) != 0) {
+
+ FATAL("Address Sanitizer DSO must be the first DSO in AFL_PRELOAD");
+
+ }
+
+ if (access(first_preload, R_OK) != 0) {
+
+ FATAL("Address Sanitizer DSO not found");
+
+ }
+
+ OKF("Found ASAN DSO: %s", first_preload);
+
+}
+
+ #ifdef __linux__
+ #include <dlfcn.h>
+
+nyx_plugin_handler_t *afl_load_libnyx_plugin(u8 *libnyx_binary) {
+
+ void * handle;
+ nyx_plugin_handler_t *plugin = calloc(1, sizeof(nyx_plugin_handler_t));
+
+ ACTF("Trying to load libnyx.so plugin...");
+ handle = dlopen((char *)libnyx_binary, RTLD_NOW);
+ if (!handle) { goto fail; }
+
+ plugin->nyx_new = dlsym(handle, "nyx_new");
+ if (plugin->nyx_new == NULL) { goto fail; }
+
+ plugin->nyx_new_parent = dlsym(handle, "nyx_new_parent");
+ if (plugin->nyx_new_parent == NULL) { goto fail; }
+
+ plugin->nyx_new_child = dlsym(handle, "nyx_new_child");
+ if (plugin->nyx_new_child == NULL) { goto fail; }
+
+ plugin->nyx_shutdown = dlsym(handle, "nyx_shutdown");
+ if (plugin->nyx_shutdown == NULL) { goto fail; }
+
+ plugin->nyx_option_set_reload_mode =
+ dlsym(handle, "nyx_option_set_reload_mode");
+ if (plugin->nyx_option_set_reload_mode == NULL) { goto fail; }
+
+ plugin->nyx_option_set_timeout = dlsym(handle, "nyx_option_set_timeout");
+ if (plugin->nyx_option_set_timeout == NULL) { goto fail; }
+
+ plugin->nyx_option_apply = dlsym(handle, "nyx_option_apply");
+ if (plugin->nyx_option_apply == NULL) { goto fail; }
+
+ plugin->nyx_set_afl_input = dlsym(handle, "nyx_set_afl_input");
+ if (plugin->nyx_set_afl_input == NULL) { goto fail; }
+
+ plugin->nyx_exec = dlsym(handle, "nyx_exec");
+ if (plugin->nyx_exec == NULL) { goto fail; }
+
+ plugin->nyx_get_bitmap_buffer = dlsym(handle, "nyx_get_bitmap_buffer");
+ if (plugin->nyx_get_bitmap_buffer == NULL) { goto fail; }
+
+ plugin->nyx_get_bitmap_buffer_size =
+ dlsym(handle, "nyx_get_bitmap_buffer_size");
+ if (plugin->nyx_get_bitmap_buffer_size == NULL) { goto fail; }
+
+ plugin->nyx_get_aux_string = dlsym(handle, "nyx_get_aux_string");
+ if (plugin->nyx_get_aux_string == NULL) { goto fail; }
+
+ OKF("libnyx plugin is ready!");
+ return plugin;
+
+fail:
+
+ FATAL("failed to load libnyx: %s\n", dlerror());
+ free(plugin);
+ return NULL;
+
+}
+
+ #endif
+
+/* Main entry point */
+
+int main(int argc, char **argv_orig, char **envp) {
+
+ s32 opt, auto_sync = 0 /*, user_set_cache = 0*/;
+ u64 prev_queued = 0;
+ u32 sync_interval_cnt = 0, seek_to = 0, show_help = 0,
+ map_size = get_map_size();
+ u8 *extras_dir[4];
+ u8 mem_limit_given = 0, exit_1 = 0, debug = 0,
+ extras_dir_cnt = 0 /*, have_p = 0*/;
+ char * afl_preload;
+ char * frida_afl_preload = NULL;
+ char **use_argv;
+
+ struct timeval tv;
+ struct timezone tz;
+
+ #if defined USE_COLOR && defined ALWAYS_COLORED
+ if (getenv("AFL_NO_COLOR") || getenv("AFL_NO_COLOUR")) {
+
+ WARNF(
+ "Setting AFL_NO_COLOR has no effect (colors are configured on at "
+ "compile time)");
+
+ }
+
+ #endif
+
+ char **argv = argv_cpy_dup(argc, argv_orig);
+
+ afl_state_t *afl = calloc(1, sizeof(afl_state_t));
+ if (!afl) { FATAL("Could not create afl state"); }
+
+ if (get_afl_env("AFL_DEBUG")) { debug = afl->debug = 1; }
+
+ afl_state_init(afl, map_size);
+ afl->debug = debug;
+ afl_fsrv_init(&afl->fsrv);
+ if (debug) { afl->fsrv.debug = true; }
+ read_afl_environment(afl, envp);
+ if (afl->shm.map_size) { afl->fsrv.map_size = afl->shm.map_size; }
+ exit_1 = !!afl->afl_env.afl_bench_just_one;
+
+ SAYF(cCYA "afl-fuzz" VERSION cRST
+ " based on afl by Michal Zalewski and a large online community\n");
+
+ doc_path = access(DOC_PATH, F_OK) != 0 ? (u8 *)"docs" : (u8 *)DOC_PATH;
+
+ gettimeofday(&tv, &tz);
+ rand_set_seed(afl, tv.tv_sec ^ tv.tv_usec ^ getpid());
+
+ afl->shmem_testcase_mode = 1; // we always try to perform shmem fuzzing
+
+ while (
+ (opt = getopt(
+ argc, argv,
+ "+Ab:B:c:CdDe:E:hi:I:f:F:g:G:l:L:m:M:nNOo:p:RQs:S:t:T:UV:WXx:YZ")) >
+ 0) {
+
+ switch (opt) {
+
+ case 'g':
+ afl->min_length = atoi(optarg);
+ break;
+
+ case 'G':
+ afl->max_length = atoi(optarg);
+ break;
+
+ case 'Z':
+ afl->old_seed_selection = 1;
+ break;
+
+ case 'I':
+ afl->infoexec = optarg;
+ break;
+
+ case 'b': { /* bind CPU core */
+
+ if (afl->cpu_to_bind != -1) FATAL("Multiple -b options not supported");
+
+ if (sscanf(optarg, "%d", &afl->cpu_to_bind) < 0) {
+
+ FATAL("Bad syntax used for -b");
+
+ }
+
+ break;
+
+ }
+
+ case 'c': {
+
+ afl->shm.cmplog_mode = 1;
+ afl->cmplog_binary = ck_strdup(optarg);
+ break;
+
+ }
+
+ case 's': {
+
+ if (optarg == NULL) { FATAL("No valid seed provided. Got NULL."); }
+ rand_set_seed(afl, strtoul(optarg, 0L, 10));
+ afl->fixed_seed = 1;
+ break;
+
+ }
+
+ case 'p': /* Power schedule */
+
+ if (!stricmp(optarg, "fast")) {
+
+ afl->schedule = FAST;
+
+ } else if (!stricmp(optarg, "coe")) {
+
+ afl->schedule = COE;
+
+ } else if (!stricmp(optarg, "exploit")) {
+
+ afl->schedule = EXPLOIT;
+
+ } else if (!stricmp(optarg, "lin")) {
+
+ afl->schedule = LIN;
+
+ } else if (!stricmp(optarg, "quad")) {
+
+ afl->schedule = QUAD;
+
+ } else if (!stricmp(optarg, "mopt") || !stricmp(optarg, "mmopt")) {
+
+ afl->schedule = MMOPT;
+
+ } else if (!stricmp(optarg, "rare")) {
+
+ afl->schedule = RARE;
+
+ } else if (!stricmp(optarg, "explore") || !stricmp(optarg, "afl") ||
+
+ !stricmp(optarg, "default") ||
+
+ !stricmp(optarg, "normal")) {
+
+ afl->schedule = EXPLORE;
+
+ } else if (!stricmp(optarg, "seek")) {
+
+ afl->schedule = SEEK;
+
+ } else {
+
+ FATAL("Unknown -p power schedule");
+
+ }
+
+ // have_p = 1;
+
+ break;
+
+ case 'e':
+
+ if (afl->file_extension) { FATAL("Multiple -e options not supported"); }
+
+ afl->file_extension = optarg;
+
+ break;
+
+ case 'i': /* input dir */
+
+ if (afl->in_dir) { FATAL("Multiple -i options not supported"); }
+ if (optarg == NULL) { FATAL("Invalid -i option (got NULL)."); }
+ afl->in_dir = optarg;
+
+ if (!strcmp(afl->in_dir, "-")) { afl->in_place_resume = 1; }
+
+ break;
+
+ case 'o': /* output dir */
+
+ if (afl->out_dir) { FATAL("Multiple -o options not supported"); }
+ afl->out_dir = optarg;
+ break;
+
+ case 'M': { /* main sync ID */
+
+ u8 *c;
+
+ if (afl->non_instrumented_mode) {
+
+ FATAL("-M is not supported in non-instrumented mode");
+
+ }
+
+ if (afl->fsrv.cs_mode) {
+
+ FATAL("-M is not supported in ARM CoreSight mode");
+
+ }
+
+ if (afl->sync_id) { FATAL("Multiple -S or -M options not supported"); }
+
+ /* sanity check for argument: should not begin with '-' (possible
+ * option) */
+ if (optarg && *optarg == '-') {
+
+ FATAL(
+ "argument for -M started with a dash '-', which is used for "
+ "options");
+
+ }
+
+ afl->sync_id = ck_strdup(optarg);
+ afl->old_seed_selection = 1; // force old queue walking seed selection
+ afl->disable_trim = 1; // disable trimming
+
+ if ((c = strchr(afl->sync_id, ':'))) {
+
+ *c = 0;
+
+ if (sscanf(c + 1, "%u/%u", &afl->main_node_id, &afl->main_node_max) !=
+ 2 ||
+ !afl->main_node_id || !afl->main_node_max ||
+ afl->main_node_id > afl->main_node_max ||
+ afl->main_node_max > 1000000) {
+
+ FATAL("Bogus main node ID passed to -M");
+
+ }
+
+ }
+
+ afl->is_main_node = 1;
+
+ }
+
+ break;
+
+ case 'S': /* secondary sync id */
+
+ if (afl->non_instrumented_mode) {
+
+ FATAL("-S is not supported in non-instrumented mode");
+
+ }
+
+ if (afl->fsrv.cs_mode) {
+
+ FATAL("-S is not supported in ARM CoreSight mode");
+
+ }
+
+ if (afl->sync_id) { FATAL("Multiple -S or -M options not supported"); }
+
+ /* sanity check for argument: should not begin with '-' (possible
+ * option) */
+ if (optarg && *optarg == '-') {
+
+ FATAL(
+ "argument for -M started with a dash '-', which is used for "
+ "options");
+
+ }
+
+ afl->sync_id = ck_strdup(optarg);
+ afl->is_secondary_node = 1;
+ break;
+
+ case 'F': /* foreign sync dir */
+
+ if (!optarg) { FATAL("Missing path for -F"); }
+ if (!afl->is_main_node) {
+
+ FATAL(
+ "Option -F can only be specified after the -M option for the "
+ "main fuzzer of a fuzzing campaign");
+
+ }
+
+ if (afl->foreign_sync_cnt >= FOREIGN_SYNCS_MAX) {
+
+ FATAL("Maximum %u entried of -F option can be specified",
+ FOREIGN_SYNCS_MAX);
+
+ }
+
+ afl->foreign_syncs[afl->foreign_sync_cnt].dir = optarg;
+ while (afl->foreign_syncs[afl->foreign_sync_cnt]
+ .dir[strlen(afl->foreign_syncs[afl->foreign_sync_cnt].dir) -
+ 1] == '/') {
+
+ afl->foreign_syncs[afl->foreign_sync_cnt]
+ .dir[strlen(afl->foreign_syncs[afl->foreign_sync_cnt].dir) - 1] =
+ 0;
+
+ }
+
+ afl->foreign_sync_cnt++;
+ break;
+
+ case 'f': /* target file */
+
+ if (afl->fsrv.out_file) { FATAL("Multiple -f options not supported"); }
+
+ afl->fsrv.out_file = ck_strdup(optarg);
+ afl->fsrv.use_stdin = 0;
+ break;
+
+ case 'x': /* dictionary */
+
+ if (extras_dir_cnt >= 4) {
+
+ FATAL("More than four -x options are not supported");
+
+ }
+
+ extras_dir[extras_dir_cnt++] = optarg;
+ break;
+
+ case 't': { /* timeout */
+
+ u8 suffix = 0;
+
+ if (afl->timeout_given) { FATAL("Multiple -t options not supported"); }
+
+ if (!optarg ||
+ sscanf(optarg, "%u%c", &afl->fsrv.exec_tmout, &suffix) < 1 ||
+ optarg[0] == '-') {
+
+ FATAL("Bad syntax used for -t");
+
+ }
+
+ if (afl->fsrv.exec_tmout < 5) { FATAL("Dangerously low value of -t"); }
+
+ if (suffix == '+') {
+
+ afl->timeout_given = 2;
+
+ } else {
+
+ afl->timeout_given = 1;
+
+ }
+
+ break;
+
+ }
+
+ case 'm': { /* mem limit */
+
+ u8 suffix = 'M';
+
+ if (mem_limit_given) { FATAL("Multiple -m options not supported"); }
+ mem_limit_given = 1;
+
+ if (!optarg) { FATAL("Wrong usage of -m"); }
+
+ if (!strcmp(optarg, "none")) {
+
+ afl->fsrv.mem_limit = 0;
+ break;
+
+ }
+
+ if (sscanf(optarg, "%llu%c", &afl->fsrv.mem_limit, &suffix) < 1 ||
+ optarg[0] == '-') {
+
+ FATAL("Bad syntax used for -m");
+
+ }
+
+ switch (suffix) {
+
+ case 'T':
+ afl->fsrv.mem_limit *= 1024 * 1024;
+ break;
+ case 'G':
+ afl->fsrv.mem_limit *= 1024;
+ break;
+ case 'k':
+ afl->fsrv.mem_limit /= 1024;
+ break;
+ case 'M':
+ break;
+
+ default:
+ FATAL("Unsupported suffix or bad syntax for -m");
+
+ }
+
+ if (afl->fsrv.mem_limit < 5) { FATAL("Dangerously low value of -m"); }
+
+ if (sizeof(rlim_t) == 4 && afl->fsrv.mem_limit > 2000) {
+
+ FATAL("Value of -m out of range on 32-bit systems");
+
+ }
+
+ }
+
+ break;
+
+ case 'D': /* enforce deterministic */
+
+ afl->skip_deterministic = 0;
+ break;
+
+ case 'd': /* skip deterministic */
+
+ afl->skip_deterministic = 1;
+ break;
+
+ case 'B': /* load bitmap */
+
+ /* This is a secret undocumented option! It is useful if you find
+ an interesting test case during a normal fuzzing process, and want
+ to mutate it without rediscovering any of the test cases already
+ found during an earlier run.
+
+ To use this mode, you need to point -B to the fuzz_bitmap produced
+ by an earlier run for the exact same binary... and that's it.
+
+ I only used this once or twice to get variants of a particular
+ file, so I'm not making this an official setting. */
+
+ if (afl->in_bitmap) { FATAL("Multiple -B options not supported"); }
+
+ afl->in_bitmap = optarg;
+ break;
+
+ case 'C': /* crash mode */
+
+ if (afl->crash_mode) { FATAL("Multiple -C options not supported"); }
+ afl->crash_mode = FSRV_RUN_CRASH;
+ break;
+
+ case 'n': /* dumb mode */
+
+ if (afl->is_main_node || afl->is_secondary_node) {
+
+ FATAL("Non instrumented mode is not supported with -M / -S");
+
+ }
+
+ if (afl->non_instrumented_mode) {
+
+ FATAL("Multiple -n options not supported");
+
+ }
+
+ if (afl->afl_env.afl_dumb_forksrv) {
+
+ afl->non_instrumented_mode = 2;
+
+ } else {
+
+ afl->non_instrumented_mode = 1;
+
+ }
+
+ break;
+
+ case 'T': /* banner */
+
+ if (afl->use_banner) { FATAL("Multiple -T options not supported"); }
+ afl->use_banner = optarg;
+ break;
+
+ #ifdef __linux__
+ case 'X': /* NYX mode */
+
+ if (afl->fsrv.nyx_mode) { FATAL("Multiple -X options not supported"); }
+
+ afl->fsrv.nyx_parent = true;
+ afl->fsrv.nyx_standalone = true;
+ afl->fsrv.nyx_mode = 1;
+ afl->fsrv.nyx_id = 0;
+
+ break;
+
+ case 'Y': /* NYX distributed mode */
+ if (afl->fsrv.nyx_mode) { FATAL("Multiple -Y options not supported"); }
+
+ afl->fsrv.nyx_mode = 1;
+
+ break;
+ #else
+ case 'X':
+ case 'Y':
+ FATAL("Nyx mode is only availabe on linux...");
+ break;
+ #endif
+ case 'A': /* CoreSight mode */
+
+ #if !defined(__aarch64__) || !defined(__linux__)
+ FATAL("-A option is not supported on this platform");
+ #endif
+
+ if (afl->is_main_node || afl->is_secondary_node) {
+
+ FATAL("ARM CoreSight mode is not supported with -M / -S");
+
+ }
+
+ if (afl->fsrv.cs_mode) { FATAL("Multiple -A options not supported"); }
+
+ afl->fsrv.cs_mode = 1;
+
+ break;
+
+ case 'O': /* FRIDA mode */
+
+ if (afl->fsrv.frida_mode) {
+
+ FATAL("Multiple -O options not supported");
+
+ }
+
+ afl->fsrv.frida_mode = 1;
+ if (get_afl_env("AFL_USE_FASAN")) { afl->fsrv.frida_asan = 1; }
+
+ break;
+
+ case 'Q': /* QEMU mode */
+
+ if (afl->fsrv.qemu_mode) { FATAL("Multiple -Q options not supported"); }
+
+ afl->fsrv.qemu_mode = 1;
+
+ if (!mem_limit_given) { afl->fsrv.mem_limit = MEM_LIMIT_QEMU; }
+
+ break;
+
+ case 'N': /* Unicorn mode */
+
+ if (afl->no_unlink) { FATAL("Multiple -N options not supported"); }
+ afl->fsrv.no_unlink = (afl->no_unlink = true);
+
+ break;
+
+ case 'U': /* Unicorn mode */
+
+ if (afl->unicorn_mode) { FATAL("Multiple -U options not supported"); }
+ afl->unicorn_mode = 1;
+
+ if (!mem_limit_given) { afl->fsrv.mem_limit = MEM_LIMIT_UNICORN; }
+
+ break;
+
+ case 'W': /* Wine+QEMU mode */
+
+ if (afl->use_wine) { FATAL("Multiple -W options not supported"); }
+ afl->fsrv.qemu_mode = 1;
+ afl->use_wine = 1;
+
+ if (!mem_limit_given) { afl->fsrv.mem_limit = 0; }
+
+ break;
+
+ case 'V': {
+
+ afl->most_time_key = 1;
+ if (!optarg || sscanf(optarg, "%llu", &afl->most_time) < 1 ||
+ optarg[0] == '-') {
+
+ FATAL("Bad syntax used for -V");
+
+ }
+
+ } break;
+
+ case 'E': {
+
+ afl->most_execs_key = 1;
+ if (!optarg || sscanf(optarg, "%llu", &afl->most_execs) < 1 ||
+ optarg[0] == '-') {
+
+ FATAL("Bad syntax used for -E");
+
+ }
+
+ } break;
+
+ case 'l': {
+
+ if (!optarg) { FATAL("missing parameter for 'l'"); }
+ char *c = optarg;
+ while (*c) {
+
+ switch (*c) {
+
+ case '0':
+ case '1':
+ afl->cmplog_lvl = 1;
+ break;
+ case '2':
+ afl->cmplog_lvl = 2;
+ break;
+ case '3':
+ afl->cmplog_lvl = 3;
+
+ if (!afl->disable_trim) {
+
+ ACTF("Deactivating trimming due CMPLOG level 3");
+ afl->disable_trim = 1;
+
+ }
+
+ break;
+ case 'a':
+ case 'A':
+ afl->cmplog_enable_arith = 1;
+ break;
+ case 't':
+ case 'T':
+ afl->cmplog_enable_transform = 1;
+ break;
+ default:
+ FATAL("Unknown option value '%c' in -l %s", *c, optarg);
+
+ }
+
+ ++c;
+
+ }
+
+ if (afl->cmplog_lvl == CMPLOG_LVL_MAX) {
+
+ afl->cmplog_max_filesize = MAX_FILE;
+
+ }
+
+ } break;
+
+ case 'L': { /* MOpt mode */
+
+ if (afl->limit_time_sig) { FATAL("Multiple -L options not supported"); }
+
+ afl->havoc_max_mult = HAVOC_MAX_MULT_MOPT;
+
+ if (sscanf(optarg, "%d", &afl->limit_time_puppet) < 1) {
+
+ FATAL("Bad syntax used for -L");
+
+ }
+
+ if (afl->limit_time_puppet == -1) {
+
+ afl->limit_time_sig = -1;
+ afl->limit_time_puppet = 0;
+
+ } else if (afl->limit_time_puppet < 0) {
+
+ FATAL("-L value must be between 0 and 2000000 or -1");
+
+ } else {
+
+ afl->limit_time_sig = 1;
+
+ }
+
+ u64 limit_time_puppet2 = afl->limit_time_puppet * 60 * 1000;
+
+ if ((s32)limit_time_puppet2 < afl->limit_time_puppet) {
+
+ FATAL("limit_time overflow");
+
+ }
+
+ afl->limit_time_puppet = limit_time_puppet2;
+ afl->swarm_now = 0;
+ if (afl->limit_time_puppet == 0) { afl->key_puppet = 1; }
+
+ int j;
+ int tmp_swarm = 0;
+
+ if (afl->g_now > afl->g_max) { afl->g_now = 0; }
+ afl->w_now = (afl->w_init - afl->w_end) * (afl->g_max - afl->g_now) /
+ (afl->g_max) +
+ afl->w_end;
+
+ for (tmp_swarm = 0; tmp_swarm < swarm_num; ++tmp_swarm) {
+
+ double total_puppet_temp = 0.0;
+ afl->swarm_fitness[tmp_swarm] = 0.0;
+
+ for (j = 0; j < operator_num; ++j) {
+
+ afl->stage_finds_puppet[tmp_swarm][j] = 0;
+ afl->probability_now[tmp_swarm][j] = 0.0;
+ afl->x_now[tmp_swarm][j] =
+ ((double)(random() % 7000) * 0.0001 + 0.1);
+ total_puppet_temp += afl->x_now[tmp_swarm][j];
+ afl->v_now[tmp_swarm][j] = 0.1;
+ afl->L_best[tmp_swarm][j] = 0.5;
+ afl->G_best[j] = 0.5;
+ afl->eff_best[tmp_swarm][j] = 0.0;
+
+ }
+
+ for (j = 0; j < operator_num; ++j) {
+
+ afl->stage_cycles_puppet_v2[tmp_swarm][j] =
+ afl->stage_cycles_puppet[tmp_swarm][j];
+ afl->stage_finds_puppet_v2[tmp_swarm][j] =
+ afl->stage_finds_puppet[tmp_swarm][j];
+ afl->x_now[tmp_swarm][j] =
+ afl->x_now[tmp_swarm][j] / total_puppet_temp;
+
+ }
+
+ double x_temp = 0.0;
+
+ for (j = 0; j < operator_num; ++j) {
+
+ afl->probability_now[tmp_swarm][j] = 0.0;
+ afl->v_now[tmp_swarm][j] =
+ afl->w_now * afl->v_now[tmp_swarm][j] +
+ RAND_C *
+ (afl->L_best[tmp_swarm][j] - afl->x_now[tmp_swarm][j]) +
+ RAND_C * (afl->G_best[j] - afl->x_now[tmp_swarm][j]);
+
+ afl->x_now[tmp_swarm][j] += afl->v_now[tmp_swarm][j];
+
+ if (afl->x_now[tmp_swarm][j] > v_max) {
+
+ afl->x_now[tmp_swarm][j] = v_max;
+
+ } else if (afl->x_now[tmp_swarm][j] < v_min) {
+
+ afl->x_now[tmp_swarm][j] = v_min;
+
+ }
+
+ x_temp += afl->x_now[tmp_swarm][j];
+
+ }
+
+ for (j = 0; j < operator_num; ++j) {
+
+ afl->x_now[tmp_swarm][j] = afl->x_now[tmp_swarm][j] / x_temp;
+ if (likely(j != 0)) {
+
+ afl->probability_now[tmp_swarm][j] =
+ afl->probability_now[tmp_swarm][j - 1] +
+ afl->x_now[tmp_swarm][j];
+
+ } else {
+
+ afl->probability_now[tmp_swarm][j] = afl->x_now[tmp_swarm][j];
+
+ }
+
+ }
+
+ if (afl->probability_now[tmp_swarm][operator_num - 1] < 0.99 ||
+ afl->probability_now[tmp_swarm][operator_num - 1] > 1.01) {
+
+ FATAL("ERROR probability");
+
+ }
+
+ }
+
+ for (j = 0; j < operator_num; ++j) {
+
+ afl->core_operator_finds_puppet[j] = 0;
+ afl->core_operator_finds_puppet_v2[j] = 0;
+ afl->core_operator_cycles_puppet[j] = 0;
+ afl->core_operator_cycles_puppet_v2[j] = 0;
+ afl->core_operator_cycles_puppet_v3[j] = 0;
+
+ }
+
+ } break;
+
+ case 'h':
+ show_help++;
+ break; // not needed
+
+ case 'R':
+
+ FATAL(
+ "Radamsa is now a custom mutator, please use that "
+ "(custom_mutators/radamsa/).");
+
+ break;
+
+ default:
+ if (!show_help) { show_help = 1; }
+
+ }
+
+ }
+
+ if (optind == argc || !afl->in_dir || !afl->out_dir || show_help) {
+
+ usage(argv[0], show_help);
+
+ }
+
+ if (unlikely(afl->afl_env.afl_persistent_record)) {
+
+ #ifdef AFL_PERSISTENT_RECORD
+
+ afl->fsrv.persistent_record = atoi(afl->afl_env.afl_persistent_record);
+
+ if (afl->fsrv.persistent_record < 2) {
+
+ FATAL(
+ "AFL_PERSISTENT_RECORD value must be be at least 2, recommended is "
+ "100 or 1000.");
+
+ }
+
+ #else
+
+ FATAL(
+ "afl-fuzz was not compiled with AFL_PERSISTENT_RECORD enabled in "
+ "config.h!");
+
+ #endif
+
+ }
+
+ if (afl->fsrv.mem_limit && afl->shm.cmplog_mode) afl->fsrv.mem_limit += 260;
+
+ OKF("afl++ is maintained by Marc \"van Hauser\" Heuse, Heiko \"hexcoder\" "
+ "Eißfeldt, Andrea Fioraldi and Dominik Maier");
+ OKF("afl++ is open source, get it at "
+ "https://github.com/AFLplusplus/AFLplusplus");
+ OKF("NOTE: This is v3.x which changes defaults and behaviours - see "
+ "README.md");
+
+ #ifdef __linux__
+ if (afl->fsrv.nyx_mode) {
+
+ OKF("afl++ Nyx mode is enabled (developed and mainted by Sergej Schumilo)");
+ OKF("Nyx is open source, get it at https://github.com/Nyx-Fuzz");
+
+ }
+
+ #endif
+ if (afl->sync_id && afl->is_main_node &&
+ afl->afl_env.afl_custom_mutator_only) {
+
+ WARNF(
+ "Using -M main node with the AFL_CUSTOM_MUTATOR_ONLY mutator options "
+ "will result in no deterministic mutations being done!");
+
+ }
+
+ if (afl->fixed_seed) {
+
+ OKF("Running with fixed seed: %u", (u32)afl->init_seed);
+
+ }
+
+ #if defined(__SANITIZE_ADDRESS__)
+ if (afl->fsrv.mem_limit) {
+
+ WARNF("in the ASAN build we disable all memory limits");
+ afl->fsrv.mem_limit = 0;
+
+ }
+
+ #endif
+
+ afl->fsrv.kill_signal =
+ parse_afl_kill_signal_env(afl->afl_env.afl_kill_signal, SIGKILL);
+
+ setup_signal_handlers();
+ check_asan_opts(afl);
+
+ afl->power_name = power_names[afl->schedule];
+
+ if (!afl->non_instrumented_mode && !afl->sync_id) {
+
+ auto_sync = 1;
+ afl->sync_id = ck_strdup("default");
+ afl->is_secondary_node = 1;
+ OKF("No -M/-S set, autoconfiguring for \"-S %s\"", afl->sync_id);
+
+ }
+
+ #ifdef __linux__
+ if (afl->fsrv.nyx_mode) {
+
+ if (afl->fsrv.nyx_standalone && strcmp(afl->sync_id, "default") != 0) {
+
+ FATAL(
+ "distributed fuzzing is not supported in this Nyx mode (use -Y "
+ "instead)");
+
+ }
+
+ if (!afl->fsrv.nyx_standalone) {
+
+ if (afl->is_main_node) {
+
+ if (strcmp("0", afl->sync_id) != 0) {
+
+ FATAL(
+ "for Nyx -Y mode, the Main (-M) parameter has to be set to 0 (-M "
+ "0)");
+
+ }
+
+ afl->fsrv.nyx_parent = true;
+ afl->fsrv.nyx_id = 0;
+
+ }
+
+ if (afl->is_secondary_node) {
+
+ long nyx_id = strtol(afl->sync_id, NULL, 10);
+
+ if (nyx_id == 0 || nyx_id == LONG_MAX) {
+
+ FATAL(
+ "for Nyx -Y mode, the Secondary (-S) parameter has to be a "
+ "numeric value and >= 1 (e.g. -S 1)");
+
+ }
+
+ afl->fsrv.nyx_id = nyx_id;
+
+ }
+
+ }
+
+ }
+
+ #endif
+
+ if (afl->sync_id) {
+
+ if (strlen(afl->sync_id) > 24) {
+
+ FATAL("sync_id max length is 24 characters");
+
+ }
+
+ fix_up_sync(afl);
+
+ }
+
+ if (!strcmp(afl->in_dir, afl->out_dir)) {
+
+ FATAL("Input and output directories can't be the same");
+
+ }
+
+ if (afl->non_instrumented_mode) {
+
+ if (afl->crash_mode) { FATAL("-C and -n are mutually exclusive"); }
+ if (afl->fsrv.frida_mode) { FATAL("-O and -n are mutually exclusive"); }
+ if (afl->fsrv.qemu_mode) { FATAL("-Q and -n are mutually exclusive"); }
+ if (afl->fsrv.cs_mode) { FATAL("-A and -n are mutually exclusive"); }
+ if (afl->unicorn_mode) { FATAL("-U and -n are mutually exclusive"); }
+
+ }
+
+ setenv("__AFL_OUT_DIR", afl->out_dir, 1);
+
+ if (get_afl_env("AFL_DISABLE_TRIM")) { afl->disable_trim = 1; }
+
+ if (getenv("AFL_NO_UI") && getenv("AFL_FORCE_UI")) {
+
+ FATAL("AFL_NO_UI and AFL_FORCE_UI are mutually exclusive");
+
+ }
+
+ if (unlikely(afl->afl_env.afl_statsd)) { statsd_setup_format(afl); }
+
+ if (!afl->use_banner) { afl->use_banner = argv[optind]; }
+
+ if (afl->shm.cmplog_mode &&
+ (!strcmp("-", afl->cmplog_binary) || !strcmp("0", afl->cmplog_binary))) {
+
+ afl->cmplog_binary = argv[optind];
+
+ }
+
+ if (strchr(argv[optind], '/') == NULL && !afl->unicorn_mode) {
+
+ WARNF(cLRD
+ "Target binary called without a prefixed path, make sure you are "
+ "fuzzing the right binary: " cRST "%s",
+ argv[optind]);
+
+ }
+
+ ACTF("Getting to work...");
+
+ switch (afl->schedule) {
+
+ case FAST:
+ OKF("Using exponential power schedule (FAST)");
+ break;
+ case COE:
+ OKF("Using cut-off exponential power schedule (COE)");
+ break;
+ case EXPLOIT:
+ OKF("Using exploitation-based constant power schedule (EXPLOIT)");
+ break;
+ case LIN:
+ OKF("Using linear power schedule (LIN)");
+ break;
+ case QUAD:
+ OKF("Using quadratic power schedule (QUAD)");
+ break;
+ case MMOPT:
+ OKF("Using modified MOpt power schedule (MMOPT)");
+ break;
+ case RARE:
+ OKF("Using rare edge focus power schedule (RARE)");
+ break;
+ case SEEK:
+ OKF("Using seek power schedule (SEEK)");
+ break;
+ case EXPLORE:
+ OKF("Using exploration-based constant power schedule (EXPLORE)");
+ break;
+ default:
+ FATAL("Unknown power schedule");
+ break;
+
+ }
+
+ if (afl->shm.cmplog_mode) { OKF("CmpLog level: %u", afl->cmplog_lvl); }
+
+ /* Dynamically allocate memory for AFLFast schedules */
+ if (afl->schedule >= FAST && afl->schedule <= RARE) {
+
+ afl->n_fuzz = ck_alloc(N_FUZZ_SIZE * sizeof(u32));
+
+ }
+
+ if (get_afl_env("AFL_NO_FORKSRV")) { afl->no_forkserver = 1; }
+ if (get_afl_env("AFL_NO_CPU_RED")) { afl->no_cpu_meter_red = 1; }
+ if (get_afl_env("AFL_NO_ARITH")) { afl->no_arith = 1; }
+ if (get_afl_env("AFL_SHUFFLE_QUEUE")) { afl->shuffle_queue = 1; }
+ if (get_afl_env("AFL_EXPAND_HAVOC_NOW")) { afl->expand_havoc = 1; }
+
+ if (afl->afl_env.afl_autoresume) {
+
+ afl->autoresume = 1;
+ if (afl->in_place_resume) {
+
+ SAYF("AFL_AUTORESUME has no effect for '-i -'");
+
+ }
+
+ }
+
+ if (afl->afl_env.afl_hang_tmout) {
+
+ s32 hang_tmout = atoi(afl->afl_env.afl_hang_tmout);
+ if (hang_tmout < 1) { FATAL("Invalid value for AFL_HANG_TMOUT"); }
+ afl->hang_tmout = (u32)hang_tmout;
+
+ }
+
+ if (afl->afl_env.afl_exit_on_time) {
+
+ u64 exit_on_time = atoi(afl->afl_env.afl_exit_on_time);
+ afl->exit_on_time = (u64)exit_on_time * 1000;
+
+ }
+
+ if (afl->afl_env.afl_max_det_extras) {
+
+ s32 max_det_extras = atoi(afl->afl_env.afl_max_det_extras);
+ if (max_det_extras < 1) { FATAL("Invalid value for AFL_MAX_DET_EXTRAS"); }
+ afl->max_det_extras = (u32)max_det_extras;
+
+ } else {
+
+ afl->max_det_extras = MAX_DET_EXTRAS;
+
+ }
+
+ if (afl->afl_env.afl_testcache_size) {
+
+ afl->q_testcase_max_cache_size =
+ (u64)atoi(afl->afl_env.afl_testcache_size) * 1048576;
+
+ }
+
+ if (afl->afl_env.afl_testcache_entries) {
+
+ afl->q_testcase_max_cache_entries =
+ (u32)atoi(afl->afl_env.afl_testcache_entries);
+
+ // user_set_cache = 1;
+
+ }
+
+ if (!afl->afl_env.afl_testcache_size || !afl->afl_env.afl_testcache_entries) {
+
+ afl->afl_env.afl_testcache_entries = 0;
+ afl->afl_env.afl_testcache_size = 0;
+
+ }
+
+ if (!afl->q_testcase_max_cache_size) {
+
+ ACTF(
+ "No testcache was configured. it is recommended to use a testcache, it "
+ "improves performance: set AFL_TESTCACHE_SIZE=(value in MB)");
+
+ } else if (afl->q_testcase_max_cache_size < 2 * MAX_FILE) {
+
+ FATAL("AFL_TESTCACHE_SIZE must be set to %ld or more, or 0 to disable",
+ (2 * MAX_FILE) % 1048576 == 0 ? (2 * MAX_FILE) / 1048576
+ : 1 + ((2 * MAX_FILE) / 1048576));
+
+ } else {
+
+ OKF("Enabled testcache with %llu MB",
+ afl->q_testcase_max_cache_size / 1048576);
+
+ }
+
+ if (afl->afl_env.afl_forksrv_init_tmout) {
+
+ afl->fsrv.init_tmout = atoi(afl->afl_env.afl_forksrv_init_tmout);
+ if (!afl->fsrv.init_tmout) {
+
+ FATAL("Invalid value of AFL_FORKSRV_INIT_TMOUT");
+
+ }
+
+ } else {
+
+ afl->fsrv.init_tmout = afl->fsrv.exec_tmout * FORK_WAIT_MULT;
+
+ }
+
+ if (afl->afl_env.afl_crash_exitcode) {
+
+ long exitcode = strtol(afl->afl_env.afl_crash_exitcode, NULL, 10);
+ if ((!exitcode && (errno == EINVAL || errno == ERANGE)) ||
+ exitcode < -127 || exitcode > 128) {
+
+ FATAL("Invalid crash exitcode, expected -127 to 128, but got %s",
+ afl->afl_env.afl_crash_exitcode);
+
+ }
+
+ afl->fsrv.uses_crash_exitcode = true;
+ // WEXITSTATUS is 8 bit unsigned
+ afl->fsrv.crash_exitcode = (u8)exitcode;
+
+ }
+
+ if (afl->non_instrumented_mode == 2 && afl->no_forkserver) {
+
+ FATAL("AFL_DUMB_FORKSRV and AFL_NO_FORKSRV are mutually exclusive");
+
+ }
+
+ OKF("Generating fuzz data with a length of min=%u max=%u", afl->min_length,
+ afl->max_length);
+ u32 min_alloc = MAX(64U, afl->min_length);
+ afl_realloc(AFL_BUF_PARAM(in_scratch), min_alloc);
+ afl_realloc(AFL_BUF_PARAM(in), min_alloc);
+ afl_realloc(AFL_BUF_PARAM(out_scratch), min_alloc);
+ afl_realloc(AFL_BUF_PARAM(out), min_alloc);
+ afl_realloc(AFL_BUF_PARAM(eff), min_alloc);
+ afl_realloc(AFL_BUF_PARAM(ex), min_alloc);
+
+ afl->fsrv.use_fauxsrv = afl->non_instrumented_mode == 1 || afl->no_forkserver;
+
+ #ifdef __linux__
+ if (!afl->fsrv.nyx_mode) {
+
+ check_crash_handling();
+ check_cpu_governor(afl);
+
+ } else {
+
+ u8 *libnyx_binary = find_afl_binary(argv[0], "libnyx.so");
+ afl->fsrv.nyx_handlers = afl_load_libnyx_plugin(libnyx_binary);
+ if (afl->fsrv.nyx_handlers == NULL) {
+
+ FATAL("failed to initialize libnyx.so...");
+
+ }
+
+ }
+
+ #else
+ check_crash_handling();
+ check_cpu_governor(afl);
+ #endif
+
+ if (getenv("LD_PRELOAD")) {
+
+ WARNF(
+ "LD_PRELOAD is set, are you sure that is what you want to do "
+ "instead of using AFL_PRELOAD?");
+
+ }
+
+ if (afl->afl_env.afl_preload) {
+
+ if (afl->fsrv.qemu_mode) {
+
+ /* afl-qemu-trace takes care of converting AFL_PRELOAD. */
+
+ } else if (afl->fsrv.frida_mode) {
+
+ afl_preload = getenv("AFL_PRELOAD");
+ u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
+ OKF("Injecting %s ...", frida_binary);
+ if (afl_preload) {
+
+ if (afl->fsrv.frida_asan) {
+
+ OKF("Using Frida Address Sanitizer Mode");
+
+ fasan_check_afl_preload(afl_preload);
+
+ setenv("ASAN_OPTIONS", "detect_leaks=false", 1);
+
+ }
+
+ u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
+ OKF("Injecting %s ...", frida_binary);
+ frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
+
+ ck_free(frida_binary);
+
+ setenv("LD_PRELOAD", frida_afl_preload, 1);
+ setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
+
+ }
+
+ } else {
+
+ /* CoreSight mode uses the default behavior. */
+
+ setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
+ setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
+
+ }
+
+ } else if (afl->fsrv.frida_mode) {
+
+ if (afl->fsrv.frida_asan) {
+
+ OKF("Using Frida Address Sanitizer Mode");
+ FATAL(
+ "Address Sanitizer DSO must be loaded using AFL_PRELOAD in Frida "
+ "Address Sanitizer Mode");
+
+ } else {
+
+ u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
+ OKF("Injecting %s ...", frida_binary);
+ setenv("LD_PRELOAD", frida_binary, 1);
+ setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
+ ck_free(frida_binary);
+
+ }
+
+ }
+
+ if (getenv("AFL_LD_PRELOAD")) {
+
+ FATAL("Use AFL_PRELOAD instead of AFL_LD_PRELOAD");
+
+ }
+
+ if (afl->afl_env.afl_target_env &&
+ !extract_and_set_env(afl->afl_env.afl_target_env)) {
+
+ FATAL("Bad value of AFL_TARGET_ENV");
+
+ }
+
+ save_cmdline(afl, argc, argv);
+ check_if_tty(afl);
+ if (afl->afl_env.afl_force_ui) { afl->not_on_tty = 0; }
+
+ if (afl->afl_env.afl_custom_mutator_only) {
+
+ /* This ensures we don't proceed to havoc/splice */
+ afl->custom_only = 1;
+
+ /* Ensure we also skip all deterministic steps */
+ afl->skip_deterministic = 1;
+
+ }
+
+ get_core_count(afl);
+
+ atexit(at_exit);
+
+ setup_dirs_fds(afl);
+
+ #ifdef HAVE_AFFINITY
+ bind_to_free_cpu(afl);
+ #endif /* HAVE_AFFINITY */
+
+ #ifdef __HAIKU__
+ /* Prioritizes performance over power saving */
+ set_scheduler_mode(SCHEDULER_MODE_LOW_LATENCY);
+ #endif
+
+ #ifdef __APPLE__
+ if (pthread_set_qos_class_self_np(QOS_CLASS_USER_INTERACTIVE, 0) != 0) {
+
+ WARNF("general thread priority settings failed");
+
+ }
+
+ #endif
+
+ init_count_class16();
+
+ if (afl->is_main_node && check_main_node_exists(afl) == 1) {
+
+ WARNF("it is wasteful to run more than one main node!");
+ sleep(1);
+
+ } else if (!auto_sync && afl->is_secondary_node &&
+
+ check_main_node_exists(afl) == 0) {
+
+ WARNF(
+ "no -M main node found. It is recommended to run exactly one main "
+ "instance.");
+ sleep(1);
+
+ }
+
+ #ifdef RAND_TEST_VALUES
+ u32 counter;
+ for (counter = 0; counter < 100000; counter++)
+ printf("DEBUG: rand %06d is %u\n", counter, rand_below(afl, 65536));
+ #endif
+
+ setup_custom_mutators(afl);
+
+ write_setup_file(afl, argc, argv);
+
+ setup_cmdline_file(afl, argv + optind);
+
+ read_testcases(afl, NULL);
+ // read_foreign_testcases(afl, 1); for the moment dont do this
+ OKF("Loaded a total of %u seeds.", afl->queued_items);
+
+ pivot_inputs(afl);
+
+ if (!afl->timeout_given) { find_timeout(afl); } // only for resumes!
+
+ if ((afl->tmp_dir = afl->afl_env.afl_tmpdir) != NULL &&
+ !afl->in_place_resume) {
+
+ char tmpfile[PATH_MAX];
+
+ if (afl->file_extension) {
+
+ snprintf(tmpfile, PATH_MAX, "%s/.cur_input.%s", afl->tmp_dir,
+ afl->file_extension);
+
+ } else {
+
+ snprintf(tmpfile, PATH_MAX, "%s/.cur_input", afl->tmp_dir);
+
+ }
+
+ /* there is still a race condition here, but well ... */
+ if (access(tmpfile, F_OK) != -1) {
+
+ FATAL(
+ "AFL_TMPDIR already has an existing temporary input file: %s - if "
+ "this is not from another instance, then just remove the file.",
+ tmpfile);
+
+ }
+
+ } else {
+
+ afl->tmp_dir = afl->out_dir;
+
+ }
+
+ /* If we don't have a file name chosen yet, use a safe default. */
+
+ if (!afl->fsrv.out_file) {
+
+ u32 j = optind + 1;
+ while (argv[j]) {
+
+ u8 *aa_loc = strstr(argv[j], "@@");
+
+ if (aa_loc && !afl->fsrv.out_file) {
+
+ afl->fsrv.use_stdin = 0;
+
+ if (afl->file_extension) {
+
+ afl->fsrv.out_file = alloc_printf("%s/.cur_input.%s", afl->tmp_dir,
+ afl->file_extension);
+
+ } else {
+
+ afl->fsrv.out_file = alloc_printf("%s/.cur_input", afl->tmp_dir);
+
+ }
+
+ detect_file_args(argv + optind + 1, afl->fsrv.out_file,
+ &afl->fsrv.use_stdin);
+ break;
+
+ }
+
+ ++j;
+
+ }
+
+ }
+
+ if (!afl->fsrv.out_file) { setup_stdio_file(afl); }
+
+ if (afl->cmplog_binary) {
+
+ if (afl->unicorn_mode) {
+
+ FATAL("CmpLog and Unicorn mode are not compatible at the moment, sorry");
+
+ }
+
+ if (!afl->fsrv.qemu_mode && !afl->fsrv.frida_mode && !afl->fsrv.cs_mode &&
+ !afl->non_instrumented_mode) {
+
+ check_binary(afl, afl->cmplog_binary);
+
+ }
+
+ }
+
+ check_binary(afl, argv[optind]);
+
+ #ifdef AFL_PERSISTENT_RECORD
+ if (unlikely(afl->fsrv.persistent_record)) {
+
+ if (!getenv(PERSIST_ENV_VAR)) {
+
+ FATAL(
+ "Target binary is not compiled in persistent mode, "
+ "AFL_PERSISTENT_RECORD makes no sense.");
+
+ }
+
+ afl->fsrv.persistent_record_dir = alloc_printf("%s/crashes", afl->out_dir);
+
+ }
+
+ #endif
+
+ if (afl->shmem_testcase_mode) { setup_testcase_shmem(afl); }
+
+ afl->start_time = get_cur_time();
+
+ if (afl->fsrv.qemu_mode) {
+
+ if (afl->use_wine) {
+
+ use_argv = get_wine_argv(argv[0], &afl->fsrv.target_path, argc - optind,
+ argv + optind);
+
+ } else {
+
+ use_argv = get_qemu_argv(argv[0], &afl->fsrv.target_path, argc - optind,
+ argv + optind);
+
+ }
+
+ } else if (afl->fsrv.cs_mode) {
+
+ use_argv = get_cs_argv(argv[0], &afl->fsrv.target_path, argc - optind,
+ argv + optind);
+
+ } else {
+
+ use_argv = argv + optind;
+
+ }
+
+ if (afl->non_instrumented_mode || afl->fsrv.qemu_mode ||
+ afl->fsrv.frida_mode || afl->fsrv.cs_mode || afl->unicorn_mode) {
+
+ map_size = afl->fsrv.real_map_size = afl->fsrv.map_size = MAP_SIZE;
+ afl->virgin_bits = ck_realloc(afl->virgin_bits, map_size);
+ afl->virgin_tmout = ck_realloc(afl->virgin_tmout, map_size);
+ afl->virgin_crash = ck_realloc(afl->virgin_crash, map_size);
+ afl->var_bytes = ck_realloc(afl->var_bytes, map_size);
+ afl->top_rated = ck_realloc(afl->top_rated, map_size * sizeof(void *));
+ afl->clean_trace = ck_realloc(afl->clean_trace, map_size);
+ afl->clean_trace_custom = ck_realloc(afl->clean_trace_custom, map_size);
+ afl->first_trace = ck_realloc(afl->first_trace, map_size);
+ afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, map_size);
+
+ }
+
+ afl->argv = use_argv;
+ afl->fsrv.trace_bits =
+ afl_shm_init(&afl->shm, afl->fsrv.map_size, afl->non_instrumented_mode);
+
+ if (!afl->non_instrumented_mode && !afl->fsrv.qemu_mode &&
+ !afl->unicorn_mode && !afl->fsrv.frida_mode && !afl->fsrv.cs_mode &&
+ !afl->afl_env.afl_skip_bin_check) {
+
+ if (map_size <= DEFAULT_SHMEM_SIZE) {
+
+ afl->fsrv.map_size = DEFAULT_SHMEM_SIZE; // dummy temporary value
+ char vbuf[16];
+ snprintf(vbuf, sizeof(vbuf), "%u", DEFAULT_SHMEM_SIZE);
+ setenv("AFL_MAP_SIZE", vbuf, 1);
+
+ }
+
+ u32 new_map_size = afl_fsrv_get_mapsize(
+ &afl->fsrv, afl->argv, &afl->stop_soon, afl->afl_env.afl_debug_child);
+
+ // only reinitialize if the map needs to be larger than what we have.
+ if (map_size < new_map_size) {
+
+ OKF("Re-initializing maps to %u bytes", new_map_size);
+
+ afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size);
+ afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size);
+ afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size);
+ afl->var_bytes = ck_realloc(afl->var_bytes, new_map_size);
+ afl->top_rated =
+ ck_realloc(afl->top_rated, new_map_size * sizeof(void *));
+ afl->clean_trace = ck_realloc(afl->clean_trace, new_map_size);
+ afl->clean_trace_custom =
+ ck_realloc(afl->clean_trace_custom, new_map_size);
+ afl->first_trace = ck_realloc(afl->first_trace, new_map_size);
+ afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_map_size);
+
+ afl_fsrv_kill(&afl->fsrv);
+ afl_shm_deinit(&afl->shm);
+ afl->fsrv.map_size = new_map_size;
+ afl->fsrv.trace_bits =
+ afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode);
+ setenv("AFL_NO_AUTODICT", "1", 1); // loaded already
+ afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon,
+ afl->afl_env.afl_debug_child);
+
+ map_size = new_map_size;
+
+ }
+
+ }
+
+ if (afl->cmplog_binary) {
+
+ ACTF("Spawning cmplog forkserver");
+ afl_fsrv_init_dup(&afl->cmplog_fsrv, &afl->fsrv);
+ // TODO: this is semi-nice
+ afl->cmplog_fsrv.trace_bits = afl->fsrv.trace_bits;
+ afl->cmplog_fsrv.cs_mode = afl->fsrv.cs_mode;
+ afl->cmplog_fsrv.qemu_mode = afl->fsrv.qemu_mode;
+ afl->cmplog_fsrv.frida_mode = afl->fsrv.frida_mode;
+ afl->cmplog_fsrv.cmplog_binary = afl->cmplog_binary;
+ afl->cmplog_fsrv.init_child_func = cmplog_exec_child;
+
+ if ((map_size <= DEFAULT_SHMEM_SIZE ||
+ afl->cmplog_fsrv.map_size < map_size) &&
+ !afl->non_instrumented_mode && !afl->fsrv.qemu_mode &&
+ !afl->fsrv.frida_mode && !afl->unicorn_mode && !afl->fsrv.cs_mode &&
+ !afl->afl_env.afl_skip_bin_check) {
+
+ afl->cmplog_fsrv.map_size = MAX(map_size, (u32)DEFAULT_SHMEM_SIZE);
+ char vbuf[16];
+ snprintf(vbuf, sizeof(vbuf), "%u", afl->cmplog_fsrv.map_size);
+ setenv("AFL_MAP_SIZE", vbuf, 1);
+
+ }
+
+ u32 new_map_size =
+ afl_fsrv_get_mapsize(&afl->cmplog_fsrv, afl->argv, &afl->stop_soon,
+ afl->afl_env.afl_debug_child);
+
+ // only reinitialize when it needs to be larger
+ if (map_size < new_map_size) {
+
+ OKF("Re-initializing maps to %u bytes due cmplog", new_map_size);
+
+ afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size);
+ afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size);
+ afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size);
+ afl->var_bytes = ck_realloc(afl->var_bytes, new_map_size);
+ afl->top_rated =
+ ck_realloc(afl->top_rated, new_map_size * sizeof(void *));
+ afl->clean_trace = ck_realloc(afl->clean_trace, new_map_size);
+ afl->clean_trace_custom =
+ ck_realloc(afl->clean_trace_custom, new_map_size);
+ afl->first_trace = ck_realloc(afl->first_trace, new_map_size);
+ afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_map_size);
+
+ afl_fsrv_kill(&afl->fsrv);
+ afl_fsrv_kill(&afl->cmplog_fsrv);
+ afl_shm_deinit(&afl->shm);
+
+ afl->cmplog_fsrv.map_size = new_map_size; // non-cmplog stays the same
+ map_size = new_map_size;
+
+ setenv("AFL_NO_AUTODICT", "1", 1); // loaded already
+ afl->fsrv.trace_bits =
+ afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode);
+ afl->cmplog_fsrv.trace_bits = afl->fsrv.trace_bits;
+ afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon,
+ afl->afl_env.afl_debug_child);
+ afl_fsrv_start(&afl->cmplog_fsrv, afl->argv, &afl->stop_soon,
+ afl->afl_env.afl_debug_child);
+
+ }
+
+ OKF("Cmplog forkserver successfully started");
+
+ }
+
+ load_auto(afl);
+
+ if (extras_dir_cnt) {
+
+ for (u8 i = 0; i < extras_dir_cnt; i++) {
+
+ load_extras(afl, extras_dir[i]);
+
+ }
+
+ }
+
+ deunicode_extras(afl);
+ dedup_extras(afl);
+ if (afl->extras_cnt) { OKF("Loaded a total of %u extras.", afl->extras_cnt); }
+
+ // after we have the correct bitmap size we can read the bitmap -B option
+ // and set the virgin maps
+ if (afl->in_bitmap) {
+
+ read_bitmap(afl->in_bitmap, afl->virgin_bits, afl->fsrv.map_size);
+
+ } else {
+
+ memset(afl->virgin_bits, 255, map_size);
+
+ }
+
+ memset(afl->virgin_tmout, 255, map_size);
+ memset(afl->virgin_crash, 255, map_size);
+
+ perform_dry_run(afl);
+
+ if (afl->q_testcase_max_cache_entries) {
+
+ afl->q_testcase_cache =
+ ck_alloc(afl->q_testcase_max_cache_entries * sizeof(size_t));
+ if (!afl->q_testcase_cache) { PFATAL("malloc failed for cache entries"); }
+
+ }
+
+ cull_queue(afl);
+
+ // ensure we have at least one seed that is not disabled.
+ u32 entry, valid_seeds = 0;
+ for (entry = 0; entry < afl->queued_items; ++entry)
+ if (!afl->queue_buf[entry]->disabled) { ++valid_seeds; }
+
+ if (!afl->pending_not_fuzzed || !valid_seeds) {
+
+ #ifdef __linux__
+ if (afl->fsrv.nyx_mode) {
+
+ afl->fsrv.nyx_handlers->nyx_shutdown(afl->fsrv.nyx_runner);
+
+ }
+
+ #endif
+ FATAL("We need at least one valid input seed that does not crash!");
+
+ }
+
+ if (afl->timeout_given == 2) { // -t ...+ option
+
+ if (valid_seeds == 1) {
+
+ WARNF(
+ "Only one valid seed is present, auto-calculating the timeout is "
+ "disabled!");
+ afl->timeout_given = 1;
+
+ } else {
+
+ u64 max_ms = 0;
+
+ for (entry = 0; entry < afl->queued_items; ++entry)
+ if (!afl->queue_buf[entry]->disabled)
+ if (afl->queue_buf[entry]->exec_us > max_ms)
+ max_ms = afl->queue_buf[entry]->exec_us;
+
+ afl->fsrv.exec_tmout = max_ms;
+
+ }
+
+ }
+
+ show_init_stats(afl);
+
+ if (unlikely(afl->old_seed_selection)) seek_to = find_start_position(afl);
+
+ afl->start_time = get_cur_time();
+ if (afl->in_place_resume || afl->afl_env.afl_autoresume) {
+
+ load_stats_file(afl);
+
+ }
+
+ if (!afl->non_instrumented_mode) { write_stats_file(afl, 0, 0, 0, 0); }
+ maybe_update_plot_file(afl, 0, 0, 0);
+ save_auto(afl);
+
+ if (afl->stop_soon) { goto stop_fuzzing; }
+
+ /* Woop woop woop */
+
+ if (!afl->not_on_tty) {
+
+ sleep(1);
+ if (afl->stop_soon) { goto stop_fuzzing; }
+
+ }
+
+ // (void)nice(-20); // does not improve the speed
+ // real start time, we reset, so this works correctly with -V
+ afl->start_time = get_cur_time();
+
+ u32 runs_in_current_cycle = (u32)-1;
+ u32 prev_queued_items = 0;
+ u8 skipped_fuzz;
+
+ #ifdef INTROSPECTION
+ char ifn[4096];
+ snprintf(ifn, sizeof(ifn), "%s/introspection.txt", afl->out_dir);
+ if ((afl->introspection_file = fopen(ifn, "w")) == NULL) {
+
+ PFATAL("could not create '%s'", ifn);
+
+ }
+
+ setvbuf(afl->introspection_file, NULL, _IONBF, 0);
+ OKF("Writing mutation introspection to '%s'", ifn);
+ #endif
+
+ while (likely(!afl->stop_soon)) {
+
+ cull_queue(afl);
+
+ if (unlikely((!afl->old_seed_selection &&
+ runs_in_current_cycle > afl->queued_items) ||
+ (afl->old_seed_selection && !afl->queue_cur))) {
+
+ if (unlikely((afl->last_sync_cycle < afl->queue_cycle ||
+ (!afl->queue_cycle && afl->afl_env.afl_import_first)) &&
+ afl->sync_id)) {
+
+ sync_fuzzers(afl);
+
+ }
+
+ ++afl->queue_cycle;
+ runs_in_current_cycle = (u32)-1;
+ afl->cur_skipped_items = 0;
+
+ // 1st april fool joke - enable pizza mode
+ // to not waste time on checking the date we only do this when the
+ // queue is fully cycled.
+ time_t cursec = time(NULL);
+ struct tm *curdate = localtime(&cursec);
+ if (likely(!afl->afl_env.afl_pizza_mode)) {
+
+ if (unlikely(curdate->tm_mon == 3 && curdate->tm_mday == 1)) {
+
+ afl->pizza_is_served = 1;
+
+ } else {
+
+ afl->pizza_is_served = 0;
+
+ }
+
+ }
+
+ if (unlikely(afl->old_seed_selection)) {
+
+ afl->current_entry = 0;
+ while (unlikely(afl->current_entry < afl->queued_items &&
+ afl->queue_buf[afl->current_entry]->disabled)) {
+
+ ++afl->current_entry;
+
+ }
+
+ if (afl->current_entry >= afl->queued_items) { afl->current_entry = 0; }
+
+ afl->queue_cur = afl->queue_buf[afl->current_entry];
+
+ if (unlikely(seek_to)) {
+
+ if (unlikely(seek_to >= afl->queued_items)) {
+
+ // This should never happen.
+ FATAL("BUG: seek_to location out of bounds!\n");
+
+ }
+
+ afl->current_entry = seek_to;
+ afl->queue_cur = afl->queue_buf[seek_to];
+ seek_to = 0;
+
+ }
+
+ }
+
+ if (unlikely(afl->not_on_tty)) {
+
+ ACTF("Entering queue cycle %llu.", afl->queue_cycle);
+ fflush(stdout);
+
+ }
+
+ /* If we had a full queue cycle with no new finds, try
+ recombination strategies next. */
+
+ if (unlikely(afl->queued_items == prev_queued
+ /* FIXME TODO BUG: && (get_cur_time() - afl->start_time) >=
+ 3600 */
+ )) {
+
+ if (afl->use_splicing) {
+
+ ++afl->cycles_wo_finds;
+
+ if (unlikely(afl->shm.cmplog_mode &&
+ afl->cmplog_max_filesize < MAX_FILE)) {
+
+ afl->cmplog_max_filesize <<= 4;
+
+ }
+
+ switch (afl->expand_havoc) {
+
+ case 0:
+ // this adds extra splicing mutation options to havoc mode
+ afl->expand_havoc = 1;
+ break;
+ case 1:
+ // add MOpt mutator
+ /*
+ if (afl->limit_time_sig == 0 && !afl->custom_only &&
+ !afl->python_only) {
+
+ afl->limit_time_sig = -1;
+ afl->limit_time_puppet = 0;
+
+ }
+
+ */
+ afl->expand_havoc = 2;
+ if (afl->cmplog_lvl && afl->cmplog_lvl < 2) afl->cmplog_lvl = 2;
+ break;
+ case 2:
+ // increase havoc mutations per fuzz attempt
+ afl->havoc_stack_pow2++;
+ afl->expand_havoc = 3;
+ break;
+ case 3:
+ // further increase havoc mutations per fuzz attempt
+ afl->havoc_stack_pow2++;
+ afl->expand_havoc = 4;
+ break;
+ case 4:
+ afl->expand_havoc = 5;
+ // if (afl->cmplog_lvl && afl->cmplog_lvl < 3) afl->cmplog_lvl =
+ // 3;
+ break;
+ case 5:
+ // nothing else currently
+ break;
+
+ }
+
+ } else {
+
+ #ifndef NO_SPLICING
+ afl->use_splicing = 1;
+ #else
+ afl->use_splicing = 0;
+ #endif
+
+ }
+
+ } else {
+
+ afl->cycles_wo_finds = 0;
+
+ }
+
+ #ifdef INTROSPECTION
+ fprintf(afl->introspection_file,
+ "CYCLE cycle=%llu cycle_wo_finds=%llu expand_havoc=%u queue=%u\n",
+ afl->queue_cycle, afl->cycles_wo_finds, afl->expand_havoc,
+ afl->queued_items);
+ #endif
+
+ if (afl->cycle_schedules) {
+
+ /* we cannot mix non-AFLfast schedules with others */
+
+ switch (afl->schedule) {
+
+ case EXPLORE:
+ afl->schedule = EXPLOIT;
+ break;
+ case EXPLOIT:
+ afl->schedule = MMOPT;
+ break;
+ case MMOPT:
+ afl->schedule = SEEK;
+ break;
+ case SEEK:
+ afl->schedule = EXPLORE;
+ break;
+ case FAST:
+ afl->schedule = COE;
+ break;
+ case COE:
+ afl->schedule = LIN;
+ break;
+ case LIN:
+ afl->schedule = QUAD;
+ break;
+ case QUAD:
+ afl->schedule = RARE;
+ break;
+ case RARE:
+ afl->schedule = FAST;
+ break;
+
+ }
+
+ // we must recalculate the scores of all queue entries
+ for (u32 i = 0; i < afl->queued_items; i++) {
+
+ if (likely(!afl->queue_buf[i]->disabled)) {
+
+ update_bitmap_score(afl, afl->queue_buf[i]);
+
+ }
+
+ }
+
+ }
+
+ prev_queued = afl->queued_items;
+
+ }
+
+ ++runs_in_current_cycle;
+
+ do {
+
+ if (likely(!afl->old_seed_selection)) {
+
+ if (unlikely(prev_queued_items < afl->queued_items ||
+ afl->reinit_table)) {
+
+ // we have new queue entries since the last run, recreate alias table
+ prev_queued_items = afl->queued_items;
+ create_alias_table(afl);
+
+ }
+
+ afl->current_entry = select_next_queue_entry(afl);
+ afl->queue_cur = afl->queue_buf[afl->current_entry];
+
+ }
+
+ skipped_fuzz = fuzz_one(afl);
+
+ if (unlikely(!afl->stop_soon && exit_1)) { afl->stop_soon = 2; }
+
+ if (unlikely(afl->old_seed_selection)) {
+
+ while (++afl->current_entry < afl->queued_items &&
+ afl->queue_buf[afl->current_entry]->disabled)
+ ;
+ if (unlikely(afl->current_entry >= afl->queued_items ||
+ afl->queue_buf[afl->current_entry] == NULL ||
+ afl->queue_buf[afl->current_entry]->disabled))
+ afl->queue_cur = NULL;
+ else
+ afl->queue_cur = afl->queue_buf[afl->current_entry];
+
+ }
+
+ } while (skipped_fuzz && afl->queue_cur && !afl->stop_soon);
+
+ if (likely(!afl->stop_soon && afl->sync_id)) {
+
+ if (likely(afl->skip_deterministic)) {
+
+ if (unlikely(afl->is_main_node)) {
+
+ if (unlikely(get_cur_time() >
+ (SYNC_TIME >> 1) + afl->last_sync_time)) {
+
+ if (!(sync_interval_cnt++ % (SYNC_INTERVAL / 3))) {
+
+ sync_fuzzers(afl);
+
+ }
+
+ }
+
+ } else {
+
+ if (unlikely(get_cur_time() > SYNC_TIME + afl->last_sync_time)) {
+
+ if (!(sync_interval_cnt++ % SYNC_INTERVAL)) { sync_fuzzers(afl); }
+
+ }
+
+ }
+
+ } else {
+
+ sync_fuzzers(afl);
+
+ }
+
+ }
+
+ }
+
+stop_fuzzing:
+
+ afl->force_ui_update = 1; // ensure the screen is reprinted
+ show_stats(afl); // print the screen one last time
+ write_bitmap(afl);
+ save_auto(afl);
+
+ if (afl->afl_env.afl_pizza_mode) {
+
+ SAYF(CURSOR_SHOW cLRD "\n\n+++ Baking aborted %s +++\n" cRST,
+ afl->stop_soon == 2 ? "programmatically" : "by the chef");
+
+ } else {
+
+ SAYF(CURSOR_SHOW cLRD "\n\n+++ Testing aborted %s +++\n" cRST,
+ afl->stop_soon == 2 ? "programmatically" : "by user");
+
+ }
+
+ if (afl->most_time_key == 2) {
+
+ SAYF(cYEL "[!] " cRST "Time limit was reached\n");
+
+ }
+
+ if (afl->most_execs_key == 2) {
+
+ SAYF(cYEL "[!] " cRST "Execution limit was reached\n");
+
+ }
+
+ /* Running for more than 30 minutes but still doing first cycle? */
+
+ if (afl->queue_cycle == 1 &&
+ get_cur_time() - afl->start_time > 30 * 60 * 1000) {
+
+ SAYF("\n" cYEL "[!] " cRST
+ "Stopped during the first cycle, results may be incomplete.\n"
+ " (For info on resuming, see %s/README.md)\n",
+ doc_path);
+
+ }
+
+ if (afl->not_on_tty) {
+
+ u32 t_bytes = count_non_255_bytes(afl, afl->virgin_bits);
+ u8 time_tmp[64];
+ u_stringify_time_diff(time_tmp, get_cur_time(), afl->start_time);
+ ACTF(
+ "Statistics: %u new corpus items found, %.02f%% coverage achieved, "
+ "%llu crashes saved, %llu timeouts saved, total runtime %s",
+ afl->queued_discovered,
+ ((double)t_bytes * 100) / afl->fsrv.real_map_size, afl->saved_crashes,
+ afl->saved_hangs, time_tmp);
+
+ }
+
+ #ifdef PROFILING
+ SAYF(cYEL "[!] " cRST
+ "Profiling information: %llu ms total work, %llu ns/run\n",
+ time_spent_working / 1000000,
+ time_spent_working / afl->fsrv.total_execs);
+ #endif
+
+ if (afl->is_main_node) {
+
+ u8 path[PATH_MAX];
+ sprintf(path, "%s/is_main_node", afl->out_dir);
+ unlink(path);
+
+ }
+
+ if (frida_afl_preload) { ck_free(frida_afl_preload); }
+
+ fclose(afl->fsrv.plot_file);
+ destroy_queue(afl);
+ destroy_extras(afl);
+ destroy_custom_mutators(afl);
+ afl_shm_deinit(&afl->shm);
+
+ if (afl->shm_fuzz) {
+
+ afl_shm_deinit(afl->shm_fuzz);
+ ck_free(afl->shm_fuzz);
+
+ }
+
+ afl_fsrv_deinit(&afl->fsrv);
+
+ /* remove tmpfile */
+ if (afl->tmp_dir != NULL && !afl->in_place_resume && afl->fsrv.out_file) {
+
+ (void)unlink(afl->fsrv.out_file);
+
+ }
+
+ if (afl->orig_cmdline) { ck_free(afl->orig_cmdline); }
+ ck_free(afl->fsrv.target_path);
+ ck_free(afl->fsrv.out_file);
+ ck_free(afl->sync_id);
+ if (afl->q_testcase_cache) { ck_free(afl->q_testcase_cache); }
+ afl_state_deinit(afl);
+ free(afl); /* not tracked */
+
+ argv_cpy_free(argv);
+
+ alloc_report();
+
+ OKF("We're done here. Have a nice day!\n");
+
+ exit(0);
+
+}
+
+#endif /* !AFL_LIB */
+
diff --git a/src/afl-gotcpu.c b/src/afl-gotcpu.c
new file mode 100644
index 00000000..539206ce
--- /dev/null
+++ b/src/afl-gotcpu.c
@@ -0,0 +1,322 @@
+/*
+ american fuzzy lop++ - free CPU gizmo
+ -----------------------------------
+
+ Originally written by Michal Zalewski
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Andrea Fioraldi <andreafioraldi@gmail.com>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ This tool provides a fairly accurate measurement of CPU preemption rate.
+ It is meant to complement the quick-and-dirty load average widget shown
+ in the afl-fuzz UI. See docs/parallel_fuzzing.md for more info.
+
+ For some work loads, the tool may actually suggest running more instances
+ than you have CPU cores. This can happen if the tested program is spending
+ a portion of its run time waiting for I/O, rather than being 100%
+ CPU-bound.
+
+ The idea for the getrusage()-based approach comes from Jakub Wilk.
+
+ */
+
+#define AFL_MAIN
+#ifndef _GNU_SOURCE
+ #define _GNU_SOURCE
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sched.h>
+
+#include <sys/time.h>
+#include <sys/times.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+#include "types.h"
+#include "debug.h"
+#include "common.h"
+
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
+ defined(__APPLE__) || defined(__DragonFly__) || defined(__sun)
+ #define HAVE_AFFINITY 1
+ #if defined(__FreeBSD__) || defined(__DragonFly__)
+ #include <pthread.h>
+ #include <pthread_np.h>
+ #if defined(__FreeBSD__)
+ #include <sys/cpuset.h>
+ #endif
+ #define cpu_set_t cpuset_t
+ #elif defined(__NetBSD__)
+ #include <pthread.h>
+ #elif defined(__APPLE__)
+ #include <pthread.h>
+ #include <mach/thread_act.h>
+ #include <mach/thread_policy.h>
+ #elif defined(__sun)
+ #include <sys/pset.h>
+ #endif
+#endif /* __linux__ || __FreeBSD__ || __NetBSD__ || __APPLE__ */
+
+/* Get CPU usage in microseconds. */
+
+static u64 get_cpu_usage_us(void) {
+
+ struct rusage u;
+
+ getrusage(RUSAGE_SELF, &u);
+
+ return (u.ru_utime.tv_sec * 1000000ULL) + u.ru_utime.tv_usec +
+ (u.ru_stime.tv_sec * 1000000ULL) + u.ru_stime.tv_usec;
+
+}
+
+/* Measure preemption rate. */
+
+static u32 measure_preemption(u32 target_ms) {
+
+ volatile u32 v1, v2 = 0;
+
+ u64 st_t, en_t, st_c, en_c, real_delta, slice_delta;
+ s32 loop_repeats = 0;
+
+ st_t = get_cur_time_us();
+ st_c = get_cpu_usage_us();
+
+repeat_loop:
+
+ v1 = CTEST_BUSY_CYCLES;
+
+ while (v1--) {
+
+ v2++;
+
+ }
+
+ sched_yield();
+
+ en_t = get_cur_time_us();
+
+ if (en_t - st_t < target_ms * 1000) {
+
+ loop_repeats++;
+ goto repeat_loop;
+
+ }
+
+ /* Let's see what percentage of this time we actually had a chance to
+ run, and how much time was spent in the penalty box. */
+
+ en_c = get_cpu_usage_us();
+
+ real_delta = (en_t - st_t) / 1000;
+ slice_delta = (en_c - st_c) / 1000;
+
+ return real_delta * 100 / slice_delta;
+
+}
+
+/* Do the benchmark thing. */
+
+int main(int argc, char **argv) {
+
+ if (argc > 1) {
+
+ printf("afl-gotcpu" VERSION " by Michal Zalewski\n");
+ printf("\n%s \n\n", argv[0]);
+ printf("afl-gotcpu does not have command line options\n");
+ printf("afl-gotcpu prints out which CPUs are available\n");
+ return -1;
+
+ }
+
+#ifdef HAVE_AFFINITY
+
+ u32 cpu_cnt = sysconf(_SC_NPROCESSORS_ONLN), idle_cpus = 0, maybe_cpus = 0, i;
+
+ SAYF(cCYA "afl-gotcpu" VERSION cRST " by Michal Zalewski\n");
+
+ ACTF("Measuring per-core preemption rate (this will take %0.02f sec)...",
+ ((double)CTEST_CORE_TRG_MS) / 1000);
+
+ for (i = 0; i < cpu_cnt; i++) {
+
+ s32 fr = fork();
+
+ if (fr < 0) { PFATAL("fork failed"); }
+
+ if (!fr) {
+
+ u32 util_perc;
+ #if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)
+ cpu_set_t c;
+
+ CPU_ZERO(&c);
+ CPU_SET(i, &c);
+ #elif defined(__NetBSD__)
+ cpuset_t *c;
+
+ c = cpuset_create();
+ if (c == NULL) PFATAL("cpuset_create failed");
+
+ cpuset_set(i, c);
+ #elif defined(__APPLE__)
+ thread_affinity_policy_data_t c = {i};
+ thread_port_t native_thread = pthread_mach_thread_np(pthread_self());
+ if (thread_policy_set(native_thread, THREAD_AFFINITY_POLICY,
+ (thread_policy_t)&c, 1) != KERN_SUCCESS)
+ PFATAL("thread_policy_set failed");
+ #elif defined(__sun)
+ psetid_t c;
+
+ if (pset_create(&c)) PFATAL("pset_create failed");
+
+ if (pset_assign(c, i, NULL)) PFATAL("pset_assign failed");
+ #endif
+
+ #if defined(__FreeBSD__) || defined(__DragonFly__)
+ if (pthread_setaffinity_np(pthread_self(), sizeof(c), &c))
+ PFATAL("pthread_setaffinity_np failed");
+ #endif
+
+ #if defined(__NetBSD__)
+ if (pthread_setaffinity_np(pthread_self(), cpuset_size(c), c))
+ PFATAL("pthread_setaffinity_np failed");
+
+ cpuset_destroy(c);
+ #endif
+
+ #if defined(__sun)
+ if (pset_bind(c, P_PID, getpid(), NULL)) PFATAL("pset_bind failed");
+
+ pset_destroy(c);
+ #endif
+
+ #if defined(__linux__)
+ if (sched_setaffinity(0, sizeof(c), &c)) {
+
+ PFATAL("sched_setaffinity failed for cpu %d", i);
+
+ }
+
+ #endif
+
+ util_perc = measure_preemption(CTEST_CORE_TRG_MS);
+
+ if (util_perc < 110) {
+
+ SAYF(" Core #%u: " cLGN "AVAILABLE" cRST "(%u%%)\n", i, util_perc);
+ exit(0);
+
+ } else if (util_perc < 250) {
+
+ SAYF(" Core #%u: " cYEL "CAUTION " cRST "(%u%%)\n", i, util_perc);
+ exit(1);
+
+ }
+
+ SAYF(" Core #%u: " cLRD "OVERBOOKED " cRST "(%u%%)\n" cRST, i,
+ util_perc);
+ exit(2);
+
+ }
+
+ }
+
+ for (i = 0; i < cpu_cnt; i++) {
+
+ int ret;
+ if (waitpid(-1, &ret, 0) < 0) { PFATAL("waitpid failed"); }
+
+ if (WEXITSTATUS(ret) == 0) { idle_cpus++; }
+ if (WEXITSTATUS(ret) <= 1) { maybe_cpus++; }
+
+ }
+
+ SAYF(cGRA "\n>>> ");
+
+ if (idle_cpus) {
+
+ if (maybe_cpus == idle_cpus) {
+
+ SAYF(cLGN "PASS: " cRST "You can run more processes on %u core%s.",
+ idle_cpus, idle_cpus > 1 ? "s" : "");
+
+ } else {
+
+ SAYF(cLGN "PASS: " cRST "You can run more processes on %u to %u core%s.",
+ idle_cpus, maybe_cpus, maybe_cpus > 1 ? "s" : "");
+
+ }
+
+ SAYF(cGRA " <<<" cRST "\n\n");
+ return 0;
+
+ }
+
+ if (maybe_cpus) {
+
+ SAYF(cYEL "CAUTION: " cRST "You may still have %u core%s available.",
+ maybe_cpus, maybe_cpus > 1 ? "s" : "");
+ SAYF(cGRA " <<<" cRST "\n\n");
+ return 1;
+
+ }
+
+ SAYF(cLRD "FAIL: " cRST "All cores are overbooked.");
+ SAYF(cGRA " <<<" cRST "\n\n");
+ return 2;
+
+#else
+
+ u32 util_perc;
+
+ SAYF(cCYA "afl-gotcpu" VERSION cRST " by Michal Zalewski\n");
+
+ /* Run a busy loop for CTEST_TARGET_MS. */
+
+ ACTF("Measuring gross preemption rate (this will take %0.02f sec)...",
+ ((double)CTEST_TARGET_MS) / 1000);
+
+ util_perc = measure_preemption(CTEST_TARGET_MS);
+
+ /* Deliver the final verdict. */
+
+ SAYF(cGRA "\n>>> ");
+
+ if (util_perc < 105) {
+
+ SAYF(cLGN "PASS: " cRST "You can probably run additional processes.");
+
+ } else if (util_perc < 130) {
+
+ SAYF(cYEL "CAUTION: " cRST "Your CPU may be somewhat overbooked (%u%%).",
+ util_perc);
+
+ } else {
+
+ SAYF(cLRD "FAIL: " cRST "Your CPU is overbooked (%u%%).", util_perc);
+
+ }
+
+ SAYF(cGRA " <<<" cRST "\n\n");
+
+ return (util_perc > 105) + (util_perc > 130);
+
+#endif /* ^HAVE_AFFINITY */
+
+}
+
diff --git a/src/afl-ld-lto.c b/src/afl-ld-lto.c
new file mode 100644
index 00000000..5797def8
--- /dev/null
+++ b/src/afl-ld-lto.c
@@ -0,0 +1,365 @@
+/*
+ american fuzzy lop++ - wrapper for llvm 11+ lld
+ -----------------------------------------------
+
+ Written by Marc Heuse <mh@mh-sec.de> for afl++
+
+ Maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de>
+ Andrea Fioraldi <andreafioraldi@gmail.com>
+ Dominik Maier <domenukk@gmail.com>
+
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ The sole purpose of this wrapper is to preprocess clang LTO files when
+ linking with lld and performing the instrumentation on the whole program.
+
+*/
+
+#define AFL_MAIN
+#define _GNU_SOURCE
+
+#include "config.h"
+#include "types.h"
+#include "debug.h"
+#include "alloc-inl.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+#include <fcntl.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+
+#include <dirent.h>
+
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || \
+ defined(__DragonFly__)
+ #include <limits.h>
+#endif
+
+#ifdef __APPLE__
+ #include <sys/syslimits.h>
+#endif
+
+#define MAX_PARAM_COUNT 4096
+
+static u8 **ld_params; /* Parameters passed to the real 'ld' */
+
+static u8 *afl_path = AFL_PATH;
+static u8 *real_ld = AFL_REAL_LD;
+
+static u8 be_quiet, /* Quiet mode (no stderr output) */
+ debug, /* AFL_DEBUG */
+ passthrough, /* AFL_LD_PASSTHROUGH - no link+optimize*/
+ just_version; /* Just show version? */
+
+static u32 ld_param_cnt = 1; /* Number of params to 'ld' */
+
+/* Examine and modify parameters to pass to 'ld', 'llvm-link' and 'llmv-ar'.
+ Note that the file name is always the last parameter passed by GCC,
+ so we exploit this property to keep the code "simple". */
+static void edit_params(int argc, char **argv) {
+
+ u32 i, gold_pos = 0, gold_present = 0, rt_present = 0, rt_lto_present = 0,
+ inst_present = 0;
+ char *ptr;
+
+ ld_params = ck_alloc(4096 * sizeof(u8 *));
+
+ ld_params[0] = (u8 *)real_ld;
+
+ if (!passthrough) {
+
+ for (i = 1; i < (u32)argc; i++) {
+
+ if (strstr(argv[i], "/afl-llvm-rt-lto.o") != NULL) rt_lto_present = 1;
+ if (strstr(argv[i], "/afl-compiler-rt.o") != NULL) rt_present = 1;
+ if (strstr(argv[i], "/afl-llvm-lto-instr") != NULL) inst_present = 1;
+
+ }
+
+ for (i = 1; i < (u32)argc && !gold_pos; i++) {
+
+ if (strcmp(argv[i], "-plugin") == 0) {
+
+ if (strncmp(argv[i], "-plugin=", strlen("-plugin=")) == 0) {
+
+ if (strcasestr(argv[i], "LLVMgold.so") != NULL)
+ gold_present = gold_pos = i + 1;
+
+ } else if (i < (u32)argc &&
+
+ strcasestr(argv[i + 1], "LLVMgold.so") != NULL) {
+
+ gold_present = gold_pos = i + 2;
+
+ }
+
+ }
+
+ }
+
+ if (!gold_pos) {
+
+ for (i = 1; i + 1 < (u32)argc && !gold_pos; i++) {
+
+ if (argv[i][0] != '-') {
+
+ if (argv[i - 1][0] == '-') {
+
+ switch (argv[i - 1][1]) {
+
+ case 'b':
+ break;
+ case 'd':
+ break;
+ case 'e':
+ break;
+ case 'F':
+ break;
+ case 'f':
+ break;
+ case 'I':
+ break;
+ case 'l':
+ break;
+ case 'L':
+ break;
+ case 'm':
+ break;
+ case 'o':
+ break;
+ case 'O':
+ break;
+ case 'p':
+ if (index(argv[i - 1], '=') == NULL) gold_pos = i;
+ break;
+ case 'R':
+ break;
+ case 'T':
+ break;
+ case 'u':
+ break;
+ case 'y':
+ break;
+ case 'z':
+ break;
+ case '-': {
+
+ if (strcmp(argv[i - 1], "--oformat") == 0) break;
+ if (strcmp(argv[i - 1], "--output") == 0) break;
+ if (strncmp(argv[i - 1], "--opt-remarks-", 14) == 0) break;
+ gold_pos = i;
+ break;
+
+ }
+
+ default:
+ gold_pos = i;
+
+ }
+
+ } else
+
+ gold_pos = i;
+
+ }
+
+ }
+
+ }
+
+ if (!gold_pos) gold_pos = 1;
+
+ }
+
+ if (getenv("AFL_LLVM_INSTRIM") ||
+ ((ptr = getenv("AFL_LLVM_INSTRUMENT")) &&
+ (strcasestr(ptr, "CFG") == 0 || strcasestr(ptr, "INSTRIM") == 0)))
+ FATAL(
+ "InsTrim was removed because it is not effective. Use a modern LLVM "
+ "and PCGUARD (which is the default in afl-cc).\n");
+
+ if (debug)
+ DEBUGF(
+ "passthrough=%s, gold_pos=%u, gold_present=%s "
+ "inst_present=%s rt_present=%s rt_lto_present=%s\n",
+ passthrough ? "true" : "false", gold_pos,
+ gold_present ? "true" : "false", inst_present ? "true" : "false",
+ rt_present ? "true" : "false", rt_lto_present ? "true" : "false");
+
+ for (i = 1; i < (u32)argc; i++) {
+
+ if (ld_param_cnt >= MAX_PARAM_COUNT)
+ FATAL(
+ "Too many command line parameters because of unpacking .a archives, "
+ "this would need to be done by hand ... sorry! :-(");
+
+ if (strcmp(argv[i], "--afl") == 0) {
+
+ if (!be_quiet) OKF("afl++ test command line flag detected, exiting.");
+ exit(0);
+
+ }
+
+ if (i == gold_pos && !passthrough) {
+
+ ld_params[ld_param_cnt++] = alloc_printf("-L%s/../lib", LLVM_BINDIR);
+
+ if (!gold_present) {
+
+ ld_params[ld_param_cnt++] = "-plugin";
+ ld_params[ld_param_cnt++] =
+ alloc_printf("%s/../lib/LLVMgold.so", LLVM_BINDIR);
+
+ }
+
+ ld_params[ld_param_cnt++] = "--allow-multiple-definition";
+
+ if (!inst_present) {
+
+ ld_params[ld_param_cnt++] = alloc_printf(
+ "-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", afl_path);
+
+ }
+
+ if (!rt_present)
+ ld_params[ld_param_cnt++] =
+ alloc_printf("%s/afl-compiler-rt.o", afl_path);
+ if (!rt_lto_present)
+ ld_params[ld_param_cnt++] =
+ alloc_printf("%s/afl-llvm-rt-lto.o", afl_path);
+
+ }
+
+ ld_params[ld_param_cnt++] = argv[i];
+
+ }
+
+ ld_params[ld_param_cnt] = NULL;
+
+}
+
+/* Main entry point */
+
+int main(int argc, char **argv) {
+
+ s32 pid, i, status;
+ char thecwd[PATH_MAX];
+
+ if (getenv("AFL_LD_CALLER") != NULL) {
+
+ FATAL("ld loop detected! Set AFL_REAL_LD!\n");
+
+ }
+
+ if (isatty(2) && !getenv("AFL_QUIET") && !getenv("AFL_DEBUG")) {
+
+ SAYF(cCYA "afl-ld-to" VERSION cRST
+ " by Marc \"vanHauser\" Heuse <mh@mh-sec.de>\n");
+
+ } else
+
+ be_quiet = 1;
+
+ if (getenv("AFL_DEBUG") != NULL) debug = 1;
+ if (getenv("AFL_PATH") != NULL) afl_path = getenv("AFL_PATH");
+ if (getenv("AFL_LD_PASSTHROUGH") != NULL) passthrough = 1;
+ if (getenv("AFL_REAL_LD") != NULL) real_ld = getenv("AFL_REAL_LD");
+
+ if (!afl_path || !*afl_path) afl_path = "/usr/local/lib/afl";
+
+ setenv("AFL_LD_CALLER", "1", 1);
+
+ if (debug) {
+
+ if (getcwd(thecwd, sizeof(thecwd)) != 0) strcpy(thecwd, ".");
+
+ DEBUGF("cd \"%s\";", thecwd);
+ for (i = 0; i < argc; i++)
+ SAYF(" \"%s\"", argv[i]);
+ SAYF("\n");
+
+ }
+
+ if (argc < 2) {
+
+ SAYF(
+ "\n"
+ "This is a helper application for afl-clang-lto.\n"
+ "It is a wrapper around llvm's 'lld' in case afl-clang-lto cannot be "
+ "used.\n"
+ "Note that the target still has to be compiled with -flto=full!\n"
+ "You probably don't want to run this program directly but rather pass "
+ "it as LD\nparameter to e.g. configure scripts.\n\n"
+
+ "Environment variables:\n"
+ " AFL_LD_PASSTHROUGH do not link+optimize == no instrumentation\n"
+ " AFL_REAL_LD point to the real llvm 11 lld if necessary\n"
+
+ "\nafl-ld-to was compiled with the fixed real 'ld' of %s and the "
+ "binary path of %s\n\n",
+ real_ld, LLVM_BINDIR);
+
+ exit(1);
+
+ }
+
+ edit_params(argc, argv); // here most of the magic happens :-)
+
+ if (debug) {
+
+ DEBUGF("cd \"%s\";", thecwd);
+ for (i = 0; i < (s32)ld_param_cnt; i++)
+ SAYF(" \"%s\"", ld_params[i]);
+ SAYF("\n");
+
+ }
+
+ if (!(pid = fork())) {
+
+ if (strlen(real_ld) > 1) execvp(real_ld, (char **)ld_params);
+ execvp("ld", (char **)ld_params); // fallback
+ FATAL("Oops, failed to execute 'ld' - check your PATH");
+
+ }
+
+ if (pid < 0) PFATAL("fork() failed");
+
+ if (waitpid(pid, &status, 0) <= 0) PFATAL("waitpid() failed");
+ if (debug) DEBUGF("linker result: %d\n", status);
+
+ if (!just_version) {
+
+ if (status == 0) {
+
+ if (!be_quiet) OKF("Linker was successful");
+
+ } else {
+
+ SAYF(cLRD "[-] " cRST
+ "Linker failed, please investigate and send a bug report. Most "
+ "likely an 'ld' option is incompatible with %s.\n",
+ AFL_CLANG_FLTO);
+
+ }
+
+ }
+
+ exit(WEXITSTATUS(status));
+
+}
+
diff --git a/src/afl-performance.c b/src/afl-performance.c
new file mode 100644
index 00000000..04507410
--- /dev/null
+++ b/src/afl-performance.c
@@ -0,0 +1,110 @@
+/*
+ Written in 2019 by David Blackman and Sebastiano Vigna (vigna@acm.org)
+
+ To the extent possible under law, the author has dedicated all copyright
+ and related and neighboring rights to this software to the public domain
+ worldwide. This software is distributed without any warranty.
+
+ See <https://creativecommons.org/publicdomain/zero/1.0/>.
+
+ This is xoshiro256++ 1.0, one of our all-purpose, rock-solid generators.
+ It has excellent (sub-ns) speed, a state (256 bits) that is large
+ enough for any parallel application, and it passes all tests we are
+ aware of.
+
+ For generating just floating-point numbers, xoshiro256+ is even faster.
+
+ The state must be seeded so that it is not everywhere zero. If you have
+ a 64-bit seed, we suggest to seed a splitmix64 generator and use its
+ output to fill s[].
+*/
+
+#include <stdint.h>
+#include "afl-fuzz.h"
+#include "types.h"
+
+#define XXH_INLINE_ALL
+#include "xxhash.h"
+#undef XXH_INLINE_ALL
+
+void rand_set_seed(afl_state_t *afl, s64 init_seed) {
+
+ afl->init_seed = init_seed;
+ afl->rand_seed[0] =
+ hash64((u8 *)&afl->init_seed, sizeof(afl->init_seed), HASH_CONST);
+ afl->rand_seed[1] = afl->rand_seed[0] ^ 0x1234567890abcdef;
+ afl->rand_seed[2] = (afl->rand_seed[0] & 0x1234567890abcdef) ^
+ (afl->rand_seed[1] | 0xfedcba9876543210);
+
+}
+
+#define ROTL(d, lrot) ((d << (lrot)) | (d >> (8 * sizeof(d) - (lrot))))
+
+#ifdef WORD_SIZE_64
+// romuDuoJr
+inline AFL_RAND_RETURN rand_next(afl_state_t *afl) {
+
+ AFL_RAND_RETURN xp = afl->rand_seed[0];
+ afl->rand_seed[0] = 15241094284759029579u * afl->rand_seed[1];
+ afl->rand_seed[1] = afl->rand_seed[1] - xp;
+ afl->rand_seed[1] = ROTL(afl->rand_seed[1], 27);
+ return xp;
+
+}
+
+#else
+// RomuTrio32
+inline AFL_RAND_RETURN rand_next(afl_state_t *afl) {
+
+ AFL_RAND_RETURN xp = afl->rand_seed[0], yp = afl->rand_seed[1],
+ zp = afl->rand_seed[2];
+ afl->rand_seed[0] = 3323815723u * zp;
+ afl->rand_seed[1] = yp - xp;
+ afl->rand_seed[1] = ROTL(afl->rand_seed[1], 6);
+ afl->rand_seed[2] = zp - yp;
+ afl->rand_seed[2] = ROTL(afl->rand_seed[2], 22);
+ return xp;
+
+}
+
+#endif
+
+#undef ROTL
+
+/* returns a double between 0.000000000 and 1.000000000 */
+
+inline double rand_next_percent(afl_state_t *afl) {
+
+ return (double)(((double)rand_next(afl)) / (double)0xffffffffffffffff);
+
+}
+
+/* we switch from afl's murmur implementation to xxh3 as it is 30% faster -
+ and get 64 bit hashes instead of just 32 bit. Less collisions! :-) */
+
+#ifdef _DEBUG
+u32 hash32(u8 *key, u32 len, u32 seed) {
+
+#else
+inline u32 hash32(u8 *key, u32 len, u32 seed) {
+
+#endif
+
+ (void)seed;
+ return (u32)XXH3_64bits(key, len);
+
+}
+
+#ifdef _DEBUG
+u64 hash64(u8 *key, u32 len, u64 seed) {
+
+#else
+inline u64 hash64(u8 *key, u32 len, u64 seed) {
+
+#endif
+
+ (void)seed;
+ return XXH3_64bits(key, len);
+
+}
+
diff --git a/src/afl-sharedmem.c b/src/afl-sharedmem.c
new file mode 100644
index 00000000..b48c6fb3
--- /dev/null
+++ b/src/afl-sharedmem.c
@@ -0,0 +1,367 @@
+/*
+ american fuzzy lop++ - shared memory related code
+ -------------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Forkserver design by Jann Horn <jannhorn@googlemail.com>
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Andrea Fioraldi <andreafioraldi@gmail.com>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ Shared code to handle the shared memory. This is used by the fuzzer
+ as well the other components like afl-tmin, afl-showmap, etc...
+
+ */
+
+#define AFL_MAIN
+
+#ifdef __ANDROID__
+ #include "android-ashmem.h"
+#endif
+#include "config.h"
+#include "types.h"
+#include "debug.h"
+#include "alloc-inl.h"
+#include "hash.h"
+#include "sharedmem.h"
+#include "cmplog.h"
+#include "list.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <signal.h>
+#include <dirent.h>
+#include <fcntl.h>
+
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/mman.h>
+
+#ifndef USEMMAP
+ #include <sys/ipc.h>
+ #include <sys/shm.h>
+#endif
+
+static list_t shm_list = {.element_prealloc_count = 0};
+
+/* Get rid of shared memory. */
+
+void afl_shm_deinit(sharedmem_t *shm) {
+
+ if (shm == NULL) { return; }
+ list_remove(&shm_list, shm);
+ if (shm->shmemfuzz_mode) {
+
+ unsetenv(SHM_FUZZ_ENV_VAR);
+
+ } else {
+
+ unsetenv(SHM_ENV_VAR);
+
+ }
+
+#ifdef USEMMAP
+ if (shm->map != NULL) {
+
+ munmap(shm->map, shm->map_size);
+ shm->map = NULL;
+
+ }
+
+ if (shm->g_shm_fd != -1) {
+
+ close(shm->g_shm_fd);
+ shm->g_shm_fd = -1;
+
+ }
+
+ if (shm->g_shm_file_path[0]) {
+
+ shm_unlink(shm->g_shm_file_path);
+ shm->g_shm_file_path[0] = 0;
+
+ }
+
+ if (shm->cmplog_mode) {
+
+ unsetenv(CMPLOG_SHM_ENV_VAR);
+
+ if (shm->cmp_map != NULL) {
+
+ munmap(shm->cmp_map, shm->map_size);
+ shm->cmp_map = NULL;
+
+ }
+
+ if (shm->cmplog_g_shm_fd != -1) {
+
+ close(shm->cmplog_g_shm_fd);
+ shm->cmplog_g_shm_fd = -1;
+
+ }
+
+ if (shm->cmplog_g_shm_file_path[0]) {
+
+ shm_unlink(shm->cmplog_g_shm_file_path);
+ shm->cmplog_g_shm_file_path[0] = 0;
+
+ }
+
+ }
+
+#else
+ shmctl(shm->shm_id, IPC_RMID, NULL);
+ if (shm->cmplog_mode) { shmctl(shm->cmplog_shm_id, IPC_RMID, NULL); }
+#endif
+
+ shm->map = NULL;
+
+}
+
+/* Configure shared memory.
+ Returns a pointer to shm->map for ease of use.
+*/
+
+u8 *afl_shm_init(sharedmem_t *shm, size_t map_size,
+ unsigned char non_instrumented_mode) {
+
+ shm->map_size = 0;
+
+ shm->map = NULL;
+ shm->cmp_map = NULL;
+
+#ifdef USEMMAP
+
+ shm->g_shm_fd = -1;
+ shm->cmplog_g_shm_fd = -1;
+
+ const int shmflags = O_RDWR | O_EXCL;
+
+ /* ======
+ generate random file name for multi instance
+
+ thanks to f*cking glibc we can not use tmpnam securely, it generates a
+ security warning that cannot be suppressed
+ so we do this worse workaround */
+ snprintf(shm->g_shm_file_path, L_tmpnam, "/afl_%d_%ld", getpid(), random());
+
+ #ifdef SHM_LARGEPAGE_ALLOC_DEFAULT
+ /* trying to get large memory segment optimised and monitorable separately as
+ * such */
+ static size_t sizes[4] = {(size_t)-1};
+ static int psizes = 0;
+ int i;
+ if (sizes[0] == (size_t)-1) { psizes = getpagesizes(sizes, 4); }
+
+ /* very unlikely to fail even if the arch supports only two sizes */
+ if (likely(psizes > 0)) {
+
+ for (i = psizes - 1; shm->g_shm_fd == -1 && i >= 0; --i) {
+
+ if (sizes[i] == 0 || map_size % sizes[i]) { continue; }
+
+ shm->g_shm_fd =
+ shm_create_largepage(shm->g_shm_file_path, shmflags, i,
+ SHM_LARGEPAGE_ALLOC_DEFAULT, DEFAULT_PERMISSION);
+
+ }
+
+ }
+
+ #endif
+
+ /* create the shared memory segment as if it was a file */
+ if (shm->g_shm_fd == -1) {
+
+ shm->g_shm_fd =
+ shm_open(shm->g_shm_file_path, shmflags | O_CREAT, DEFAULT_PERMISSION);
+
+ }
+
+ if (shm->g_shm_fd == -1) { PFATAL("shm_open() failed"); }
+
+ /* configure the size of the shared memory segment */
+ if (ftruncate(shm->g_shm_fd, map_size)) {
+
+ PFATAL("setup_shm(): ftruncate() failed");
+
+ }
+
+ /* map the shared memory segment to the address space of the process */
+ shm->map =
+ mmap(0, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm->g_shm_fd, 0);
+ if (shm->map == MAP_FAILED) {
+
+ close(shm->g_shm_fd);
+ shm->g_shm_fd = -1;
+ shm_unlink(shm->g_shm_file_path);
+ shm->g_shm_file_path[0] = 0;
+ PFATAL("mmap() failed");
+
+ }
+
+ /* If somebody is asking us to fuzz instrumented binaries in non-instrumented
+ mode, we don't want them to detect instrumentation, since we won't be
+ sending fork server commands. This should be replaced with better
+ auto-detection later on, perhaps? */
+
+ if (!non_instrumented_mode) setenv(SHM_ENV_VAR, shm->g_shm_file_path, 1);
+
+ if (shm->map == (void *)-1 || !shm->map) PFATAL("mmap() failed");
+
+ if (shm->cmplog_mode) {
+
+ snprintf(shm->cmplog_g_shm_file_path, L_tmpnam, "/afl_cmplog_%d_%ld",
+ getpid(), random());
+
+ /* create the shared memory segment as if it was a file */
+ shm->cmplog_g_shm_fd =
+ shm_open(shm->cmplog_g_shm_file_path, O_CREAT | O_RDWR | O_EXCL,
+ DEFAULT_PERMISSION);
+ if (shm->cmplog_g_shm_fd == -1) { PFATAL("shm_open() failed"); }
+
+ /* configure the size of the shared memory segment */
+ if (ftruncate(shm->cmplog_g_shm_fd, map_size)) {
+
+ PFATAL("setup_shm(): cmplog ftruncate() failed");
+
+ }
+
+ /* map the shared memory segment to the address space of the process */
+ shm->cmp_map = mmap(0, map_size, PROT_READ | PROT_WRITE, MAP_SHARED,
+ shm->cmplog_g_shm_fd, 0);
+ if (shm->cmp_map == MAP_FAILED) {
+
+ close(shm->cmplog_g_shm_fd);
+ shm->cmplog_g_shm_fd = -1;
+ shm_unlink(shm->cmplog_g_shm_file_path);
+ shm->cmplog_g_shm_file_path[0] = 0;
+ PFATAL("mmap() failed");
+
+ }
+
+ /* If somebody is asking us to fuzz instrumented binaries in
+ non-instrumented mode, we don't want them to detect instrumentation,
+ since we won't be sending fork server commands. This should be replaced
+ with better auto-detection later on, perhaps? */
+
+ if (!non_instrumented_mode)
+ setenv(CMPLOG_SHM_ENV_VAR, shm->cmplog_g_shm_file_path, 1);
+
+ if (shm->cmp_map == (void *)-1 || !shm->cmp_map)
+ PFATAL("cmplog mmap() failed");
+
+ }
+
+#else
+ u8 *shm_str;
+
+ // for qemu+unicorn we have to increase by 8 to account for potential
+ // compcov map overwrite
+ shm->shm_id =
+ shmget(IPC_PRIVATE, map_size == MAP_SIZE ? map_size + 8 : map_size,
+ IPC_CREAT | IPC_EXCL | DEFAULT_PERMISSION);
+ if (shm->shm_id < 0) {
+
+ PFATAL("shmget() failed, try running afl-system-config");
+
+ }
+
+ if (shm->cmplog_mode) {
+
+ shm->cmplog_shm_id = shmget(IPC_PRIVATE, sizeof(struct cmp_map),
+ IPC_CREAT | IPC_EXCL | DEFAULT_PERMISSION);
+
+ if (shm->cmplog_shm_id < 0) {
+
+ shmctl(shm->shm_id, IPC_RMID, NULL); // do not leak shmem
+ PFATAL("shmget() failed, try running afl-system-config");
+
+ }
+
+ }
+
+ if (!non_instrumented_mode) {
+
+ shm_str = alloc_printf("%d", shm->shm_id);
+
+ /* If somebody is asking us to fuzz instrumented binaries in
+ non-instrumented mode, we don't want them to detect instrumentation,
+ since we won't be sending fork server commands. This should be replaced
+ with better auto-detection later on, perhaps? */
+
+ setenv(SHM_ENV_VAR, shm_str, 1);
+
+ ck_free(shm_str);
+
+ }
+
+ if (shm->cmplog_mode && !non_instrumented_mode) {
+
+ shm_str = alloc_printf("%d", shm->cmplog_shm_id);
+
+ setenv(CMPLOG_SHM_ENV_VAR, shm_str, 1);
+
+ ck_free(shm_str);
+
+ }
+
+ shm->map = shmat(shm->shm_id, NULL, 0);
+
+ if (shm->map == (void *)-1 || !shm->map) {
+
+ shmctl(shm->shm_id, IPC_RMID, NULL); // do not leak shmem
+
+ if (shm->cmplog_mode) {
+
+ shmctl(shm->cmplog_shm_id, IPC_RMID, NULL); // do not leak shmem
+
+ }
+
+ PFATAL("shmat() failed");
+
+ }
+
+ if (shm->cmplog_mode) {
+
+ shm->cmp_map = shmat(shm->cmplog_shm_id, NULL, 0);
+
+ if (shm->cmp_map == (void *)-1 || !shm->cmp_map) {
+
+ shmctl(shm->shm_id, IPC_RMID, NULL); // do not leak shmem
+
+ shmctl(shm->cmplog_shm_id, IPC_RMID, NULL); // do not leak shmem
+
+ PFATAL("shmat() failed");
+
+ }
+
+ }
+
+#endif
+
+ shm->map_size = map_size;
+ list_append(&shm_list, shm);
+
+ return shm->map;
+
+}
+
diff --git a/src/afl-showmap.c b/src/afl-showmap.c
new file mode 100644
index 00000000..3fdbe8fe
--- /dev/null
+++ b/src/afl-showmap.c
@@ -0,0 +1,1464 @@
+/*
+ american fuzzy lop++ - map display utility
+ ------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Forkserver design by Jann Horn <jannhorn@googlemail.com>
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Andrea Fioraldi <andreafioraldi@gmail.com> and
+ Dominik Maier <mail@dmnk.co>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ A very simple tool that runs the targeted binary and displays
+ the contents of the trace bitmap in a human-readable form. Useful in
+ scripts to eliminate redundant inputs and perform other checks.
+
+ Exit code is 2 if the target program crashes; 1 if it times out or
+ there is a problem executing it; or 0 if execution is successful.
+
+ */
+
+#define AFL_MAIN
+
+#include "config.h"
+#include "types.h"
+#include "debug.h"
+#include "alloc-inl.h"
+#include "hash.h"
+#include "sharedmem.h"
+#include "forkserver.h"
+#include "common.h"
+#include "hash.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <signal.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <limits.h>
+
+#include <dirent.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#ifndef USEMMAP
+ #include <sys/shm.h>
+#endif
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+
+static char *stdin_file; /* stdin file */
+
+static u8 *in_dir = NULL, /* input folder */
+ *out_file = NULL, *at_file = NULL; /* Substitution string for @@ */
+
+static u8 outfile[PATH_MAX];
+
+static u8 *in_data, /* Input data */
+ *coverage_map; /* Coverage map */
+
+static u64 total; /* tuple content information */
+static u32 tcnt, highest; /* tuple content information */
+
+static u32 in_len; /* Input data length */
+
+static u32 map_size = MAP_SIZE, timed_out = 0;
+
+static bool quiet_mode, /* Hide non-essential messages? */
+ edges_only, /* Ignore hit counts? */
+ raw_instr_output, /* Do not apply AFL filters */
+ cmin_mode, /* Generate output in afl-cmin mode? */
+ binary_mode, /* Write output as a binary map */
+ keep_cores, /* Allow coredumps? */
+ remove_shm = true, /* remove shmem? */
+ collect_coverage, /* collect coverage */
+ have_coverage, /* have coverage? */
+ no_classify, /* do not classify counts */
+ debug, /* debug mode */
+ print_filenames, /* print the current filename */
+ wait_for_gdb;
+
+static volatile u8 stop_soon, /* Ctrl-C pressed? */
+ child_crashed; /* Child crashed? */
+
+static sharedmem_t shm;
+static afl_forkserver_t *fsrv;
+static sharedmem_t * shm_fuzz;
+
+/* Classify tuple counts. Instead of mapping to individual bits, as in
+ afl-fuzz.c, we map to more user-friendly numbers between 1 and 8. */
+
+static const u8 count_class_human[256] = {
+
+ [0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4,
+ [8] = 5, [16] = 6, [32] = 7, [128] = 8
+
+};
+
+static const u8 count_class_binary[256] = {
+
+ [0] = 0,
+ [1] = 1,
+ [2] = 2,
+ [3] = 4,
+ [4 ... 7] = 8,
+ [8 ... 15] = 16,
+ [16 ... 31] = 32,
+ [32 ... 127] = 64,
+ [128 ... 255] = 128
+
+};
+
+static void kill_child() {
+
+ timed_out = 1;
+ if (fsrv->child_pid > 0) {
+
+ kill(fsrv->child_pid, fsrv->kill_signal);
+ fsrv->child_pid = -1;
+
+ }
+
+}
+
+static void classify_counts(afl_forkserver_t *fsrv) {
+
+ u8 * mem = fsrv->trace_bits;
+ const u8 *map = binary_mode ? count_class_binary : count_class_human;
+
+ u32 i = map_size;
+
+ if (edges_only) {
+
+ while (i--) {
+
+ if (*mem) { *mem = 1; }
+ mem++;
+
+ }
+
+ } else if (!raw_instr_output) {
+
+ while (i--) {
+
+ *mem = map[*mem];
+ mem++;
+
+ }
+
+ }
+
+}
+
+static sharedmem_t *deinit_shmem(afl_forkserver_t *fsrv,
+ sharedmem_t * shm_fuzz) {
+
+ afl_shm_deinit(shm_fuzz);
+ fsrv->support_shmem_fuzz = 0;
+ fsrv->shmem_fuzz_len = NULL;
+ fsrv->shmem_fuzz = NULL;
+ ck_free(shm_fuzz);
+ return NULL;
+
+}
+
+/* Get rid of temp files (atexit handler). */
+
+static void at_exit_handler(void) {
+
+ if (stdin_file) { unlink(stdin_file); }
+
+ if (remove_shm) {
+
+ if (shm.map) afl_shm_deinit(&shm);
+ if (fsrv->use_shmem_fuzz) deinit_shmem(fsrv, shm_fuzz);
+
+ }
+
+ afl_fsrv_killall();
+
+}
+
+/* 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) {
+
+ s32 fd;
+ u32 i, ret = 0;
+
+ u8 cco = !!getenv("AFL_CMIN_CRASHES_ONLY"),
+ caa = !!getenv("AFL_CMIN_ALLOW_ANY");
+
+ if (!outfile || !*outfile) {
+
+ FATAL("Output filename not set (Bug in AFL++?)");
+
+ }
+
+ if (cmin_mode &&
+ (fsrv->last_run_timed_out || (!caa && child_crashed != cco))) {
+
+ if (strcmp(outfile, "-")) {
+
+ // create empty file to prevent error messages in afl-cmin
+ fd = open(outfile, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
+ close(fd);
+
+ }
+
+ return ret;
+
+ }
+
+ if (!strncmp(outfile, "/dev/", 5)) {
+
+ fd = open(outfile, O_WRONLY);
+
+ if (fd < 0) { PFATAL("Unable to open '%s'", out_file); }
+
+ } else if (!strcmp(outfile, "-")) {
+
+ fd = dup(1);
+ if (fd < 0) { PFATAL("Unable to open stdout"); }
+
+ } else {
+
+ unlink(outfile); /* Ignore errors */
+ fd = open(outfile, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
+ if (fd < 0) { PFATAL("Unable to create '%s'", outfile); }
+
+ }
+
+ if (binary_mode) {
+
+ for (i = 0; i < map_size; i++) {
+
+ if (fsrv->trace_bits[i]) { ret++; }
+
+ }
+
+ ck_write(fd, fsrv->trace_bits, map_size, outfile);
+ close(fd);
+
+ } else {
+
+ FILE *f = fdopen(fd, "w");
+
+ if (!f) { PFATAL("fdopen() failed"); }
+
+ for (i = 0; i < map_size; i++) {
+
+ if (!fsrv->trace_bits[i]) { continue; }
+ ret++;
+
+ total += fsrv->trace_bits[i];
+ if (highest < fsrv->trace_bits[i]) { highest = fsrv->trace_bits[i]; }
+
+ if (cmin_mode) {
+
+ fprintf(f, "%u%u\n", fsrv->trace_bits[i], i);
+
+ } else {
+
+ fprintf(f, "%06u:%u\n", i, fsrv->trace_bits[i]);
+
+ }
+
+ }
+
+ fclose(f);
+
+ }
+
+ return ret;
+
+}
+
+/* Execute target application. */
+
+static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem,
+ u32 len) {
+
+ afl_fsrv_write_to_testcase(fsrv, mem, len);
+
+ if (!quiet_mode) { SAYF("-- Program output begins --\n" cRST); }
+
+ if (afl_fsrv_run_target(fsrv, fsrv->exec_tmout, &stop_soon) ==
+ FSRV_RUN_ERROR) {
+
+ FATAL("Error running target");
+
+ }
+
+ if (fsrv->trace_bits[0] == 1) {
+
+ fsrv->trace_bits[0] = 0;
+ have_coverage = true;
+
+ } else {
+
+ have_coverage = false;
+
+ }
+
+ if (!no_classify) { classify_counts(fsrv); }
+
+ if (!quiet_mode) { SAYF(cRST "-- Program output ends --\n"); }
+
+ if (!fsrv->last_run_timed_out && !stop_soon &&
+ WIFSIGNALED(fsrv->child_status)) {
+
+ child_crashed = true;
+
+ } else {
+
+ child_crashed = false;
+
+ }
+
+ if (!quiet_mode) {
+
+ if (timed_out || fsrv->last_run_timed_out) {
+
+ SAYF(cLRD "\n+++ Program timed off +++\n" cRST);
+ timed_out = 0;
+
+ } else if (stop_soon) {
+
+ SAYF(cLRD "\n+++ Program aborted by user +++\n" cRST);
+
+ } else if (child_crashed) {
+
+ SAYF(cLRD "\n+++ Program killed by signal %u +++\n" cRST,
+ WTERMSIG(fsrv->child_status));
+
+ }
+
+ }
+
+ if (stop_soon) {
+
+ SAYF(cRST cLRD "\n+++ afl-showmap folder mode aborted by user +++\n" cRST);
+ exit(1);
+
+ }
+
+}
+
+/* Read initial file. */
+
+static u32 read_file(u8 *in_file) {
+
+ if (print_filenames) {
+
+ SAYF("Processing %s\n", in_file);
+ fflush(stdout);
+
+ }
+
+ struct stat st;
+ s32 fd = open(in_file, O_RDONLY);
+
+ if (fd < 0) { WARNF("Unable to open '%s'", in_file); }
+
+ if (fstat(fd, &st) || !st.st_size) {
+
+ if (!be_quiet && !quiet_mode) {
+
+ WARNF("Zero-sized input file '%s'.", in_file);
+
+ }
+
+ }
+
+ if (st.st_size > MAX_FILE) {
+
+ if (!be_quiet && !quiet_mode) {
+
+ WARNF("Input file '%s' is too large, only reading %ld bytes.", in_file,
+ MAX_FILE);
+
+ }
+
+ in_len = MAX_FILE;
+
+ } else {
+
+ in_len = st.st_size;
+
+ }
+
+ in_data = ck_alloc_nozero(in_len);
+
+ ck_read(fd, in_data, in_len, in_file);
+
+ close(fd);
+
+ // OKF("Read %u byte%s from '%s'.", in_len, in_len == 1 ? "" : "s", in_file);
+
+ return in_len;
+
+}
+
+/* Execute target application. */
+
+static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) {
+
+ static struct itimerval it;
+ int status = 0;
+
+ if (!quiet_mode) { SAYF("-- Program output begins --\n" cRST); }
+
+ MEM_BARRIER();
+
+ fsrv->child_pid = fork();
+
+ if (fsrv->child_pid < 0) { PFATAL("fork() failed"); }
+
+ if (!fsrv->child_pid) {
+
+ struct rlimit r;
+
+ if (quiet_mode) {
+
+ s32 fd = open("/dev/null", O_RDWR);
+
+ if (fd < 0 || dup2(fd, 1) < 0 || dup2(fd, 2) < 0) {
+
+ *(u32 *)fsrv->trace_bits = EXEC_FAIL_SIG;
+ PFATAL("Descriptor initialization failed");
+
+ }
+
+ close(fd);
+
+ }
+
+ if (fsrv->mem_limit) {
+
+ r.rlim_max = r.rlim_cur = ((rlim_t)fsrv->mem_limit) << 20;
+
+#ifdef RLIMIT_AS
+
+ setrlimit(RLIMIT_AS, &r); /* Ignore errors */
+
+#else
+
+ setrlimit(RLIMIT_DATA, &r); /* Ignore errors */
+
+#endif /* ^RLIMIT_AS */
+
+ }
+
+ if (!keep_cores) {
+
+ r.rlim_max = r.rlim_cur = 0;
+
+ } else {
+
+ r.rlim_max = r.rlim_cur = RLIM_INFINITY;
+
+ }
+
+ setrlimit(RLIMIT_CORE, &r); /* Ignore errors */
+
+ if (!getenv("LD_BIND_LAZY")) { setenv("LD_BIND_NOW", "1", 0); }
+
+ setsid();
+
+ execv(fsrv->target_path, argv);
+
+ *(u32 *)fsrv->trace_bits = EXEC_FAIL_SIG;
+ exit(0);
+
+ }
+
+ /* Configure timeout, wait for child, cancel timeout. */
+
+ if (fsrv->exec_tmout) {
+
+ fsrv->last_run_timed_out = 0;
+ it.it_value.tv_sec = (fsrv->exec_tmout / 1000);
+ it.it_value.tv_usec = (fsrv->exec_tmout % 1000) * 1000;
+
+ }
+
+ signal(SIGALRM, kill_child);
+
+ setitimer(ITIMER_REAL, &it, NULL);
+
+ if (waitpid(fsrv->child_pid, &status, 0) <= 0) { FATAL("waitpid() failed"); }
+
+ fsrv->child_pid = 0;
+ it.it_value.tv_sec = 0;
+ it.it_value.tv_usec = 0;
+ setitimer(ITIMER_REAL, &it, NULL);
+
+ MEM_BARRIER();
+
+ /* Clean up bitmap, analyze exit condition, etc. */
+
+ if (*(u32 *)fsrv->trace_bits == EXEC_FAIL_SIG) {
+
+ FATAL("Unable to execute '%s'", argv[0]);
+
+ }
+
+ if (fsrv->trace_bits[0] == 1) {
+
+ fsrv->trace_bits[0] = 0;
+ have_coverage = true;
+
+ } else {
+
+ have_coverage = false;
+
+ }
+
+ if (!no_classify) { classify_counts(fsrv); }
+
+ if (!quiet_mode) { SAYF(cRST "-- Program output ends --\n"); }
+
+ if (!fsrv->last_run_timed_out && !stop_soon && WIFSIGNALED(status)) {
+
+ child_crashed = true;
+
+ }
+
+ if (!quiet_mode) {
+
+ if (timed_out || fsrv->last_run_timed_out) {
+
+ SAYF(cLRD "\n+++ Program timed off +++\n" cRST);
+ timed_out = 0;
+
+ } else if (stop_soon) {
+
+ SAYF(cLRD "\n+++ Program aborted by user +++\n" cRST);
+
+ } else if (child_crashed) {
+
+ SAYF(cLRD "\n+++ Program killed by signal %u +++\n" cRST,
+ WTERMSIG(status));
+
+ }
+
+ }
+
+}
+
+/* Handle Ctrl-C and the like. */
+
+static void handle_stop_sig(int sig) {
+
+ (void)sig;
+ stop_soon = true;
+ afl_fsrv_killall();
+
+}
+
+/* Do basic preparations - persistent fds, filenames, etc. */
+
+static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
+
+ char *afl_preload;
+ char *frida_afl_preload = NULL;
+ setenv("ASAN_OPTIONS",
+ "abort_on_error=1:"
+ "detect_leaks=0:"
+ "allocator_may_return_null=1:"
+ "symbolize=0:"
+ "detect_odr_violation=0:"
+ "handle_segv=0:"
+ "handle_sigbus=0:"
+ "handle_abort=0:"
+ "handle_sigfpe=0:"
+ "handle_sigill=0",
+ 0);
+
+ setenv("LSAN_OPTIONS",
+ "exitcode=" STRINGIFY(LSAN_ERROR) ":"
+ "fast_unwind_on_malloc=0:"
+ "symbolize=0:"
+ "print_suppressions=0",
+ 0);
+
+ setenv("UBSAN_OPTIONS",
+ "halt_on_error=1:"
+ "abort_on_error=1:"
+ "malloc_context_size=0:"
+ "allocator_may_return_null=1:"
+ "symbolize=0:"
+ "handle_segv=0:"
+ "handle_sigbus=0:"
+ "handle_abort=0:"
+ "handle_sigfpe=0:"
+ "handle_sigill=0",
+ 0);
+
+ setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":"
+ "abort_on_error=1:"
+ "msan_track_origins=0"
+ "allocator_may_return_null=1:"
+ "symbolize=0:"
+ "handle_segv=0:"
+ "handle_sigbus=0:"
+ "handle_abort=0:"
+ "handle_sigfpe=0:"
+ "handle_sigill=0", 0);
+
+ if (get_afl_env("AFL_PRELOAD")) {
+
+ if (fsrv->qemu_mode) {
+
+ /* afl-qemu-trace takes care of converting AFL_PRELOAD. */
+
+ } else if (fsrv->frida_mode) {
+
+ afl_preload = getenv("AFL_PRELOAD");
+ u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
+ if (afl_preload) {
+
+ frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
+
+ } else {
+
+ frida_afl_preload = alloc_printf("%s", frida_binary);
+
+ }
+
+ ck_free(frida_binary);
+
+ setenv("LD_PRELOAD", frida_afl_preload, 1);
+ setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
+
+ } else {
+
+ /* CoreSight mode uses the default behavior. */
+
+ setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
+ setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
+
+ }
+
+ } else if (fsrv->frida_mode) {
+
+ u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
+ setenv("LD_PRELOAD", frida_binary, 1);
+ setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
+ ck_free(frida_binary);
+
+ }
+
+ if (frida_afl_preload) { ck_free(frida_afl_preload); }
+
+}
+
+/* Setup signal handlers, duh. */
+
+static void setup_signal_handlers(void) {
+
+ struct sigaction sa;
+
+ sa.sa_handler = NULL;
+ sa.sa_flags = SA_RESTART;
+ sa.sa_sigaction = NULL;
+
+ sigemptyset(&sa.sa_mask);
+
+ /* Various ways of saying "stop". */
+
+ sa.sa_handler = handle_stop_sig;
+ sigaction(SIGHUP, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGTERM, &sa, NULL);
+
+}
+
+u32 execute_testcases(u8 *dir) {
+
+ struct dirent **nl;
+ s32 nl_cnt, subdirs = 1;
+ u32 i, done = 0;
+ u8 val_buf[2][STRINGIFY_VAL_SIZE_MAX];
+
+ if (!be_quiet) { ACTF("Scanning '%s'...", dir); }
+
+ /* We use scandir() + alphasort() rather than readdir() because otherwise,
+ the ordering of test cases would vary somewhat randomly and would be
+ difficult to control. */
+
+ nl_cnt = scandir(dir, &nl, NULL, alphasort);
+
+ if (nl_cnt < 0) { return 0; }
+
+ for (i = 0; i < (u32)nl_cnt; ++i) {
+
+ struct stat st;
+
+ u8 *fn2 = alloc_printf("%s/%s", dir, nl[i]->d_name);
+
+ if (lstat(fn2, &st) || access(fn2, R_OK)) {
+
+ PFATAL("Unable to access '%s'", fn2);
+
+ }
+
+ /* obviously we want to skip "descending" into . and .. directories,
+ however it is a good idea to skip also directories that start with
+ a dot */
+ if (subdirs && S_ISDIR(st.st_mode) && nl[i]->d_name[0] != '.') {
+
+ free(nl[i]); /* not tracked */
+ done += execute_testcases(fn2);
+ ck_free(fn2);
+ continue;
+
+ }
+
+ if (!S_ISREG(st.st_mode) || !st.st_size) {
+
+ free(nl[i]);
+ ck_free(fn2);
+ continue;
+
+ }
+
+ if (st.st_size > MAX_FILE && !be_quiet && !quiet_mode) {
+
+ WARNF("Test case '%s' is too big (%s, limit is %s), partial reading", fn2,
+ stringify_mem_size(val_buf[0], sizeof(val_buf[0]), st.st_size),
+ stringify_mem_size(val_buf[1], sizeof(val_buf[1]), MAX_FILE));
+
+ }
+
+ if (!collect_coverage)
+ snprintf(outfile, sizeof(outfile), "%s/%s", out_file, nl[i]->d_name);
+
+ free(nl[i]);
+
+ if (read_file(fn2)) {
+
+ if (wait_for_gdb) {
+
+ fprintf(stderr, "exec: gdb -p %d\n", fsrv->child_pid);
+ fprintf(stderr, "exec: kill -CONT %d\n", getpid());
+ kill(0, SIGSTOP);
+
+ }
+
+ showmap_run_target_forkserver(fsrv, in_data, in_len);
+ ck_free(in_data);
+ ++done;
+
+ if (collect_coverage)
+ analyze_results(fsrv);
+ else
+ tcnt = write_results_to_file(fsrv, outfile);
+
+ }
+
+ }
+
+ free(nl); /* not tracked */
+ return done;
+
+}
+
+/* Show banner. */
+
+static void show_banner(void) {
+
+ SAYF(cCYA "afl-showmap" VERSION cRST " by Michal Zalewski\n");
+
+}
+
+/* Display usage hints. */
+
+static void usage(u8 *argv0) {
+
+ show_banner();
+
+ SAYF(
+ "\n%s [ options ] -- /path/to/target_app [ ... ]\n\n"
+
+ "Required parameters:\n"
+ " -o file - file to write the trace data to\n\n"
+
+ "Execution control settings:\n"
+ " -t msec - timeout for each run (none)\n"
+ " -m megs - memory limit for child process (%u MB)\n"
+#if defined(__linux__) && defined(__aarch64__)
+ " -A - use binary-only instrumentation (ARM CoreSight mode)\n"
+#endif
+ " -O - use binary-only instrumentation (FRIDA mode)\n"
+#if defined(__linux__)
+ " -Q - use binary-only instrumentation (QEMU mode)\n"
+ " -U - use Unicorn-based instrumentation (Unicorn mode)\n"
+ " -W - use qemu-based instrumentation with Wine (Wine mode)\n"
+ " (Not necessary, here for consistency with other afl-* "
+ "tools)\n"
+#endif
+ "\n"
+ "Other settings:\n"
+ " -i dir - process all files below 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"
+ " -s - do not classify the map\n"
+ " -c - allow core dumps\n\n"
+
+ "This tool displays raw tuple data captured by AFL instrumentation.\n"
+ "For additional help, consult %s/README.md.\n\n"
+
+ "Environment variables used:\n"
+ "LD_BIND_LAZY: do not set LD_BIND_NOW env var for target\n"
+ "AFL_CMIN_CRASHES_ONLY: (cmin_mode) only write tuples for crashing "
+ "inputs\n"
+ "AFL_CMIN_ALLOW_ANY: (cmin_mode) write tuples for crashing inputs also\n"
+ "AFL_CRASH_EXITCODE: optional child exit code to be interpreted as "
+ "crash\n"
+ "AFL_DEBUG: enable extra developer output\n"
+ "AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during "
+ "startup (in milliseconds)\n"
+ "AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, "
+ "etc. (default: SIGKILL)\n"
+ "AFL_MAP_SIZE: the shared memory size for that target. must be >= the "
+ "size the target was compiled for\n"
+ "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
+ "AFL_PRINT_FILENAMES: If set, the filename currently processed will be "
+ "printed to stdout\n"
+ "AFL_QUIET: do not print extra informational output\n"
+ "AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n",
+ argv0, MEM_LIMIT, doc_path);
+
+ exit(1);
+
+}
+
+/* Main entry point */
+
+int main(int argc, char **argv_orig, char **envp) {
+
+ // TODO: u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */
+
+ s32 opt, i;
+ bool mem_limit_given = false, timeout_given = false, unicorn_mode = false,
+ use_wine = false;
+ char **use_argv;
+
+ char **argv = argv_cpy_dup(argc, argv_orig);
+
+ afl_forkserver_t fsrv_var = {0};
+ if (getenv("AFL_DEBUG")) { debug = true; }
+ if (get_afl_env("AFL_PRINT_FILENAMES")) { print_filenames = true; }
+
+ fsrv = &fsrv_var;
+ afl_fsrv_init(fsrv);
+ map_size = get_map_size();
+ fsrv->map_size = map_size;
+
+ doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
+
+ if (getenv("AFL_QUIET") != NULL) { be_quiet = true; }
+
+ while ((opt = getopt(argc, argv, "+i:o:f:m:t:AeqCZOH:QUWbcrsh")) > 0) {
+
+ switch (opt) {
+
+ case 's':
+ no_classify = true;
+ break;
+
+ case 'C':
+ collect_coverage = true;
+ quiet_mode = true;
+ break;
+
+ case 'i':
+ if (in_dir) { FATAL("Multiple -i options not supported"); }
+ in_dir = optarg;
+ break;
+
+ case 'o':
+
+ if (out_file) { FATAL("Multiple -o options not supported"); }
+ out_file = optarg;
+ break;
+
+ case 'm': {
+
+ u8 suffix = 'M';
+
+ if (mem_limit_given) { FATAL("Multiple -m options not supported"); }
+ mem_limit_given = true;
+
+ if (!optarg) { FATAL("Wrong usage of -m"); }
+
+ if (!strcmp(optarg, "none")) {
+
+ fsrv->mem_limit = 0;
+ break;
+
+ }
+
+ if (sscanf(optarg, "%llu%c", &fsrv->mem_limit, &suffix) < 1 ||
+ optarg[0] == '-') {
+
+ FATAL("Bad syntax used for -m");
+
+ }
+
+ switch (suffix) {
+
+ case 'T':
+ fsrv->mem_limit *= 1024 * 1024;
+ break;
+ case 'G':
+ fsrv->mem_limit *= 1024;
+ break;
+ case 'k':
+ fsrv->mem_limit /= 1024;
+ break;
+ case 'M':
+ break;
+
+ default:
+ FATAL("Unsupported suffix or bad syntax for -m");
+
+ }
+
+ if (fsrv->mem_limit < 5) { FATAL("Dangerously low value of -m"); }
+
+ if (sizeof(rlim_t) == 4 && fsrv->mem_limit > 2000) {
+
+ FATAL("Value of -m out of range on 32-bit systems");
+
+ }
+
+ }
+
+ break;
+
+ case 'f': // only in here to avoid a compiler warning for use_stdin
+
+ FATAL("Option -f is not supported in afl-showmap");
+ // currently not reached:
+ fsrv->use_stdin = 0;
+ fsrv->out_file = strdup(optarg);
+
+ break;
+
+ case 't':
+
+ if (timeout_given) { FATAL("Multiple -t options not supported"); }
+ timeout_given = true;
+
+ if (!optarg) { FATAL("Wrong usage of -t"); }
+
+ if (strcmp(optarg, "none")) {
+
+ fsrv->exec_tmout = atoi(optarg);
+
+ if (fsrv->exec_tmout < 20 || optarg[0] == '-') {
+
+ FATAL("Dangerously low value of -t");
+
+ }
+
+ }
+
+ break;
+
+ case 'e':
+
+ if (edges_only) { FATAL("Multiple -e options not supported"); }
+ if (raw_instr_output) { FATAL("-e and -r are mutually exclusive"); }
+ edges_only = true;
+ break;
+
+ case 'q':
+
+ quiet_mode = true;
+ break;
+
+ case 'Z':
+
+ /* This is an undocumented option to write data in the syntax expected
+ by afl-cmin. Nobody else should have any use for this. */
+
+ cmin_mode = true;
+ quiet_mode = true;
+ break;
+
+ case 'H':
+ /* Another afl-cmin specific feature. */
+ at_file = optarg;
+ break;
+
+ case 'O': /* FRIDA mode */
+
+ if (fsrv->frida_mode) { FATAL("Multiple -O options not supported"); }
+
+ fsrv->frida_mode = true;
+ setenv("AFL_FRIDA_INST_SEED", "1", 1);
+
+ break;
+
+ /* FIXME: We want to use -P for consistency, but it is already unsed for
+ * undocumenetd feature "Another afl-cmin specific feature." */
+ case 'A': /* CoreSight mode */
+
+#if !defined(__aarch64__) || !defined(__linux__)
+ FATAL("-A option is not supported on this platform");
+#endif
+
+ if (fsrv->cs_mode) { FATAL("Multiple -A options not supported"); }
+
+ fsrv->cs_mode = true;
+ break;
+
+ case 'Q':
+
+ if (fsrv->qemu_mode) { FATAL("Multiple -Q options not supported"); }
+
+ fsrv->qemu_mode = true;
+ break;
+
+ case 'U':
+
+ if (unicorn_mode) { FATAL("Multiple -U options not supported"); }
+
+ unicorn_mode = true;
+ break;
+
+ case 'W': /* Wine+QEMU mode */
+
+ if (use_wine) { FATAL("Multiple -W options not supported"); }
+ fsrv->qemu_mode = true;
+ use_wine = true;
+
+ break;
+
+ case 'b':
+
+ /* Secret undocumented mode. Writes output in raw binary format
+ similar to that dumped by afl-fuzz in <out_dir/queue/fuzz_bitmap. */
+
+ binary_mode = true;
+ break;
+
+ case 'c':
+
+ if (keep_cores) { FATAL("Multiple -c options not supported"); }
+ keep_cores = true;
+ break;
+
+ case 'r':
+
+ if (raw_instr_output) { FATAL("Multiple -r options not supported"); }
+ if (edges_only) { FATAL("-e and -r are mutually exclusive"); }
+ raw_instr_output = true;
+ break;
+
+ case 'h':
+ usage(argv[0]);
+ return -1;
+ break;
+
+ default:
+ usage(argv[0]);
+
+ }
+
+ }
+
+ 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; }
+
+ check_environment_vars(envp);
+
+ if (getenv("AFL_NO_FORKSRV")) { /* if set, use the fauxserver */
+ fsrv->use_fauxsrv = true;
+
+ }
+
+ if (getenv("AFL_DEBUG")) {
+
+ DEBUGF("");
+ for (i = 0; i < argc; i++)
+ SAYF(" %s", argv[i]);
+ SAYF("\n");
+
+ }
+
+ // if (afl->shmem_testcase_mode) { setup_testcase_shmem(afl); }
+
+ setenv("AFL_NO_AUTODICT", "1", 1);
+
+ /* initialize cmplog_mode */
+ shm.cmplog_mode = 0;
+ setup_signal_handlers();
+
+ set_up_environment(fsrv, argv);
+
+ fsrv->target_path = find_binary(argv[optind]);
+ fsrv->trace_bits = afl_shm_init(&shm, map_size, 0);
+
+ if (!quiet_mode) {
+
+ show_banner();
+ ACTF("Executing '%s'...", fsrv->target_path);
+
+ }
+
+ if (in_dir) {
+
+ /* If we don't have a file name chosen yet, use a safe default. */
+ u8 *use_dir = ".";
+
+ if (access(use_dir, R_OK | W_OK | X_OK)) {
+
+ use_dir = get_afl_env("TMPDIR");
+ if (!use_dir) { use_dir = "/tmp"; }
+
+ }
+
+ stdin_file = at_file ? strdup(at_file)
+ : (char *)alloc_printf("%s/.afl-showmap-temp-%u",
+ use_dir, (u32)getpid());
+ unlink(stdin_file);
+
+ // If @@ are in the target args, replace them and also set use_stdin=false.
+ detect_file_args(argv + optind, stdin_file, &fsrv->use_stdin);
+
+ } else {
+
+ // If @@ are in the target args, replace them and also set use_stdin=false.
+ detect_file_args(argv + optind, at_file, &fsrv->use_stdin);
+
+ }
+
+ if (fsrv->qemu_mode) {
+
+ if (use_wine) {
+
+ use_argv = get_wine_argv(argv[0], &fsrv->target_path, argc - optind,
+ argv + optind);
+
+ } else {
+
+ use_argv = get_qemu_argv(argv[0], &fsrv->target_path, argc - optind,
+ argv + optind);
+
+ }
+
+ } else if (fsrv->cs_mode) {
+
+ use_argv =
+ get_cs_argv(argv[0], &fsrv->target_path, argc - optind, argv + optind);
+
+ } else {
+
+ use_argv = argv + optind;
+
+ }
+
+ if (in_dir) { (void)check_binary_signatures(fsrv->target_path); }
+
+ shm_fuzz = ck_alloc(sizeof(sharedmem_t));
+
+ /* initialize cmplog_mode */
+ shm_fuzz->cmplog_mode = 0;
+ u8 *map = afl_shm_init(shm_fuzz, MAX_FILE + sizeof(u32), 1);
+ shm_fuzz->shmemfuzz_mode = true;
+ if (!map) { FATAL("BUG: Zero return from afl_shm_init."); }
+#ifdef USEMMAP
+ setenv(SHM_FUZZ_ENV_VAR, shm_fuzz->g_shm_file_path, 1);
+#else
+ u8 *shm_str = alloc_printf("%d", shm_fuzz->shm_id);
+ setenv(SHM_FUZZ_ENV_VAR, shm_str, 1);
+ ck_free(shm_str);
+#endif
+ fsrv->support_shmem_fuzz = true;
+ fsrv->shmem_fuzz_len = (u32 *)map;
+ fsrv->shmem_fuzz = map + sizeof(u32);
+
+ if (!fsrv->cs_mode && !fsrv->qemu_mode && !unicorn_mode) {
+
+ u32 save_be_quiet = be_quiet;
+ be_quiet = !debug;
+ fsrv->map_size = 4194304; // dummy temporary value
+ u32 new_map_size =
+ afl_fsrv_get_mapsize(fsrv, use_argv, &stop_soon,
+ (get_afl_env("AFL_DEBUG_CHILD") ||
+ get_afl_env("AFL_DEBUG_CHILD_OUTPUT"))
+ ? 1
+ : 0);
+ be_quiet = save_be_quiet;
+
+ fsrv->kill_signal =
+ parse_afl_kill_signal_env(getenv("AFL_KILL_SIGNAL"), SIGKILL);
+
+ if (new_map_size) {
+
+ // only reinitialize when it makes sense
+ if (map_size < new_map_size ||
+ (new_map_size > map_size && new_map_size - map_size > MAP_SIZE)) {
+
+ if (!be_quiet)
+ ACTF("Aquired new map size for target: %u bytes\n", new_map_size);
+
+ afl_shm_deinit(&shm);
+ afl_fsrv_kill(fsrv);
+ fsrv->map_size = new_map_size;
+ fsrv->trace_bits = afl_shm_init(&shm, new_map_size, 0);
+
+ }
+
+ map_size = new_map_size;
+
+ }
+
+ fsrv->map_size = map_size;
+
+ }
+
+ if (in_dir) {
+
+ DIR *dir_in, *dir_out = NULL;
+
+ if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = true;
+
+ fsrv->dev_null_fd = open("/dev/null", O_RDWR);
+ if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
+
+ // 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 (!collect_coverage) {
+
+ if (!(dir_out = opendir(out_file))) {
+
+ if (mkdir(out_file, 0700)) {
+
+ PFATAL("cannot create output directory %s", out_file);
+
+ }
+
+ }
+
+ } else {
+
+ if ((coverage_map = (u8 *)malloc(map_size + 64)) == NULL)
+ FATAL("coult not grab memory");
+ edges_only = false;
+ raw_instr_output = true;
+
+ }
+
+ atexit(at_exit_handler);
+ fsrv->out_file = stdin_file;
+ fsrv->out_fd =
+ open(stdin_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
+ if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", out_file); }
+
+ if (get_afl_env("AFL_DEBUG")) {
+
+ int j = optind;
+ DEBUGF("%s:", fsrv->target_path);
+ while (argv[j] != NULL) {
+
+ SAYF(" \"%s\"", argv[j++]);
+
+ }
+
+ SAYF("\n");
+
+ }
+
+ if (getenv("AFL_FORKSRV_INIT_TMOUT")) {
+
+ s32 forksrv_init_tmout = atoi(getenv("AFL_FORKSRV_INIT_TMOUT"));
+ if (forksrv_init_tmout < 1) {
+
+ FATAL("Bad value specified for AFL_FORKSRV_INIT_TMOUT");
+
+ }
+
+ fsrv->init_tmout = (u32)forksrv_init_tmout;
+
+ }
+
+ if (getenv("AFL_CRASH_EXITCODE")) {
+
+ long exitcode = strtol(getenv("AFL_CRASH_EXITCODE"), NULL, 10);
+ if ((!exitcode && (errno == EINVAL || errno == ERANGE)) ||
+ exitcode < -127 || exitcode > 128) {
+
+ FATAL("Invalid crash exitcode, expected -127 to 128, but got %s",
+ getenv("AFL_CRASH_EXITCODE"));
+
+ }
+
+ fsrv->uses_crash_exitcode = true;
+ // WEXITSTATUS is 8 bit unsigned
+ fsrv->crash_exitcode = (u8)exitcode;
+
+ }
+
+ afl_fsrv_start(fsrv, use_argv, &stop_soon,
+ (get_afl_env("AFL_DEBUG_CHILD") ||
+ 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);
+
+ if (execute_testcases(in_dir) == 0) {
+
+ FATAL("could not read input testcases from %s", in_dir);
+
+ }
+
+ if (!quiet_mode) { OKF("Processed %llu input files.", fsrv->total_execs); }
+
+ 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)
+ shm_fuzz = deinit_shmem(fsrv, shm_fuzz);
+
+ showmap_run_target(fsrv, use_argv);
+ tcnt = write_results_to_file(fsrv, out_file);
+ if (!quiet_mode) {
+
+ OKF("Hash of coverage map: %llx",
+ hash64(fsrv->trace_bits, fsrv->map_size, HASH_CONST));
+
+ }
+
+ }
+
+ if (!quiet_mode || collect_coverage) {
+
+ if (!tcnt && !have_coverage) { FATAL("No instrumentation detected" cRST); }
+ OKF("Captured %u tuples (map size %u, highest value %u, total values %llu) "
+ "in '%s'." cRST,
+ tcnt, fsrv->real_map_size, 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);
+
+ }
+
+ if (stdin_file) {
+
+ unlink(stdin_file);
+ ck_free(stdin_file);
+ stdin_file = NULL;
+
+ }
+
+ remove_shm = 0;
+ afl_shm_deinit(&shm);
+ if (fsrv->use_shmem_fuzz) shm_fuzz = deinit_shmem(fsrv, shm_fuzz);
+
+ u32 ret;
+
+ if (cmin_mode && !!getenv("AFL_CMIN_CRASHES_ONLY")) {
+
+ ret = fsrv->last_run_timed_out;
+
+ } else {
+
+ ret = child_crashed * 2 + fsrv->last_run_timed_out;
+
+ }
+
+ if (fsrv->target_path) { ck_free(fsrv->target_path); }
+
+ afl_fsrv_deinit(fsrv);
+
+ if (stdin_file) { ck_free(stdin_file); }
+ if (collect_coverage) { free(coverage_map); }
+
+ argv_cpy_free(argv);
+ if (fsrv->qemu_mode) { free(use_argv[2]); }
+
+ exit(ret);
+
+}
+
diff --git a/src/afl-tmin.c b/src/afl-tmin.c
new file mode 100644
index 00000000..1bf4af38
--- /dev/null
+++ b/src/afl-tmin.c
@@ -0,0 +1,1354 @@
+/*
+ american fuzzy lop++ - test case minimizer
+ ------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Forkserver design by Jann Horn <jannhorn@googlemail.com>
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Andrea Fioraldi <andreafioraldi@gmail.com> and
+ Dominik Maier <mail@dmnk.co>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ A simple test case minimizer that takes an input file and tries to remove
+ as much data as possible while keeping the binary in a crashing state
+ *or* producing consistent instrumentation output (the mode is auto-selected
+ based on the initially observed behavior).
+
+ */
+
+#define AFL_MAIN
+
+#include "config.h"
+#include "types.h"
+#include "debug.h"
+#include "alloc-inl.h"
+#include "hash.h"
+#include "forkserver.h"
+#include "sharedmem.h"
+#include "common.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <signal.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <limits.h>
+
+#include <sys/wait.h>
+#include <sys/time.h>
+#ifndef USEMMAP
+ #include <sys/shm.h>
+#endif
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+
+static u8 *mask_bitmap; /* Mask for trace bits (-B) */
+
+static u8 *in_file, /* Minimizer input test case */
+ *out_file, *output_file; /* Minimizer output file */
+
+static u8 *in_data; /* Input data for trimming */
+
+static u32 in_len, /* Input data length */
+ missed_hangs, /* Misses due to hangs */
+ missed_crashes, /* Misses due to crashes */
+ missed_paths, /* Misses due to exec path diffs */
+ map_size = MAP_SIZE;
+
+static u64 orig_cksum; /* Original checksum */
+
+static u8 crash_mode, /* Crash-centric mode? */
+ hang_mode, /* Minimize as long as it hangs */
+ exit_crash, /* Treat non-zero exit as crash? */
+ edges_only, /* Ignore hit counts? */
+ exact_mode, /* Require path match for crashes? */
+ remove_out_file, /* remove out_file on exit? */
+ remove_shm = 1, /* remove shmem on exit? */
+ debug; /* debug mode */
+
+static volatile u8 stop_soon; /* Ctrl-C pressed? */
+
+static afl_forkserver_t *fsrv;
+static sharedmem_t shm;
+static sharedmem_t * shm_fuzz;
+
+/*
+ * forkserver section
+ */
+
+/* Classify tuple counts. This is a slow & naive version, but good enough here.
+ */
+
+static const u8 count_class_lookup[256] = {
+
+ [0] = 0,
+ [1] = 1,
+ [2] = 2,
+ [3] = 4,
+ [4 ... 7] = 8,
+ [8 ... 15] = 16,
+ [16 ... 31] = 32,
+ [32 ... 127] = 64,
+ [128 ... 255] = 128
+
+};
+
+static void kill_child() {
+
+ if (fsrv->child_pid > 0) {
+
+ kill(fsrv->child_pid, fsrv->kill_signal);
+ fsrv->child_pid = -1;
+
+ }
+
+}
+
+static sharedmem_t *deinit_shmem(afl_forkserver_t *fsrv,
+ sharedmem_t * shm_fuzz) {
+
+ afl_shm_deinit(shm_fuzz);
+ fsrv->support_shmem_fuzz = 0;
+ fsrv->shmem_fuzz_len = NULL;
+ fsrv->shmem_fuzz = NULL;
+ ck_free(shm_fuzz);
+ return NULL;
+
+}
+
+/* Apply mask to classified bitmap (if set). */
+
+static void apply_mask(u32 *mem, u32 *mask) {
+
+ u32 i = (map_size >> 2);
+
+ if (!mask) { return; }
+
+ while (i--) {
+
+ *mem &= ~*mask;
+ mem++;
+ mask++;
+
+ }
+
+}
+
+static void classify_counts(afl_forkserver_t *fsrv) {
+
+ u8 *mem = fsrv->trace_bits;
+ u32 i = map_size;
+
+ if (edges_only) {
+
+ while (i--) {
+
+ if (*mem) { *mem = 1; }
+ mem++;
+
+ }
+
+ } else {
+
+ while (i--) {
+
+ *mem = count_class_lookup[*mem];
+ mem++;
+
+ }
+
+ }
+
+}
+
+/* See if any bytes are set in the bitmap. */
+
+static inline u8 anything_set(afl_forkserver_t *fsrv) {
+
+ u32 *ptr = (u32 *)fsrv->trace_bits;
+ u32 i = (map_size >> 2);
+
+ while (i--) {
+
+ if (*(ptr++)) { return 1; }
+
+ }
+
+ return 0;
+
+}
+
+static void at_exit_handler(void) {
+
+ if (remove_shm) {
+
+ if (shm.map) afl_shm_deinit(&shm);
+ if (fsrv->use_shmem_fuzz) deinit_shmem(fsrv, shm_fuzz);
+
+ }
+
+ afl_fsrv_killall();
+ if (remove_out_file) unlink(out_file);
+
+}
+
+/* Read initial file. */
+
+static void read_initial_file(void) {
+
+ struct stat st;
+ s32 fd = open(in_file, O_RDONLY);
+
+ if (fd < 0) { PFATAL("Unable to open '%s'", in_file); }
+
+ if (fstat(fd, &st) || !st.st_size) { FATAL("Zero-sized input file."); }
+
+ if (st.st_size >= TMIN_MAX_FILE) {
+
+ FATAL("Input file is too large (%ld MB max)", TMIN_MAX_FILE / 1024 / 1024);
+
+ }
+
+ in_len = st.st_size;
+ in_data = ck_alloc_nozero(in_len);
+
+ ck_read(fd, in_data, in_len, in_file);
+
+ close(fd);
+
+ OKF("Read %u byte%s from '%s'.", in_len, in_len == 1 ? "" : "s", in_file);
+
+}
+
+/* Write output file. */
+
+static s32 write_to_file(u8 *path, u8 *mem, u32 len) {
+
+ s32 ret;
+
+ unlink(path); /* Ignore errors */
+
+ ret = open(path, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
+
+ if (ret < 0) { PFATAL("Unable to create '%s'", path); }
+
+ ck_write(ret, mem, len, path);
+
+ lseek(ret, 0, SEEK_SET);
+
+ return ret;
+
+}
+
+/* Execute target application. Returns 0 if the changes are a dud, or
+ 1 if they should be kept. */
+
+static u8 tmin_run_target(afl_forkserver_t *fsrv, u8 *mem, u32 len,
+ u8 first_run) {
+
+ afl_fsrv_write_to_testcase(fsrv, mem, len);
+
+ fsrv_run_result_t ret =
+ afl_fsrv_run_target(fsrv, fsrv->exec_tmout, &stop_soon);
+
+ if (ret == FSRV_RUN_ERROR) { FATAL("Couldn't run child"); }
+
+ if (stop_soon) {
+
+ SAYF(cRST cLRD "\n+++ Minimization aborted by user +++\n" cRST);
+ close(write_to_file(output_file, in_data, in_len));
+ exit(1);
+
+ }
+
+ /* Always discard inputs that time out, unless we are in hang mode */
+
+ if (hang_mode) {
+
+ switch (ret) {
+
+ case FSRV_RUN_TMOUT:
+ return 1;
+ case FSRV_RUN_CRASH:
+ missed_crashes++;
+ return 0;
+ default:
+ missed_hangs++;
+ return 0;
+
+ }
+
+ }
+
+ classify_counts(fsrv);
+ apply_mask((u32 *)fsrv->trace_bits, (u32 *)mask_bitmap);
+
+ if (ret == FSRV_RUN_TMOUT) {
+
+ missed_hangs++;
+ return 0;
+
+ }
+
+ /* Handle crashing inputs depending on current mode. */
+
+ if (ret == FSRV_RUN_CRASH) {
+
+ if (first_run) { crash_mode = 1; }
+
+ if (crash_mode) {
+
+ if (!exact_mode) { return 1; }
+
+ } else {
+
+ missed_crashes++;
+ return 0;
+
+ }
+
+ } else {
+
+ /* Handle non-crashing inputs appropriately. */
+
+ if (crash_mode) {
+
+ missed_paths++;
+ return 0;
+
+ }
+
+ }
+
+ if (ret == FSRV_RUN_NOINST) { FATAL("Binary not instrumented?"); }
+
+ u64 cksum = hash64(fsrv->trace_bits, fsrv->map_size, HASH_CONST);
+
+ if (first_run) { orig_cksum = cksum; }
+
+ if (orig_cksum == cksum) { return 1; }
+
+ missed_paths++;
+ return 0;
+
+}
+
+/* Actually minimize! */
+
+static void minimize(afl_forkserver_t *fsrv) {
+
+ static u32 alpha_map[256];
+
+ u8 *tmp_buf = ck_alloc_nozero(in_len);
+ u32 orig_len = in_len, stage_o_len;
+
+ u32 del_len, set_len, del_pos, set_pos, i, alpha_size, cur_pass = 0;
+ u32 syms_removed, alpha_del0 = 0, alpha_del1, alpha_del2, alpha_d_total = 0;
+ u8 changed_any, prev_del;
+
+ /***********************
+ * BLOCK NORMALIZATION *
+ ***********************/
+
+ set_len = next_pow2(in_len / TMIN_SET_STEPS);
+ set_pos = 0;
+
+ if (set_len < TMIN_SET_MIN_SIZE) { set_len = TMIN_SET_MIN_SIZE; }
+
+ ACTF(cBRI "Stage #0: " cRST "One-time block normalization...");
+
+ while (set_pos < in_len) {
+
+ u32 use_len = MIN(set_len, in_len - set_pos);
+
+ for (i = 0; i < use_len; i++) {
+
+ if (in_data[set_pos + i] != '0') { break; }
+
+ }
+
+ if (i != use_len) {
+
+ memcpy(tmp_buf, in_data, in_len);
+ memset(tmp_buf + set_pos, '0', use_len);
+
+ u8 res;
+ res = tmin_run_target(fsrv, tmp_buf, in_len, 0);
+
+ if (res) {
+
+ memset(in_data + set_pos, '0', use_len);
+ /* changed_any = 1; value is not used */
+ alpha_del0 += use_len;
+
+ }
+
+ }
+
+ set_pos += set_len;
+
+ }
+
+ alpha_d_total += alpha_del0;
+
+ OKF("Block normalization complete, %u byte%s replaced.", alpha_del0,
+ alpha_del0 == 1 ? "" : "s");
+
+next_pass:
+
+ ACTF(cYEL "--- " cBRI "Pass #%u " cYEL "---", ++cur_pass);
+ changed_any = 0;
+
+ /******************
+ * BLOCK DELETION *
+ ******************/
+
+ del_len = next_pow2(in_len / TRIM_START_STEPS);
+ stage_o_len = in_len;
+
+ ACTF(cBRI "Stage #1: " cRST "Removing blocks of data...");
+
+next_del_blksize:
+
+ if (!del_len) { del_len = 1; }
+ del_pos = 0;
+ prev_del = 1;
+
+ SAYF(cGRA " Block length = %u, remaining size = %u\n" cRST, del_len,
+ in_len);
+
+ while (del_pos < in_len) {
+
+ u8 res;
+ s32 tail_len;
+
+ tail_len = in_len - del_pos - del_len;
+ if (tail_len < 0) { tail_len = 0; }
+
+ /* If we have processed at least one full block (initially, prev_del == 1),
+ and we did so without deleting the previous one, and we aren't at the
+ very end of the buffer (tail_len > 0), and the current block is the same
+ as the previous one... skip this step as a no-op. */
+
+ if (!prev_del && tail_len &&
+ !memcmp(in_data + del_pos - del_len, in_data + del_pos, del_len)) {
+
+ del_pos += del_len;
+ continue;
+
+ }
+
+ prev_del = 0;
+
+ /* Head */
+ memcpy(tmp_buf, in_data, del_pos);
+
+ /* Tail */
+ memcpy(tmp_buf + del_pos, in_data + del_pos + del_len, tail_len);
+
+ res = tmin_run_target(fsrv, tmp_buf, del_pos + tail_len, 0);
+
+ if (res) {
+
+ memcpy(in_data, tmp_buf, del_pos + tail_len);
+ prev_del = 1;
+ in_len = del_pos + tail_len;
+
+ changed_any = 1;
+
+ } else {
+
+ del_pos += del_len;
+
+ }
+
+ }
+
+ if (del_len > 1 && in_len >= 1) {
+
+ del_len /= 2;
+ goto next_del_blksize;
+
+ }
+
+ OKF("Block removal complete, %u bytes deleted.", stage_o_len - in_len);
+
+ if (!in_len && changed_any) {
+
+ WARNF(cLRD
+ "Down to zero bytes - check the command line and mem limit!" cRST);
+
+ }
+
+ if (cur_pass > 1 && !changed_any) { goto finalize_all; }
+
+ /*************************
+ * ALPHABET MINIMIZATION *
+ *************************/
+
+ alpha_size = 0;
+ alpha_del1 = 0;
+ syms_removed = 0;
+
+ memset(alpha_map, 0, sizeof(alpha_map));
+
+ for (i = 0; i < in_len; i++) {
+
+ if (!alpha_map[in_data[i]]) { alpha_size++; }
+ alpha_map[in_data[i]]++;
+
+ }
+
+ ACTF(cBRI "Stage #2: " cRST "Minimizing symbols (%u code point%s)...",
+ alpha_size, alpha_size == 1 ? "" : "s");
+
+ for (i = 0; i < 256; i++) {
+
+ u32 r;
+ u8 res;
+
+ if (i == '0' || !alpha_map[i]) { continue; }
+
+ memcpy(tmp_buf, in_data, in_len);
+
+ for (r = 0; r < in_len; r++) {
+
+ if (tmp_buf[r] == i) { tmp_buf[r] = '0'; }
+
+ }
+
+ res = tmin_run_target(fsrv, tmp_buf, in_len, 0);
+
+ if (res) {
+
+ memcpy(in_data, tmp_buf, in_len);
+ syms_removed++;
+ alpha_del1 += alpha_map[i];
+ changed_any = 1;
+
+ }
+
+ }
+
+ alpha_d_total += alpha_del1;
+
+ OKF("Symbol minimization finished, %u symbol%s (%u byte%s) replaced.",
+ syms_removed, syms_removed == 1 ? "" : "s", alpha_del1,
+ alpha_del1 == 1 ? "" : "s");
+
+ /**************************
+ * CHARACTER MINIMIZATION *
+ **************************/
+
+ alpha_del2 = 0;
+
+ ACTF(cBRI "Stage #3: " cRST "Character minimization...");
+
+ memcpy(tmp_buf, in_data, in_len);
+
+ for (i = 0; i < in_len; i++) {
+
+ u8 res, orig = tmp_buf[i];
+
+ if (orig == '0') { continue; }
+ tmp_buf[i] = '0';
+
+ res = tmin_run_target(fsrv, tmp_buf, in_len, 0);
+
+ if (res) {
+
+ in_data[i] = '0';
+ alpha_del2++;
+ changed_any = 1;
+
+ } else {
+
+ tmp_buf[i] = orig;
+
+ }
+
+ }
+
+ alpha_d_total += alpha_del2;
+
+ OKF("Character minimization done, %u byte%s replaced.", alpha_del2,
+ alpha_del2 == 1 ? "" : "s");
+
+ if (changed_any) { goto next_pass; }
+
+finalize_all:
+
+ if (tmp_buf) { ck_free(tmp_buf); }
+
+ if (hang_mode) {
+
+ SAYF("\n" cGRA " File size reduced by : " cRST
+ "%0.02f%% (to %u byte%s)\n" cGRA " Characters simplified : " cRST
+ "%0.02f%%\n" cGRA " Number of execs done : " cRST "%llu\n" cGRA
+ " Fruitless execs : " cRST "termination=%u crash=%u\n\n",
+ 100 - ((double)in_len) * 100 / orig_len, in_len,
+ in_len == 1 ? "" : "s",
+ ((double)(alpha_d_total)) * 100 / (in_len ? in_len : 1),
+ fsrv->total_execs, missed_paths, missed_crashes);
+ return;
+
+ }
+
+ SAYF("\n" cGRA " File size reduced by : " cRST
+ "%0.02f%% (to %u byte%s)\n" cGRA " Characters simplified : " cRST
+ "%0.02f%%\n" cGRA " Number of execs done : " cRST "%llu\n" cGRA
+ " Fruitless execs : " cRST "path=%u crash=%u hang=%s%u\n\n",
+ 100 - ((double)in_len) * 100 / orig_len, in_len, in_len == 1 ? "" : "s",
+ ((double)(alpha_d_total)) * 100 / (in_len ? in_len : 1),
+ fsrv->total_execs, missed_paths, missed_crashes,
+ missed_hangs ? cLRD : "", missed_hangs);
+
+ if (fsrv->total_execs > 50 && missed_hangs * 10 > fsrv->total_execs &&
+ !hang_mode) {
+
+ WARNF(cLRD "Frequent timeouts - results may be skewed." cRST);
+
+ }
+
+}
+
+/* Handle Ctrl-C and the like. */
+
+static void handle_stop_sig(int sig) {
+
+ (void)sig;
+ stop_soon = 1;
+ afl_fsrv_killall();
+
+}
+
+/* Do basic preparations - persistent fds, filenames, etc. */
+
+static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
+
+ u8 * x;
+ char *afl_preload;
+ char *frida_afl_preload = NULL;
+
+ fsrv->dev_null_fd = open("/dev/null", O_RDWR);
+ if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
+
+ if (!out_file) {
+
+ u8 *use_dir = ".";
+
+ if (access(use_dir, R_OK | W_OK | X_OK)) {
+
+ use_dir = get_afl_env("TMPDIR");
+ if (!use_dir) { use_dir = "/tmp"; }
+
+ }
+
+ out_file = alloc_printf("%s/.afl-tmin-temp-%u", use_dir, (u32)getpid());
+ remove_out_file = 1;
+
+ }
+
+ unlink(out_file);
+
+ fsrv->out_file = out_file;
+ fsrv->out_fd = open(out_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
+
+ if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", out_file); }
+
+ /* Set sane defaults... */
+
+ x = get_afl_env("ASAN_OPTIONS");
+
+ if (x) {
+
+ if (!strstr(x, "abort_on_error=1")) {
+
+ FATAL("Custom ASAN_OPTIONS set without abort_on_error=1 - please fix!");
+
+ }
+
+#ifndef ASAN_BUILD
+ if (!getenv("AFL_DEBUG") && !strstr(x, "symbolize=0")) {
+
+ FATAL("Custom ASAN_OPTIONS set without symbolize=0 - please fix!");
+
+ }
+
+#endif
+
+ }
+
+ x = get_afl_env("MSAN_OPTIONS");
+
+ if (x) {
+
+ if (!strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR))) {
+
+ FATAL("Custom MSAN_OPTIONS set without exit_code=" STRINGIFY(
+ MSAN_ERROR) " - please fix!");
+
+ }
+
+ if (!strstr(x, "symbolize=0")) {
+
+ FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!");
+
+ }
+
+ }
+
+ x = get_afl_env("LSAN_OPTIONS");
+
+ if (x) {
+
+ if (!strstr(x, "symbolize=0")) {
+
+ FATAL("Custom LSAN_OPTIONS set without symbolize=0 - please fix!");
+
+ }
+
+ }
+
+ setenv("ASAN_OPTIONS",
+ "abort_on_error=1:"
+ "detect_leaks=0:"
+ "allocator_may_return_null=1:"
+ "symbolize=0:"
+ "detect_odr_violation=0:"
+ "handle_segv=0:"
+ "handle_sigbus=0:"
+ "handle_abort=0:"
+ "handle_sigfpe=0:"
+ "handle_sigill=0",
+ 0);
+
+ setenv("UBSAN_OPTIONS",
+ "halt_on_error=1:"
+ "abort_on_error=1:"
+ "malloc_context_size=0:"
+ "allocator_may_return_null=1:"
+ "symbolize=0:"
+ "handle_segv=0:"
+ "handle_sigbus=0:"
+ "handle_abort=0:"
+ "handle_sigfpe=0:"
+ "handle_sigill=0",
+ 0);
+
+ setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":"
+ "abort_on_error=1:"
+ "msan_track_origins=0"
+ "allocator_may_return_null=1:"
+ "symbolize=0:"
+ "handle_segv=0:"
+ "handle_sigbus=0:"
+ "handle_abort=0:"
+ "handle_sigfpe=0:"
+ "handle_sigill=0", 0);
+
+ setenv("LSAN_OPTIONS",
+ "exitcode=" STRINGIFY(LSAN_ERROR) ":"
+ "fast_unwind_on_malloc=0:"
+ "symbolize=0:"
+ "print_suppressions=0",
+ 0);
+
+ if (get_afl_env("AFL_PRELOAD")) {
+
+ if (fsrv->qemu_mode) {
+
+ /* afl-qemu-trace takes care of converting AFL_PRELOAD. */
+
+ } else if (fsrv->frida_mode) {
+
+ afl_preload = getenv("AFL_PRELOAD");
+ u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
+ if (afl_preload) {
+
+ frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
+
+ } else {
+
+ frida_afl_preload = alloc_printf("%s", frida_binary);
+
+ }
+
+ ck_free(frida_binary);
+
+ setenv("LD_PRELOAD", frida_afl_preload, 1);
+ setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
+
+ } else {
+
+ /* CoreSight mode uses the default behavior. */
+
+ setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
+ setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
+
+ }
+
+ } else if (fsrv->frida_mode) {
+
+ u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
+ setenv("LD_PRELOAD", frida_binary, 1);
+ setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
+ ck_free(frida_binary);
+
+ }
+
+ if (frida_afl_preload) { ck_free(frida_afl_preload); }
+
+}
+
+/* Setup signal handlers, duh. */
+
+static void setup_signal_handlers(void) {
+
+ struct sigaction sa;
+
+ sa.sa_handler = NULL;
+ sa.sa_flags = SA_RESTART;
+ sa.sa_sigaction = NULL;
+
+ sigemptyset(&sa.sa_mask);
+
+ /* Various ways of saying "stop". */
+
+ sa.sa_handler = handle_stop_sig;
+ sigaction(SIGHUP, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGTERM, &sa, NULL);
+
+}
+
+/* Display usage hints. */
+
+static void usage(u8 *argv0) {
+
+ SAYF(
+ "\n%s [ options ] -- /path/to/target_app [ ... ]\n\n"
+
+ "Required parameters:\n"
+
+ " -i file - input test case to be shrunk by the tool\n"
+ " -o file - final output location for the minimized data\n\n"
+
+ "Execution control settings:\n"
+
+ " -f file - input file read by the tested program (stdin)\n"
+ " -t msec - timeout for each run (%u ms)\n"
+ " -m megs - memory limit for child process (%u MB)\n"
+#if defined(__linux__) && defined(__aarch64__)
+ " -A - use binary-only instrumentation (ARM CoreSight mode)\n"
+#endif
+ " -O - use binary-only instrumentation (FRIDA mode)\n"
+#if defined(__linux__)
+ " -Q - use binary-only instrumentation (QEMU mode)\n"
+ " -U - use unicorn-based instrumentation (Unicorn mode)\n"
+ " -W - use qemu-based instrumentation with Wine (Wine "
+ "mode)\n"
+ " (Not necessary, here for consistency with other afl-* "
+ "tools)\n"
+#endif
+ "\n"
+
+ "Minimization settings:\n"
+
+ " -e - solve for edge coverage only, ignore hit counts\n"
+ " -x - treat non-zero exit codes as crashes\n\n"
+ " -H - minimize a hang (hang mode)\n"
+
+ "For additional tips, please consult %s/README.md.\n\n"
+
+ "Environment variables used:\n"
+ "AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n"
+ "AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during startup (in milliseconds)\n"
+ "AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, etc. (default: SIGKILL)\n"
+ "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n"
+ " the target was compiled for\n"
+ "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
+ "AFL_TMIN_EXACT: require execution paths to match for crashing inputs\n"
+ "AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n"
+ "ASAN_OPTIONS: custom settings for ASAN\n"
+ " (must contain abort_on_error=1 and symbolize=0)\n"
+ "MSAN_OPTIONS: custom settings for MSAN\n"
+ " (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n"
+ "TMPDIR: directory to use for temporary input files\n",
+ argv0, EXEC_TIMEOUT, MEM_LIMIT, doc_path);
+
+ exit(1);
+
+}
+
+/* Main entry point */
+
+int main(int argc, char **argv_orig, char **envp) {
+
+ s32 opt;
+ u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0;
+ char **use_argv;
+
+ char **argv = argv_cpy_dup(argc, argv_orig);
+
+ afl_forkserver_t fsrv_var = {0};
+ if (getenv("AFL_DEBUG")) { debug = 1; }
+ fsrv = &fsrv_var;
+ afl_fsrv_init(fsrv);
+ map_size = get_map_size();
+ fsrv->map_size = map_size;
+
+ doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
+
+ SAYF(cCYA "afl-tmin" VERSION cRST " by Michal Zalewski\n");
+
+ while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeAOQUWHh")) > 0) {
+
+ switch (opt) {
+
+ case 'i':
+
+ if (in_file) { FATAL("Multiple -i options not supported"); }
+ in_file = optarg;
+ break;
+
+ case 'o':
+
+ if (output_file) { FATAL("Multiple -o options not supported"); }
+ output_file = optarg;
+ break;
+
+ case 'f':
+
+ if (out_file) { FATAL("Multiple -f options not supported"); }
+ fsrv->use_stdin = 0;
+ out_file = ck_strdup(optarg);
+ break;
+
+ case 'e':
+
+ if (edges_only) { FATAL("Multiple -e options not supported"); }
+ if (hang_mode) {
+
+ FATAL("Edges only and hang mode are mutually exclusive.");
+
+ }
+
+ edges_only = 1;
+ break;
+
+ case 'x':
+
+ if (exit_crash) { FATAL("Multiple -x options not supported"); }
+ exit_crash = 1;
+ break;
+
+ case 'm': {
+
+ u8 suffix = 'M';
+
+ if (mem_limit_given) { FATAL("Multiple -m options not supported"); }
+ mem_limit_given = 1;
+
+ if (!optarg) { FATAL("Wrong usage of -m"); }
+
+ if (!strcmp(optarg, "none")) {
+
+ fsrv->mem_limit = 0;
+ break;
+
+ }
+
+ if (sscanf(optarg, "%llu%c", &fsrv->mem_limit, &suffix) < 1 ||
+ optarg[0] == '-') {
+
+ FATAL("Bad syntax used for -m");
+
+ }
+
+ switch (suffix) {
+
+ case 'T':
+ fsrv->mem_limit *= 1024 * 1024;
+ break;
+ case 'G':
+ fsrv->mem_limit *= 1024;
+ break;
+ case 'k':
+ fsrv->mem_limit /= 1024;
+ break;
+ case 'M':
+ break;
+
+ default:
+ FATAL("Unsupported suffix or bad syntax for -m");
+
+ }
+
+ if (fsrv->mem_limit < 5) { FATAL("Dangerously low value of -m"); }
+
+ if (sizeof(rlim_t) == 4 && fsrv->mem_limit > 2000) {
+
+ FATAL("Value of -m out of range on 32-bit systems");
+
+ }
+
+ }
+
+ break;
+
+ case 't':
+
+ if (timeout_given) { FATAL("Multiple -t options not supported"); }
+ timeout_given = 1;
+
+ if (!optarg) { FATAL("Wrong usage of -t"); }
+
+ fsrv->exec_tmout = atoi(optarg);
+
+ if (fsrv->exec_tmout < 10 || optarg[0] == '-') {
+
+ FATAL("Dangerously low value of -t");
+
+ }
+
+ break;
+
+ case 'A': /* CoreSight mode */
+
+#if !defined(__aarch64__) || !defined(__linux__)
+ FATAL("-A option is not supported on this platform");
+#endif
+
+ if (fsrv->cs_mode) { FATAL("Multiple -A options not supported"); }
+
+ fsrv->cs_mode = 1;
+ break;
+
+ case 'O': /* FRIDA mode */
+
+ if (fsrv->frida_mode) { FATAL("Multiple -O options not supported"); }
+
+ fsrv->frida_mode = 1;
+ setenv("AFL_FRIDA_INST_SEED", "1", 1);
+
+ break;
+
+ case 'Q':
+
+ if (fsrv->qemu_mode) { FATAL("Multiple -Q options not supported"); }
+ if (!mem_limit_given) { fsrv->mem_limit = MEM_LIMIT_QEMU; }
+
+ fsrv->qemu_mode = 1;
+ break;
+
+ case 'U':
+
+ if (unicorn_mode) { FATAL("Multiple -Q options not supported"); }
+ if (!mem_limit_given) { fsrv->mem_limit = MEM_LIMIT_UNICORN; }
+
+ unicorn_mode = 1;
+ break;
+
+ case 'W': /* Wine+QEMU mode */
+
+ if (use_wine) { FATAL("Multiple -W options not supported"); }
+ fsrv->qemu_mode = 1;
+ use_wine = 1;
+
+ if (!mem_limit_given) { fsrv->mem_limit = 0; }
+
+ break;
+
+ case 'H': /* Hang Mode */
+
+ /* Minimizes a testcase to the minimum that still times out */
+
+ if (hang_mode) { FATAL("Multipe -H options not supported"); }
+ if (edges_only) {
+
+ FATAL("Edges only and hang mode are mutually exclusive.");
+
+ }
+
+ hang_mode = 1;
+ break;
+
+ case 'B': /* load bitmap */
+
+ /* This is a secret undocumented option! It is speculated to be useful
+ if you have a baseline "boring" input file and another "interesting"
+ file you want to minimize.
+
+ You can dump a binary bitmap for the boring file using
+ afl-showmap -b, and then load it into afl-tmin via -B. The minimizer
+ will then minimize to preserve only the edges that are unique to
+ the interesting input file, but ignoring everything from the
+ original map.
+
+ The option may be extended and made more official if it proves
+ to be useful. */
+
+ if (mask_bitmap) { FATAL("Multiple -B options not supported"); }
+ mask_bitmap = ck_alloc(map_size);
+ read_bitmap(optarg, mask_bitmap, map_size);
+ break;
+
+ case 'h':
+ usage(argv[0]);
+ return -1;
+ break;
+
+ default:
+ usage(argv[0]);
+
+ }
+
+ }
+
+ if (optind == argc || !in_file || !output_file) { usage(argv[0]); }
+
+ check_environment_vars(envp);
+
+ if (getenv("AFL_NO_FORKSRV")) { /* if set, use the fauxserver */
+ fsrv->use_fauxsrv = true;
+
+ }
+
+ setenv("AFL_NO_AUTODICT", "1", 1);
+
+ /* initialize cmplog_mode */
+ shm.cmplog_mode = 0;
+
+ atexit(at_exit_handler);
+ setup_signal_handlers();
+
+ set_up_environment(fsrv, argv);
+
+ fsrv->target_path = find_binary(argv[optind]);
+ fsrv->trace_bits = afl_shm_init(&shm, map_size, 0);
+ detect_file_args(argv + optind, out_file, &fsrv->use_stdin);
+ signal(SIGALRM, kill_child);
+
+ if (fsrv->qemu_mode) {
+
+ if (use_wine) {
+
+ use_argv = get_wine_argv(argv[0], &fsrv->target_path, argc - optind,
+ argv + optind);
+
+ } else {
+
+ use_argv = get_qemu_argv(argv[0], &fsrv->target_path, argc - optind,
+ argv + optind);
+
+ }
+
+ } else if (fsrv->cs_mode) {
+
+ use_argv =
+ get_cs_argv(argv[0], &fsrv->target_path, argc - optind, argv + optind);
+
+ } else {
+
+ use_argv = argv + optind;
+
+ }
+
+ exact_mode = !!get_afl_env("AFL_TMIN_EXACT");
+
+ if (hang_mode && exact_mode) {
+
+ SAYF("AFL_TMIN_EXACT won't work for loops in hang mode, ignoring.");
+ exact_mode = 0;
+
+ }
+
+ SAYF("\n");
+
+ if (getenv("AFL_FORKSRV_INIT_TMOUT")) {
+
+ s32 forksrv_init_tmout = atoi(getenv("AFL_FORKSRV_INIT_TMOUT"));
+ if (forksrv_init_tmout < 1) {
+
+ FATAL("Bad value specified for AFL_FORKSRV_INIT_TMOUT");
+
+ }
+
+ fsrv->init_tmout = (u32)forksrv_init_tmout;
+
+ }
+
+ fsrv->kill_signal =
+ parse_afl_kill_signal_env(getenv("AFL_KILL_SIGNAL"), SIGKILL);
+
+ if (getenv("AFL_CRASH_EXITCODE")) {
+
+ long exitcode = strtol(getenv("AFL_CRASH_EXITCODE"), NULL, 10);
+ if ((!exitcode && (errno == EINVAL || errno == ERANGE)) ||
+ exitcode < -127 || exitcode > 128) {
+
+ FATAL("Invalid crash exitcode, expected -127 to 128, but got %s",
+ getenv("AFL_CRASH_EXITCODE"));
+
+ }
+
+ fsrv->uses_crash_exitcode = true;
+ // WEXITSTATUS is 8 bit unsigned
+ fsrv->crash_exitcode = (u8)exitcode;
+
+ }
+
+ shm_fuzz = ck_alloc(sizeof(sharedmem_t));
+
+ /* initialize cmplog_mode */
+ shm_fuzz->cmplog_mode = 0;
+ u8 *map = afl_shm_init(shm_fuzz, MAX_FILE + sizeof(u32), 1);
+ shm_fuzz->shmemfuzz_mode = 1;
+ if (!map) { FATAL("BUG: Zero return from afl_shm_init."); }
+#ifdef USEMMAP
+ setenv(SHM_FUZZ_ENV_VAR, shm_fuzz->g_shm_file_path, 1);
+#else
+ u8 *shm_str = alloc_printf("%d", shm_fuzz->shm_id);
+ setenv(SHM_FUZZ_ENV_VAR, shm_str, 1);
+ ck_free(shm_str);
+#endif
+ fsrv->support_shmem_fuzz = 1;
+ fsrv->shmem_fuzz_len = (u32 *)map;
+ fsrv->shmem_fuzz = map + sizeof(u32);
+
+ read_initial_file();
+ (void)check_binary_signatures(fsrv->target_path);
+
+ if (!fsrv->qemu_mode && !unicorn_mode) {
+
+ fsrv->map_size = 4194304; // dummy temporary value
+ u32 new_map_size =
+ afl_fsrv_get_mapsize(fsrv, use_argv, &stop_soon,
+ (get_afl_env("AFL_DEBUG_CHILD") ||
+ get_afl_env("AFL_DEBUG_CHILD_OUTPUT"))
+ ? 1
+ : 0);
+
+ if (new_map_size) {
+
+ if (map_size < new_map_size ||
+ (new_map_size > map_size && new_map_size - map_size > MAP_SIZE)) {
+
+ if (!be_quiet)
+ ACTF("Aquired new map size for target: %u bytes\n", new_map_size);
+
+ afl_shm_deinit(&shm);
+ afl_fsrv_kill(fsrv);
+ fsrv->map_size = new_map_size;
+ fsrv->trace_bits = afl_shm_init(&shm, new_map_size, 0);
+ afl_fsrv_start(fsrv, use_argv, &stop_soon,
+ (get_afl_env("AFL_DEBUG_CHILD") ||
+ get_afl_env("AFL_DEBUG_CHILD_OUTPUT"))
+ ? 1
+ : 0);
+
+ }
+
+ map_size = new_map_size;
+
+ }
+
+ fsrv->map_size = map_size;
+
+ } else {
+
+ afl_fsrv_start(fsrv, use_argv, &stop_soon,
+ (get_afl_env("AFL_DEBUG_CHILD") ||
+ get_afl_env("AFL_DEBUG_CHILD_OUTPUT"))
+ ? 1
+ : 0);
+
+ }
+
+ if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz)
+ shm_fuzz = deinit_shmem(fsrv, shm_fuzz);
+
+ ACTF("Performing dry run (mem limit = %llu MB, timeout = %u ms%s)...",
+ fsrv->mem_limit, fsrv->exec_tmout, edges_only ? ", edges only" : "");
+
+ tmin_run_target(fsrv, in_data, in_len, 1);
+
+ if (hang_mode && !fsrv->last_run_timed_out) {
+
+ FATAL(
+ "Target binary did not time out but hang minimization mode "
+ "(-H) was set (-t %u).",
+ fsrv->exec_tmout);
+
+ }
+
+ if (fsrv->last_run_timed_out && !hang_mode) {
+
+ FATAL(
+ "Target binary times out (adjusting -t may help). Use -H to minimize a "
+ "hang.");
+
+ }
+
+ if (hang_mode) {
+
+ OKF("Program hangs as expected, minimizing in " cCYA "hang" cRST " mode.");
+
+ } else if (!crash_mode) {
+
+ OKF("Program terminates normally, minimizing in " cCYA "instrumented" cRST
+ " mode.");
+
+ if (!anything_set(fsrv)) { FATAL("No instrumentation detected."); }
+
+ } else {
+
+ OKF("Program exits with a signal, minimizing in " cMGN "%scrash" cRST
+ " mode.",
+ exact_mode ? "EXACT " : "");
+
+ }
+
+ minimize(fsrv);
+
+ ACTF("Writing output to '%s'...", output_file);
+
+ unlink(out_file);
+ if (out_file) { ck_free(out_file); }
+ out_file = NULL;
+
+ close(write_to_file(output_file, in_data, in_len));
+
+ OKF("We're done here. Have a nice day!\n");
+
+ remove_shm = 0;
+ afl_shm_deinit(&shm);
+ if (fsrv->use_shmem_fuzz) shm_fuzz = deinit_shmem(fsrv, shm_fuzz);
+ afl_fsrv_deinit(fsrv);
+ if (fsrv->target_path) { ck_free(fsrv->target_path); }
+ if (mask_bitmap) { ck_free(mask_bitmap); }
+ if (in_data) { ck_free(in_data); }
+
+ argv_cpy_free(argv);
+
+ exit(0);
+
+}
+
diff --git a/test-instr.c b/test-instr.c
new file mode 100644
index 00000000..b2caa1fe
--- /dev/null
+++ b/test-instr.c
@@ -0,0 +1,71 @@
+/*
+ american fuzzy lop++ - a trivial program to test the build
+ --------------------------------------------------------
+ Originally written by Michal Zalewski
+ Copyright 2014 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+ https://www.apache.org/licenses/LICENSE-2.0
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifdef TEST_SHARED_OBJECT
+ #define main main_exported
+#endif
+
+int main(int argc, char **argv) {
+
+ int fd = 0;
+ char buff[8];
+ char *buf = buff;
+
+ // we support command line parameter and stdin
+ if (argc == 2) {
+
+ buf = argv[1];
+ printf("Input %s - ", buf);
+
+ } else {
+
+ if (argc >= 3 && strcmp(argv[1], "-f") == 0) {
+
+ if ((fd = open(argv[2], O_RDONLY)) < 0) {
+
+ fprintf(stderr, "Error: unable to open %s\n", argv[2]);
+ exit(-1);
+
+ }
+
+ }
+
+ if (read(fd, buf, sizeof(buf)) < 1) {
+
+ printf("Hum?\n");
+ return 1;
+
+ }
+
+ }
+
+ // we support three input cases (plus a 4th if stdin is used but there is no
+ // input)
+ if (buf[0] == '0')
+ printf("Looks like a zero to me!\n");
+ else if (buf[0] == '1')
+ printf("Pretty sure that is a one!\n");
+ else
+ printf("Neither one or zero? How quaint!\n");
+
+ return 0;
+
+}
+
diff --git a/test/checkcommit.sh b/test/checkcommit.sh
new file mode 100755
index 00000000..35eae540
--- /dev/null
+++ b/test/checkcommit.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+CMDLINE="/prg/tests/normal/tiff-4.0.4/tools/thumbnail @@ /dev/null"
+INDIR="/prg/tests/normal/tiff-4.0.4/in-small"
+
+test -z "$1" -o -n "$4" && {
+ echo "Syntax: $0 commit-id <indir> \"<cmdline>\""
+ echo
+ echo "Switches to the defined commit ID, compiles with profiling and runs"
+ echo "afl-fuzz on a defind target and input directory, saving timing,"
+ echo "fuzzer_stats and profiling output to \"<commit-id>.out\""
+ echo "Honors CFLAGS and LDFLAGS"
+ echo
+ echo "Defaults:"
+ echo " indir: \"$INDIR\""
+ echo " cmdline: \"$CMDLINE\""
+ exit 1
+}
+
+C=$1
+test -n "$2" && INDIR=$2
+test -n "$3" && CMDLINE=$3
+
+git checkout "$C" || { echo "CHECKOUT FAIL $C" > $C.out ; exit 1 ; }
+export AFL_BENCH_JUST_ONE=1
+test -z "$CFLAGS" && CFLAGS="-O3 -funroll-loops"
+export CFLAGS="$CFLAGS -pg"
+export LDFLAGS="$LDFLAGS -pg"
+make >/dev/null 2>&1 || echo ERROR: BUILD FAILURE
+test -x ./afl-fuzz || { echo "BUILD FAIL $C" > $C.out ; make clean ; exit 1 ; }
+
+START=`date +%s`
+echo $START > $C.out
+time nice -n -20 ./afl-fuzz -i "$INDIR" -s 123 -o out-profile -- $CMDLINE 2>> $C.out
+STOP=`date +%s`
+echo $STOP >> $C.out
+echo RUNTIME: `expr $STOP - $START` >> $C.out
+cat out-profile/default/fuzzer_stats >> $C.out
+gprof ./afl-fuzz gmon.out >> $C.out
+
+make clean >/dev/null 2>&1
+rm -rf out-profile gmon.out
diff --git a/test/test-all.sh b/test/test-all.sh
new file mode 100755
index 00000000..0c189727
--- /dev/null
+++ b/test/test-all.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+. ./test-pre.sh
+
+. ./test-basic.sh
+
+. ./test-llvm.sh
+
+. ./test-llvm-lto.sh
+
+. ./test-gcc-plugin.sh
+
+. ./test-libextensions.sh
+
+. ./test-qemu-mode.sh
+
+. ./test-frida-mode.sh
+
+. ./test-unicorn-mode.sh
+
+. ./test-custom-mutators.sh
+
+. ./test-unittests.sh
+
+. ./test-post.sh
diff --git a/test/test-basic.sh b/test/test-basic.sh
new file mode 100755
index 00000000..bec42b4d
--- /dev/null
+++ b/test/test-basic.sh
@@ -0,0 +1,262 @@
+#!/bin/sh
+
+. ./test-pre.sh
+
+
+AFL_GCC=afl-gcc
+$ECHO "$BLUE[*] Testing: ${AFL_GCC}, afl-showmap, afl-fuzz, afl-cmin and afl-tmin"
+test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" -o "$SYS" = "i386" && {
+ test -e ../${AFL_GCC} -a -e ../afl-showmap -a -e ../afl-fuzz && {
+ ../${AFL_GCC} -o test-instr.plain -O0 ../test-instr.c > /dev/null 2>&1
+ AFL_HARDEN=1 ../${AFL_GCC} -o test-compcov.harden test-compcov.c > /dev/null 2>&1
+ test -e test-instr.plain && {
+ $ECHO "$GREEN[+] ${AFL_GCC} compilation succeeded"
+ echo 0 | AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.plain.0 -r -- ./test-instr.plain > /dev/null 2>&1
+ AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.plain.1 -r -- ./test-instr.plain < /dev/null > /dev/null 2>&1
+ test -e test-instr.plain.0 -a -e test-instr.plain.1 && {
+ diff test-instr.plain.0 test-instr.plain.1 > /dev/null 2>&1 && {
+ $ECHO "$RED[!] ${AFL_GCC} instrumentation should be different on different input but is not"
+ CODE=1
+ } || {
+ $ECHO "$GREEN[+] ${AFL_GCC} instrumentation present and working correctly"
+ }
+ } || {
+ $ECHO "$RED[!] ${AFL_GCC} instrumentation failed"
+ CODE=1
+ }
+ rm -f test-instr.plain.0 test-instr.plain.1
+ SKIP=
+ TUPLES=`echo 1|AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -- ./test-instr.plain 2>&1 | grep Captur | awk '{print$3}'`
+ test "$TUPLES" -gt 1 -a "$TUPLES" -lt 12 && {
+ $ECHO "$GREEN[+] ${AFL_GCC} run reported $TUPLES instrumented locations which is fine"
+ } || {
+ $ECHO "$RED[!] ${AFL_GCC} instrumentation produces weird numbers: $TUPLES"
+ CODE=1
+ }
+ test "$TUPLES" -lt 3 && SKIP=1
+ true # this is needed because of the test above
+ } || {
+ $ECHO "$RED[!] ${AFL_GCC} failed"
+ echo CUT------------------------------------------------------------------CUT
+ uname -a
+ ../${AFL_GCC} -o test-instr.plain -O0 ../test-instr.c
+ echo CUT------------------------------------------------------------------CUT
+ CODE=1
+ }
+ test -e test-compcov.harden && {
+ nm test-compcov.harden | grep -Eq 'stack_chk_fail|fstack-protector-all|fortified' > /dev/null 2>&1 && {
+ $ECHO "$GREEN[+] ${AFL_GCC} hardened mode succeeded and is working"
+ } || {
+ $ECHO "$RED[!] ${AFL_GCC} hardened mode is not hardened"
+ env | egrep 'AFL|PATH|LLVM'
+ AFL_DEBUG=1 AFL_HARDEN=1 ../${AFL_GCC} -o test-compcov.harden test-compcov.c
+ nm test-compcov.harden
+ CODE=1
+ }
+ rm -f test-compcov.harden
+ } || {
+ $ECHO "$RED[!] ${AFL_GCC} hardened mode compilation failed"
+ CODE=1
+ }
+ # now we want to be sure that afl-fuzz is working
+ # make sure crash reporter is disabled on Mac OS X
+ (test "$(uname -s)" = "Darwin" && test $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') && {
+ $ECHO "$RED[!] we cannot run afl-fuzz with enabled crash reporter. Run 'sudo sh afl-system-config'.$RESET"
+ true
+ }) || {
+ mkdir -p in
+ echo 0 > in/in
+ test -z "$SKIP" && {
+ $ECHO "$GREY[*] running afl-fuzz for ${AFL_GCC}, this will take approx 10 seconds"
+ {
+ ../afl-fuzz -V10 -m ${MEM_LIMIT} -i in -o out -D -- ./test-instr.plain >>errors 2>&1
+ } >>errors 2>&1
+ test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && {
+ $ECHO "$GREEN[+] afl-fuzz is working correctly with ${AFL_GCC}"
+ } || {
+ echo CUT------------------------------------------------------------------CUT
+ cat errors
+ echo CUT------------------------------------------------------------------CUT
+ $ECHO "$RED[!] afl-fuzz is not working correctly with ${AFL_GCC}"
+ CODE=1
+ }
+ }
+ echo 000000000000000000000000 > in/in2
+ echo 111 > in/in3
+ mkdir -p in2
+ ../afl-cmin -m ${MEM_LIMIT} -i in -o in2 -- ./test-instr.plain >/dev/null 2>&1 # why is afl-forkserver writing to stderr?
+ CNT=`ls in2/* 2>/dev/null | wc -l`
+ case "$CNT" in
+ *2) $ECHO "$GREEN[+] afl-cmin correctly minimized the number of testcases" ;;
+ *) $ECHO "$RED[!] afl-cmin did not correctly minimize the number of testcases ($CNT)"
+ CODE=1
+ ;;
+ esac
+ rm -f in2/in*
+ export AFL_QUIET=1
+ if command -v bash >/dev/null ; then {
+ ../afl-cmin.bash -m ${MEM_LIMIT} -i in -o in2 -- ./test-instr.plain >/dev/null
+ CNT=`ls in2/* 2>/dev/null | wc -l`
+ case "$CNT" in
+ *2) $ECHO "$GREEN[+] afl-cmin.bash correctly minimized the number of testcases" ;;
+ *) $ECHO "$RED[!] afl-cmin.bash did not correctly minimize the number of testcases ($CNT)"
+ CODE=1
+ ;;
+ esac
+ } else {
+ $ECHO "$GREY[*] 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
+ SIZE=`ls -l in2/in2 2>/dev/null | awk '{print$5}'`
+ test "$SIZE" = 1 && $ECHO "$GREEN[+] afl-tmin correctly minimized the testcase"
+ test "$SIZE" = 1 || {
+ $ECHO "$RED[!] afl-tmin did incorrectly minimize the testcase to $SIZE"
+ CODE=1
+ }
+ rm -rf in out errors in2
+ unset AFL_QUIET
+ }
+ rm -f test-instr.plain
+ } || {
+ $ECHO "$YELLOW[-] afl is not compiled, cannot test"
+ INCOMPLETE=1
+ }
+ if [ ${AFL_GCC} = "afl-gcc" ] ; then AFL_GCC=afl-clang ; else AFL_GCC=afl-gcc ; fi
+ $ECHO "$BLUE[*] Testing: ${AFL_GCC}, afl-showmap, afl-fuzz, afl-cmin and afl-tmin"
+ SKIP=
+ test -e ../${AFL_GCC} -a -e ../afl-showmap -a -e ../afl-fuzz && {
+ ../${AFL_GCC} -o test-instr.plain -O0 ../test-instr.c > /dev/null 2>&1
+ AFL_HARDEN=1 ../${AFL_GCC} -o test-compcov.harden test-compcov.c > /dev/null 2>&1
+ test -e test-instr.plain && {
+ $ECHO "$GREEN[+] ${AFL_GCC} compilation succeeded"
+ echo 0 | AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.plain.0 -r -- ./test-instr.plain > /dev/null 2>&1
+ AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.plain.1 -r -- ./test-instr.plain < /dev/null > /dev/null 2>&1
+ test -e test-instr.plain.0 -a -e test-instr.plain.1 && {
+ diff test-instr.plain.0 test-instr.plain.1 > /dev/null 2>&1 && {
+ $ECHO "$RED[!] ${AFL_GCC} instrumentation should be different on different input but is not"
+ CODE=1
+ } || {
+ $ECHO "$GREEN[+] ${AFL_GCC} instrumentation present and working correctly"
+ }
+ } || {
+ $ECHO "$RED[!] ${AFL_GCC} instrumentation failed"
+ CODE=1
+ }
+ rm -f test-instr.plain.0 test-instr.plain.1
+ TUPLES=`echo 1|AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -- ./test-instr.plain 2>&1 | grep Captur | awk '{print$3}'`
+ test "$TUPLES" -gt 1 -a "$TUPLES" -lt 12 && {
+ $ECHO "$GREEN[+] ${AFL_GCC} run reported $TUPLES instrumented locations which is fine"
+ } || {
+ $ECHO "$RED[!] ${AFL_GCC} instrumentation produces weird numbers: $TUPLES"
+ CODE=1
+ }
+ test "$TUPLES" -lt 3 && SKIP=1
+ true # this is needed because of the test above
+ } || {
+ $ECHO "$RED[!] ${AFL_GCC} failed"
+ echo CUT------------------------------------------------------------------CUT
+ uname -a
+ ../${AFL_GCC} -o test-instr.plain ../test-instr.c
+ echo CUT------------------------------------------------------------------CUT
+ CODE=1
+ }
+ test -e test-compcov.harden && {
+ nm test-compcov.harden | grep -Eq 'stack_chk_fail|fstack-protector-all|fortified' > /dev/null 2>&1 && {
+ $ECHO "$GREEN[+] ${AFL_GCC} hardened mode succeeded and is working"
+ } || {
+ $ECHO "$RED[!] ${AFL_GCC} hardened mode is not hardened"
+ CODE=1
+ }
+ rm -f test-compcov.harden
+ } || {
+ $ECHO "$RED[!] ${AFL_GCC} hardened mode compilation failed"
+ CODE=1
+ }
+ # now we want to be sure that afl-fuzz is working
+ # make sure crash reporter is disabled on Mac OS X
+ (test "$(uname -s)" = "Darwin" && test $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') && {
+ $ECHO "$RED[!] we cannot run afl-fuzz with enabled crash reporter. Run 'sudo sh afl-system-config'.$RESET"
+ true
+ }) || {
+ mkdir -p in
+ echo 0 > in/in
+ test -z "$SKIP" && {
+ $ECHO "$GREY[*] running afl-fuzz for ${AFL_GCC}, this will take approx 10 seconds"
+ {
+ ../afl-fuzz -V10 -m ${MEM_LIMIT} -i in -o out -D -- ./test-instr.plain >>errors 2>&1
+ } >>errors 2>&1
+ test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && {
+ $ECHO "$GREEN[+] afl-fuzz is working correctly with ${AFL_GCC}"
+ } || {
+ echo CUT------------------------------------------------------------------CUT
+ cat errors
+ echo CUT------------------------------------------------------------------CUT
+ $ECHO "$RED[!] afl-fuzz is not working correctly with ${AFL_GCC}"
+ CODE=1
+ }
+ }
+ echo 000000000000000000000000 > in/in2
+ echo AAA > in/in3
+ mkdir -p in2
+ ../afl-cmin -m ${MEM_LIMIT} -i in -o in2 -- ./test-instr.plain >/dev/null 2>&1 # why is afl-forkserver writing to stderr?
+ CNT=`ls in2/* 2>/dev/null | wc -l`
+ case "$CNT" in
+ *2) $ECHO "$GREEN[+] afl-cmin correctly minimized the number of testcases" ;;
+ \ *1|1) { # allow leading whitecase for portability
+ test -s in2/* && $ECHO "$YELLOW[?] afl-cmin did minimize to one testcase. This can be a bug or due compiler optimization."
+ test -s in2/* || {
+ $ECHO "$RED[!] afl-cmin did not correctly minimize the number of testcases ($CNT)"
+ CODE=1
+ }
+ }
+ ;;
+ *) $ECHO "$RED[!] afl-cmin did not correctly minimize the number of testcases ($CNT)"
+ CODE=1
+ ;;
+ esac
+ rm -f in2/in*
+ export AFL_QUIET=1
+ if command -v bash >/dev/null ; then {
+ ../afl-cmin.bash -m ${MEM_LIMIT} -i in -o in2 -- ./test-instr.plain >/dev/null
+ CNT=`ls in2/* 2>/dev/null | wc -l`
+ case "$CNT" in
+ *2) $ECHO "$GREEN[+] afl-cmin.bash correctly minimized the number of testcases" ;;
+ \ *1|1) { # allow leading whitecase for portability
+ test -s in2/* && $ECHO "$YELLOW[?] afl-cmin.bash did minimize to one testcase. This can be a bug or due compiler optimization."
+ test -s in2/* || {
+ $ECHO "$RED[!] afl-cmin.bash did not correctly minimize the number of testcases ($CNT)"
+ CODE=1
+ }
+ }
+ ;;
+ *) $ECHO "$RED[!] afl-cmin.bash did not correctly minimize the number of testcases ($CNT)"
+ CODE=1
+ ;;
+ esac
+ } else {
+ $ECHO "$GREY[*] 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
+ SIZE=`ls -l in2/in2 2>/dev/null | awk '{print$5}'`
+ test "$SIZE" = 1 && $ECHO "$GREEN[+] afl-tmin correctly minimized the testcase"
+ test "$SIZE" = 1 || {
+ $ECHO "$RED[!] afl-tmin did incorrectly minimize the testcase to $SIZE"
+ CODE=1
+ }
+ rm -rf in out errors in2
+ unset AFL_QUIET
+ }
+ rm -f test-instr.plain
+ } || {
+ $ECHO "$YELLOW[-] afl is not compiled, cannot test"
+ INCOMPLETE=1
+ }
+} || {
+ $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-cmplog.c b/test/test-cmplog.c
new file mode 100644
index 00000000..d724ecaf
--- /dev/null
+++ b/test/test-cmplog.c
@@ -0,0 +1,43 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+
+int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t i) {
+
+ if (i < 30) return 0;
+ if (buf[0] != 'A') return 0;
+ if (buf[1] != 'B') return 0;
+ if (buf[2] != 'C') return 0;
+ if (buf[3] != 'D') return 0;
+ int *icmp = (int *)(buf + 4);
+ if (*icmp != 0x69694141) return 0;
+ if (memcmp(buf + 8, "1234", 4) || memcmp(buf + 12, "EFGH", 4)) return 0;
+ if (strncmp(buf + 16, "IJKL", 4) == 0 && strcmp(buf + 20, "DEADBEEF") == 0)
+ abort();
+ return 0;
+
+}
+
+#ifdef __AFL_COMPILER
+int main(int argc, char *argv[]) {
+
+ unsigned char buf[1024];
+ ssize_t i;
+ while (__AFL_LOOP(1000)) {
+
+ i = read(0, (char *)buf, sizeof(buf) - 1);
+ if (i > 0) buf[i] = 0;
+ LLVMFuzzerTestOneInput(buf, i);
+
+ }
+
+ return 0;
+
+}
+
+#endif
+
diff --git a/test/test-compcov.c b/test/test-compcov.c
new file mode 100644
index 00000000..32efb3e9
--- /dev/null
+++ b/test/test-compcov.c
@@ -0,0 +1,62 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+char global_cmpval[] = "GLOBALVARIABLE";
+
+int main(int argc, char **argv) {
+
+ char *input = argv[1], *buf, buffer[20];
+ char cmpval[] = "LOCALVARIABLE";
+ char shortval[4] = "abc";
+
+ if (argc < 2) {
+
+ ssize_t ret = read(0, buffer, sizeof(buffer) - 1);
+ buffer[ret] = 0;
+ input = buffer;
+
+ }
+
+ if (strcmp(input, "LIBTOKENCAP") == 0)
+ printf("your string was LIBTOKENCAP\n");
+ else if (strcmp(input, "BUGMENOT") == 0)
+ printf("your string was BUGMENOT\n");
+ else if (strncmp(input, "BANANA", 3) == 0)
+ printf("your string started with BAN\n");
+ else if (strcmp(input, "APRI\0COT") == 0)
+ printf("your string was APRI\n");
+ else if (strcasecmp(input, "Kiwi") == 0)
+ printf("your string was Kiwi\n");
+ else if (strncasecmp(input, "avocado", 9) == 0)
+ printf("your string was avocado\n");
+ else if (strncasecmp(input, "Grapes", argc > 2 ? atoi(argv[2]) : 3) == 0)
+ printf("your string was a prefix of Grapes\n");
+ else if (strstr(input, "tsala") != NULL)
+ printf("your string is a fruit salad\n");
+ else if (strcmp(input, "BUFFEROVERFLOW") == 0) {
+
+ buf = (char *)malloc(16);
+ strcpy(buf, "TEST");
+ strcat(buf, input);
+ printf("This will only crash with libdislocator: %s\n", buf);
+
+ } else if (*(unsigned int *)input == 0xabadcafe)
+
+ printf("GG you eat cmp tokens for breakfast!\n");
+ else if (memcmp(cmpval, input, 8) == 0)
+ printf("local var memcmp works!\n");
+ else if (memcmp(shortval, input, 4) == 0)
+ printf("short local var memcmp works!\n");
+ else if (memcmp(global_cmpval, input, sizeof(global_cmpval)) == 0)
+ printf("global var memcmp works!\n");
+ else if (strncasecmp("-h", input, 2) == 0)
+ printf("this is not the help you are looking for\n");
+ else
+ printf("I do not know your string\n");
+
+ return 0;
+
+}
+
diff --git a/test/test-custom-mutator.c b/test/test-custom-mutator.c
new file mode 100644
index 00000000..f868550c
--- /dev/null
+++ b/test/test-custom-mutator.c
@@ -0,0 +1,20 @@
+/**
+ * Reference:
+ * https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/blob/master/4_libprotobuf_aflpp_custom_mutator/vuln.c
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[]) {
+
+ char str[100];
+ read(0, str, 100);
+ if (str[6] == 'A') { abort(); }
+ return 0;
+
+}
+
diff --git a/test/test-custom-mutators.sh b/test/test-custom-mutators.sh
new file mode 100755
index 00000000..5d679a82
--- /dev/null
+++ b/test/test-custom-mutators.sh
@@ -0,0 +1,125 @@
+#!/bin/sh
+
+. ./test-pre.sh
+
+$ECHO "$BLUE[*] Testing: custom mutator"
+test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && {
+ # normalize path
+ CUSTOM_MUTATOR_PATH=$(cd $(pwd)/../custom_mutators/examples;pwd)
+ test -e test-custom-mutator.c -a -e ${CUSTOM_MUTATOR_PATH}/example.c -a -e ${CUSTOM_MUTATOR_PATH}/example.py && {
+ unset AFL_CC
+ # Compile the vulnerable program for single mutator
+ test -e ../afl-clang-fast && {
+ ../afl-clang-fast -o test-custom-mutator test-custom-mutator.c > /dev/null 2>&1
+ } || {
+ test -e ../afl-gcc-fast && {
+ ../afl-gcc-fast -o test-custom-mutator test-custom-mutator.c > /dev/null 2>&1
+ } || {
+ ../afl-gcc -o test-custom-mutator test-custom-mutator.c > /dev/null 2>&1
+ }
+ }
+ # Compile the vulnerable program for multiple mutators
+ test -e ../afl-clang-fast && {
+ ../afl-clang-fast -o test-multiple-mutators test-multiple-mutators.c > /dev/null 2>&1
+ } || {
+ test -e ../afl-gcc-fast && {
+ ../afl-gcc-fast -o test-multiple-mutators test-multiple-mutators.c > /dev/null 2>&1
+ } || {
+ ../afl-gcc -o test-multiple-mutators test-multiple-mutators.c > /dev/null 2>&1
+ }
+ }
+ # Compile the custom mutator
+ cc -D_FIXED_CHAR=0x41 -g -fPIC -shared -I../include ../custom_mutators/examples/simple_example.c -o libexamplemutator.so > /dev/null 2>&1
+ cc -D_FIXED_CHAR=0x42 -g -fPIC -shared -I../include ../custom_mutators/examples/simple_example.c -o libexamplemutator2.so > /dev/null 2>&1
+ test -e test-custom-mutator -a -e ./libexamplemutator.so && {
+ # Create input directory
+ mkdir -p in
+ echo "00000" > in/in
+
+ # Run afl-fuzz w/ the C mutator
+ $ECHO "$GREY[*] running afl-fuzz for the C mutator, this will take approx 10 seconds"
+ {
+ AFL_CUSTOM_MUTATOR_LIBRARY=./libexamplemutator.so AFL_CUSTOM_MUTATOR_ONLY=1 ../afl-fuzz -V10 -m ${MEM_LIMIT} -i in -o out -- ./test-custom-mutator >>errors 2>&1
+ } >>errors 2>&1
+
+ # Check results
+ test -n "$( ls out/default/crashes/id:000000* 2>/dev/null )" && { # TODO: update here
+ $ECHO "$GREEN[+] afl-fuzz is working correctly with the C mutator"
+ } || {
+ echo CUT------------------------------------------------------------------CUT
+ cat errors
+ echo CUT------------------------------------------------------------------CUT
+ $ECHO "$RED[!] afl-fuzz is not working correctly with the C mutator"
+ CODE=1
+ }
+
+ # Clean
+ rm -rf out errors core.*
+
+ # Run afl-fuzz w/ multiple C mutators
+ $ECHO "$GREY[*] running afl-fuzz with multiple custom C mutators, this will take approx 10 seconds"
+ {
+ AFL_CUSTOM_MUTATOR_LIBRARY="./libexamplemutator.so;./libexamplemutator2.so" AFL_CUSTOM_MUTATOR_ONLY=1 ../afl-fuzz -V10 -m ${MEM_LIMIT} -i in -o out -- ./test-multiple-mutators >>errors 2>&1
+ } >>errors 2>&1
+
+ test -n "$( ls out/default/crashes/id:000000* 2>/dev/null )" && { # TODO: update here
+ $ECHO "$GREEN[+] afl-fuzz is working correctly with multiple C mutators"
+ } || {
+ echo CUT------------------------------------------------------------------CUT
+ cat errors
+ echo CUT------------------------------------------------------------------CUT
+ $ECHO "$RED[!] afl-fuzz is not working correctly with multiple C mutators"
+ CODE=1
+ }
+
+ # Clean
+ rm -rf out errors core.*
+
+ # Run afl-fuzz w/ the Python mutator
+ $ECHO "$GREY[*] running afl-fuzz for the Python mutator, this will take approx 10 seconds"
+ {
+ export PYTHONPATH=${CUSTOM_MUTATOR_PATH}
+ export AFL_PYTHON_MODULE=example
+ AFL_CUSTOM_MUTATOR_ONLY=1 ../afl-fuzz -V10 -m ${MEM_LIMIT} -i in -o out -- ./test-custom-mutator >>errors 2>&1
+ unset PYTHONPATH
+ unset AFL_PYTHON_MODULE
+ } >>errors 2>&1
+
+ # Check results
+ test -n "$( ls out/default/crashes/id:000000* 2>/dev/null )" && { # TODO: update here
+ $ECHO "$GREEN[+] afl-fuzz is working correctly with the Python mutator"
+ } || {
+ echo CUT------------------------------------------------------------------CUT
+ cat errors
+ echo CUT------------------------------------------------------------------CUT
+ $ECHO "$RED[!] afl-fuzz is not working correctly with the Python mutator"
+ CODE=1
+ }
+
+ # Clean
+ rm -rf in out errors core.*
+ rm -rf ${CUSTOM_MUTATOR_PATH}/__pycache__/
+ rm -f test-multiple-mutators test-custom-mutator libexamplemutator.so libexamplemutator2.so
+ } || {
+ ls .
+ ls ${CUSTOM_MUTATOR_PATH}
+ $ECHO "$RED[!] cannot compile the test program or the custom mutator"
+ CODE=1
+ }
+
+ #test "$CODE" = 1 && { $ECHO "$YELLOW[!] custom mutator tests currently will not fail travis" ; CODE=0 ; }
+
+ make -C ../utils/custom_mutators clean > /dev/null 2>&1
+ rm -f test-custom-mutator
+ rm -f test-custom-mutators
+ } || {
+ $ECHO "$YELLOW[-] no custom mutators in $CUSTOM_MUTATOR_PATH, cannot test"
+ INCOMPLETE=1
+ }
+ unset CUSTOM_MUTATOR_PATH
+} || {
+ $ECHO "$YELLOW[-] no python support in afl-fuzz, cannot test"
+ INCOMPLETE=1
+}
+
+. ./test-post.sh
diff --git a/test/test-dlopen.c b/test/test-dlopen.c
new file mode 100644
index 00000000..b81bab13
--- /dev/null
+++ b/test/test-dlopen.c
@@ -0,0 +1,39 @@
+#include <stdio.h>
+#include <errno.h>
+#include <dlfcn.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv) {
+
+ if (!getenv("TEST_DLOPEN_TARGET")) {
+
+ fprintf(stderr, "Error: TEST_DLOPEN_TARGET not set!\n");
+ return 1;
+
+ }
+
+ void *lib = dlopen(getenv("TEST_DLOPEN_TARGET"), RTLD_LAZY);
+ if (!lib) {
+
+ perror(dlerror());
+ return 2;
+
+ }
+
+ int (*func)(int, char **) = dlsym(lib, "main_exported");
+ if (!func) {
+
+ fprintf(stderr, "Error: main_exported not found!\n");
+ return 3;
+
+ }
+
+ // must use deferred forkserver as otherwise afl++ instrumentation aborts
+ // because all dlopen() of instrumented libs must be before the forkserver
+ __AFL_INIT();
+
+ fprintf(stderr, "Running main_exported\n");
+ return func(argc, argv);
+
+}
+
diff --git a/test/test-floatingpoint.c b/test/test-floatingpoint.c
new file mode 100644
index 00000000..febfae05
--- /dev/null
+++ b/test/test-floatingpoint.c
@@ -0,0 +1,33 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <stdint.h>
+
+__AFL_FUZZ_INIT();
+
+int main(void) {
+
+ ssize_t bytes_read;
+
+ __AFL_INIT();
+ float *magic = (float *)__AFL_FUZZ_TESTCASE_BUF;
+
+ while (__AFL_LOOP(INT_MAX)) {
+
+ int len = __AFL_FUZZ_TESTCASE_LEN;
+ if (len < sizeof(float)) return 1;
+
+ /* 15 + 1/2 = 15.5 */
+ /* 15 + 1/2 + 1/8 = 15.625 */
+ /* 15 + 1/2 + 1/8 + 1/32 = 15.65625 */
+ /* 15 + 1/2 + 1/8 + 1/32 + 1/128 = 15.6640625 */
+ if ((*magic >= 15.0 + 0.5 + 0.125 + 0.03125) &&
+ (*magic <= 15.0 + 0.5 + 0.125 + 0.03125 + 0.0078125))
+ abort();
+
+ }
+
+ return 0;
+
+}
+
diff --git a/test/test-fpExtra.sh b/test/test-fpExtra.sh
new file mode 100755
index 00000000..aecc6258
--- /dev/null
+++ b/test/test-fpExtra.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+. ./test-pre.sh
+
+test -e ../afl-clang-fast -a -e ../split-switches-pass.so && {
+ $ECHO "$GREY[*] llvm_mode laf-intel/compcov testing splitting floating point types with Nan, infinity, minusZero"
+ for testcase in ./test-fp_minusZerocases.c ./test-fp_Infcases.c ./test-fp_NaNcases.c; do
+ #for testcase in ./test-fp_cases.c ./test-fp_Infcases.c ./test-fp_NaNcases.c ./test-fp_minusZerocases.c ; do
+ for I in float double "long double"; do
+ #for I in double; do
+ for BITS in 64 32 16 8; do
+ #for BITS in 64; do
+ bin="$testcase-split-$I-$BITS.compcov"
+#AFL_DONT_OPTIMIZE=1 AFL_LLVM_INSTRUMENT=AFL AFL_DEBUG=1 AFL_LLVM_LAF_SPLIT_COMPARES_BITW=$BITS AFL_LLVM_LAF_SPLIT_COMPARES=1 AFL_LLVM_LAF_SPLIT_FLOATS=1 ../afl-clang-fast -DFLOAT_TYPE="$I" -S "$testcase"
+#AFL_DONT_OPTIMIZE=1 AFL_LLVM_INSTRUMENT=AFL AFL_DEBUG=1 AFL_LLVM_LAF_SPLIT_COMPARES_BITW=$BITS AFL_LLVM_LAF_SPLIT_COMPARES=1 AFL_LLVM_LAF_SPLIT_FLOATS=1 ../afl-clang-fast -DFLOAT_TYPE="$I" -S -emit-llvm "$testcase"
+AFL_DONT_OPTIMIZE=1 AFL_LLVM_INSTRUMENT=AFL AFL_DEBUG=1 AFL_LLVM_LAF_SPLIT_COMPARES_BITW=$BITS AFL_LLVM_LAF_SPLIT_COMPARES=1 AFL_LLVM_LAF_SPLIT_FLOATS=1 ../afl-clang-fast -DFLOAT_TYPE="$I" -o "$bin" "$testcase" > test.out 2>&1;
+ if ! test -e "$bin"; then
+ cat test.out
+ $ECHO "$RED[!] llvm_mode laf-intel/compcov float splitting failed! ($testcase with type $I split to $BITS)!";
+ CODE=1
+ break
+ fi
+ if ! "$bin"; then
+ $ECHO "$RED[!] llvm_mode laf-intel/compcov float splitting resulted in miscompilation (type $I split to $BITS)!";
+ CODE=1
+ break
+ fi
+ rm -f "$bin" test.out || true
+ done
+ done
+ done
+ rm -f test-fp_cases*.compcov test.out
+
+} || {
+ $ECHO "$YELLOW[-] llvm_mode not compiled, cannot test"
+ INCOMPLETE=1
+}
+
+. ./test-post.sh
diff --git a/test/test-fp_Infcases.c b/test/test-fp_Infcases.c
new file mode 100644
index 00000000..458202d6
--- /dev/null
+++ b/test/test-fp_Infcases.c
@@ -0,0 +1,124 @@
+/* test cases for floating point comparison transformations
+ * compile with -DFLOAT_TYPE=float
+ * or -DFLOAT_TYPE=double
+ * or -DFLOAT_TYPE="long double"
+ */
+
+#include <assert.h>
+#define _GNU_SOURCE
+#include <math.h> /* for NaNs and infinity values */
+
+int main() {
+
+ volatile FLOAT_TYPE a, b;
+
+#ifdef INFINITY
+ FLOAT_TYPE inf = (FLOAT_TYPE)INFINITY;
+#else
+ FLOAT_TYPE inf = 1.0 / 0.0; /* produces infinity */
+#endif
+ FLOAT_TYPE negZero = 1.0 / -inf;
+ FLOAT_TYPE posZero = 0.0;
+
+ /* plus infinity */
+ a = (1.0 / 0.0); /* positive infinity */
+ b = (1.0 / 0.0); /* positive infinity */
+ assert(!(a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert((a >= b));
+ assert(!(a != b));
+ assert((a == b));
+
+ b = -(1.0 / 0.0); /* negative infinity */
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a > b));
+ assert((a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ b = 1.0 / -(1.0 / 0.0); /* negative 0 */
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a > b));
+ assert((a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ b = 0.0; /* positive 0 */
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a > b));
+ assert((a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ b = -42.0;
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a > b));
+ assert((a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ b = 42.0;
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a > b));
+ assert((a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ /* negative infinity */
+ a = -(1.0 / 0.0);
+ b = (1.0 / 0.0); /* positive infinity */
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ b = -(1.0 / 0.0); /* negative infinity */
+ assert(!(a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert((a >= b));
+ assert(!(a != b));
+ assert((a == b));
+
+ b = 1.0 / -(1.0 / 0.0); /* negative 0 */
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ b = 0.0; /* positive 0 */
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ b = -42.0;
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ b = 42.0;
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+}
+
diff --git a/test/test-fp_NaNcases.c b/test/test-fp_NaNcases.c
new file mode 100644
index 00000000..94a0ff71
--- /dev/null
+++ b/test/test-fp_NaNcases.c
@@ -0,0 +1,86 @@
+/* test cases for floating point comparison transformations
+ * compile with -DFLOAT_TYPE=float
+ * or -DFLOAT_TYPE=double
+ * or -DFLOAT_TYPE="long double"
+ */
+
+#include <assert.h>
+#define _GNU_SOURCE
+#include <math.h> /* for NaNs and infinity values */
+
+int main() {
+
+ volatile FLOAT_TYPE a, b;
+
+ /* NaN */
+#ifdef NAN
+ a = (FLOAT_TYPE)NAN; /* produces NaN */
+#else
+ a = 0.0 / 0.0; /* produces NaN */
+#endif
+#ifdef INFINITY
+ FLOAT_TYPE inf = (FLOAT_TYPE)INFINITY;
+#else
+ FLOAT_TYPE inf = 1.0 / 0.0; /* produces infinity */
+#endif
+ FLOAT_TYPE negZero = 1.0 / -inf;
+ FLOAT_TYPE posZero = 0.0;
+ b = a;
+
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ b = 0.0;
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ b = 1.0 / -(1.0 / 0.0); /* negative 0 */
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ b = 42.0;
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ b = -42.0;
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ b = (1.0 / 0.0); /* positive infinity */
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ b = -(1.0 / 0.0); /* negative infinity */
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+}
+
diff --git a/test/test-fp_cases.c b/test/test-fp_cases.c
new file mode 100644
index 00000000..b0f792bc
--- /dev/null
+++ b/test/test-fp_cases.c
@@ -0,0 +1,213 @@
+/* test cases for floating point comparison transformations
+ * compile with -DFLOAT_TYPE=float
+ * or -DFLOAT_TYPE=double
+ * or -DFLOAT_TYPE="long double"
+ */
+
+#include <assert.h>
+
+int main() {
+
+ volatile FLOAT_TYPE a, b;
+ /* different values */
+ a = -2.1;
+ b = -2; /* signs equal, exp equal, mantissa > */
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = 1.8;
+ b = 2.1; /* signs equal, exp differ, mantissa > */
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = 2;
+ b = 2.1; /* signs equal, exp equal, mantissa < */
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = -2;
+ b = -1.8; /* signs equal, exp differ, mantissa < */
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = -1;
+ b = 1; /* signs differ, exp equal, mantissa equal */
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = -1;
+ b = 0; /* signs differ, exp differ, mantissa equal */
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = -2;
+ b = 2.8; /* signs differ, exp equal, mantissa < */
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = -2;
+ b = 1.8; /* signs differ, exp differ, mantissa < */
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = -2;
+ b = -2.1; /* signs equal, exp equal, mantissa > */
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = 2.1;
+ b = 1.8; /* signs equal, exp differ, mantissa > */
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = 2.1;
+ b = 2; /* signs equal, exp equal, mantissa < */
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = -1.8;
+ b = -2; /* signs equal, exp differ, mantissa < */
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = 1;
+ b = -1; /* signs differ, exp equal, mantissa equal */
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = 0;
+ b = -1; /* signs differ, exp differ, mantissa equal */
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = 2.8;
+ b = -2; /* signs differ, exp equal, mantissa < */
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = 1.8;
+ b = -2; /* signs differ, exp differ, mantissa < */
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ /* equal values */
+ a = 0;
+ b = 0;
+ assert(!(a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert((a >= b));
+ assert(!(a != b));
+ assert((a == b));
+
+ a = -0;
+ b = 0;
+ assert(!(a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert((a >= b));
+ assert(!(a != b));
+ assert((a == b));
+
+ a = 1;
+ b = 1;
+ assert(!(a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert((a >= b));
+ assert(!(a != b));
+ assert((a == b));
+
+ a = 0.5;
+ b = 0.5;
+ assert(!(a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert((a >= b));
+ assert(!(a != b));
+ assert((a == b));
+
+ a = -1;
+ b = -1;
+ assert(!(a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert((a >= b));
+ assert(!(a != b));
+ assert((a == b));
+
+ a = -0.5;
+ b = -0.5;
+ assert(!(a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert((a >= b));
+ assert(!(a != b));
+ assert((a == b));
+
+}
+
diff --git a/test/test-fp_minusZerocases.c b/test/test-fp_minusZerocases.c
new file mode 100644
index 00000000..f821f2ab
--- /dev/null
+++ b/test/test-fp_minusZerocases.c
@@ -0,0 +1,35 @@
+/* test cases for floating point comparison transformations
+ * compile with -DFLOAT_TYPE=float
+ * or -DFLOAT_TYPE=double
+ * or -DFLOAT_TYPE="long double"
+ */
+
+#include <assert.h>
+#define _GNU_SOURCE
+#include <math.h> /* for NaNs and infinity values */
+
+int main() {
+
+ volatile FLOAT_TYPE a, b;
+
+ /* negative zero */
+ a = 1.0 / -(1.0 / 0.0); /* negative 0 */
+ b = 0.0; /* positive 0 */
+ assert(!(a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert((a >= b));
+ assert(!(a != b));
+ assert((a == b));
+
+ a = 1.0 / -(1.0 / 0.0); /* negative 0 */
+ b = 1.0 / -(1.0 / 0.0); /* negative 0 */
+ assert(!(a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert((a >= b));
+ assert(!(a != b));
+ assert((a == b));
+
+}
+
diff --git a/test/test-frida-mode.sh b/test/test-frida-mode.sh
new file mode 100755
index 00000000..59b8e307
--- /dev/null
+++ b/test/test-frida-mode.sh
@@ -0,0 +1,111 @@
+#!/bin/sh
+
+. ./test-pre.sh
+
+$ECHO "$BLUE[*] Testing: frida_mode"
+test -z "$AFL_CC" && {
+ if type gcc >/dev/null; then
+ export AFL_CC=gcc
+ else
+ if type clang >/dev/null; then
+ export AFL_CC=clang
+ fi
+ fi
+}
+
+test -e ../afl-frida-trace.so && {
+ cc -no-pie -o test-instr ../test-instr.c
+ cc -o test-compcov test-compcov.c
+ test -e test-instr -a -e test-compcov && {
+ {
+ mkdir -p in
+ echo 00000 > in/in
+ $ECHO "$GREY[*] running afl-fuzz for frida_mode, this will take approx 10 seconds"
+ {
+ AFL_DEBUG=1 AFL_FRIDA_VERBOSE=1 ../afl-fuzz -m ${MEM_LIMIT} -V10 -O -i in -o out -- ./test-instr >>errors 2>&1
+ } >>errors 2>&1
+ test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && {
+ $ECHO "$GREEN[+] afl-fuzz is working correctly with frida_mode"
+ RUNTIME=`grep execs_done out/default/fuzzer_stats | awk '{print$3}'`
+ } || {
+ echo CUT------------------------------------------------------------------CUT
+ cat errors
+ echo CUT------------------------------------------------------------------CUT
+ $ECHO "$RED[!] afl-fuzz is not working correctly with frida_mode"
+ CODE=1
+ }
+ rm -f errors
+
+ test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" -o "$SYS" = "aarch64" -o ! "${SYS%%arm*}" && {
+ $ECHO "$GREY[*] running afl-fuzz for frida_mode cmplog, this will take approx 10 seconds"
+ {
+ ../afl-fuzz -m none -V10 -O -c 0 -i in -o out -- ./test-compcov >>errors 2>&1
+ } >>errors 2>&1
+ test -n "$( ls out/default/queue/id:000003* 2>/dev/null )" && {
+ $ECHO "$GREEN[+] afl-fuzz is working correctly with frida_mode cmplog"
+ } || {
+ echo CUT------------------------------------------------------------------CUT
+ cat errors
+ echo CUT------------------------------------------------------------------CUT
+ $ECHO "$RED[!] afl-fuzz is not working correctly with frida_mode cmplog"
+ CODE=1
+ }
+ rm -f errors
+ } || {
+ $ECHO "$YELLOW[-] not an intel or arm platform, cannot test frida_mode cmplog"
+ }
+
+ test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" -o "$SYS" = "aarch64" -o ! "${SYS%%arm*}" && {
+ $ECHO "$GREY[*] running afl-fuzz for persistent frida_mode, this will take approx 10 seconds"
+ {
+ #if file test-instr | grep -q "32-bit"; then
+ #else
+ #fi
+ export AFL_FRIDA_PERSISTENT_ADDR=0x`nm test-instr | grep -Ei "T _main|T main" | awk '{print $1}'`
+ $ECHO "Info: AFL_FRIDA_PERSISTENT_ADDR=$AFL_FRIDA_PERSISTENT_ADDR <= $(nm test-instr | grep "T main" | awk '{print $1}')"
+ env|grep AFL_|sort
+ file test-instr
+ export AFL_DEBUG_CHILD=1
+ export AFL_FRIDA_VERBOSE=1
+ ../afl-fuzz -m ${MEM_LIMIT} -V10 -O -i in -o out -- ./test-instr
+ nm test-instr | grep -i "main"
+ unset AFL_FRIDA_PERSISTENT_ADDR
+ } >>errors 2>&1
+ test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && {
+ $ECHO "$GREEN[+] afl-fuzz is working correctly with persistent frida_mode"
+ RUNTIMEP=`grep execs_done out/default/fuzzer_stats | awk '{print$3}'`
+ test -n "$RUNTIME" -a -n "$RUNTIMEP" && {
+ DIFF=`expr $RUNTIMEP / $RUNTIME`
+ test "$DIFF" -gt 1 && { # must be at least twice as fast
+ $ECHO "$GREEN[+] persistent frida_mode was noticeable faster than standard frida_mode"
+ } || {
+ $ECHO "$YELLOW[-] persistent frida_mode was not noticeable faster than standard frida_mode"
+ }
+ } || {
+ $ECHO "$YELLOW[-] we got no data on executions performed? weird!"
+ }
+ } || {
+ echo CUT------------------------------------------------------------------CUT
+ cat errors
+ echo CUT------------------------------------------------------------------CUT
+ $ECHO "$RED[!] afl-fuzz is not working correctly with persistent frida_mode"
+ CODE=1
+ }
+ rm -rf in out errors
+ } || {
+ $ECHO "$YELLOW[-] not an intel or arm platform, cannot test persistent frida_mode"
+ }
+
+ }
+ } || {
+ $ECHO "$RED[!] gcc compilation of test targets failed - what is going on??"
+ CODE=1
+ }
+
+ rm -f test-instr test-compcov
+} || {
+ $ECHO "$YELLOW[-] frida_mode is not compiled, cannot test"
+ INCOMPLETE=1
+}
+
+. ./test-post.sh
diff --git a/test/test-gcc-plugin.sh b/test/test-gcc-plugin.sh
new file mode 100755
index 00000000..95ae9c47
--- /dev/null
+++ b/test/test-gcc-plugin.sh
@@ -0,0 +1,116 @@
+#!/bin/sh
+
+. ./test-pre.sh
+
+$ECHO "$BLUE[*] Testing: gcc_plugin"
+test -e ../afl-gcc-fast -a -e ../afl-compiler-rt.o && {
+ SAVE_AFL_CC=${AFL_CC}
+ export AFL_CC=`command -v gcc`
+ ../afl-gcc-fast -o test-instr.plain.gccpi ../test-instr.c > /dev/null 2>&1
+ AFL_HARDEN=1 ../afl-gcc-fast -o test-compcov.harden.gccpi test-compcov.c > /dev/null 2>&1
+ test -e test-instr.plain.gccpi && {
+ $ECHO "$GREEN[+] gcc_plugin compilation succeeded"
+ echo 0 | AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.plain.0 -r -- ./test-instr.plain.gccpi > /dev/null 2>&1
+ AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.plain.1 -r -- ./test-instr.plain.gccpi < /dev/null > /dev/null 2>&1
+ test -e test-instr.plain.0 -a -e test-instr.plain.1 && {
+ diff test-instr.plain.0 test-instr.plain.1 > /dev/null 2>&1 && {
+ $ECHO "$RED[!] gcc_plugin instrumentation should be different on different input but is not"
+ CODE=1
+ } || {
+ $ECHO "$GREEN[+] gcc_plugin instrumentation present and working correctly"
+ TUPLES=`echo 0|AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -- ./test-instr.plain.gccpi 2>&1 | grep Captur | awk '{print$3}'`
+ test "$TUPLES" -gt 1 -a "$TUPLES" -lt 9 && {
+ $ECHO "$GREEN[+] gcc_plugin run reported $TUPLES instrumented locations which is fine"
+ } || {
+ $ECHO "$RED[!] gcc_plugin instrumentation produces a weird numbers: $TUPLES"
+ $ECHO "$YELLOW[-] this is a known issue in gcc, not afl++. It is not flagged as an error because travis builds would all fail otherwise :-("
+ #CODE=1
+ }
+ test "$TUPLES" -lt 2 && SKIP=1
+ true
+ }
+ } || {
+ $ECHO "$RED[!] gcc_plugin instrumentation failed"
+ CODE=1
+ }
+ rm -f test-instr.plain.0 test-instr.plain.1
+ } || {
+ $ECHO "$RED[!] gcc_plugin failed"
+ CODE=1
+ }
+
+ test -e test-compcov.harden.gccpi && test_compcov_binary_functionality ./test-compcov.harden.gccpi && {
+ nm test-compcov.harden.gccpi | grep -Eq 'stack_chk_fail|fstack-protector-all|fortified' > /dev/null 2>&1 && {
+ $ECHO "$GREEN[+] gcc_plugin hardened mode succeeded and is working"
+ } || {
+ $ECHO "$RED[!] gcc_plugin hardened mode is not hardened"
+ CODE=1
+ }
+ rm -f test-compcov.harden.gccpi
+ } || {
+ $ECHO "$RED[!] gcc_plugin hardened mode compilation failed"
+ CODE=1
+ }
+ # now we want to be sure that afl-fuzz is working
+ # make sure crash reporter is disabled on Mac OS X
+ (test "$(uname -s)" = "Darwin" && test $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') && {
+ $ECHO "$RED[!] we cannot run afl-fuzz with enabled crash reporter. Run 'sudo sh afl-system-config'.$RESET"
+ CODE=1
+ true
+ }) || {
+ test -z "$SKIP" && {
+ mkdir -p in
+ echo 0 > in/in
+ $ECHO "$GREY[*] running afl-fuzz for gcc_plugin, this will take approx 10 seconds"
+ {
+ ../afl-fuzz -V10 -m ${MEM_LIMIT} -i in -o out -D -- ./test-instr.plain.gccpi >>errors 2>&1
+ } >>errors 2>&1
+ test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && {
+ $ECHO "$GREEN[+] afl-fuzz is working correctly with gcc_plugin"
+ } || {
+ echo CUT------------------------------------------------------------------CUT
+ cat errors
+ echo CUT------------------------------------------------------------------CUT
+ $ECHO "$RED[!] afl-fuzz is not working correctly with gcc_plugin"
+ CODE=1
+ }
+ rm -rf in out errors
+ }
+ }
+ rm -f test-instr.plain.gccpi
+
+ # now for the special gcc_plugin things
+ echo foobar.c > instrumentlist.txt
+ AFL_GCC_INSTRUMENT_FILE=instrumentlist.txt ../afl-gcc-fast -o test-compcov test-compcov.c > /dev/null 2>&1
+ test -x test-compcov && test_compcov_binary_functionality ./test-compcov && {
+ echo 1 | AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o - -r -- ./test-compcov 2>&1 | grep -q "Captured 0 tuples" && {
+ $ECHO "$GREEN[+] gcc_plugin instrumentlist feature works correctly"
+ } || {
+ $ECHO "$RED[!] gcc_plugin instrumentlist feature failed"
+ CODE=1
+ }
+ } || {
+ $ECHO "$RED[!] gcc_plugin instrumentlist feature compilation failed."
+ CODE=1
+ }
+ rm -f test-compcov test.out instrumentlist.txt
+ ../afl-gcc-fast -o test-persistent ../utils/persistent_mode/persistent_demo.c > /dev/null 2>&1
+ test -e test-persistent && {
+ echo foo | AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -q -r ./test-persistent && {
+ $ECHO "$GREEN[+] gcc_plugin persistent mode feature works correctly"
+ } || {
+ $ECHO "$RED[!] gcc_plugin persistent mode feature failed to work"
+ CODE=1
+ }
+ } || {
+ $ECHO "$RED[!] gcc_plugin persistent mode feature compilation failed"
+ CODE=1
+ }
+ rm -f test-persistent
+ export AFL_CC=${SAVE_AFL_CC}
+} || {
+ $ECHO "$YELLOW[-] gcc_plugin not compiled, cannot test"
+ INCOMPLETE=1
+}
+
+. ./test-post.sh
diff --git a/test/test-int_cases.c b/test/test-int_cases.c
new file mode 100644
index 00000000..93848d21
--- /dev/null
+++ b/test/test-int_cases.c
@@ -0,0 +1,443 @@
+/* test cases for integer comparison transformations
+ * compile with -DINT_TYPE="signed char"
+ * or -DINT_TYPE="short"
+ * or -DINT_TYPE="int"
+ * or -DINT_TYPE="long"
+ * or -DINT_TYPE="long long"
+ */
+
+#include <assert.h>
+
+int main() {
+
+ volatile INT_TYPE a, b;
+ /* different values */
+ a = -21;
+ b = -2; /* signs equal */
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = 1;
+ b = 8; /* signs equal */
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ if ((unsigned)(INT_TYPE)(~0) > 255) { /* short or bigger */
+ volatile short a, b;
+ a = 2;
+ b = 256 + 1; /* signs equal */
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = -1 - 256;
+ b = -8; /* signs equal */
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ if ((unsigned)(INT_TYPE)(~0) > 65535) { /* int or bigger */
+ volatile int a, b;
+ a = 2;
+ b = 65536 + 1; /* signs equal */
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = -1 - 65536;
+ b = -8; /* signs equal */
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ if ((unsigned)(INT_TYPE)(~0) > 4294967295) { /* long or bigger */
+ volatile long a, b;
+ a = 2;
+ b = 4294967296 + 1; /* signs equal */
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = -1 - 4294967296;
+ b = -8; /* signs equal */
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ }
+
+ }
+
+ }
+
+ a = -1;
+ b = 1; /* signs differ */
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = -1;
+ b = 0; /* signs differ */
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = -2;
+ b = 8; /* signs differ */
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = -1;
+ b = -2; /* signs equal */
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = 8;
+ b = 1; /* signs equal */
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ if ((unsigned)(INT_TYPE)(~0) > 255) {
+
+ volatile short a, b;
+ a = 1 + 256;
+ b = 3; /* signs equal */
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = -1;
+ b = -256; /* signs equal */
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ if ((unsigned)(INT_TYPE)(~0) > 65535) {
+
+ volatile int a, b;
+ a = 1 + 65536;
+ b = 3; /* signs equal */
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = -1;
+ b = -65536; /* signs equal */
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ if ((unsigned)(INT_TYPE)(~0) > 4294967295) {
+
+ volatile long a, b;
+ a = 1 + 4294967296;
+ b = 3; /* signs equal */
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = -1;
+ b = -4294967296; /* signs equal */
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ }
+
+ }
+
+ }
+
+ a = 1;
+ b = -1; /* signs differ */
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = 0;
+ b = -1; /* signs differ */
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = 8;
+ b = -2; /* signs differ */
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = 1;
+ b = -2; /* signs differ */
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ if ((unsigned)(INT_TYPE)(~0) > 255) {
+
+ volatile short a, b;
+ a = 1 + 256;
+ b = -2; /* signs differ */
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = -1;
+ b = -2 - 256; /* signs differ */
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ if ((unsigned)(INT_TYPE)(~0) > 65535) {
+
+ volatile int a, b;
+ a = 1 + 65536;
+ b = -2; /* signs differ */
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = -1;
+ b = -2 - 65536; /* signs differ */
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ if ((unsigned)(INT_TYPE)(~0) > 4294967295) {
+
+ volatile long a, b;
+ a = 1 + 4294967296;
+ b = -2; /* signs differ */
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = -1;
+ b = -2 - 4294967296; /* signs differ */
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ }
+
+ }
+
+ }
+
+ /* equal values */
+ a = 0;
+ b = 0;
+ assert(!(a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert((a >= b));
+ assert(!(a != b));
+ assert((a == b));
+
+ a = -0;
+ b = 0;
+ assert(!(a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert((a >= b));
+ assert(!(a != b));
+ assert((a == b));
+
+ a = 1;
+ b = 1;
+ assert(!(a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert((a >= b));
+ assert(!(a != b));
+ assert((a == b));
+
+ a = 5;
+ b = 5;
+ assert(!(a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert((a >= b));
+ assert(!(a != b));
+ assert((a == b));
+
+ a = -1;
+ b = -1;
+ assert(!(a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert((a >= b));
+ assert(!(a != b));
+ assert((a == b));
+
+ a = -5;
+ b = -5;
+ assert(!(a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert((a >= b));
+ assert(!(a != b));
+ assert((a == b));
+
+ if ((unsigned)(INT_TYPE)(~0) > 255) {
+
+ volatile short a, b;
+ a = 1 + 256;
+ b = 1 + 256;
+ assert(!(a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert((a >= b));
+ assert(!(a != b));
+ assert((a == b));
+
+ a = -2 - 256;
+ b = -2 - 256;
+ assert(!(a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert((a >= b));
+ assert(!(a != b));
+ assert((a == b));
+
+ if ((unsigned)(INT_TYPE)(~0) > 65535) {
+
+ volatile int a, b;
+ a = 1 + 65536;
+ b = 1 + 65536;
+ assert(!(a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert((a >= b));
+ assert(!(a != b));
+ assert((a == b));
+
+ a = -2 - 65536;
+ b = -2 - 65536;
+ assert(!(a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert((a >= b));
+ assert(!(a != b));
+ assert((a == b));
+
+ if ((unsigned)(INT_TYPE)(~0) > 4294967295) {
+
+ volatile long a, b;
+ a = 1 + 4294967296;
+ b = 1 + 4294967296;
+ assert(!(a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert((a >= b));
+ assert(!(a != b));
+ assert((a == b));
+
+ a = -2 - 4294967296;
+ b = -2 - 4294967296;
+ assert(!(a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert((a >= b));
+ assert(!(a != b));
+ assert((a == b));
+
+ }
+
+ }
+
+ }
+
+}
+
diff --git a/test/test-libextensions.sh b/test/test-libextensions.sh
new file mode 100755
index 00000000..40a898c8
--- /dev/null
+++ b/test/test-libextensions.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+. ./test-pre.sh
+
+test -z "$AFL_CC" && unset AFL_CC
+
+$ECHO "$BLUE[*] Testing: shared library extensions"
+cc $CFLAGS -o test-compcov test-compcov.c > /dev/null 2>&1
+test -e ../libtokencap.so && {
+ AFL_TOKEN_FILE=token.out LD_PRELOAD=../libtokencap.so DYLD_INSERT_LIBRARIES=../libtokencap.so DYLD_FORCE_FLAT_NAMESPACE=1 ./test-compcov foobar > /dev/null 2>&1
+ grep -q BUGMENOT token.out > /dev/null 2>&1 && {
+ $ECHO "$GREEN[+] libtokencap did successfully capture tokens"
+ } || {
+ $ECHO "$RED[!] libtokencap did not capture tokens"
+ CODE=1
+ }
+ rm -f token.out
+} || {
+ $ECHO "$YELLOW[-] libtokencap is not compiled, cannot test"
+ INCOMPLETE=1
+}
+test -e ../libdislocator.so && {
+ {
+ ulimit -c 1
+ # DYLD_INSERT_LIBRARIES and DYLD_FORCE_FLAT_NAMESPACE is used on Darwin/MacOSX
+ LD_PRELOAD=../libdislocator.so DYLD_INSERT_LIBRARIES=../libdislocator.so DYLD_FORCE_FLAT_NAMESPACE=1 ./test-compcov BUFFEROVERFLOW > test.out 2>/dev/null
+ } > /dev/null 2>&1
+ grep -q BUFFEROVERFLOW test.out > /dev/null 2>&1 && {
+ $ECHO "$RED[!] libdislocator did not detect the memory corruption"
+ CODE=1
+ } || {
+ $ECHO "$GREEN[+] libdislocator did successfully detect the memory corruption"
+ }
+ rm -f test.out core test-compcov.core core.test-compcov
+} || {
+ $ECHO "$YELLOW[-] libdislocator is not compiled, cannot test"
+ INCOMPLETE=1
+}
+rm -f test-compcov
+
+. ./test-post.sh
diff --git a/test/test-llvm-lto.sh b/test/test-llvm-lto.sh
new file mode 100755
index 00000000..bb4a9f7c
--- /dev/null
+++ b/test/test-llvm-lto.sh
@@ -0,0 +1,81 @@
+#!/bin/sh
+
+. ./test-pre.sh
+
+$ECHO "$BLUE[*] Testing: LTO llvm_mode"
+test -e ../afl-clang-lto -a -e ../SanitizerCoverageLTO.so && {
+ # on FreeBSD need to set AFL_CC
+ test `uname -s` = 'FreeBSD' && {
+ if type clang >/dev/null; then
+ export AFL_CC=`command -v clang`
+ else
+ export AFL_CC=`$LLVM_CONFIG --bindir`/clang
+ fi
+ }
+
+ ../afl-clang-lto -o test-instr.plain ../test-instr.c > /dev/null 2>&1
+ test -e test-instr.plain && {
+ $ECHO "$GREEN[+] llvm_mode LTO compilation succeeded"
+ echo 0 | AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.plain.0 -r -- ./test-instr.plain > /dev/null 2>&1
+ AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.plain.1 -r -- ./test-instr.plain < /dev/null > /dev/null 2>&1
+ test -e test-instr.plain.0 -a -e test-instr.plain.1 && {
+ diff -q test-instr.plain.0 test-instr.plain.1 > /dev/null 2>&1 && {
+ $ECHO "$RED[!] llvm_mode LTO instrumentation should be different on different input but is not"
+ CODE=1
+ } || {
+ $ECHO "$GREEN[+] llvm_mode LTO instrumentation present and working correctly"
+ TUPLES=`echo 0|AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -- ./test-instr.plain 2>&1 | grep Captur | awk '{print$3}'`
+ test "$TUPLES" -gt 2 -a "$TUPLES" -lt 7 && {
+ $ECHO "$GREEN[+] llvm_mode LTO run reported $TUPLES instrumented locations which is fine"
+ } || {
+ $ECHO "$RED[!] llvm_mode LTO instrumentation produces weird numbers: $TUPLES"
+ CODE=1
+ }
+ }
+ } || {
+ $ECHO "$RED[!] llvm_mode LTO instrumentation failed"
+ CODE=1
+ }
+ rm -f test-instr.plain.0 test-instr.plain.1
+ } || {
+ $ECHO "$RED[!] LTO llvm_mode failed"
+ CODE=1
+ }
+ rm -f test-instr.plain
+
+ echo foobar.c > instrumentlist.txt
+ AFL_DEBUG=1 AFL_LLVM_INSTRUMENT_FILE=instrumentlist.txt ../afl-clang-lto -o test-compcov test-compcov.c > test.out 2>&1
+ test -e test-compcov && {
+ grep -q "No instrumentation targets found" test.out && {
+ $ECHO "$GREEN[+] llvm_mode LTO instrumentlist feature works correctly"
+ } || {
+ echo CUT------------------------------------------------------------------CUT
+ cat test.out
+ echo CUT------------------------------------------------------------------CUT
+ $ECHO "$RED[!] llvm_mode LTO instrumentlist feature failed"
+ CODE=1
+ }
+ } || {
+ $ECHO "$RED[!] llvm_mode LTO instrumentlist feature compilation failed"
+ CODE=1
+ }
+ rm -f test-compcov test.out instrumentlist.txt
+ ../afl-clang-lto -o test-persistent ../utils/persistent_mode/persistent_demo.c > /dev/null 2>&1
+ test -e test-persistent && {
+ echo foo | AFL_QUIET=1 ../afl-showmap -m none -o /dev/null -q -r ./test-persistent && {
+ $ECHO "$GREEN[+] llvm_mode LTO persistent mode feature works correctly"
+ } || {
+ $ECHO "$RED[!] llvm_mode LTO persistent mode feature failed to work"
+ CODE=1
+ }
+ } || {
+ $ECHO "$RED[!] llvm_mode LTO persistent mode feature compilation failed"
+ CODE=1
+ }
+ rm -f test-persistent
+} || {
+ $ECHO "$YELLOW[-] LTO llvm_mode not compiled, cannot test"
+ INCOMPLETE=1
+}
+
+. ./test-post.sh
diff --git a/test/test-llvm.sh b/test/test-llvm.sh
new file mode 100755
index 00000000..ce64d76c
--- /dev/null
+++ b/test/test-llvm.sh
@@ -0,0 +1,299 @@
+#!/bin/sh
+
+. ./test-pre.sh
+
+$ECHO "$BLUE[*] Testing: llvm_mode, afl-showmap, afl-fuzz, afl-cmin and afl-tmin"
+test -e ../afl-clang-fast -a -e ../split-switches-pass.so && {
+ ../afl-clang-fast -o test-instr.plain ../test-instr.c > /dev/null 2>&1
+ AFL_HARDEN=1 ../afl-clang-fast -o test-compcov.harden test-compcov.c > /dev/null 2>&1
+ test -e test-instr.plain && {
+ $ECHO "$GREEN[+] llvm_mode compilation succeeded"
+ echo 0 | AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.plain.0 -r -- ./test-instr.plain > /dev/null 2>&1
+ AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.plain.1 -r -- ./test-instr.plain < /dev/null > /dev/null 2>&1
+ test -e test-instr.plain.0 -a -e test-instr.plain.1 && {
+ diff test-instr.plain.0 test-instr.plain.1 > /dev/null 2>&1 && {
+ $ECHO "$RED[!] llvm_mode instrumentation should be different on different input but is not"
+ CODE=1
+ } || {
+ $ECHO "$GREEN[+] llvm_mode instrumentation present and working correctly"
+ TUPLES=`echo 0|AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -- ./test-instr.plain 2>&1 | grep Captur | awk '{print$3}'`
+ test "$TUPLES" -gt 2 -a "$TUPLES" -lt 8 && {
+ $ECHO "$GREEN[+] llvm_mode run reported $TUPLES instrumented locations which is fine"
+ } || {
+ $ECHO "$RED[!] llvm_mode instrumentation produces weird numbers: $TUPLES"
+ CODE=1
+ }
+ test "$TUPLES" -lt 3 && SKIP=1
+ true
+ }
+ } || {
+ $ECHO "$RED[!] llvm_mode instrumentation failed"
+ CODE=1
+ }
+ rm -f test-instr.plain.0 test-instr.plain.1
+ } || {
+ $ECHO "$RED[!] llvm_mode failed"
+ CODE=1
+ }
+ AFL_LLVM_INSTRUMENT=CLASSIC AFL_LLVM_THREADSAFE_INST=1 ../afl-clang-fast -o test-instr.ts ../test-instr.c > /dev/null 2>&1
+ test -e test-instr.ts && {
+ $ECHO "$GREEN[+] llvm_mode threadsafe compilation succeeded"
+ echo 0 | AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.ts.0 -r -- ./test-instr.ts > /dev/null 2>&1
+ AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.ts.1 -r -- ./test-instr.ts < /dev/null > /dev/null 2>&1
+ test -e test-instr.ts.0 -a -e test-instr.ts.1 && {
+ diff test-instr.ts.0 test-instr.ts.1 > /dev/null 2>&1 && {
+ $ECHO "$RED[!] llvm_mode threadsafe instrumentation should be different on different input but is not"
+ CODE=1
+ } || {
+ $ECHO "$GREEN[+] llvm_mode threadsafe instrumentation present and working correctly"
+ TUPLES=`echo 0|AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -- ./test-instr.ts 2>&1 | grep Captur | awk '{print$3}'`
+ test "$TUPLES" -gt 2 -a "$TUPLES" -lt 8 && {
+ $ECHO "$GREEN[+] llvm_mode run reported $TUPLES threadsafe instrumented locations which is fine"
+ } || {
+ $ECHO "$RED[!] llvm_mode threadsafe instrumentation produces weird numbers: $TUPLES"
+ CODE=1
+ }
+ test "$TUPLES" -lt 3 && SKIP=1
+ true
+ }
+ } || {
+ $ECHO "$RED[!] llvm_mode threadsafe instrumentation failed"
+ CODE=1
+ }
+ rm -f test-instr.ts.0 test-instr.ts.1
+ } || {
+ $ECHO "$RED[!] llvm_mode (threadsafe) failed"
+ CODE=1
+ }
+ ../afl-clang-fast -DTEST_SHARED_OBJECT=1 -z defs -fPIC -shared -o test-instr.so ../test-instr.c > /dev/null 2>&1
+ test -e test-instr.so && {
+ $ECHO "$GREEN[+] llvm_mode shared object with -z defs compilation succeeded"
+ test `uname -s` = 'Linux' && LIBS=-ldl
+ ../afl-clang-fast -o test-dlopen.plain test-dlopen.c ${LIBS} > /dev/null 2>&1
+ test -e test-dlopen.plain && {
+ $ECHO "$GREEN[+] llvm_mode test-dlopen compilation succeeded"
+ echo 0 | DYLD_INSERT_LIBRARIES=./test-instr.so LD_PRELOAD=./test-instr.so TEST_DLOPEN_TARGET=./test-instr.so AFL_QUIET=1 ./test-dlopen.plain > /dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ $ECHO "$RED[!] llvm_mode test-dlopen exits with an error"
+ CODE=1
+ fi
+ echo 0 | AFL_PRELOAD=./test-instr.so TEST_DLOPEN_TARGET=./test-instr.so AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-dlopen.plain.0 -r -- ./test-dlopen.plain > /dev/null 2>&1
+ AFL_PRELOAD=./test-instr.so TEST_DLOPEN_TARGET=./test-instr.so AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-dlopen.plain.1 -r -- ./test-dlopen.plain < /dev/null > /dev/null 2>&1
+ test -e test-dlopen.plain.0 -a -e test-dlopen.plain.1 && {
+ diff test-dlopen.plain.0 test-dlopen.plain.1 > /dev/null 2>&1 && {
+ $ECHO "$RED[!] llvm_mode test-dlopen instrumentation should be different on different input but is not"
+ CODE=1
+ } || {
+ $ECHO "$GREEN[+] llvm_mode test-dlopen instrumentation present and working correctly"
+ TUPLES=`echo 0|AFL_PRELOAD=./test-instr.so TEST_DLOPEN_TARGET=./test-instr.so AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -- ./test-dlopen.plain 2>&1 | grep Captur | awk '{print$3}'`
+ test "$TUPLES" -gt 3 -a "$TUPLES" -lt 12 && {
+ $ECHO "$GREEN[+] llvm_mode test-dlopen run reported $TUPLES instrumented locations which is fine"
+ } || {
+ $ECHO "$RED[!] llvm_mode test-dlopen instrumentation produces weird numbers: $TUPLES"
+ CODE=1
+ }
+ test "$TUPLES" -lt 3 && SKIP=1
+ true
+ }
+ } || {
+ $ECHO "$RED[!] llvm_mode test-dlopen instrumentation failed"
+ CODE=1
+ }
+ } || {
+ $ECHO "$RED[!] llvm_mode test-dlopen compilation failed"
+ CODE=1
+ }
+ rm -f test-dlopen.plain test-dlopen.plain.0 test-dlopen.plain.1 test-instr.so
+ unset LIBS
+ } || {
+ $ECHO "$RED[!] llvm_mode shared object with -z defs compilation failed"
+ CODE=1
+ }
+ test -e test-compcov.harden && test_compcov_binary_functionality ./test-compcov.harden && {
+ nm test-compcov.harden | grep -Eq 'stack_chk_fail|fstack-protector-all|fortified' > /dev/null 2>&1 && {
+ $ECHO "$GREEN[+] llvm_mode hardened mode succeeded and is working"
+ } || {
+ $ECHO "$RED[!] llvm_mode hardened mode is not hardened"
+ CODE=1
+ }
+ rm -f test-compcov.harden
+ } || {
+ $ECHO "$RED[!] llvm_mode hardened mode compilation failed"
+ CODE=1
+ }
+ # now we want to be sure that afl-fuzz is working
+ # make sure crash reporter is disabled on Mac OS X
+ (test "$(uname -s)" = "Darwin" && test $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') && {
+ $ECHO "$RED[!] we cannot run afl-fuzz with enabled crash reporter. Run 'sudo sh afl-system-config'.$RESET"
+ CODE=1
+ true
+ }) || {
+ mkdir -p in
+ echo 0 > in/in
+ test -z "$SKIP" && {
+ $ECHO "$GREY[*] running afl-fuzz for llvm_mode, this will take approx 10 seconds"
+ {
+ ../afl-fuzz -V10 -m ${MEM_LIMIT} -i in -o out -D -- ./test-instr.plain >>errors 2>&1
+ } >>errors 2>&1
+ test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && {
+ $ECHO "$GREEN[+] afl-fuzz is working correctly with llvm_mode"
+ } || {
+ echo CUT------------------------------------------------------------------CUT
+ cat errors
+ echo CUT------------------------------------------------------------------CUT
+ $ECHO "$RED[!] afl-fuzz is not working correctly with llvm_mode"
+ CODE=1
+ }
+ }
+ test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" || {
+ echo 000000000000000000000000 > in/in2
+ echo 111 > in/in3
+ mkdir -p in2
+ ../afl-cmin -m ${MEM_LIMIT} -i in -o in2 -- ./test-instr.plain >/dev/null 2>&1 # why is afl-forkserver writing to stderr?
+ CNT=`ls in2/* 2>/dev/null | wc -l`
+ case "$CNT" in
+ *2) $ECHO "$GREEN[+] afl-cmin correctly minimized the number of testcases" ;;
+ *) $ECHO "$RED[!] afl-cmin did not correctly minimize the number of testcases ($CNT)"
+ CODE=1
+ ;;
+ esac
+ rm -f in2/in*
+ export AFL_QUIET=1
+ if type bash >/dev/null ; then {
+ ../afl-cmin.bash -m ${MEM_LIMIT} -i in -o in2 -- ./test-instr.plain >/dev/null
+ CNT=`ls in2/* 2>/dev/null | wc -l`
+ case "$CNT" in
+ *2) $ECHO "$GREEN[+] afl-cmin.bash correctly minimized the number of testcases" ;;
+ *) $ECHO "$RED[!] afl-cmin.bash did not correctly minimize the number of testcases ($CNT)"
+ CODE=1
+ ;;
+ esac
+ } else {
+ $ECHO "$YELLOW[-] no bash available, cannot test afl-cmin.bash"
+ INCOMPLETE=1
+ }
+ fi
+ ../afl-tmin -m ${MEM_LIMIT} -i in/in2 -o in2/in2 -- ./test-instr.plain > /dev/null 2>&1
+ SIZE=`ls -l in2/in2 2>/dev/null | awk '{print$5}'`
+ test "$SIZE" = 1 && $ECHO "$GREEN[+] afl-tmin correctly minimized the testcase"
+ test "$SIZE" = 1 || {
+ $ECHO "$RED[!] afl-tmin did incorrectly minimize the testcase to $SIZE"
+ CODE=1
+ }
+ rm -rf in2
+ }
+ rm -rf in out errors
+ }
+ rm -f test-instr.plain
+
+ $ECHO "$GREY[*] llvm_mode laf-intel/compcov testing splitting integer types (this might take some time)"
+ for testcase in ./test-int_cases.c ./test-uint_cases.c; do
+ for I in char short int long "long long"; do
+ for BITS in 8 16 32 64; do
+ bin="$testcase-split-$I-$BITS.compcov"
+ AFL_LLVM_INSTRUMENT=AFL AFL_DEBUG=1 AFL_LLVM_LAF_SPLIT_COMPARES_BITW=$BITS AFL_LLVM_LAF_SPLIT_COMPARES=1 ../afl-clang-fast -fsigned-char -DINT_TYPE="$I" -o "$bin" "$testcase" > test.out 2>&1;
+ if ! test -e "$bin"; then
+ cat test.out
+ $ECHO "$RED[!] llvm_mode laf-intel/compcov integer splitting failed! ($testcase with type $I split to $BITS)!";
+ CODE=1
+ break
+ fi
+ if ! "$bin"; then
+ $ECHO "$RED[!] llvm_mode laf-intel/compcov integer splitting resulted in miscompilation (type $I split to $BITS)!";
+ CODE=1
+ break
+ fi
+ rm -f "$bin" test.out || true
+ done
+ done
+ done
+ rm -f test-int-split*.compcov test.out
+
+ AFL_LLVM_INSTRUMENT=AFL AFL_DEBUG=1 AFL_LLVM_LAF_SPLIT_SWITCHES=1 AFL_LLVM_LAF_TRANSFORM_COMPARES=1 AFL_LLVM_LAF_SPLIT_COMPARES=1 ../afl-clang-fast -o test-compcov.compcov test-compcov.c > test.out 2>&1
+ test -e test-compcov.compcov && test_compcov_binary_functionality ./test-compcov.compcov && {
+ grep --binary-files=text -Eq " [ 123][0-9][0-9] location| [3-9][0-9] location" test.out && {
+ $ECHO "$GREEN[+] llvm_mode laf-intel/compcov feature works correctly"
+ } || {
+ $ECHO "$RED[!] llvm_mode laf-intel/compcov feature failed"
+ CODE=1
+ }
+ } || {
+ $ECHO "$RED[!] llvm_mode laf-intel/compcov feature compilation failed"
+ CODE=1
+ }
+ rm -f test-compcov.compcov test.out
+ AFL_LLVM_INSTRUMENT=AFL AFL_LLVM_LAF_SPLIT_FLOATS=1 ../afl-clang-fast -o test-floatingpoint test-floatingpoint.c >errors 2>&1
+ test -e test-floatingpoint && {
+ mkdir -p in
+ echo ZZZZ > in/in
+ $ECHO "$GREY[*] running afl-fuzz with floating point splitting, this will take max. 45 seconds"
+ {
+ AFL_BENCH_UNTIL_CRASH=1 AFL_NO_UI=1 ../afl-fuzz -Z -s 123 -V50 -m ${MEM_LIMIT} -i in -o out -D -- ./test-floatingpoint >>errors 2>&1
+ } >>errors 2>&1
+ test -n "$( ls out/default/crashes/id:* 2>/dev/null )" && {
+ $ECHO "$GREEN[+] llvm_mode laf-intel floatingpoint splitting feature works correctly"
+ } || {
+ cat errors
+ $ECHO "$RED[!] llvm_mode laf-intel floatingpoint splitting feature failed"
+ CODE=1
+ }
+ } || {
+ $ECHO "$RED[!] llvm_mode laf-intel floatingpoint splitting feature compilation failed"
+ CODE=1
+ }
+ rm -f test-floatingpoint test.out in/in errors core.*
+ echo foobar.c > instrumentlist.txt
+ AFL_DEBUG=1 AFL_LLVM_INSTRUMENT_FILE=instrumentlist.txt ../afl-clang-fast -o test-compcov test-compcov.c > test.out 2>&1
+ test -e test-compcov && test_compcov_binary_functionality ./test-compcov && {
+ grep -q "No instrumentation targets found" test.out && {
+ $ECHO "$GREEN[+] llvm_mode instrumentlist feature works correctly"
+ } || {
+ $ECHO "$RED[!] llvm_mode instrumentlist feature failed"
+ CODE=1
+ }
+ } || {
+ $ECHO "$RED[!] llvm_mode instrumentlist feature compilation failed"
+ CODE=1
+ }
+ rm -f test-compcov test.out instrumentlist.txt
+ AFL_LLVM_CMPLOG=1 ../afl-clang-fast -o test-cmplog test-cmplog.c > /dev/null 2>&1
+ test -e test-cmplog && {
+ $ECHO "$GREY[*] running afl-fuzz for llvm_mode cmplog, this will take approx 10 seconds"
+ {
+ mkdir -p in
+ echo 00000000000000000000000000000000 > in/in
+ AFL_BENCH_UNTIL_CRASH=1 ../afl-fuzz -m none -V60 -i in -o out -c./test-cmplog -- ./test-cmplog >>errors 2>&1
+ } >>errors 2>&1
+ test -n "$( ls out/default/crashes/id:000000* out/default/hangs/id:000000* 2>/dev/null )" & {
+ $ECHO "$GREEN[+] afl-fuzz is working correctly with llvm_mode cmplog"
+ } || {
+ echo CUT------------------------------------------------------------------CUT
+ cat errors
+ echo CUT------------------------------------------------------------------CUT
+ $ECHO "$RED[!] afl-fuzz is not working correctly with llvm_mode cmplog"
+ CODE=1
+ }
+ } || {
+ $ECHO "$YELLOW[-] we cannot test llvm_mode cmplog because it is not present"
+ INCOMPLETE=1
+ }
+ rm -rf errors test-cmplog in core.*
+ ../afl-clang-fast -o test-persistent ../utils/persistent_mode/persistent_demo.c > /dev/null 2>&1
+ test -e test-persistent && {
+ echo foo | AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -q -r ./test-persistent && {
+ $ECHO "$GREEN[+] llvm_mode persistent mode feature works correctly"
+ } || {
+ $ECHO "$RED[!] llvm_mode persistent mode feature failed to work"
+ CODE=1
+ }
+ } || {
+ $ECHO "$RED[!] llvm_mode persistent mode feature compilation failed"
+ CODE=1
+ }
+ rm -f test-persistent
+} || {
+ $ECHO "$YELLOW[-] llvm_mode not compiled, cannot test"
+ INCOMPLETE=1
+}
+
+. ./test-post.sh
diff --git a/test/test-multiple-mutators.c b/test/test-multiple-mutators.c
new file mode 100644
index 00000000..dafc817c
--- /dev/null
+++ b/test/test-multiple-mutators.c
@@ -0,0 +1,23 @@
+/**
+ * Test-Case for multiple custom mutators in C
+ * Reference:
+ * https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/blob/master/4_libprotobuf_aflpp_custom_mutator/vuln.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int main(int argc, char **argv) {
+
+ int a = 0;
+ char s[100];
+ read(0, s, 100);
+
+ if (s[7] == 'B') { abort(); }
+
+ return 0;
+
+}
+
diff --git a/test/test-performance.sh b/test/test-performance.sh
new file mode 100755
index 00000000..d61e2f2a
--- /dev/null
+++ b/test/test-performance.sh
@@ -0,0 +1,239 @@
+#!/bin/bash
+
+# if you want a specific performance file (e.g. to compare features to another)
+# you can set the AFL_PERFORMANCE_FILE environment variable:
+FILE=$AFL_PERFORMANCE_FILE
+# otherwise we use ~/.afl_performance
+test -z "$FILE" && FILE=.afl_performance
+
+test -e $FILE || {
+ echo Warning: This script measure the performance of afl++ and saves the result for future comparisons into $FILE
+ echo Press ENTER to continue or CONTROL-C to abort
+ read IN
+}
+
+test -e ./test-performance.sh || { echo Error: this script must be run from the directory in which it lies. ; exit 1 ; }
+
+export AFL_QUIET=1
+export AFL_PATH=`pwd`/..
+
+unset AFL_EXIT_WHEN_DONE
+unset AFL_EXIT_ON_TIME
+unset AFL_SKIP_CPUFREQ
+unset AFL_DEBUG
+unset AFL_HARDEN
+unset AFL_USE_ASAN
+unset AFL_USE_MSAN
+unset AFL_CC
+unset AFL_PRELOAD
+unset AFL_GCC_INSTRUMENT_FILE
+unset AFL_LLVM_INSTRUMENT_FILE
+unset AFL_LLVM_INSTRIM
+unset AFL_LLVM_LAF_SPLIT_SWITCHES
+unset AFL_LLVM_LAF_TRANSFORM_COMPARES
+unset AFL_LLVM_LAF_SPLIT_COMPARES
+
+# on OpenBSD we need to work with llvm from /usr/local/bin
+test -e /usr/local/bin/opt && {
+ export PATH=/usr/local/bin:${PATH}
+}
+# on MacOS X we prefer afl-clang over afl-gcc, because
+# afl-gcc does not work there
+test `uname -s` = 'Darwin' -o `uname -s` = 'FreeBSD' && {
+ AFL_GCC=afl-clang
+ CC=clang
+} || {
+ AFL_GCC=afl-gcc
+ CC=gcc
+}
+
+ECHO="printf %b\\n"
+$ECHO \\101 2>&1 | grep -qE '^A' || {
+ ECHO=
+ test -e /bin/printf && {
+ ECHO="/bin/printf %b\\n"
+ $ECHO '\\101' 2>&1 | grep -qE '^A' || ECHO=
+ }
+}
+test -z "$ECHO" && { printf Error: printf command does not support octal character codes ; exit 1 ; }
+
+GREY="\\033[1;90m"
+BLUE="\\033[1;94m"
+GREEN="\\033[0;32m"
+RED="\\033[0;31m"
+YELLOW="\\033[1;93m"
+RESET="\\033[0m"
+
+MEM_LIMIT=500
+
+touch $FILE || { echo Error: can not write to $FILE ; exit 1 ; }
+
+echo Warning: this script is setting performance parameters with afl-system-config
+sleep 1
+afl-system-config > /dev/null 2>&1
+echo Performance settings applied.
+echo
+
+$ECHO "${RESET}${GREY}[*] starting afl++ performance test framework ..."
+
+$ECHO "$BLUE[*] Testing: ${AFL_GCC}"
+GCC=x
+test -e ../${AFL_GCC} -a -e ../afl-fuzz && {
+ ../${AFL_GCC} -o test-instr.plain ../test-instr.c > /dev/null 2>&1
+ test -e test-instr.plain && {
+ $ECHO "$GREEN[+] ${AFL_GCC} compilation succeeded"
+ mkdir -p in
+ echo 0 > in/in
+ $ECHO "$GREY[*] running afl-fuzz for ${AFL_GCC} for 30 seconds"
+ {
+ ../afl-fuzz -V 30 -s 123 -m ${MEM_LIMIT} -i in -o out-gcc -- ./test-instr.plain
+ } >>errors 2>&1
+ test -n "$( ls out-gcc/default/queue/id:000002* 2> /dev/null )" && {
+ GCC=`grep execs_done out-gcc/default/fuzzer_stats | awk '{print$3}'`
+ } || {
+ echo CUT----------------------------------------------------------------
+ cat errors
+ echo CUT----------------------------------------------------------------
+ $ECHO "$RED[!] afl-fuzz is not working correctly with ${AFL_GCC}"
+ }
+ rm -rf in out-gcc errors test-instr.plain
+ } || $ECHO "$RED[!] ${AFL_GCC} instrumentation failed"
+} || $ECHO "$YELLOW[-] afl is not compiled, cannot test"
+
+$ECHO "$BLUE[*] Testing: llvm_mode"
+LLVM=x
+test -e ../afl-clang-fast -a -e ../afl-fuzz && {
+ ../afl-clang-fast -o test-instr.llvm ../test-instr.c > /dev/null 2>&1
+ test -e test-instr.llvm && {
+ $ECHO "$GREEN[+] llvm_mode compilation succeeded"
+ mkdir -p in
+ echo 0 > in/in
+ $ECHO "$GREY[*] running afl-fuzz for llvm_mode for 30 seconds"
+ {
+ ../afl-fuzz -V 30 -s 123 -m ${MEM_LIMIT} -i in -o out-llvm -- ./test-instr.llvm
+ } >>errors 2>&1
+ test -n "$( ls out-llvm/default/queue/id:000002* 2> /dev/null )" && {
+ LLVM=`grep execs_done out-llvm/default/fuzzer_stats | awk '{print$3}'`
+ } || {
+ echo CUT----------------------------------------------------------------
+ cat errors
+ echo CUT----------------------------------------------------------------
+ $ECHO "$RED[!] afl-fuzz is not working correctly with llvm_mode"
+ }
+ rm -rf in out-llvm errors test-instr.llvm
+ } || $ECHO "$RED[!] llvm_mode instrumentation failed"
+} || $ECHO "$YELLOW[-] llvm_mode is not compiled, cannot test"
+
+$ECHO "$BLUE[*] Testing: gcc_plugin"
+GCCP=x
+test -e ../afl-gcc-fast -a -e ../afl-fuzz && {
+ ../afl-gcc-fast -o test-instr.gccp ../test-instr.c > /dev/null 2>&1
+ test -e test-instr.gccp && {
+ $ECHO "$GREEN[+] gcc_plugin compilation succeeded"
+ mkdir -p in
+ echo 0 > in/in
+ $ECHO "$GREY[*] running afl-fuzz for gcc_plugin for 30 seconds"
+ {
+ ../afl-fuzz -V 30 -s 123 -m ${MEM_LIMIT} -i in -o out-gccp -- ./test-instr.gccp
+ } >>errors 2>&1
+ test -n "$( ls out-gccp/default/queue/id:000002* 2> /dev/null )" && {
+ GCCP=`grep execs_done out-gccp/default/fuzzer_stats | awk '{print$3}'`
+ } || {
+ echo CUT----------------------------------------------------------------
+ cat errors
+ echo CUT----------------------------------------------------------------
+ $ECHO "$RED[!] afl-fuzz is not working correctly with gcc_plugin"
+ }
+ rm -rf in out-gccp errors test-instr.gccp
+ } || $ECHO "$RED[!] gcc_plugin instrumentation failed"
+} || $ECHO "$YELLOW[-] gcc_plugin is not compiled, cannot test"
+
+$ECHO "$BLUE[*] Testing: qemu_mode"
+QEMU=x
+test -e ../afl-qemu-trace -a -e ../afl-fuzz && {
+ $CC -o test-instr.qemu ../test-instr.c > /dev/null 2>&1
+ test -e test-instr.qemu && {
+ $ECHO "$GREEN[+] native compilation with cc succeeded"
+ mkdir -p in
+ echo 0 > in/in
+ $ECHO "$GREY[*] running afl-fuzz for qemu_mode for 30 seconds"
+ {
+ ../afl-fuzz -Q -V 30 -s 123 -m ${MEM_LIMIT} -i in -o out-qemu -- ./test-instr.qemu
+ } >>errors 2>&1
+ test -n "$( ls out-qemu/default/queue/id:000002* 2> /dev/null )" && {
+ QEMU=`grep execs_done out-qemu/default/fuzzer_stats | awk '{print$3}'`
+ } || {
+ echo CUT----------------------------------------------------------------
+ echo ../afl-fuzz -Q -V 30 -s 123 -m ${MEM_LIMIT} -i in -o out-qemu -- ./test-instr.qemu
+ cat errors
+ echo CUT----------------------------------------------------------------
+ $ECHO "$RED[!] afl-fuzz is not working correctly with qemu_mode"
+ }
+ rm -rf in out-qemu errors test-instr.qemu
+ } || $ECHO "$RED[!] qemu_mode instrumentation failed"
+} || $ECHO "$YELLOW[-] qemu_mode is not compiled, cannot test"
+
+LOW_GCC=
+HIGH_GCC=
+LAST_GCC=
+LOW_LLVM=
+HIGH_LLVM=
+LAST_LLVM=
+LOW_GCCP=
+HIGH_GCCP=
+LAST_GCCP=
+LOW_QEMU=
+HIGH_QEMU=
+LAST_QEMU=
+
+test -s $FILE && {
+ while read LINE; do
+ G=`echo $LINE | awk '{print$1}'`
+ L=`echo $LINE | awk '{print$2}'`
+ P=`echo $LINE | awk '{print$3}'`
+ Q=`echo $LINE | awk '{print$4}'`
+ test "$G" = x && G=
+ test "$L" = x && L=
+ test "$P" = x && P=
+ test "$Q" = x && Q=
+ test -n "$G" && LAST_GCC=$G
+ test -n "$L" && LAST_LLVM=$L
+ test -n "$P" && LAST_GCCP=$P
+ test -n "$Q" && LAST_QEMU=$Q
+ test -n "$G" -a -z "$LOW_GCC" && LOW_GCC=$G || {
+ test -n "$G" -a "$G" -lt "$LOW_GCC" 2> /dev/null && LOW_GCC=$G
+ }
+ test -n "$L" -a -z "$LOW_LLVM" && LOW_LLVM=$L || {
+ test -n "$L" -a "$L" -lt "$LOW_LLVM" 2> /dev/null && LOW_LLVM=$L
+ }
+ test -n "$P" -a -z "$LOW_GCCP" && LOW_GCCP=$P || {
+ test -n "$P" -a "$P" -lt "$LOW_GCCP" 2> /dev/null && LOW_GCCP=$P
+ }
+ test -n "$Q" -a -z "$LOW_QEMU" && LOW_QEMU=$Q || {
+ test -n "$Q" -a "$Q" -lt "$LOW_QEMU" 2> /dev/null && LOW_QEMU=$Q
+ }
+ test -n "$G" -a -z "$HIGH_GCC" && HIGH_GCC=$G || {
+ test -n "$G" -a "$G" -gt "$HIGH_GCC" 2> /dev/null && HIGH_GCC=$G
+ }
+ test -n "$L" -a -z "$HIGH_LLVM" && HIGH_LLVM=$L || {
+ test -n "$L" -a "$L" -gt "$HIGH_LLVM" 2> /dev/null && HIGH_LLVM=$L
+ }
+ test -n "$P" -a -z "$HIGH_GCCP" && HIGH_GCCP=$P || {
+ test -n "$P" -a "$P" -gt "$HIGH_GCCP" 2> /dev/null && HIGH_GCCP=$P
+ }
+ test -n "$Q" -a -z "$HIGH_QEMU" && HIGH_QEMU=$Q || {
+ test -n "$Q" -a "$Q" -gt "$HIGH_QEMU" 2> /dev/null && HIGH_QEMU=$Q
+ }
+ done < $FILE
+ $ECHO "$YELLOW[!] Reading saved data from $FILE completed, please compare the results:"
+ $ECHO "$BLUE[!] afl-cc: lowest=$LOW_GCC highest=$HIGH_GCC last=$LAST_GCC current=$GCC"
+ $ECHO "$BLUE[!] llvm_mode: lowest=$LOW_LLVM highest=$HIGH_LLVM last=$LAST_LLVM current=$LLVM"
+ $ECHO "$BLUE[!] gcc_plugin: lowest=$LOW_GCCP highest=$HIGH_GCCP last=$LAST_GCCP current=$GCCP"
+ $ECHO "$BLUE[!] qemu_mode: lowest=$LOW_QEMU highest=$HIGH_QEMU last=$LAST_QEMU current=$QEMU"
+} || {
+ $ECHO "$YELLOW[!] First run, just saving data"
+ $ECHO "$BLUE[!] afl-gcc=$GCC llvm_mode=$LLVM gcc_plugin=$GCCP qemu_mode=$QEMU"
+}
+echo "$GCC $LLVM $GCCP $QEMU" >> $FILE
+$ECHO "$GREY[*] done."
+$ECHO "$RESET"
diff --git a/test/test-post.sh b/test/test-post.sh
new file mode 100755
index 00000000..0911e2cd
--- /dev/null
+++ b/test/test-post.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+AFL_TEST_DEPTH=$((AFL_TEST_DEPTH-1))
+
+if [ $AFL_TEST_DEPTH = 0 ]; then
+# All runs done :)
+
+$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"
+test "$CODE" = "0" || $ECHO "$RED[!] failure in tests :-($RESET"
+exit $CODE
+
+fi
diff --git a/test/test-pre.sh b/test/test-pre.sh
new file mode 100755
index 00000000..b8b286e5
--- /dev/null
+++ b/test/test-pre.sh
@@ -0,0 +1,143 @@
+#!/bin/sh
+
+# All tests should start with sourcing test-pre.sh and finish with sourcing test-post.sh
+# 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
+# First run :)
+
+#
+# Ensure we have: test, type, diff, grep -qE
+#
+test -z "" 2>/dev/null || { echo Error: test command not found ; exit 1 ; }
+GREP=`type grep > /dev/null 2>&1 && echo OK`
+test "$GREP" = OK || { echo Error: grep command not found ; exit 1 ; }
+echo foobar | grep -qE 'asd|oob' 2>/dev/null || { echo Error: grep command does not support -q and/or -E option ; exit 1 ; }
+test -e ./test-all.sh || cd $(dirname $0) || exit 1
+test -e ./test-all.sh || { echo Error: you must be in the test/ directory ; exit 1 ; }
+export AFL_PATH=`pwd`/..
+export AFL_NO_AFFINITY=1 # workaround for travis that fails for no avail cores
+
+echo 1 > test.1
+echo 1 > test.2
+OK=OK
+diff test.1 test.2 >/dev/null 2>&1 || OK=
+rm -f test.1 test.2
+test -z "$OK" && { echo Error: diff is not working ; exit 1 ; }
+test -z "$LLVM_CONFIG" && LLVM_CONFIG=llvm-config
+
+# check for '-a' option of grep
+if grep -a test test-all.sh >/dev/null 2>&1; then
+ GREPAOPTION=' -a'
+else
+ GREPAOPTION=
+fi
+
+test_compcov_binary_functionality() {
+ RUN="../afl-showmap -m ${MEM_LIMIT} -o /dev/null -- $1"
+ $RUN 'LIBTOKENCAP' | grep 'your string was LIBTOKENCAP' \
+ && $RUN 'BUGMENOT' | grep 'your string was BUGMENOT' \
+ && $RUN 'BANANA' | grep 'your string started with BAN' \
+ && $RUN 'APRI' | grep 'your string was APRI' \
+ && $RUN 'kiWI' | grep 'your string was Kiwi' \
+ && $RUN 'Avocado' | grep 'your string was avocado' \
+ && $RUN 'GRAX' 3 | grep 'your string was a prefix of Grapes' \
+ && $RUN 'LOCALVARIABLE' | grep 'local var memcmp works!' \
+ && $RUN 'abc' | grep 'short local var memcmp works!' \
+ && $RUN 'GLOBALVARIABLE' | grep 'global var memcmp works!'
+} > /dev/null
+
+ECHO="printf %b\\n"
+$ECHO \\101 2>&1 | grep -qE '^A' || {
+ ECHO=
+ test -e /bin/printf && {
+ ECHO="/bin/printf %b\\n"
+ $ECHO "\\101" 2>&1 | grep -qE '^A' || ECHO=
+ }
+}
+test -z "$ECHO" && { printf Error: printf command does not support octal character codes ; exit 1 ; }
+
+export AFL_EXIT_WHEN_DONE=1
+export AFL_EXIT_ON_TIME=60
+export AFL_SKIP_CPUFREQ=1
+export AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1
+unset AFL_NO_X86
+unset AFL_QUIET
+unset AFL_DEBUG
+unset AFL_HARDEN
+unset AFL_USE_ASAN
+unset AFL_USE_MSAN
+unset AFL_USE_UBSAN
+unset AFL_USE_LSAN
+unset AFL_TMPDIR
+unset AFL_CC
+unset AFL_PRELOAD
+unset AFL_GCC_INSTRUMENT_FILE
+unset AFL_LLVM_INSTRUMENT_FILE
+unset AFL_LLVM_INSTRIM
+unset AFL_LLVM_LAF_SPLIT_SWITCHES
+unset AFL_LLVM_LAF_TRANSFORM_COMPARES
+unset AFL_LLVM_LAF_SPLIT_COMPARES
+unset AFL_QEMU_PERSISTENT_ADDR
+unset AFL_QEMU_PERSISTENT_RETADDR_OFFSET
+unset AFL_QEMU_PERSISTENT_GPR
+unset AFL_QEMU_PERSISTENT_RET
+unset AFL_QEMU_PERSISTENT_HOOK
+unset AFL_QEMU_PERSISTENT_CNT
+unset AFL_QEMU_PERSISTENT_MEM
+unset AFL_QEMU_PERSISTENT_EXITS
+unset AFL_CUSTOM_MUTATOR_LIBRARY
+unset AFL_PYTHON_MODULE
+unset AFL_PRELOAD
+unset LD_PRELOAD
+unset SKIP
+
+rm -rf in in2 out
+
+test -z "$TRAVIS_OS_NAME" && {
+ export ASAN_OPTIONS=detect_leaks=0:allocator_may_return_null=1:abort_on_error=1:symbolize=0
+}
+test -n "$TRAVIS_OS_NAME" && {
+ export ASAN_OPTIONS=detect_leaks=0:allocator_may_return_null=1:abort_on_error=1:symbolize=1
+}
+
+#export AFL_LLVM_INSTRUMENT=AFL # AFL mode makes dlopen not link on macos
+
+# on OpenBSD we need to work with llvm from /usr/local/bin
+test -e /usr/local/bin/opt && {
+ test `uname -s` = 'Darwin' || export PATH="/usr/local/bin:${PATH}"
+}
+# on MacOS X we prefer afl-clang over afl-gcc, because
+# afl-gcc does not work there (it is a symlink from clang)
+test `uname -s` = 'Darwin' -o `uname -s` = 'FreeBSD' && {
+ AFL_GCC=afl-clang
+} || {
+ AFL_GCC=afl-gcc
+}
+command -v gcc >/dev/null 2>&1 || AFL_GCC=afl-clang
+
+SYS=`uname -m`
+
+GREY="\\033[1;90m"
+BLUE="\\033[1;94m"
+GREEN="\\033[0;32m"
+RED="\\033[0;31m"
+YELLOW="\\033[1;93m"
+RESET="\\033[0m"
+
+MEM_LIMIT=none
+
+export PATH="${PATH}:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin"
+
+$ECHO "${RESET}${GREY}[*] starting afl++ test framework ..."
+
+test -z "$SYS" && $ECHO "$YELLOW[-] uname -m did not succeed"
+
+CODE=0
+INCOMPLETE=0
+
+fi
diff --git a/test/test-qemu-mode.sh b/test/test-qemu-mode.sh
new file mode 100755
index 00000000..46b138ff
--- /dev/null
+++ b/test/test-qemu-mode.sh
@@ -0,0 +1,214 @@
+#!/bin/sh
+
+. ./test-pre.sh
+
+$ECHO "$BLUE[*] Testing: qemu_mode"
+test -z "$AFL_CC" && {
+ if type gcc >/dev/null; then
+ export AFL_CC=gcc
+ else
+ if type clang >/dev/null; then
+ export AFL_CC=clang
+ fi
+ fi
+}
+
+test -e ../afl-qemu-trace && {
+ cc -pie -fPIE -o test-instr ../test-instr.c
+ cc -o test-compcov test-compcov.c
+ test -e test-instr -a -e test-compcov && {
+ {
+ mkdir -p in
+ echo 00000 > in/in
+ $ECHO "$GREY[*] running afl-fuzz for qemu_mode, this will take approx 10 seconds"
+ {
+ ../afl-fuzz -m ${MEM_LIMIT} -V10 -Q -i in -o out -- ./test-instr >>errors 2>&1
+ } >>errors 2>&1
+ test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && {
+ $ECHO "$GREEN[+] afl-fuzz is working correctly with qemu_mode"
+ RUNTIME=`grep execs_done out/default/fuzzer_stats | awk '{print$3}'`
+ } || {
+ echo CUT------------------------------------------------------------------CUT
+ cat errors
+ echo CUT------------------------------------------------------------------CUT
+ $ECHO "$RED[!] afl-fuzz is not working correctly with qemu_mode"
+ CODE=1
+ }
+ rm -f errors
+
+ $ECHO "$GREY[*] running afl-fuzz for qemu_mode AFL_ENTRYPOINT, this will take approx 6 seconds"
+ {
+ {
+ export AFL_ENTRYPOINT=`printf 1 | AFL_DEBUG=1 ../afl-qemu-trace ./test-instr 2>&1 >/dev/null | awk '/forkserver/{print $4; exit}'`
+ $ECHO AFL_ENTRYPOINT=$AFL_ENTRYPOINT - $(nm test-instr | grep "T main") - $(file ./test-instr)
+ ../afl-fuzz -m ${MEM_LIMIT} -V2 -Q -i in -o out -- ./test-instr
+ unset AFL_ENTRYPOINT
+ } >>errors 2>&1
+ } >>errors 2>&1
+ test -n "$( ls out/default/queue/id:000001* 2>/dev/null )" && {
+ $ECHO "$GREEN[+] afl-fuzz is working correctly with qemu_mode AFL_ENTRYPOINT"
+ RUNTIME=`grep execs_done out/default/fuzzer_stats | awk '{print$3}'`
+ } || {
+ echo CUT------------------------------------------------------------------CUT
+ cat errors
+ echo CUT------------------------------------------------------------------CUT
+ $ECHO "$RED[!] afl-fuzz is not working correctly with qemu_mode AFL_ENTRYPOINT"
+ CODE=1
+ }
+ rm -f errors
+
+ test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" -o "$SYS" = "aarch64" -o ! "${SYS%%arm*}" && {
+ test -e ../libcompcov.so && {
+ $ECHO "$GREY[*] running afl-fuzz for qemu_mode compcov, this will take approx 10 seconds"
+ {
+ export AFL_PRELOAD=../libcompcov.so
+ export AFL_COMPCOV_LEVEL=2
+ ../afl-fuzz -m ${MEM_LIMIT} -V10 -Q -i in -o out -- ./test-compcov >>errors 2>&1
+ unset AFL_PRELOAD
+ unset AFL_COMPCOV_LEVEL
+ } >>errors 2>&1
+ test -n "$( ls out/default/queue/id:000001* 2>/dev/null )" && {
+ $ECHO "$GREEN[+] afl-fuzz is working correctly with qemu_mode compcov"
+ } || {
+ echo CUT------------------------------------------------------------------CUT
+ cat errors
+ echo CUT------------------------------------------------------------------CUT
+ $ECHO "$RED[!] afl-fuzz is not working correctly with qemu_mode compcov"
+ CODE=1
+ }
+ } || {
+ $ECHO "$YELLOW[-] we cannot test qemu_mode compcov because it is not present"
+ INCOMPLETE=1
+ }
+ rm -f errors
+ } || {
+ $ECHO "$YELLOW[-] not an intel or arm platform, cannot test qemu_mode compcov"
+ }
+
+ test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" -o "$SYS" = "aarch64" -o ! "${SYS%%arm*}" && {
+ $ECHO "$GREY[*] running afl-fuzz for qemu_mode cmplog, this will take approx 10 seconds"
+ {
+ ../afl-fuzz -m none -V10 -Q -c 0 -i in -o out -- ./test-compcov >>errors 2>&1
+ } >>errors 2>&1
+ test -n "$( ls out/default/queue/id:000001* 2>/dev/null )" && {
+ $ECHO "$GREEN[+] afl-fuzz is working correctly with qemu_mode cmplog"
+ } || {
+ echo CUT------------------------------------------------------------------CUT
+ cat errors
+ echo CUT------------------------------------------------------------------CUT
+ $ECHO "$RED[!] afl-fuzz is not working correctly with qemu_mode cmplog"
+ CODE=1
+ }
+ rm -f errors
+ } || {
+ $ECHO "$YELLOW[-] not an intel or arm platform, cannot test qemu_mode cmplog"
+ }
+
+ test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" -o "$SYS" = "aarch64" -o ! "${SYS%%arm*}" && {
+ $ECHO "$GREY[*] running afl-fuzz for persistent qemu_mode, this will take approx 10 seconds"
+ {
+ if file test-instr | grep -q "32-bit"; then
+ # for 32-bit reduce 8 nibbles to the lower 7 nibbles
+ ADDR_LOWER_PART=`nm test-instr | grep "T main" | awk '{print $1}' | sed 's/^.//'`
+ else
+ # for 64-bit reduce 16 nibbles to the lower 9 nibbles
+ ADDR_LOWER_PART=`nm test-instr | grep "T main" | awk '{print $1}' | sed 's/^.......//'`
+ fi
+ export AFL_QEMU_PERSISTENT_ADDR=`expr 0x4${ADDR_LOWER_PART}`
+ export AFL_QEMU_PERSISTENT_GPR=1
+ $ECHO "Info: AFL_QEMU_PERSISTENT_ADDR=$AFL_QEMU_PERSISTENT_ADDR <= $(nm test-instr | grep "T main" | awk '{print $1}')"
+ env|grep AFL_|sort
+ file test-instr
+ ../afl-fuzz -m ${MEM_LIMIT} -V10 -Q -i in -o out -- ./test-instr
+ unset AFL_QEMU_PERSISTENT_ADDR
+ } >>errors 2>&1
+ test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && {
+ $ECHO "$GREEN[+] afl-fuzz is working correctly with persistent qemu_mode"
+ RUNTIMEP=`grep execs_done out/default/fuzzer_stats | awk '{print$3}'`
+ test -n "$RUNTIME" -a -n "$RUNTIMEP" && {
+ DIFF=`expr $RUNTIMEP / $RUNTIME`
+ test "$DIFF" -gt 1 && { # must be at least twice as fast
+ $ECHO "$GREEN[+] persistent qemu_mode was noticeable faster than standard qemu_mode"
+ } || {
+ $ECHO "$YELLOW[-] persistent qemu_mode was not noticeable faster than standard qemu_mode"
+ }
+ } || {
+ $ECHO "$YELLOW[-] we got no data on executions performed? weird!"
+ }
+ } || {
+ echo CUT------------------------------------------------------------------CUT
+ cat errors
+ echo CUT------------------------------------------------------------------CUT
+ $ECHO "$RED[!] afl-fuzz is not working correctly with persistent qemu_mode"
+ CODE=1
+ }
+ rm -rf in out errors
+ } || {
+ $ECHO "$YELLOW[-] not an intel or arm platform, cannot test persistent qemu_mode"
+ }
+
+ test -e ../qemu_mode/unsigaction/unsigaction32.so && {
+ ${AFL_CC} -o test-unsigaction32 -m32 test-unsigaction.c >> errors 2>&1 && {
+ ./test-unsigaction32
+ RETVAL_NORMAL32=$?
+ LD_PRELOAD=../qemu_mode/unsigaction/unsigaction32.so ./test-unsigaction32
+ RETVAL_LIBUNSIGACTION32=$?
+ test $RETVAL_NORMAL32 = "2" -a $RETVAL_LIBUNSIGACTION32 = "0" && {
+ $ECHO "$GREEN[+] qemu_mode unsigaction library (32 bit) ignores signals"
+ } || {
+ test $RETVAL_NORMAL32 != "2" && {
+ $ECHO "$RED[!] cannot trigger signal in test program (32 bit)"
+ }
+ test $RETVAL_LIBUNSIGACTION32 != "0" && {
+ $ECHO "$RED[!] signal in test program (32 bit) is not ignored with unsigaction"
+ }
+ CODE=1
+ }
+ } || {
+ $ECHO "$YELLOW[-] cannot compile test program (32 bit) for unsigaction library"
+ INCOMPLETE=1
+ }
+ } || {
+ $ECHO "$YELLOW[-] we cannot test qemu_mode unsigaction library (32 bit) because it is not present"
+ INCOMPLETE=1
+ }
+ test -e ../qemu_mode/unsigaction/unsigaction64.so && {
+ ${AFL_CC} -o test-unsigaction64 -m64 test-unsigaction.c >> errors 2>&1 && {
+ ./test-unsigaction64
+ RETVAL_NORMAL64=$?
+ LD_PRELOAD=../qemu_mode/unsigaction/unsigaction64.so ./test-unsigaction64
+ RETVAL_LIBUNSIGACTION64=$?
+ test $RETVAL_NORMAL64 = "2" -a $RETVAL_LIBUNSIGACTION64 = "0" && {
+ $ECHO "$GREEN[+] qemu_mode unsigaction library (64 bit) ignores signals"
+ } || {
+ test $RETVAL_NORMAL64 != "2" && {
+ $ECHO "$RED[!] cannot trigger signal in test program (64 bit)"
+ }
+ test $RETVAL_LIBUNSIGACTION64 != "0" && {
+ $ECHO "$RED[!] signal in test program (64 bit) is not ignored with unsigaction"
+ }
+ CODE=1
+ }
+ unset LD_PRELOAD
+ } || {
+ $ECHO "$YELLOW[-] cannot compile test program (64 bit) for unsigaction library"
+ INCOMPLETE=1
+ }
+ } || {
+ $ECHO "$YELLOW[-] we cannot test qemu_mode unsigaction library (64 bit) because it is not present"
+ INCOMPLETE=1
+ }
+ rm -rf errors test-unsigaction32 test-unsigaction64
+ }
+ } || {
+ $ECHO "$RED[!] gcc compilation of test targets failed - what is going on??"
+ CODE=1
+ }
+
+ rm -f test-instr test-compcov
+} || {
+ $ECHO "$YELLOW[-] qemu_mode is not compiled, cannot test"
+ INCOMPLETE=1
+}
+
+. ./test-post.sh
diff --git a/test/test-uint_cases.c b/test/test-uint_cases.c
new file mode 100644
index 00000000..bb57f408
--- /dev/null
+++ b/test/test-uint_cases.c
@@ -0,0 +1,232 @@
+/*
+ * compile with -DINT_TYPE="char"
+ * or -DINT_TYPE="short"
+ * or -DINT_TYPE="int"
+ * or -DINT_TYPE="long"
+ * or -DINT_TYPE="long long"
+ */
+
+#include <assert.h>
+
+int main() {
+
+ volatile unsigned INT_TYPE a, b;
+
+ a = 1;
+ b = 8;
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ if ((INT_TYPE)(~0) > 255) {
+
+ volatile unsigned short a, b;
+ a = 256 + 2;
+ b = 256 + 21;
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = 21;
+ b = 256 + 1;
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ if ((INT_TYPE)(~0) > 65535) {
+
+ volatile unsigned int a, b;
+ a = 65536 + 2;
+ b = 65536 + 21;
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = 21;
+ b = 65536 + 1;
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ }
+
+ if ((INT_TYPE)(~0) > 4294967295) {
+
+ volatile unsigned long a, b;
+ a = 4294967296 + 2;
+ b = 4294967296 + 21;
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = 21;
+ b = 4294967296 + 1;
+ assert((a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert(!(a >= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ }
+
+ }
+
+ a = 8;
+ b = 1;
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ if ((INT_TYPE)(~0) > 255) {
+
+ volatile unsigned short a, b;
+ a = 256 + 2;
+ b = 256 + 1;
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = 256 + 2;
+ b = 6;
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ if ((INT_TYPE)(~0) > 65535) {
+
+ volatile unsigned int a, b;
+ a = 65536 + 2;
+ b = 65536 + 1;
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = 65536 + 2;
+ b = 6;
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ if ((INT_TYPE)(~0) > 4294967295) {
+
+ volatile unsigned long a, b;
+ a = 4294967296 + 2;
+ b = 4294967296 + 1;
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ a = 4294967296 + 2;
+ b = 6;
+ assert((a > b));
+ assert((a >= b));
+ assert(!(a < b));
+ assert(!(a <= b));
+ assert((a != b));
+ assert(!(a == b));
+
+ }
+
+ }
+
+ }
+
+ a = 0;
+ b = 0;
+ assert(!(a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert((a >= b));
+ assert(!(a != b));
+ assert((a == b));
+
+ a = 1;
+ b = 1;
+ assert(!(a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert((a >= b));
+ assert(!(a != b));
+ assert((a == b));
+
+ if ((INT_TYPE)(~0) > 255) {
+
+ volatile unsigned short a, b;
+ a = 256 + 5;
+ b = 256 + 5;
+ assert(!(a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert((a >= b));
+ assert(!(a != b));
+ assert((a == b));
+
+ if ((INT_TYPE)(~0) > 65535) {
+
+ volatile unsigned int a, b;
+ a = 65536 + 5;
+ b = 65536 + 5;
+ assert(!(a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert((a >= b));
+ assert(!(a != b));
+ assert((a == b));
+
+ if ((INT_TYPE)(~0) > 4294967295) {
+
+ volatile unsigned long a, b;
+ a = 4294967296 + 5;
+ b = 4294967296 + 5;
+ assert(!(a < b));
+ assert((a <= b));
+ assert(!(a > b));
+ assert((a >= b));
+ assert(!(a != b));
+ assert((a == b));
+
+ }
+
+ }
+
+ }
+
+}
+
diff --git a/test/test-unicorn-mode.sh b/test/test-unicorn-mode.sh
new file mode 100755
index 00000000..f8ff4190
--- /dev/null
+++ b/test/test-unicorn-mode.sh
@@ -0,0 +1,112 @@
+#!/bin/sh
+
+. ./test-pre.sh
+
+$ECHO "$BLUE[*] Testing: unicorn_mode"
+test -d ../unicorn_mode/unicornafl -a -e ../unicorn_mode/unicornafl/Makefile && {
+ test -e ../unicorn_mode/samples/python_simple/simple_target.bin -a -e ../unicorn_mode/samples/compcov_x64/compcov_target.bin && {
+ {
+ # We want to see python errors etc. in logs, in case something doesn't work
+ export AFL_DEBUG_CHILD=1
+
+ # some python version should be available now
+ PYTHONS="`command -v python3` `command -v python` `command -v python2`"
+ EASY_INSTALL_FOUND=0
+ for PYTHON in $PYTHONS ; do
+
+ if $PYTHON -c "import setuptools" ; then
+
+ EASY_INSTALL_FOUND=1
+ PY=$PYTHON
+ break
+
+ fi
+
+ done
+ if [ "0" = $EASY_INSTALL_FOUND ]; then
+
+ echo "[-] Error: Python setup-tools not found. Run 'sudo apt-get install python-setuptools'."
+ PREREQ_NOTFOUND=1
+
+ fi
+
+
+ cd ../unicorn_mode/samples/persistent
+ make >>errors 2>&1
+ $ECHO "$GREY[*] running afl-fuzz for unicorn_mode (persistent), this will take approx 25 seconds"
+ AFL_DEBUG_CHILD=1 ../../../afl-fuzz -m none -V25 -U -i sample_inputs -o out -d -- ./harness @@ >>errors 2>&1
+ test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && {
+ $ECHO "$GREEN[+] afl-fuzz is working correctly with unicorn_mode (persistent)"
+ } || {
+ echo CUT------------------------------------------------------------------CUT
+ cat errors
+ echo CUT------------------------------------------------------------------CUT
+ $ECHO "$RED[!] afl-fuzz is not working correctly with unicorn_mode (persistent)"
+ CODE=1
+ }
+
+ rm -rf out errors >/dev/null
+ make clean >/dev/null
+ cd ../../../test
+
+ # travis workaround
+ test "$PY" = "/opt/pyenv/shims/python" -a -x /usr/bin/python && PY=/usr/bin/python
+ mkdir -p in
+ echo 0 > in/in
+ $ECHO "$GREY[*] Using python binary $PY"
+ if ! $PY -c 'import unicornafl' 2>/dev/null ; then
+ $ECHO "$YELLOW[-] we cannot test unicorn_mode for python because it is not present"
+ INCOMPLETE=1
+ else
+ {
+ $ECHO "$GREY[*] running afl-fuzz for unicorn_mode in python, this will take approx 25 seconds"
+ {
+ ../afl-fuzz -m ${MEM_LIMIT} -V25 -U -i in -o out -d -- "$PY" ../unicorn_mode/samples/python_simple/simple_test_harness.py @@ >>errors 2>&1
+ } >>errors 2>&1
+ test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && {
+ $ECHO "$GREEN[+] afl-fuzz is working correctly with unicorn_mode"
+ } || {
+ echo CUT------------------------------------------------------------------CUT
+ cat errors
+ echo CUT------------------------------------------------------------------CUT
+ $ECHO "$RED[!] afl-fuzz is not working correctly with unicorn_mode"
+ CODE=1
+ }
+ rm -f errors
+
+ printf '\x01\x01' > in/in
+ # This seed is close to the first byte of the comparison.
+ # If CompCov works, a new tuple will appear in the map => new input in queue
+ $ECHO "$GREY[*] running afl-fuzz for unicorn_mode compcov, this will take approx 35 seconds"
+ {
+ export AFL_COMPCOV_LEVEL=2
+ ../afl-fuzz -m ${MEM_LIMIT} -V35 -U -i in -o out -d -- "$PY" ../unicorn_mode/samples/compcov_x64/compcov_test_harness.py @@ >>errors 2>&1
+ unset AFL_COMPCOV_LEVEL
+ } >>errors 2>&1
+ test -n "$( ls out/default/queue/id:000001* 2>/dev/null )" && {
+ $ECHO "$GREEN[+] afl-fuzz is working correctly with unicorn_mode compcov"
+ } || {
+ echo CUT------------------------------------------------------------------CUT
+ cat errors
+ echo CUT------------------------------------------------------------------CUT
+ $ECHO "$RED[!] afl-fuzz is not working correctly with unicorn_mode compcov"
+ CODE=1
+ }
+ rm -rf in out errors
+ }
+ fi
+
+ unset AFL_DEBUG_CHILD
+
+ }
+ } || {
+ $ECHO "$RED[!] missing sample binaries in unicorn_mode/samples/ - what is going on??"
+ CODE=1
+ }
+
+} || {
+ $ECHO "$YELLOW[-] unicorn_mode is not compiled, cannot test"
+ INCOMPLETE=1
+}
+
+. ./test-post.sh
diff --git a/test/test-unittests.sh b/test/test-unittests.sh
new file mode 100755
index 00000000..9a405e2f
--- /dev/null
+++ b/test/test-unittests.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+. ./test-pre.sh
+
+$ECHO "$BLUE[*] Execution cmocka Unit-Tests $GREY"
+unset AFL_CC
+make -C .. unit || CODE=1 INCOMPLETE=1 :
+rm -rf unittests/unit_hash unittests/unit_rand
+
+. ./test-post.sh
+
diff --git a/test/test-unsigaction.c b/test/test-unsigaction.c
new file mode 100644
index 00000000..8c6c7f41
--- /dev/null
+++ b/test/test-unsigaction.c
@@ -0,0 +1,31 @@
+#include <signal.h> /* sigemptyset(), sigaction(), kill(), SIGUSR1 */
+#include <stdlib.h> /* exit() */
+#include <unistd.h> /* getpid() */
+#include <errno.h> /* errno */
+#include <stdio.h> /* fprintf() */
+
+static void mysig_handler(int sig) {
+
+ exit(2);
+
+}
+
+int main() {
+
+ /* setup sig handler */
+ struct sigaction sa;
+ sa.sa_handler = mysig_handler;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ if (sigaction(SIGCHLD, &sa, NULL)) {
+
+ fprintf(stderr, "could not set signal handler %d, aborted\n", errno);
+ exit(1);
+
+ }
+
+ kill(getpid(), SIGCHLD);
+ return 0;
+
+}
+
diff --git a/test/unittests/unit_hash.c b/test/unittests/unit_hash.c
new file mode 100644
index 00000000..22245ed6
--- /dev/null
+++ b/test/unittests/unit_hash.c
@@ -0,0 +1,80 @@
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <assert.h>
+#include <cmocka.h>
+/* cmocka < 1.0 didn't support these features we need */
+#ifndef assert_ptr_equal
+#define assert_ptr_equal(a, b) \
+ _assert_int_equal(cast_ptr_to_largest_integral_type(a), \
+ cast_ptr_to_largest_integral_type(b), \
+ __FILE__, __LINE__)
+#define CMUnitTest UnitTest
+#define cmocka_unit_test unit_test
+#define cmocka_run_group_tests(t, setup, teardown) run_tests(t)
+#endif
+
+
+extern void mock_assert(const int result, const char* const expression,
+ const char * const file, const int line);
+#undef assert
+#define assert(expression) \
+ mock_assert((int)(expression), #expression, __FILE__, __LINE__);
+
+#include "afl-fuzz.h"
+#include "hash.h"
+
+/* remap exit -> assert, then use cmocka's mock_assert
+ (compile with `--wrap=exit`) */
+extern void exit(int status);
+extern void __real_exit(int status);
+void __wrap_exit(int status);
+void __wrap_exit(int status) {
+ (void)status;
+ assert(0);
+}
+
+/* ignore all printfs */
+#undef printf
+extern int printf(const char *format, ...);
+extern int __real_printf(const char *format, ...);
+int __wrap_printf(const char *format, ...);
+int __wrap_printf(const char *format, ...) {
+ (void)format;
+ return 1;
+}
+
+/* Rand with 0 seed would broke in the past */
+static void test_hash(void **state) {
+ (void)state;
+
+ char bitmap[64] = {0};
+ u64 hash0 = hash64(bitmap, sizeof(bitmap), 0xa5b35705);
+
+ bitmap[10] = 1;
+ u64 hash1 = hash64(bitmap, sizeof(bitmap), 0xa5b35705);
+
+ assert_int_not_equal(hash0, hash1);
+
+ bitmap[10] = 0;
+ assert_int_equal(hash0, hash64(bitmap, sizeof(bitmap), 0xa5b35705));
+
+ bitmap[10] = 1;
+ assert_int_equal(hash1, hash64(bitmap, sizeof(bitmap), 0xa5b35705));
+
+}
+
+int main(int argc, char **argv) {
+ (void)argc;
+ (void)argv;
+
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_hash)
+ };
+
+ //return cmocka_run_group_tests (tests, setup, teardown);
+ __real_exit( cmocka_run_group_tests (tests, NULL, NULL) );
+
+ // fake return for dumb compilers
+ return 0;
+}
diff --git a/test/unittests/unit_list.c b/test/unittests/unit_list.c
new file mode 100644
index 00000000..43665f1a
--- /dev/null
+++ b/test/unittests/unit_list.c
@@ -0,0 +1,140 @@
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <assert.h>
+#include <cmocka.h>
+/* cmocka < 1.0 didn't support these features we need */
+#ifndef assert_ptr_equal
+#define assert_ptr_equal(a, b) \
+ _assert_int_equal(cast_ptr_to_largest_integral_type(a), \
+ cast_ptr_to_largest_integral_type(b), \
+ __FILE__, __LINE__)
+#define CMUnitTest UnitTest
+#define cmocka_unit_test unit_test
+#define cmocka_run_group_tests(t, setup, teardown) run_tests(t)
+#endif
+
+
+extern void mock_assert(const int result, const char* const expression,
+ const char * const file, const int line);
+#undef assert
+#define assert(expression) \
+ mock_assert((int)(expression), #expression, __FILE__, __LINE__);
+
+#include "list.h"
+
+/* remap exit -> assert, then use cmocka's mock_assert
+ (compile with `--wrap=exit`) */
+extern void exit(int status);
+extern void __real_exit(int status);
+//void __wrap_exit(int status);
+void __wrap_exit(int status) {
+ (void)status;
+ assert(0);
+}
+
+/* ignore all printfs */
+#undef printf
+extern int printf(const char *format, ...);
+//extern int __real_printf(const char *format, ...);
+int __wrap_printf(const char *format, ...);
+int __wrap_printf(const char *format, ...) {
+ (void)format;
+ return 1;
+}
+
+static list_t testlist = {.element_prealloc_count = 0};
+
+static void test_contains(void **state) {
+ (void)state;
+
+ u32 one = 1;
+ u32 two = 2;
+
+ list_append(&testlist, &one);
+ assert_true(list_contains(&testlist, &one));
+ assert_false(list_contains(&testlist, &two));
+ list_remove(&testlist, &one);
+ assert_false(list_contains(&testlist, &one));
+}
+
+static void test_foreach(void **state) {
+ (void)state;
+
+ u32 one = 1;
+ u32 two = 2;
+ u32 result = 0;
+
+ list_append(&testlist, &one);
+ list_append(&testlist, &two);
+ list_append(&testlist, &one);
+
+ /* The list is for pointers, so int doesn't work as type directly */
+ LIST_FOREACH(&testlist, u32, {
+ result += *el;
+ });
+
+ assert_int_equal(result, 4);
+
+}
+
+static void test_long_list(void **state) {
+ (void)state;
+
+ u32 result1 = 0;
+ u32 result2 = 0;
+ u32 i;
+
+ u32 vals[100];
+
+ for (i = 0; i < 100; i++) {
+ vals[i] = i;
+ }
+
+ LIST_FOREACH_CLEAR(&testlist, void, {});
+ for (i = 0; i < 100; i++) {
+ list_append(&testlist, &vals[i]);
+ }
+ LIST_FOREACH(&testlist, u32, {
+ result1 += *el;
+ });
+ //printf("removing %d\n", vals[50]);
+ list_remove(&testlist, &vals[50]);
+
+ LIST_FOREACH(&testlist, u32, {
+ // printf("var: %d\n", *el);
+ result2 += *el;
+ });
+ assert_int_not_equal(result1, result2);
+ assert_int_equal(result1, result2 + 50);
+
+ result1 = 0;
+ LIST_FOREACH_CLEAR(&testlist, u32, {
+ result1 += *el;
+ });
+ assert_int_equal(result1, result2);
+
+ result1 = 0;
+ LIST_FOREACH(&testlist, u32, {
+ result1 += *el;
+ });
+ assert_int_equal(result1, 0);
+
+}
+
+int main(int argc, char **argv) {
+ (void)argc;
+ (void)argv;
+
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_contains),
+ cmocka_unit_test(test_foreach),
+ cmocka_unit_test(test_long_list),
+ };
+
+ //return cmocka_run_group_tests (tests, setup, teardown);
+ __real_exit( cmocka_run_group_tests (tests, NULL, NULL) );
+
+ // fake return for dumb compilers
+ return 0;
+}
diff --git a/test/unittests/unit_maybe_alloc.c b/test/unittests/unit_maybe_alloc.c
new file mode 100644
index 00000000..e452e2f2
--- /dev/null
+++ b/test/unittests/unit_maybe_alloc.c
@@ -0,0 +1,227 @@
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <assert.h>
+#include <cmocka.h>
+/* cmocka < 1.0 didn't support these features we need */
+#ifndef assert_ptr_equal
+#define assert_ptr_equal(a, b) \
+ _assert_int_equal(cast_ptr_to_largest_integral_type(a), \
+ cast_ptr_to_largest_integral_type(b), \
+ __FILE__, __LINE__)
+#define CMUnitTest UnitTest
+#define cmocka_unit_test unit_test
+#define cmocka_run_group_tests(t, setup, teardown) run_tests(t)
+#endif
+
+
+extern void mock_assert(const int result, const char* const expression,
+ const char * const file, const int line);
+#undef assert
+#define assert(expression) \
+ mock_assert((int)(expression), #expression, __FILE__, __LINE__);
+#include "alloc-inl.h"
+
+void __wrap_exit(int status);
+/* remap exit -> assert, then use cmocka's mock_assert
+ (compile with `--wrap=exit`) */
+extern void exit(int status);
+extern void __real_exit(int status);
+void __wrap_exit(int status) {
+ (void) status;
+ assert(0);
+}
+
+int __wrap_printf(const char *format, ...);
+/* ignore all printfs */
+#undef printf
+extern int printf(const char *format, ...);
+//extern int __real_printf(const char *format, ...);
+int __wrap_printf(const char *format, ...) {
+ (void)format;
+ return 1;
+}
+
+#define VOID_BUF (void **)&buf
+
+static void *create_fake_maybe_grow_of(size_t size) {
+
+ size += AFL_ALLOC_SIZE_OFFSET;
+
+ // fake a realloc buf
+
+ struct afl_alloc_buf *buf = malloc(size);
+ if (!buf) {
+ perror("Could not allocate fake buf");
+ return NULL;
+ }
+ buf->complete_size = size; // The size
+ void *actual_buf = (void *)(buf->buf);
+ return actual_buf;
+
+}
+
+/*
+static int setup(void **state) {
+
+ return 0;
+
+}
+*/
+
+static void test_pow2(void **state) {
+ (void)state;
+
+ assert_int_equal(next_pow2(64), 64);
+ assert_int_equal(next_pow2(63), 64);
+ assert_int_not_equal(next_pow2(65), 65);
+ assert_int_equal(next_pow2(0x100), 0x100);
+ assert_int_equal(next_pow2(0x180), 0x200);
+ assert_int_equal(next_pow2(108), 0x80);
+ assert_int_equal(next_pow2(0), 0);
+ assert_int_equal(next_pow2(1), 1);
+ assert_int_equal(next_pow2(2), 2);
+ assert_int_equal(next_pow2(3), 4);
+ assert_int_equal(next_pow2(0xFFFFFF), 0x1000000);
+ assert_int_equal(next_pow2(0xFFFFFFF), 0x10000000);
+ assert_int_equal(next_pow2(0xFFFFFF0), 0x10000000);
+ assert_int_equal(next_pow2(SIZE_MAX), 0);
+ assert_int_equal(next_pow2(-1), 0);
+ assert_int_equal(next_pow2(-2), 0);
+
+}
+
+static void test_null_allocs(void **state) {
+ (void)state;
+
+ void *buf = NULL;
+ void *ptr = afl_realloc(VOID_BUF, 100);
+ if (unlikely(!buf)) { PFATAL("alloc"); }
+ size_t size = afl_alloc_bufsize(buf);
+ assert_true(buf == ptr);
+ assert_true(size >= 100);
+ afl_free(ptr);
+
+}
+
+static void test_nonpow2_size(void **state) {
+ (void)state;
+
+ char *buf = create_fake_maybe_grow_of(150);
+
+ buf[140] = '5';
+
+ char *ptr = afl_realloc(VOID_BUF, 160);
+ if (unlikely(!ptr)) { PFATAL("alloc"); }
+ size_t size = afl_alloc_bufsize(buf);
+ assert_ptr_equal(buf, ptr);
+ assert_true(size >= 160);
+ assert_true(buf[140] == '5');
+ afl_free(ptr);
+
+}
+
+static void test_zero_size(void **state) {
+ (void)state;
+
+ char *buf = NULL;
+ size_t size = 0;
+ char *new_buf = afl_realloc(VOID_BUF, 0);
+ assert_non_null(new_buf);
+ assert_ptr_equal(buf, new_buf);
+ afl_free(buf);
+ buf = NULL;
+ size = 0;
+
+ char *ptr = afl_realloc(VOID_BUF, 100);
+ if (unlikely(!ptr)) { PFATAL("alloc"); }
+ size = afl_alloc_bufsize(buf);
+ assert_non_null(ptr);
+ assert_ptr_equal(buf, ptr);
+ assert_true(size >= 100);
+
+ afl_free(ptr);
+
+}
+
+
+static void test_unchanged_size(void **state) {
+ (void)state;
+
+ // fake a realloc buf
+ void *actual_buf = create_fake_maybe_grow_of(100);
+
+ void *buf_before = actual_buf;
+ void *buf_after = afl_realloc(&actual_buf, 100);
+ if (unlikely(!buf_after)) { PFATAL("alloc"); }
+ assert_ptr_equal(actual_buf, buf_after);
+ assert_ptr_equal(buf_after, buf_before);
+ afl_free(buf_after);
+
+}
+
+static void test_grow_multiple(void **state) {
+ (void)state;
+
+ char *buf = NULL;
+ size_t size = 0;
+
+ char *ptr = afl_realloc(VOID_BUF, 100);
+ if (unlikely(!ptr)) { PFATAL("alloc"); }
+ size = afl_alloc_bufsize(ptr);
+ assert_ptr_equal(ptr, buf);
+ assert_true(size >= 100);
+ assert_int_equal(size, next_pow2(size) - AFL_ALLOC_SIZE_OFFSET);
+ buf[50] = '5';
+
+ ptr = (char *)afl_realloc(VOID_BUF, 1000);
+ if (unlikely(!ptr)) { PFATAL("alloc"); }
+ size = afl_alloc_bufsize(ptr);
+ assert_ptr_equal(ptr, buf);
+ assert_true(size >= 100);
+ assert_int_equal(size, next_pow2(size) - AFL_ALLOC_SIZE_OFFSET);
+ buf[500] = '5';
+
+ ptr = (char *)afl_realloc(VOID_BUF, 10000);
+ if (unlikely(!ptr)) { PFATAL("alloc"); }
+ size = afl_alloc_bufsize(ptr);
+ assert_ptr_equal(ptr, buf);
+ assert_true(size >= 10000);
+ assert_int_equal(size, next_pow2(size) - AFL_ALLOC_SIZE_OFFSET);
+ buf[5000] = '5';
+
+ assert_int_equal(buf[50], '5');
+ assert_int_equal(buf[500], '5');
+ assert_int_equal(buf[5000], '5');
+
+ afl_free(buf);
+
+}
+
+/*
+static int teardown(void **state) {
+
+ return 0;
+
+}
+*/
+
+int main(int argc, char **argv) {
+ (void)argc;
+ (void)argv;
+
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_pow2),
+ cmocka_unit_test(test_null_allocs),
+ cmocka_unit_test(test_nonpow2_size),
+ cmocka_unit_test(test_zero_size),
+ cmocka_unit_test(test_unchanged_size),
+ cmocka_unit_test(test_grow_multiple),
+ };
+
+ //return cmocka_run_group_tests (tests, setup, teardown);
+ __real_exit( cmocka_run_group_tests (tests, NULL, NULL) );
+
+ // fake return for dumb compilers
+ return 0;
+}
diff --git a/test/unittests/unit_preallocable.c b/test/unittests/unit_preallocable.c
new file mode 100644
index 00000000..2f9c0b91
--- /dev/null
+++ b/test/unittests/unit_preallocable.c
@@ -0,0 +1,122 @@
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <assert.h>
+#include <cmocka.h>
+/* cmocka < 1.0 didn't support these features we need */
+#ifndef assert_ptr_equal
+#define assert_ptr_equal(a, b) \
+ _assert_int_equal(cast_ptr_to_largest_integral_type(a), \
+ cast_ptr_to_largest_integral_type(b), \
+ __FILE__, __LINE__)
+#define CMUnitTest UnitTest
+#define cmocka_unit_test unit_test
+#define cmocka_run_group_tests(t, setup, teardown) run_tests(t)
+#endif
+
+
+extern void mock_assert(const int result, const char* const expression,
+ const char * const file, const int line);
+#undef assert
+#define assert(expression) \
+ mock_assert((int)(expression), #expression, __FILE__, __LINE__);
+
+#include "afl-prealloc.h"
+
+/* remap exit -> assert, then use cmocka's mock_assert
+ (compile with `--wrap=exit`) */
+extern void exit(int status);
+extern void __real_exit(int status);
+void __wrap_exit(int status);
+void __wrap_exit(int status) {
+ (void)status;
+ assert(0);
+}
+
+/* ignore all printfs */
+#undef printf
+extern int printf(const char *format, ...);
+extern int __real_printf(const char *format, ...);
+//int __wrap_printf(const char *format, ...);
+int __wrap_printf(const char *format, ...) {
+ (void)format;
+ return 1;
+}
+
+typedef struct prealloc_me
+{
+ PREALLOCABLE;
+
+ u8 *content[128];
+
+} element_t;
+
+#define PREALLOCED_BUF_SIZE (64)
+element_t prealloc_me_buf[PREALLOCED_BUF_SIZE];
+s32 prealloc_me_size = 0;
+
+static void test_alloc_free(void **state) {
+ (void)state;
+
+ element_t *prealloced = NULL;
+ PRE_ALLOC(prealloced, prealloc_me_buf, PREALLOCED_BUF_SIZE, prealloc_me_size);
+ assert_non_null(prealloced);
+ PRE_FREE(prealloced, prealloc_me_size);
+
+}
+
+static void test_prealloc_overflow(void **state) {
+ (void)state;
+
+ u32 i = 0;
+ element_t *prealloced[PREALLOCED_BUF_SIZE + 10];
+
+ for (i = 0; i < PREALLOCED_BUF_SIZE + 10; i++) {
+
+ PRE_ALLOC(prealloced[i], prealloc_me_buf, PREALLOCED_BUF_SIZE, prealloc_me_size);
+ assert_non_null(prealloced[i]);
+
+ }
+ assert_int_equal(prealloced[0]->pre_status, PRE_STATUS_USED);
+ assert_int_equal(prealloced[PREALLOCED_BUF_SIZE]->pre_status, PRE_STATUS_MALLOC);
+
+ PRE_FREE(prealloced[20], prealloc_me_size);
+ PRE_ALLOC(prealloced[20], prealloc_me_buf, PREALLOCED_BUF_SIZE, prealloc_me_size);
+ assert_non_null(prealloced[20]);
+ assert_int_equal(prealloced[20]->pre_status, PRE_STATUS_USED);
+
+ PRE_FREE(prealloced[PREALLOCED_BUF_SIZE], prealloc_me_size);
+ PRE_FREE(prealloced[0], prealloc_me_size);
+ PRE_ALLOC(prealloced[PREALLOCED_BUF_SIZE], prealloc_me_buf, PREALLOCED_BUF_SIZE, prealloc_me_size);
+ assert_non_null(prealloced[PREALLOCED_BUF_SIZE]);
+ /* there should be space now! */
+ assert_int_equal(prealloced[PREALLOCED_BUF_SIZE]->pre_status, PRE_STATUS_USED);
+
+ PRE_ALLOC(prealloced[0], prealloc_me_buf, PREALLOCED_BUF_SIZE, prealloc_me_size);
+ assert_non_null(prealloced[0]);
+ /* no more space */
+ assert_int_equal(prealloced[0]->pre_status, PRE_STATUS_MALLOC);
+
+ for (i = 0; i < PREALLOCED_BUF_SIZE + 10; i++) {
+
+ PRE_FREE(prealloced[i], prealloc_me_size);
+
+ }
+
+}
+
+int main(int argc, char **argv) {
+ (void)argc;
+ (void)argv;
+
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_alloc_free),
+ cmocka_unit_test(test_prealloc_overflow),
+ };
+
+ //return cmocka_run_group_tests (tests, setup, teardown);
+ __real_exit( cmocka_run_group_tests (tests, NULL, NULL) );
+
+ // fake return for dumb compilers
+ return 0;
+}
diff --git a/test/unittests/unit_rand.c b/test/unittests/unit_rand.c
new file mode 100644
index 00000000..1ad02a80
--- /dev/null
+++ b/test/unittests/unit_rand.c
@@ -0,0 +1,90 @@
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <assert.h>
+#include <cmocka.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+/* cmocka < 1.0 didn't support these features we need */
+#ifndef assert_ptr_equal
+#define assert_ptr_equal(a, b) \
+ _assert_int_equal(cast_ptr_to_largest_integral_type(a), \
+ cast_ptr_to_largest_integral_type(b), \
+ __FILE__, __LINE__)
+#define CMUnitTest UnitTest
+#define cmocka_unit_test unit_test
+#define cmocka_run_group_tests(t, setup, teardown) run_tests(t)
+#endif
+
+
+extern void mock_assert(const int result, const char* const expression,
+ const char * const file, const int line);
+#undef assert
+#define assert(expression) \
+ mock_assert((int)(expression), #expression, __FILE__, __LINE__);
+
+#include "afl-fuzz.h"
+
+/* remap exit -> assert, then use cmocka's mock_assert
+ (compile with `--wrap=exit`) */
+extern void exit(int status);
+extern void __real_exit(int status);
+//void __wrap_exit(int status);
+void __wrap_exit(int status) {
+ (void)status;
+ assert(0);
+}
+
+/* ignore all printfs */
+#undef printf
+extern int printf(const char *format, ...);
+extern int __real_printf(const char *format, ...);
+int __wrap_printf(const char *format, ...);
+int __wrap_printf(const char *format, ...) {
+ (void)format;
+ return 1;
+}
+
+/* Rand with 0 seed would broke in the past */
+static void test_rand_0(void **state) {
+ (void)state;
+
+ afl_state_t afl = {0};
+ rand_set_seed(&afl, 0);
+
+ /* give this one chance to retry */
+ assert_int_not_equal(
+ (rand_next(&afl) != rand_next(&afl)
+ || rand_next(&afl) != rand_next(&afl))
+ , 0);
+
+}
+
+static void test_rand_below(void **state) {
+ (void)state;
+
+ afl_state_t afl = {0};
+ rand_set_seed(&afl, 1337);
+
+ afl.fsrv.dev_urandom_fd = open("/dev/urandom", O_RDONLY);
+
+ assert(!(rand_below(&afl, 9000) > 9000));
+ assert_int_equal(rand_below(&afl, 1), 0);
+
+}
+
+int main(int argc, char **argv) {
+ (void)argc;
+ (void)argv;
+
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_rand_0),
+ cmocka_unit_test(test_rand_below)
+ };
+
+ //return cmocka_run_group_tests (tests, setup, teardown);
+ __real_exit( cmocka_run_group_tests (tests, NULL, NULL) );
+
+ // fake return for dumb compilers
+ return 0;
+}
diff --git a/testcases/README.md b/testcases/README.md
new file mode 100644
index 00000000..119fd272
--- /dev/null
+++ b/testcases/README.md
@@ -0,0 +1,17 @@
+# AFL++ starting test cases
+
+For the general instruction manual, see [docs/README.md](../docs/README.md).
+
+The archives/, images/, multimedia/, and others/ subdirectories contain small,
+standalone files that can be used to seed afl-fuzz when testing parsers for a
+variety of common data formats.
+
+There is probably not much to be said about these files, except that they were
+optimized for size and stripped of any non-essential fluff. Some directories
+contain several examples that exercise various features of the underlying format.
+For example, there is a PNG file with and without a color profile.
+
+Additional test cases are always welcome.
+
+In addition to well-chosen starting files, many fuzzing jobs benefit from a
+small and concise dictionary. See [../dictionaries/README.md](../dictionaries/README.md) for more.
diff --git a/testcases/archives/common/ar/small_archive.a b/testcases/archives/common/ar/small_archive.a
new file mode 100644
index 00000000..8c50bc28
--- /dev/null
+++ b/testcases/archives/common/ar/small_archive.a
@@ -0,0 +1,8 @@
+!<arch>
+limerick/ 1415337776 500 500 100640 191 `
+There was a young man from Japan
+Whose limericks never would scan.
+When asked why that was,
+He replied "It's because
+I always try to cram as many words into the last line as I possibly can."
+
diff --git a/testcases/archives/common/bzip2/small_archive.bz2 b/testcases/archives/common/bzip2/small_archive.bz2
new file mode 100644
index 00000000..83914ad2
--- /dev/null
+++ b/testcases/archives/common/bzip2/small_archive.bz2
Binary files differ
diff --git a/testcases/archives/common/cab/small_archive.cab b/testcases/archives/common/cab/small_archive.cab
new file mode 100644
index 00000000..3f429043
--- /dev/null
+++ b/testcases/archives/common/cab/small_archive.cab
Binary files differ
diff --git a/testcases/archives/common/compress/small_archive.Z b/testcases/archives/common/compress/small_archive.Z
new file mode 100644
index 00000000..73bf3151
--- /dev/null
+++ b/testcases/archives/common/compress/small_archive.Z
Binary files differ
diff --git a/testcases/archives/common/cpio/small_archive.cpio b/testcases/archives/common/cpio/small_archive.cpio
new file mode 100644
index 00000000..d1ee8a2c
--- /dev/null
+++ b/testcases/archives/common/cpio/small_archive.cpio
Binary files differ
diff --git a/testcases/archives/common/gzip/small_archive.gz b/testcases/archives/common/gzip/small_archive.gz
new file mode 100644
index 00000000..4a6cd8e1
--- /dev/null
+++ b/testcases/archives/common/gzip/small_archive.gz
Binary files differ
diff --git a/testcases/archives/common/lzo/small_archive.lzo b/testcases/archives/common/lzo/small_archive.lzo
new file mode 100644
index 00000000..bf310368
--- /dev/null
+++ b/testcases/archives/common/lzo/small_archive.lzo
Binary files differ
diff --git a/testcases/archives/common/rar/small_archive.rar b/testcases/archives/common/rar/small_archive.rar
new file mode 100644
index 00000000..a5aae4ce
--- /dev/null
+++ b/testcases/archives/common/rar/small_archive.rar
Binary files differ
diff --git a/testcases/archives/common/tar/small_archive.tar b/testcases/archives/common/tar/small_archive.tar
new file mode 100644
index 00000000..8f694fde
--- /dev/null
+++ b/testcases/archives/common/tar/small_archive.tar
Binary files differ
diff --git a/testcases/archives/common/xz/small_archive.xz b/testcases/archives/common/xz/small_archive.xz
new file mode 100644
index 00000000..f30df04f
--- /dev/null
+++ b/testcases/archives/common/xz/small_archive.xz
Binary files differ
diff --git a/testcases/archives/common/zip/small_archive.zip b/testcases/archives/common/zip/small_archive.zip
new file mode 100644
index 00000000..dc7992cd
--- /dev/null
+++ b/testcases/archives/common/zip/small_archive.zip
Binary files differ
diff --git a/testcases/archives/exotic/arj/small_archive.arj b/testcases/archives/exotic/arj/small_archive.arj
new file mode 100644
index 00000000..8bcd12eb
--- /dev/null
+++ b/testcases/archives/exotic/arj/small_archive.arj
Binary files differ
diff --git a/testcases/archives/exotic/lha/small_archive.lha b/testcases/archives/exotic/lha/small_archive.lha
new file mode 100644
index 00000000..e70f325b
--- /dev/null
+++ b/testcases/archives/exotic/lha/small_archive.lha
Binary files differ
diff --git a/testcases/archives/exotic/lrzip/small_archive.lrz b/testcases/archives/exotic/lrzip/small_archive.lrz
new file mode 100644
index 00000000..1a0415f1
--- /dev/null
+++ b/testcases/archives/exotic/lrzip/small_archive.lrz
Binary files differ
diff --git a/testcases/archives/exotic/lzip/small_archive.lz b/testcases/archives/exotic/lzip/small_archive.lz
new file mode 100644
index 00000000..89e2448e
--- /dev/null
+++ b/testcases/archives/exotic/lzip/small_archive.lz
Binary files differ
diff --git a/testcases/archives/exotic/lzma/small_archive.lzma b/testcases/archives/exotic/lzma/small_archive.lzma
new file mode 100644
index 00000000..bbd056a5
--- /dev/null
+++ b/testcases/archives/exotic/lzma/small_archive.lzma
Binary files differ
diff --git a/testcases/archives/exotic/rzip/small_archive.rz b/testcases/archives/exotic/rzip/small_archive.rz
new file mode 100644
index 00000000..d1950c4b
--- /dev/null
+++ b/testcases/archives/exotic/rzip/small_archive.rz
Binary files differ
diff --git a/testcases/archives/exotic/zoo/small_archive.zoo b/testcases/archives/exotic/zoo/small_archive.zoo
new file mode 100644
index 00000000..1614e5fb
--- /dev/null
+++ b/testcases/archives/exotic/zoo/small_archive.zoo
Binary files differ
diff --git a/testcases/images/bmp/not_kitty.bmp b/testcases/images/bmp/not_kitty.bmp
new file mode 100644
index 00000000..0309c928
--- /dev/null
+++ b/testcases/images/bmp/not_kitty.bmp
Binary files differ
diff --git a/testcases/images/gif/not_kitty.gif b/testcases/images/gif/not_kitty.gif
new file mode 100644
index 00000000..244fcc64
--- /dev/null
+++ b/testcases/images/gif/not_kitty.gif
Binary files differ
diff --git a/testcases/images/ico/not_kitty.ico b/testcases/images/ico/not_kitty.ico
new file mode 100644
index 00000000..d2bb2916
--- /dev/null
+++ b/testcases/images/ico/not_kitty.ico
Binary files differ
diff --git a/testcases/images/jp2/not_kitty.jp2 b/testcases/images/jp2/not_kitty.jp2
new file mode 100644
index 00000000..14bca292
--- /dev/null
+++ b/testcases/images/jp2/not_kitty.jp2
Binary files differ
diff --git a/testcases/images/jpeg/not_kitty.jpg b/testcases/images/jpeg/not_kitty.jpg
new file mode 100644
index 00000000..0497be49
--- /dev/null
+++ b/testcases/images/jpeg/not_kitty.jpg
Binary files differ
diff --git a/testcases/images/jxr/not_kitty.jxr b/testcases/images/jxr/not_kitty.jxr
new file mode 100644
index 00000000..0fa2c8ec
--- /dev/null
+++ b/testcases/images/jxr/not_kitty.jxr
Binary files differ
diff --git a/testcases/images/png/not_kitty.png b/testcases/images/png/not_kitty.png
new file mode 100644
index 00000000..eff7c170
--- /dev/null
+++ b/testcases/images/png/not_kitty.png
Binary files differ
diff --git a/testcases/images/png/not_kitty_alpha.png b/testcases/images/png/not_kitty_alpha.png
new file mode 100644
index 00000000..2fb8da2c
--- /dev/null
+++ b/testcases/images/png/not_kitty_alpha.png
Binary files differ
diff --git a/testcases/images/png/not_kitty_gamma.png b/testcases/images/png/not_kitty_gamma.png
new file mode 100644
index 00000000..939d9d29
--- /dev/null
+++ b/testcases/images/png/not_kitty_gamma.png
Binary files differ
diff --git a/testcases/images/png/not_kitty_icc.png b/testcases/images/png/not_kitty_icc.png
new file mode 100644
index 00000000..f0c7804d
--- /dev/null
+++ b/testcases/images/png/not_kitty_icc.png
Binary files differ
diff --git a/testcases/images/tiff/not_kitty.tiff b/testcases/images/tiff/not_kitty.tiff
new file mode 100644
index 00000000..506ca1ad
--- /dev/null
+++ b/testcases/images/tiff/not_kitty.tiff
Binary files differ
diff --git a/testcases/images/webp/not_kitty.webp b/testcases/images/webp/not_kitty.webp
new file mode 100644
index 00000000..8592d823
--- /dev/null
+++ b/testcases/images/webp/not_kitty.webp
Binary files differ
diff --git a/testcases/multimedia/h264/small_movie.mp4 b/testcases/multimedia/h264/small_movie.mp4
new file mode 100644
index 00000000..adc6c9cb
--- /dev/null
+++ b/testcases/multimedia/h264/small_movie.mp4
Binary files differ
diff --git a/testcases/others/elf/small_exec.elf b/testcases/others/elf/small_exec.elf
new file mode 100644
index 00000000..bebc60fb
--- /dev/null
+++ b/testcases/others/elf/small_exec.elf
Binary files differ
diff --git a/testcases/others/js/small_script.js b/testcases/others/js/small_script.js
new file mode 100644
index 00000000..bb632d8a
--- /dev/null
+++ b/testcases/others/js/small_script.js
@@ -0,0 +1 @@
+if (1==1) eval('1'); \ No newline at end of file
diff --git a/testcases/others/pcap/small_capture.pcap b/testcases/others/pcap/small_capture.pcap
new file mode 100644
index 00000000..60e2210b
--- /dev/null
+++ b/testcases/others/pcap/small_capture.pcap
Binary files differ
diff --git a/testcases/others/pdf/small.pdf b/testcases/others/pdf/small.pdf
new file mode 100644
index 00000000..d31b4eb2
--- /dev/null
+++ b/testcases/others/pdf/small.pdf
@@ -0,0 +1,2 @@
+%PDF-1.0
+1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj 2 0 obj<</Type/Pages/Kids[3 0 R]/Count 1>>endobj 3 0 obj<</Type/Page/MediaBox[0 0 3 3]>>endobj trailer<</Size 4/Root 1 0 R>> \ No newline at end of file
diff --git a/testcases/others/rtf/small_document.rtf b/testcases/others/rtf/small_document.rtf
new file mode 100644
index 00000000..0fdedc32
--- /dev/null
+++ b/testcases/others/rtf/small_document.rtf
@@ -0,0 +1 @@
+{\rtf1\pard Test\par} \ No newline at end of file
diff --git a/testcases/others/sql/simple_queries.sql b/testcases/others/sql/simple_queries.sql
new file mode 100644
index 00000000..5fff4072
--- /dev/null
+++ b/testcases/others/sql/simple_queries.sql
@@ -0,0 +1,3 @@
+create table t1(one smallint);
+insert into t1 values(1);
+select * from t1;
diff --git a/testcases/others/text/hello_world.txt b/testcases/others/text/hello_world.txt
new file mode 100644
index 00000000..ce013625
--- /dev/null
+++ b/testcases/others/text/hello_world.txt
@@ -0,0 +1 @@
+hello
diff --git a/testcases/others/xml/small_document.xml b/testcases/others/xml/small_document.xml
new file mode 100644
index 00000000..684e2846
--- /dev/null
+++ b/testcases/others/xml/small_document.xml
@@ -0,0 +1 @@
+<a b="c">d</a>
diff --git a/types.h b/types.h
new file mode 120000
index 00000000..67149a67
--- /dev/null
+++ b/types.h
@@ -0,0 +1 @@
+include/types.h \ No newline at end of file
diff --git a/utils/README.md b/utils/README.md
new file mode 100644
index 00000000..debc86e8
--- /dev/null
+++ b/utils/README.md
@@ -0,0 +1,75 @@
+# AFL++ Examples
+
+Here's a quick overview of the stuff you can find in this directory:
+
+ - aflpp_driver - easily instrument LLVMFuzzerTestOneInput()
+ harnesses.
+
+ - afl_network_proxy - fuzz a target over the network: afl-fuzz on
+ a host, target on an embedded system.
+
+ - plot_ui - simple UI window utility to display the
+ plots generated by afl-plot
+
+ - afl_proxy - skeleton file example to show how to fuzz
+ something where you gather coverage data via
+ different means, e.g., hw debugger
+
+ - afl_untracer - fuzz binary-only libraries much faster but with
+ less coverage than QEMU mode
+
+ - analysis_scripts - random -o out analysis scripts
+
+ - argv_fuzzing - a simple wrapper to allow cmdline to be fuzzed
+ (e.g., to test setuid programs).
+
+ - asan_cgroups - a contributed script to simplify fuzzing ASAN
+ binaries with robust memory limits on Linux.
+
+ - autodict_ql - generate dictionary files from source code.
+
+ - bash_shellshock - a simple hack used to find a bunch of
+ post-Shellshock bugs in bash.
+
+ - canvas_harness - a test harness used to find browser bugs with a
+ corpus generated using simple image parsing
+ binaries & afl-fuzz.
+
+ - clang_asm_normalize - a script that makes it easy to instrument
+ hand-written assembly, provided that you have clang.
+
+ - crash_triage - a very rudimentary example of how to annotate crashes
+ with additional gdb metadata.
+
+ - custom_mutators - examples for the AFL++ custom mutator interface in
+ C and Python. Note: They were moved to
+ ../custom_mutators/examples/
+
+ - defork - intercept fork() in targets
+
+ - distributed_fuzzing - a sample script for synchronizing fuzzer instances
+ across multiple machines.
+
+ - libdislocator - like ASAN but lightweight.
+
+ - libtokencap - collect string tokens for a dictionary.
+
+ - libpng_no_checksum - a sample patch for removing CRC checks in libpng.
+
+ - optimin - An optimal corpus minimizer.
+
+ - persistent_mode - an example of how to use the LLVM persistent process
+ mode to speed up certain fuzzing jobs.
+
+ - qemu_persistent_hook - persistent mode support module for qemu.
+
+ - socket_fuzzing - a LD_PRELOAD library 'redirects' a socket to stdin
+ for fuzzing access with AFL++
+
+Note that the minimize_corpus.sh tool has graduated from the utils/
+directory and is now available as ../afl-cmin. The LLVM mode has likewise
+graduated to ../instrumentation/*.
+
+Most of the tools in this directory are meant chiefly as examples that need to
+be tweaked for your specific needs. They come with some basic documentation,
+but are not necessarily production-grade.
diff --git a/utils/afl_network_proxy/GNUmakefile b/utils/afl_network_proxy/GNUmakefile
new file mode 100644
index 00000000..7c8c22ff
--- /dev/null
+++ b/utils/afl_network_proxy/GNUmakefile
@@ -0,0 +1,50 @@
+PREFIX ?= /usr/local
+BIN_PATH = $(PREFIX)/bin
+HELPER_PATH = $(PREFIX)/lib/afl
+DOC_PATH = $(PREFIX)/share/doc/afl
+
+SYS = $(shell uname -s)
+
+PROGRAMS = afl-network-client afl-network-server
+
+HASH=\#
+
+CFLAGS += -Wno-pointer-sign
+
+ifdef STATIC
+ CFLAGS += -static
+endif
+
+ifeq "$(SYS)" "SunOS"
+ LDFLAGS += -lnsl -lsocket
+endif
+
+ifeq "$(shell echo '$(HASH)include <libdeflate.h>@int main() { struct libdeflate_compressor *d = libdeflate_alloc_compressor(1); return 0;}' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test2 -ldeflate 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
+ CFLAGS += -DUSE_DEFLATE=1
+ LDFLAGS += -ldeflate
+ $(info libdeflate-dev was detected, using compression)
+else
+ $(warn did not find libdeflate-dev, cannot use compression)
+endif
+
+all: $(PROGRAMS)
+
+help:
+ @echo make options:
+ @echo STATIC - build as static binaries
+ @echo COMPRESS_TESTCASES - compress test cases
+
+afl-network-client: afl-network-client.c
+ $(CC) $(CFLAGS) -I../../include -o afl-network-client afl-network-client.c $(LDFLAGS)
+
+afl-network-server: afl-network-server.c
+ $(CC) $(CFLAGS) -I../../include -o afl-network-server afl-network-server.c ../../src/afl-forkserver.c ../../src/afl-sharedmem.c ../../src/afl-common.c -DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" $(LDFLAGS)
+
+clean:
+ rm -f $(PROGRAMS) *~ core
+
+install: all
+ install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(DOC_PATH)
+ install -m 755 $(PROGRAMS) $${DESTDIR}$(BIN_PATH)
+ install -T -m 644 README.md $${DESTDIR}$(DOC_PATH)/README.network_proxy.md
+
diff --git a/utils/afl_network_proxy/Makefile b/utils/afl_network_proxy/Makefile
new file mode 100644
index 00000000..0b306dde
--- /dev/null
+++ b/utils/afl_network_proxy/Makefile
@@ -0,0 +1,2 @@
+all:
+ @echo please use GNU make, thanks!
diff --git a/utils/afl_network_proxy/README.md b/utils/afl_network_proxy/README.md
new file mode 100644
index 00000000..c34463e2
--- /dev/null
+++ b/utils/afl_network_proxy/README.md
@@ -0,0 +1,64 @@
+# afl-network-proxy
+
+If you want to run afl-fuzz over the network, then this is what you need. :)
+Note that the impact on fuzzing speed will be huge, expect a loss of 90%.
+
+## When to use this
+
+1. when you have to fuzz a target that has to run on a system that cannot
+ contain the fuzzing output (e.g., /tmp too small and file system is
+ read-only)
+2. when the target instantly reboots on crashes
+3. ... any other reason you would need this
+
+## how to get it running
+
+### Compiling
+
+Just type `make` and let the autodetection do everything for you.
+
+Note that you will get a 40-50% performance increase if you have libdeflate-dev
+installed. The GNUmakefile will autodetect it if present.
+
+If your target has large test cases (10+kb) that are ascii only or large chunks
+of zero blocks then set `CFLAGS=-DCOMPRESS_TESTCASES=1` to compress them.
+For most targets this hurts performance though so it is disabled by default.
+
+### on the target
+
+Run `afl-network-server` with your target with the -m and -t values you need.
+Important is the -i parameter which is the TCP port to listen on.
+e.g.:
+
+```
+afl-network-server -i 1111 -m 25M -t 1000 -- /bin/target -f @@
+```
+
+### on the (afl-fuzz) main node
+
+Just run afl-fuzz with your normal options, however, the target should be
+`afl-network-client` with the IP and PORT of the `afl-network-server` and
+increase the -t value:
+
+```
+afl-fuzz -i in -o out -t 2000+ -- afl-network-client TARGET-IP 1111
+```
+
+Note the '+' on the -t parameter value. The afl-network-server will take care of
+proper timeouts hence afl-fuzz should not. The '+' increases the timeout and the
+value itself should be 500-1000 higher than the one on afl-network-server.
+
+### networking
+
+The TARGET can be an IPv4 or IPv6 address, or a host name that resolves to
+either. Note that also the outgoing interface can be specified with a '%' for
+`afl-network-client`, e.g., `fe80::1234%eth0`.
+
+Also make sure your default TCP window size is larger than your MAP_SIZE
+(130kb is a good value).
+On Linux that is the middle value of `/proc/sys/net/ipv4/tcp_rmem`
+
+## how to compile and install
+
+`make && sudo make install`
+
diff --git a/utils/afl_network_proxy/afl-network-client.c b/utils/afl_network_proxy/afl-network-client.c
new file mode 100644
index 00000000..7d04a89a
--- /dev/null
+++ b/utils/afl_network_proxy/afl-network-client.c
@@ -0,0 +1,417 @@
+/*
+ american fuzzy lop++ - afl-network-client
+ ---------------------------------------
+
+ Written by Marc Heuse <mh@mh-sec.de>
+
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+*/
+
+#ifdef __ANDROID__
+ #include "android-ashmem.h"
+#endif
+#include "config.h"
+#include "types.h"
+#include "debug.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <arpa/inet.h>
+#include <sys/mman.h>
+#ifndef USEMMAP
+ #include <sys/shm.h>
+#endif
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <fcntl.h>
+
+#ifdef USE_DEFLATE
+ #include <libdeflate.h>
+#endif
+
+u8 *__afl_area_ptr;
+
+#ifdef __ANDROID__
+u32 __afl_map_size = MAP_SIZE;
+#else
+__thread u32 __afl_map_size = MAP_SIZE;
+#endif
+
+/* Error reporting to forkserver controller */
+
+void send_forkserver_error(int error) {
+
+ u32 status;
+ if (!error || error > 0xffff) return;
+ status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error));
+ if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return;
+
+}
+
+/* SHM setup. */
+
+static void __afl_map_shm(void) {
+
+ char *id_str = getenv(SHM_ENV_VAR);
+ char *ptr;
+
+ if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) {
+
+ u32 val = atoi(ptr);
+ if (val > 0) __afl_map_size = val;
+
+ }
+
+ if (__afl_map_size > MAP_SIZE) {
+
+ if (__afl_map_size > 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_map_size);
+ if (id_str) {
+
+ send_forkserver_error(FS_ERROR_MAP_SIZE);
+ exit(-1);
+
+ }
+
+ } 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_map_size);
+
+ }
+
+ }
+
+ if (id_str) {
+
+#ifdef USEMMAP
+ const char * shm_file_path = id_str;
+ int shm_fd = -1;
+ unsigned char *shm_base = NULL;
+
+ /* create the shared memory segment as if it was a file */
+ shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
+ if (shm_fd == -1) {
+
+ fprintf(stderr, "shm_open() failed\n");
+ send_forkserver_error(FS_ERROR_SHM_OPEN);
+ exit(1);
+
+ }
+
+ /* map the shared memory segment to the address space of the process */
+ shm_base =
+ mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
+
+ if (shm_base == MAP_FAILED) {
+
+ close(shm_fd);
+ shm_fd = -1;
+
+ fprintf(stderr, "mmap() failed\n");
+ send_forkserver_error(FS_ERROR_MMAP);
+ exit(2);
+
+ }
+
+ __afl_area_ptr = shm_base;
+#else
+ u32 shm_id = atoi(id_str);
+
+ __afl_area_ptr = shmat(shm_id, 0, 0);
+
+#endif
+
+ if (__afl_area_ptr == (void *)-1) {
+
+ send_forkserver_error(FS_ERROR_SHMAT);
+ exit(1);
+
+ }
+
+ /* Write something into the bitmap so that the parent doesn't give up */
+
+ __afl_area_ptr[0] = 1;
+
+ }
+
+}
+
+/* Fork server logic. */
+
+static void __afl_start_forkserver(void) {
+
+ u8 tmp[4] = {0, 0, 0, 0};
+ u32 status = 0;
+
+ if (__afl_map_size <= FS_OPT_MAX_MAPSIZE)
+ status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
+ if (status) status |= (FS_OPT_ENABLED);
+ memcpy(tmp, &status, 4);
+
+ /* Phone home and tell the parent that we're OK. */
+
+ if (write(FORKSRV_FD + 1, tmp, 4) != 4) return;
+
+}
+
+static u32 __afl_next_testcase(u8 *buf, u32 max_len) {
+
+ s32 status, res = 0x0fffffff; // res is a dummy pid
+
+ /* Wait for parent by reading from the pipe. Abort if read fails. */
+ if (read(FORKSRV_FD, &status, 4) != 4) return 0;
+
+ /* we have a testcase - read it */
+ status = read(0, buf, max_len);
+
+ /* report that we are starting the target */
+ if (write(FORKSRV_FD + 1, &res, 4) != 4) return 0;
+
+ if (status < 1)
+ return 0;
+ else
+ return status;
+
+}
+
+static void __afl_end_testcase(int status) {
+
+ if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(1);
+
+}
+
+/* you just need to modify the while() loop in this main() */
+
+int main(int argc, char *argv[]) {
+
+ u8 * interface, *buf, *ptr;
+ s32 s = -1;
+ struct addrinfo hints, *hres, *aip;
+ u32 * lenptr, max_len = 65536;
+#ifdef USE_DEFLATE
+ u8 * buf2;
+ u32 * lenptr1, *lenptr2, buf2_len, compress_len;
+ size_t decompress_len;
+#endif
+
+ if (argc < 3 || argc > 4) {
+
+ printf("Syntax: %s host port [max-input-size]\n\n", argv[0]);
+ printf("Requires host and port of the remote afl-proxy-server instance.\n");
+ printf(
+ "IPv4 and IPv6 are supported, also binding to an interface with "
+ "\"%%\"\n");
+ printf("The max-input-size default is %u.\n", max_len);
+ printf(
+ "The default map size is %u and can be changed with setting "
+ "AFL_MAP_SIZE.\n",
+ __afl_map_size);
+ exit(-1);
+
+ }
+
+ if ((interface = strchr(argv[1], '%')) != NULL) *interface++ = 0;
+
+ if (argc > 3)
+ if ((max_len = atoi(argv[3])) < 0)
+ FATAL("max-input-size may not be negative or larger than 2GB: %s",
+ argv[3]);
+
+ if ((ptr = getenv("AFL_MAP_SIZE")) != NULL)
+ if ((__afl_map_size = atoi(ptr)) < 8)
+ FATAL("illegal map size, may not be < 8 or >= 2^30: %s", ptr);
+
+ if ((buf = malloc(max_len + 4)) == NULL)
+ PFATAL("can not allocate %u memory", max_len + 4);
+ lenptr = (u32 *)buf;
+
+#ifdef USE_DEFLATE
+ buf2_len = (max_len > __afl_map_size ? max_len : __afl_map_size);
+ if ((buf2 = malloc(buf2_len + 8)) == NULL)
+ PFATAL("can not allocate %u memory", buf2_len + 8);
+ lenptr1 = (u32 *)buf2;
+ lenptr2 = (u32 *)(buf2 + 4);
+#endif
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_family = PF_UNSPEC;
+
+ if (getaddrinfo(argv[1], argv[2], &hints, &hres) != 0)
+ PFATAL("could not resolve target %s", argv[1]);
+
+ for (aip = hres; aip != NULL && s == -1; aip = aip->ai_next) {
+
+ if ((s = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol)) >= 0) {
+
+#ifdef SO_BINDTODEVICE
+ if (interface != NULL)
+ if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, interface,
+ strlen(interface) + 1) < 0)
+ fprintf(stderr, "Warning: could not bind to device %s\n", interface);
+#else
+ fprintf(stderr,
+ "Warning: binding to interface is not supported for your OS\n");
+#endif
+
+#ifdef SO_PRIORITY
+ int priority = 7;
+ if (setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) <
+ 0) {
+
+ priority = 6;
+ if (setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority,
+ sizeof(priority)) < 0)
+ WARNF("could not set priority on socket");
+
+ }
+
+#endif
+
+ if (connect(s, aip->ai_addr, aip->ai_addrlen) == -1) s = -1;
+
+ }
+
+ }
+
+#ifdef USE_DEFLATE
+ struct libdeflate_compressor *compressor;
+ compressor = libdeflate_alloc_compressor(1);
+ struct libdeflate_decompressor *decompressor;
+ decompressor = libdeflate_alloc_decompressor();
+ fprintf(stderr, "Compiled with compression support\n");
+#endif
+
+ if (s == -1)
+ FATAL("could not connect to target tcp://%s:%s", argv[1], argv[2]);
+ else
+ fprintf(stderr, "Connected to target tcp://%s:%s\n", argv[1], argv[2]);
+
+ /* we initialize the shared memory map and start the forkserver */
+ __afl_map_shm();
+ __afl_start_forkserver();
+
+ int i = 1, j, status, ret, received;
+
+ // fprintf(stderr, "Waiting for first testcase\n");
+ while ((*lenptr = __afl_next_testcase(buf + 4, max_len)) > 0) {
+
+ // fprintf(stderr, "Sending testcase with len %u\n", *lenptr);
+#ifdef USE_DEFLATE
+ #ifdef COMPRESS_TESTCASES
+ // we only compress the testcase if it does not fit in the TCP packet
+ if (*lenptr > 1500 - 20 - 32 - 4) {
+
+ // set highest byte to signify compression
+ *lenptr1 = (*lenptr | 0xff000000);
+ *lenptr2 = (u32)libdeflate_deflate_compress(compressor, buf + 4, *lenptr,
+ buf2 + 8, buf2_len);
+ if (send(s, buf2, *lenptr2 + 8, 0) != *lenptr2 + 8)
+ PFATAL("sending test data failed");
+ // fprintf(stderr, "COMPRESS (%u->%u):\n", *lenptr, *lenptr2);
+ // for (u32 i = 0; i < *lenptr; i++)
+ // fprintf(stderr, "%02x", buf[i + 4]);
+ // fprintf(stderr, "\n");
+ // for (u32 i = 0; i < *lenptr2; i++)
+ // fprintf(stderr, "%02x", buf2[i + 8]);
+ // fprintf(stderr, "\n");
+
+ } else {
+
+ #endif
+#endif
+ if (send(s, buf, *lenptr + 4, 0) != *lenptr + 4)
+ PFATAL("sending test data failed");
+#ifdef USE_DEFLATE
+ #ifdef COMPRESS_TESTCASES
+ // fprintf(stderr, "unCOMPRESS (%u)\n", *lenptr);
+
+ }
+
+ #endif
+#endif
+
+ received = 0;
+ while (received < 4 &&
+ (ret = recv(s, &status + received, 4 - received, 0)) > 0)
+ received += ret;
+ if (received != 4)
+ FATAL("did not receive waitpid data (%d, %d)", received, ret);
+ // fprintf(stderr, "Received status\n");
+
+ received = 0;
+#ifdef USE_DEFLATE
+ while (received < 4 &&
+ (ret = recv(s, &compress_len + received, 4 - received, 0)) > 0)
+ received += ret;
+ if (received != 4)
+ FATAL("did not receive compress_len (%d, %d)", received, ret);
+ // fprintf(stderr, "Received status\n");
+
+ received = 0;
+ while (received < compress_len &&
+ (ret = recv(s, buf2 + received, buf2_len - received, 0)) > 0)
+ received += ret;
+ if (received != compress_len)
+ FATAL("did not receive coverage data (%d, %d)", received, ret);
+
+ if (libdeflate_deflate_decompress(decompressor, buf2, compress_len,
+ __afl_area_ptr, __afl_map_size,
+ &decompress_len) != LIBDEFLATE_SUCCESS ||
+ decompress_len != __afl_map_size)
+ FATAL("decompression failed");
+ // fprintf(stderr, "DECOMPRESS (%u->%u): ", compress_len, decompress_len);
+ // for (u32 i = 0; i < __afl_map_size; i++) fprintf(stderr, "%02x",
+ // __afl_area_ptr[i]); fprintf(stderr, "\n");
+#else
+ while (received < __afl_map_size &&
+ (ret = recv(s, __afl_area_ptr + received, __afl_map_size - received,
+ 0)) > 0)
+ received += ret;
+ if (received != __afl_map_size)
+ FATAL("did not receive coverage data (%d, %d)", received, ret);
+#endif
+ // fprintf(stderr, "Received coverage\n");
+
+ /* report the test case is done and wait for the next */
+ __afl_end_testcase(status);
+ // fprintf(stderr, "Waiting for next testcase %d\n", ++i);
+
+ }
+
+#ifdef USE_DEFLATE
+ libdeflate_free_compressor(compressor);
+ libdeflate_free_decompressor(decompressor);
+ free(buf2);
+#endif
+ free(buf);
+
+ return 0;
+
+}
+
diff --git a/utils/afl_network_proxy/afl-network-server.c b/utils/afl_network_proxy/afl-network-server.c
new file mode 100644
index 00000000..3e5e275d
--- /dev/null
+++ b/utils/afl_network_proxy/afl-network-server.c
@@ -0,0 +1,686 @@
+/*
+ american fuzzy lop++ - network proxy server
+ -------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Forkserver design by Jann Horn <jannhorn@googlemail.com>
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Andrea Fioraldi <andreafioraldi@gmail.com> and
+ Dominik Maier <mail@dmnk.co>
+
+ Copyright 2016, 2017 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ */
+
+#define AFL_MAIN
+
+#include "config.h"
+#include "types.h"
+#include "debug.h"
+#include "alloc-inl.h"
+#include "hash.h"
+#include "forkserver.h"
+#include "sharedmem.h"
+#include "common.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <signal.h>
+#include <dirent.h>
+#include <fcntl.h>
+
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <arpa/inet.h>
+#include <sys/mman.h>
+#ifndef USEMMAP
+ #include <sys/shm.h>
+#endif
+#include <sys/socket.h>
+#include <netdb.h>
+
+#ifdef USE_DEFLATE
+ #include <libdeflate.h>
+struct libdeflate_compressor * compressor;
+struct libdeflate_decompressor *decompressor;
+#endif
+
+static u8 *in_file, /* Minimizer input test case */
+ *out_file;
+
+static u8 *in_data; /* Input data for trimming */
+static u8 *buf2;
+
+static s32 in_len;
+static s32 buf2_len;
+static u32 map_size = MAP_SIZE;
+
+static volatile u8 stop_soon; /* Ctrl-C pressed? */
+
+/* See if any bytes are set in the bitmap. */
+
+static inline u8 anything_set(afl_forkserver_t *fsrv) {
+
+ u32 *ptr = (u32 *)fsrv->trace_bits;
+ u32 i = (map_size >> 2);
+
+ while (i--) {
+
+ if (*(ptr++)) { return 1; }
+
+ }
+
+ return 0;
+
+}
+
+static void at_exit_handler(void) {
+
+ afl_fsrv_killall();
+
+}
+
+/* Write output file. */
+
+static s32 write_to_file(u8 *path, u8 *mem, u32 len) {
+
+ s32 ret;
+
+ unlink(path); /* Ignore errors */
+
+ ret = open(path, O_RDWR | O_CREAT | O_EXCL, 0600);
+
+ if (ret < 0) { PFATAL("Unable to create '%s'", path); }
+
+ ck_write(ret, mem, len, path);
+
+ lseek(ret, 0, SEEK_SET);
+
+ return ret;
+
+}
+
+/* Execute target application. Returns 0 if the changes are a dud, or
+ 1 if they should be kept. */
+
+static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len,
+ u8 first_run) {
+
+ afl_fsrv_write_to_testcase(fsrv, mem, len);
+
+ fsrv_run_result_t ret =
+ afl_fsrv_run_target(fsrv, fsrv->exec_tmout, &stop_soon);
+
+ if (ret == FSRV_RUN_ERROR) { FATAL("Couldn't run child"); }
+
+ if (stop_soon) {
+
+ SAYF(cRST cLRD "\n+++ aborted by user +++\n" cRST);
+ exit(1);
+
+ }
+
+ return ret;
+
+}
+
+/* Handle Ctrl-C and the like. */
+
+static void handle_stop_sig(int sig) {
+
+ stop_soon = 1;
+ afl_fsrv_killall();
+
+}
+
+/* Do basic preparations - persistent fds, filenames, etc. */
+
+static void set_up_environment(afl_forkserver_t *fsrv) {
+
+ u8 *x;
+
+ fsrv->dev_null_fd = open("/dev/null", O_RDWR);
+ if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
+
+ if (!out_file) {
+
+ u8 *use_dir = ".";
+
+ if (access(use_dir, R_OK | W_OK | X_OK)) {
+
+ use_dir = get_afl_env("TMPDIR");
+ if (!use_dir) { use_dir = "/tmp"; }
+
+ }
+
+ out_file = alloc_printf("%s/.afl-input-temp-%u", use_dir, getpid());
+
+ }
+
+ unlink(out_file);
+
+ fsrv->out_fd = open(out_file, O_RDWR | O_CREAT | O_EXCL, 0600);
+
+ if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", out_file); }
+
+ /* Set sane defaults... */
+
+ x = get_afl_env("ASAN_OPTIONS");
+
+ if (x) {
+
+ if (!strstr(x, "abort_on_error=1")) {
+
+ FATAL("Custom ASAN_OPTIONS set without abort_on_error=1 - please fix!");
+
+ }
+
+ if (!strstr(x, "symbolize=0")) {
+
+ FATAL("Custom ASAN_OPTIONS set without symbolize=0 - please fix!");
+
+ }
+
+ }
+
+ x = get_afl_env("MSAN_OPTIONS");
+
+ if (x) {
+
+ if (!strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR))) {
+
+ FATAL("Custom MSAN_OPTIONS set without exit_code=" STRINGIFY(
+ MSAN_ERROR) " - please fix!");
+
+ }
+
+ if (!strstr(x, "symbolize=0")) {
+
+ FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!");
+
+ }
+
+ }
+
+ setenv("ASAN_OPTIONS",
+ "abort_on_error=1:"
+ "detect_leaks=0:"
+ "symbolize=0:"
+ "allocator_may_return_null=1",
+ 0);
+
+ setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":"
+ "symbolize=0:"
+ "abort_on_error=1:"
+ "allocator_may_return_null=1:"
+ "msan_track_origins=0", 0);
+
+ if (get_afl_env("AFL_PRELOAD")) {
+
+ if (fsrv->qemu_mode) {
+
+ /* afl-qemu-trace takes care of converting AFL_PRELOAD. */
+
+ } else {
+
+ setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
+ setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
+
+ }
+
+ }
+
+}
+
+/* Setup signal handlers, duh. */
+
+static void setup_signal_handlers(void) {
+
+ struct sigaction sa;
+
+ sa.sa_handler = NULL;
+ sa.sa_flags = SA_RESTART;
+ sa.sa_sigaction = NULL;
+
+ sigemptyset(&sa.sa_mask);
+
+ /* Various ways of saying "stop". */
+
+ sa.sa_handler = handle_stop_sig;
+ sigaction(SIGHUP, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGTERM, &sa, NULL);
+
+}
+
+/* Display usage hints. */
+
+static void usage(u8 *argv0) {
+
+ SAYF(
+ "\n%s [ options ] -- /path/to/target_app [ ... ]\n\n"
+
+ "Required parameters:\n"
+
+ " -i port - the port to listen for the client to connect to\n\n"
+
+ "Execution control settings:\n"
+
+ " -f file - input file read by the tested program (stdin)\n"
+ " -t msec - timeout for each run (%d ms)\n"
+ " -m megs - memory limit for child process (%d MB)\n"
+ " -Q - use binary-only instrumentation (QEMU mode)\n"
+ " -U - use unicorn-based instrumentation (Unicorn mode)\n"
+ " -W - use qemu-based instrumentation with Wine (Wine "
+ "mode)\n\n"
+
+ "Environment variables used:\n"
+ "TMPDIR: directory to use for temporary input files\n"
+ "ASAN_OPTIONS: custom settings for ASAN\n"
+ " (must contain abort_on_error=1 and symbolize=0)\n"
+ "MSAN_OPTIONS: custom settings for MSAN\n"
+ " (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n"
+ "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n"
+ " the target was compiled for\n"
+ "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
+
+ , argv0, EXEC_TIMEOUT, MEM_LIMIT);
+
+ exit(1);
+
+}
+
+int recv_testcase(int s, void **buf) {
+
+ u32 size;
+ s32 ret;
+ size_t received;
+
+ received = 0;
+ while (received < 4 && (ret = recv(s, &size + received, 4 - received, 0)) > 0)
+ received += ret;
+ if (received != 4) FATAL("did not receive size information");
+ if (size == 0) FATAL("did not receive valid size information");
+ // fprintf(stderr, "received size information of %d\n", size);
+
+ if ((size & 0xff000000) != 0xff000000) {
+
+ *buf = afl_realloc(buf, size);
+ if (unlikely(!*buf)) { PFATAL("Alloc"); }
+ received = 0;
+ // fprintf(stderr, "unCOMPRESS (%u)\n", size);
+ while (received < size &&
+ (ret = recv(s, ((char *)*buf) + received, size - received, 0)) > 0)
+ received += ret;
+
+ } else {
+
+#ifdef USE_DEFLATE
+ u32 clen;
+ size -= 0xff000000;
+ *buf = afl_realloc(buf, size);
+ if (unlikely(!*buf)) { PFATAL("Alloc"); }
+ received = 0;
+ while (received < 4 &&
+ (ret = recv(s, &clen + received, 4 - received, 0)) > 0)
+ received += ret;
+ if (received != 4) FATAL("did not receive clen1 information");
+ // fprintf(stderr, "received clen information of %d\n", clen);
+ if (clen < 1)
+ FATAL("did not receive valid compressed len information: %u", clen);
+ buf2 = afl_realloc((void **)&buf2, clen);
+ buf2_len = clen;
+ if (unlikely(!buf2)) { PFATAL("Alloc"); }
+ received = 0;
+ while (received < clen &&
+ (ret = recv(s, buf2 + received, clen - received, 0)) > 0)
+ received += ret;
+ if (received != clen) FATAL("did not receive compressed information");
+ if (libdeflate_deflate_decompress(decompressor, buf2, clen, (char *)*buf,
+ size, &received) != LIBDEFLATE_SUCCESS)
+ FATAL("decompression failed");
+ // fprintf(stderr, "DECOMPRESS (%u->%u):\n", clen, received);
+ // for (u32 i = 0; i < clen; i++) fprintf(stderr, "%02x", buf2[i]);
+ // fprintf(stderr, "\n");
+ // for (u32 i = 0; i < received; i++) fprintf(stderr, "%02x",
+ // ((u8*)(*buf))[i]); fprintf(stderr, "\n");
+#else
+ FATAL("Received compressed data but not compiled with compression support");
+#endif
+
+ }
+
+ // fprintf(stderr, "receiving testcase %p %p max %u\n", buf, *buf, *max_len);
+ if (received != size)
+ FATAL("did not receive testcase data %lu != %u, %d", received, size, ret);
+ // fprintf(stderr, "received testcase\n");
+ return size;
+
+}
+
+/* Main entry point */
+
+int main(int argc, char **argv_orig, char **envp) {
+
+ s32 opt, s, sock, on = 1, port = -1;
+ u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0;
+ char **use_argv;
+ struct sockaddr_in6 serveraddr, clientaddr;
+ int addrlen = sizeof(clientaddr);
+ char str[INET6_ADDRSTRLEN];
+ char ** argv = argv_cpy_dup(argc, argv_orig);
+ u8 * send_buf;
+#ifdef USE_DEFLATE
+ u32 *lenptr;
+#endif
+
+ afl_forkserver_t fsrv_var = {0};
+ afl_forkserver_t *fsrv = &fsrv_var;
+ afl_fsrv_init(fsrv);
+ map_size = get_map_size();
+ fsrv->map_size = map_size;
+
+ if ((send_buf = malloc(map_size + 4)) == NULL) PFATAL("malloc");
+
+ while ((opt = getopt(argc, argv, "+i:f:m:t:QUWh")) > 0) {
+
+ switch (opt) {
+
+ case 'i':
+
+ if (port > 0) { FATAL("Multiple -i options not supported"); }
+ port = atoi(optarg);
+ if (port < 1 || port > 65535)
+ FATAL("invalid port definition, must be between 1-65535: %s", optarg);
+ break;
+
+ case 'f':
+
+ if (out_file) { FATAL("Multiple -f options not supported"); }
+ fsrv->use_stdin = 0;
+ out_file = optarg;
+ break;
+
+ case 'm': {
+
+ u8 suffix = 'M';
+
+ if (mem_limit_given) { FATAL("Multiple -m options not supported"); }
+ mem_limit_given = 1;
+
+ if (!optarg) { FATAL("Wrong usage of -m"); }
+
+ if (!strcmp(optarg, "none")) {
+
+ fsrv->mem_limit = 0;
+ break;
+
+ }
+
+ if (sscanf(optarg, "%llu%c", &fsrv->mem_limit, &suffix) < 1 ||
+ optarg[0] == '-') {
+
+ FATAL("Bad syntax used for -m");
+
+ }
+
+ switch (suffix) {
+
+ case 'T':
+ fsrv->mem_limit *= 1024 * 1024;
+ break;
+ case 'G':
+ fsrv->mem_limit *= 1024;
+ break;
+ case 'k':
+ fsrv->mem_limit /= 1024;
+ break;
+ case 'M':
+ break;
+
+ default:
+ FATAL("Unsupported suffix or bad syntax for -m");
+
+ }
+
+ if (fsrv->mem_limit < 5) { FATAL("Dangerously low value of -m"); }
+
+ if (sizeof(rlim_t) == 4 && fsrv->mem_limit > 2000) {
+
+ FATAL("Value of -m out of range on 32-bit systems");
+
+ }
+
+ }
+
+ break;
+
+ case 't':
+
+ if (timeout_given) { FATAL("Multiple -t options not supported"); }
+ timeout_given = 1;
+
+ if (!optarg) { FATAL("Wrong usage of -t"); }
+
+ fsrv->exec_tmout = atoi(optarg);
+
+ if (fsrv->exec_tmout < 10 || optarg[0] == '-') {
+
+ FATAL("Dangerously low value of -t");
+
+ }
+
+ break;
+
+ case 'Q':
+
+ if (fsrv->qemu_mode) { FATAL("Multiple -Q options not supported"); }
+ if (!mem_limit_given) { fsrv->mem_limit = MEM_LIMIT_QEMU; }
+
+ fsrv->qemu_mode = 1;
+ break;
+
+ case 'U':
+
+ if (unicorn_mode) { FATAL("Multiple -Q options not supported"); }
+ if (!mem_limit_given) { fsrv->mem_limit = MEM_LIMIT_UNICORN; }
+
+ unicorn_mode = 1;
+ break;
+
+ case 'W': /* Wine+QEMU mode */
+
+ if (use_wine) { FATAL("Multiple -W options not supported"); }
+ fsrv->qemu_mode = 1;
+ use_wine = 1;
+
+ if (!mem_limit_given) { fsrv->mem_limit = 0; }
+
+ break;
+
+ case 'h':
+ usage(argv[0]);
+ return -1;
+ break;
+
+ default:
+ usage(argv[0]);
+
+ }
+
+ }
+
+ if (optind == argc || port < 1) { usage(argv[0]); }
+
+ check_environment_vars(envp);
+
+ sharedmem_t shm = {0};
+ fsrv->trace_bits = afl_shm_init(&shm, map_size, 0);
+
+ in_data = afl_realloc((void **)&in_data, 65536);
+ if (unlikely(!in_data)) { PFATAL("Alloc"); }
+
+ atexit(at_exit_handler);
+ setup_signal_handlers();
+
+ set_up_environment(fsrv);
+
+ fsrv->target_path = find_binary(argv[optind]);
+ detect_file_args(argv + optind, out_file, &fsrv->use_stdin);
+
+ if (fsrv->qemu_mode) {
+
+ if (use_wine) {
+
+ use_argv = get_wine_argv(argv[0], &fsrv->target_path, argc - optind,
+ argv + optind);
+
+ } else {
+
+ use_argv = get_qemu_argv(argv[0], &fsrv->target_path, argc - optind,
+ argv + optind);
+
+ }
+
+ } else {
+
+ use_argv = argv + optind;
+
+ }
+
+ if ((sock = socket(AF_INET6, SOCK_STREAM, 0)) < 0) PFATAL("socket() failed");
+
+#ifdef SO_REUSEADDR
+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) {
+
+ WARNF("setsockopt(SO_REUSEADDR) failed");
+
+ }
+
+#endif
+
+#ifdef SO_PRIORITY
+ int priority = 7;
+ if (setsockopt(sock, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) <
+ 0) {
+
+ priority = 6;
+ if (setsockopt(sock, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) <
+ 0)
+ WARNF("could not set priority on socket");
+
+ }
+
+#endif
+
+ memset(&serveraddr, 0, sizeof(serveraddr));
+ serveraddr.sin6_family = AF_INET6;
+ serveraddr.sin6_port = htons(port);
+ serveraddr.sin6_addr = in6addr_any;
+
+ if (bind(sock, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
+ PFATAL("bind() failed");
+
+ if (listen(sock, 1) < 0) { PFATAL("listen() failed"); }
+
+ afl_fsrv_start(
+ fsrv, use_argv, &stop_soon,
+ (get_afl_env("AFL_DEBUG_CHILD") || get_afl_env("AFL_DEBUG_CHILD_OUTPUT"))
+ ? 1
+ : 0);
+
+#ifdef USE_DEFLATE
+ compressor = libdeflate_alloc_compressor(1);
+ decompressor = libdeflate_alloc_decompressor();
+ buf2 = afl_realloc((void **)&buf2, map_size + 16);
+ buf2_len = map_size + 16;
+ if (unlikely(!buf2)) { PFATAL("alloc"); }
+ lenptr = (u32 *)(buf2 + 4);
+ fprintf(stderr, "Compiled with compression support\n");
+#endif
+
+ fprintf(stderr,
+ "Waiting for incoming connection from afl-network-client on port %d "
+ "...\n",
+ port);
+
+ if ((s = accept(sock, NULL, NULL)) < 0) { PFATAL("accept() failed"); }
+ fprintf(stderr, "Received connection, starting ...\n");
+
+#ifdef SO_PRIORITY
+ priority = 7;
+ if (setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0) {
+
+ priority = 6;
+ if (setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0)
+ WARNF("could not set priority on socket");
+
+ }
+
+#endif
+
+ while ((in_len = recv_testcase(s, (void **)&in_data)) > 0) {
+
+ // fprintf(stderr, "received %u\n", in_len);
+ (void)run_target(fsrv, use_argv, in_data, in_len, 1);
+
+ memcpy(send_buf + 4, fsrv->trace_bits, fsrv->map_size);
+
+#ifdef USE_DEFLATE
+ memcpy(buf2, &fsrv->child_status, 4);
+ *lenptr = (u32)libdeflate_deflate_compress(
+ compressor, send_buf + 4, fsrv->map_size, buf2 + 8, buf2_len - 8);
+ // fprintf(stderr, "COMPRESS (%u->%u): ", fsrv->map_size, *lenptr);
+ // for (u32 i = 0; i < fsrv->map_size; i++) fprintf(stderr, "%02x",
+ // fsrv->trace_bits[i]); fprintf(stderr, "\n");
+ if (send(s, buf2, *lenptr + 8, 0) != 8 + *lenptr)
+ FATAL("could not send data");
+#else
+ memcpy(send_buf, &fsrv->child_status, 4);
+ if (send(s, send_buf, fsrv->map_size + 4, 0) != 4 + fsrv->map_size)
+ FATAL("could not send data");
+#endif
+
+ // fprintf(stderr, "sent result\n");
+
+ }
+
+ unlink(out_file);
+ if (out_file) { ck_free(out_file); }
+ out_file = NULL;
+
+ afl_shm_deinit(&shm);
+ afl_fsrv_deinit(fsrv);
+ if (fsrv->target_path) { ck_free(fsrv->target_path); }
+ afl_free(in_data);
+#if USE_DEFLATE
+ afl_free(buf2);
+ libdeflate_free_compressor(compressor);
+ libdeflate_free_decompressor(decompressor);
+#endif
+
+ argv_cpy_free(argv);
+
+ exit(0);
+
+}
+
diff --git a/utils/afl_proxy/Makefile b/utils/afl_proxy/Makefile
new file mode 100644
index 00000000..4b368f8d
--- /dev/null
+++ b/utils/afl_proxy/Makefile
@@ -0,0 +1,7 @@
+all: afl-proxy
+
+afl-proxy: afl-proxy.c
+ $(CC) -I../../include -o afl-proxy afl-proxy.c
+
+clean:
+ rm -f afl-proxy *~ core
diff --git a/utils/afl_proxy/README.md b/utils/afl_proxy/README.md
new file mode 100644
index 00000000..3c768a19
--- /dev/null
+++ b/utils/afl_proxy/README.md
@@ -0,0 +1,9 @@
+# afl-proxy
+
+afl-proxy is an example skeleton file which can easily be used to fuzz
+and instrument non-standard things.
+
+You only need to change the while() loop of the main() to send the
+data of buf[] with length len to the target and write the coverage
+information to __afl_area_ptr[__afl_map_size]
+
diff --git a/utils/afl_proxy/afl-proxy.c b/utils/afl_proxy/afl-proxy.c
new file mode 100644
index 00000000..05247c60
--- /dev/null
+++ b/utils/afl_proxy/afl-proxy.c
@@ -0,0 +1,251 @@
+/*
+ american fuzzy lop++ - afl-proxy skeleton example
+ ---------------------------------------------------
+
+ Written by Marc Heuse <mh@mh-sec.de>
+
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+
+ HOW-TO
+ ======
+
+ You only need to change the while() loop of the main() to send the
+ data of buf[] with length len to the target and write the coverage
+ information to __afl_area_ptr[__afl_map_size]
+
+
+*/
+
+#ifdef __ANDROID__
+ #include "android-ashmem.h"
+#endif
+#include "config.h"
+#include "types.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include <sys/mman.h>
+#include <sys/shm.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+u8 *__afl_area_ptr;
+
+#ifdef __ANDROID__
+u32 __afl_map_size = MAP_SIZE;
+#else
+__thread u32 __afl_map_size = MAP_SIZE;
+#endif
+
+/* Error reporting to forkserver controller */
+
+void send_forkserver_error(int error) {
+
+ u32 status;
+ if (!error || error > 0xffff) return;
+ status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error));
+ if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return;
+
+}
+
+/* SHM setup. */
+
+static void __afl_map_shm(void) {
+
+ char *id_str = getenv(SHM_ENV_VAR);
+ char *ptr;
+
+ /* NOTE TODO BUG FIXME: if you want to supply a variable sized map then
+ uncomment the following: */
+
+ /*
+ if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) {
+
+ u32 val = atoi(ptr);
+ if (val > 0) __afl_map_size = val;
+
+ }
+
+ */
+
+ if (__afl_map_size > MAP_SIZE) {
+
+ if (__afl_map_size > 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_map_size);
+ if (id_str) {
+
+ send_forkserver_error(FS_ERROR_MAP_SIZE);
+ exit(-1);
+
+ }
+
+ } 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_map_size);
+
+ }
+
+ }
+
+ if (id_str) {
+
+#ifdef USEMMAP
+ const char * shm_file_path = id_str;
+ int shm_fd = -1;
+ unsigned char *shm_base = NULL;
+
+ /* create the shared memory segment as if it was a file */
+ shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
+ if (shm_fd == -1) {
+
+ fprintf(stderr, "shm_open() failed\n");
+ send_forkserver_error(FS_ERROR_SHM_OPEN);
+ exit(1);
+
+ }
+
+ /* map the shared memory segment to the address space of the process */
+ shm_base =
+ mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
+
+ if (shm_base == MAP_FAILED) {
+
+ close(shm_fd);
+ shm_fd = -1;
+
+ fprintf(stderr, "mmap() failed\n");
+ send_forkserver_error(FS_ERROR_MMAP);
+ exit(2);
+
+ }
+
+ __afl_area_ptr = shm_base;
+#else
+ u32 shm_id = atoi(id_str);
+
+ __afl_area_ptr = shmat(shm_id, 0, 0);
+
+#endif
+
+ if (__afl_area_ptr == (void *)-1) {
+
+ send_forkserver_error(FS_ERROR_SHMAT);
+ exit(1);
+
+ }
+
+ /* Write something into the bitmap so that the parent doesn't give up */
+
+ __afl_area_ptr[0] = 1;
+
+ }
+
+}
+
+/* Fork server logic. */
+
+static void __afl_start_forkserver(void) {
+
+ u8 tmp[4] = {0, 0, 0, 0};
+ u32 status = 0;
+
+ if (__afl_map_size <= FS_OPT_MAX_MAPSIZE)
+ status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
+ if (status) status |= (FS_OPT_ENABLED);
+ memcpy(tmp, &status, 4);
+
+ /* Phone home and tell the parent that we're OK. */
+
+ if (write(FORKSRV_FD + 1, tmp, 4) != 4) return;
+
+}
+
+static u32 __afl_next_testcase(u8 *buf, u32 max_len) {
+
+ s32 status, res = 0xffffff;
+
+ /* Wait for parent by reading from the pipe. Abort if read fails. */
+ if (read(FORKSRV_FD, &status, 4) != 4) return 0;
+
+ /* we have a testcase - read it */
+ status = read(0, buf, max_len);
+
+ /* report that we are starting the target */
+ if (write(FORKSRV_FD + 1, &res, 4) != 4) return 0;
+
+ return status;
+
+}
+
+static void __afl_end_testcase(void) {
+
+ int status = 0xffffff;
+
+ if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(1);
+
+}
+
+/* you just need to modify the while() loop in this main() */
+
+int main(int argc, char *argv[]) {
+
+ /* This is were the testcase data is written into */
+ u8 buf[1024]; // this is the maximum size for a test case! set it!
+ s32 len;
+
+ /* here you specify the map size you need that you are reporting to
+ afl-fuzz. Any value is fine as long as it can be divided by 32. */
+ __afl_map_size = MAP_SIZE; // default is 65536
+
+ /* then we initialize the shared memory map and start the forkserver */
+ __afl_map_shm();
+ __afl_start_forkserver();
+
+ while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) {
+
+ if (len > 4) { // the minimum data size you need for the target
+
+ /* here you have to create the magic that feeds the buf/len to the
+ target and write the coverage to __afl_area_ptr */
+
+ // ... the magic ...
+
+ // remove this, this is just to make afl-fuzz not complain when run
+ if (buf[0] == 0xff)
+ __afl_area_ptr[1] = 1;
+ else
+ __afl_area_ptr[2] = 2;
+
+ }
+
+ /* report the test case is done and wait for the next */
+ __afl_end_testcase();
+
+ }
+
+ return 0;
+
+}
+
diff --git a/utils/afl_untracer/Makefile b/utils/afl_untracer/Makefile
new file mode 100644
index 00000000..14a09b41
--- /dev/null
+++ b/utils/afl_untracer/Makefile
@@ -0,0 +1,16 @@
+ifdef DEBUG
+ OPT=-O0
+else
+ OPT=-O3
+endif
+
+all: afl-untracer libtestinstr.so
+
+afl-untracer: afl-untracer.c
+ $(CC) $(OPT) -I../../include -g -o afl-untracer afl-untracer.c -ldl
+
+libtestinstr.so: libtestinstr.c
+ $(CC) -g -O0 -fPIC -o libtestinstr.so -shared libtestinstr.c
+
+clean:
+ rm -f afl-untracer libtestinstr.so *~ core
diff --git a/utils/afl_untracer/README.md b/utils/afl_untracer/README.md
new file mode 100644
index 00000000..da0e0c77
--- /dev/null
+++ b/utils/afl_untracer/README.md
@@ -0,0 +1,66 @@
+# afl-untracer - fast fuzzing of binary-only libraries
+
+## Introduction
+
+afl-untracer is an example skeleton file which can easily be used to fuzz
+a closed source library.
+
+It requires less memory and is x3-5 faster than QEMU mode, however, it is way
+more course grained and does not provide interesting features like compcov or
+cmplog.
+
+Supported is so far Intel (i386/x86_64) and AARCH64.
+
+## How-to
+
+### Modify afl-untracer.c
+
+Read and modify afl-untracer.c, then `make`.
+To adapt afl-untracer.c to your needs, read the header of the file and then
+search and edit the `STEP 1`, `STEP 2` and `STEP 3` locations.
+
+### Generate patches.txt file
+
+To generate the `patches.txt` file for your target library use the
+`ida_get_patchpoints.py` script for IDA Pro or
+`ghidra_get_patchpoints.java` for Ghidra.
+
+The patches.txt file has to be pointed to by `AFL_UNTRACER_FILE`.
+
+To easily run the scripts without needing to run the GUI with Ghidra:
+
+```
+/opt/ghidra/support/analyzeHeadless /tmp/ tmp$$ -import libtestinstr.so -postscript ./ghidra_get_patchpoints.java
+rm -rf /tmp/tmp$$
+```
+
+The file is created at `~/Desktop/patches.txt`
+
+### Fuzzing
+
+Example (after modifying afl-untracer.c to your needs, compiling and creating
+patches.txt):
+
+```
+LD_LIBRARY_PATH=/path/to/target/library AFL_UNTRACER_FILE=./patches.txt afl-fuzz -i in -o out -- ./afl-untracer
+```
+
+(or even remote via afl-network-proxy).
+
+### Testing and debugging
+
+For testing/debugging you can try:
+
+```
+make DEBUG=1
+AFL_UNTRACER_FILE=./patches.txt AFL_DEBUG=1 gdb ./afl-untracer
+```
+
+and then you can easily set breakpoints to "breakpoint" and "fuzz".
+
+# Background
+
+This idea is based on [UnTracer](https://github.com/FoRTE-Research/UnTracer-AFL)
+and modified by [Trapfuzz](https://github.com/googleprojectzero/p0tools/tree/master/TrapFuzz).
+This implementation is slower because the traps are not patched out with each
+run, but on the other hand gives much better coverage information. \ No newline at end of file
diff --git a/utils/afl_untracer/TODO b/utils/afl_untracer/TODO
new file mode 100644
index 00000000..fffffacf
--- /dev/null
+++ b/utils/afl_untracer/TODO
@@ -0,0 +1,2 @@
+ * add shmem fuzzing
+ * add snapshot feature?
diff --git a/utils/afl_untracer/afl-untracer.c b/utils/afl_untracer/afl-untracer.c
new file mode 100644
index 00000000..fd4c3b8c
--- /dev/null
+++ b/utils/afl_untracer/afl-untracer.c
@@ -0,0 +1,781 @@
+/*
+ american fuzzy lop++ - afl-untracer skeleton example
+ ---------------------------------------------------
+
+ Written by Marc Heuse <mh@mh-sec.de>
+
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+
+ HOW-TO
+ ======
+
+ You only need to change the following:
+
+ 1. decide if you want to receive data from stdin [DEFAULT] or file(name)
+ -> use_stdin = 0 if via file, and what the maximum input size is
+ 2. dl load the library you want to fuzz, lookup the functions you need
+ and setup the calls to these
+ 3. in the while loop you call the functions in the necessary order -
+ incl the cleanup. the cleanup is important!
+
+ Just look these steps up in the code, look for "// STEP x:"
+
+
+*/
+
+#define __USE_GNU
+#define _GNU_SOURCE
+
+#ifdef __ANDROID__
+ #include "android-ashmem.h"
+#endif
+#include "config.h"
+#include "types.h"
+#include "debug.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+#include <stdint.h>
+#include <errno.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <pthread.h>
+
+#include <sys/mman.h>
+#include <sys/shm.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+
+#if defined(__linux__)
+ #include <sys/personality.h>
+ #include <sys/ucontext.h>
+#elif defined(__APPLE__) && defined(__LP64__)
+ #include <mach-o/dyld_images.h>
+#elif defined(__FreeBSD__)
+ #include <sys/sysctl.h>
+ #include <sys/user.h>
+ #include <sys/procctl.h>
+#else
+ #error "Unsupported platform"
+#endif
+
+#define MEMORY_MAP_DECREMENT 0x200000000000
+#define MAX_LIB_COUNT 128
+
+// STEP 1:
+
+/* here you need to specify the parameter for the target function */
+static void *(*o_function)(u8 *buf, int len);
+
+/* use stdin (1) or a file on the commandline (0) */
+static u32 use_stdin = 1;
+
+/* This is were the testcase data is written into */
+static u8 buf[10000]; // this is the maximum size for a test case! set it!
+
+/* If you want to have debug output set this to 1, can also be set with
+ AFL_DEBUG */
+static u32 debug = 0;
+
+// END STEP 1
+
+typedef struct library_list {
+
+ u8 *name;
+ u64 addr_start, addr_end;
+
+} library_list_t;
+
+#ifdef __ANDROID__
+u32 __afl_map_size = MAP_SIZE;
+u32 do_exit;
+#else
+__thread u32 __afl_map_size = MAP_SIZE;
+__thread u32 do_exit;
+#endif
+
+static pid_t pid = 65537;
+static pthread_t __afl_thread;
+static u8 __afl_dummy[MAP_SIZE];
+static u8 * __afl_area_ptr = __afl_dummy;
+static u8 * inputfile; // this will point to argv[1]
+static u32 len;
+
+static library_list_t liblist[MAX_LIB_COUNT];
+static u32 liblist_cnt;
+
+static void sigtrap_handler(int signum, siginfo_t *si, void *context);
+static void fuzz(void);
+
+/* read the library information */
+void read_library_information(void) {
+
+#if defined(__linux__)
+ FILE *f;
+ u8 buf[1024], *b, *m, *e, *n;
+
+ if ((f = fopen("/proc/self/maps", "r")) == NULL)
+ FATAL("cannot open /proc/self/maps");
+
+ if (debug) fprintf(stderr, "Library list:\n");
+ while (fgets(buf, sizeof(buf), f)) {
+
+ if (strstr(buf, " r-x")) {
+
+ if (liblist_cnt >= MAX_LIB_COUNT) {
+
+ WARNF("too many libraries to old, maximum count of %d reached",
+ liblist_cnt);
+ return;
+
+ }
+
+ b = buf;
+ m = index(buf, '-');
+ e = index(buf, ' ');
+ if ((n = strrchr(buf, '/')) == NULL) n = strrchr(buf, ' ');
+ if (n &&
+ ((*n >= '0' && *n <= '9') || *n == '[' || *n == '{' || *n == '('))
+ n = NULL;
+ else
+ n++;
+ if (b && m && e && n && *n) {
+
+ *m++ = 0;
+ *e = 0;
+ if (n[strlen(n) - 1] == '\n') n[strlen(n) - 1] = 0;
+
+ liblist[liblist_cnt].name = strdup(n);
+ liblist[liblist_cnt].addr_start = strtoull(b, NULL, 16);
+ liblist[liblist_cnt].addr_end = strtoull(m, NULL, 16);
+ if (debug)
+ fprintf(
+ stderr, "%s:%llx (%llx-%llx)\n", liblist[liblist_cnt].name,
+ liblist[liblist_cnt].addr_end - liblist[liblist_cnt].addr_start,
+ liblist[liblist_cnt].addr_start,
+ liblist[liblist_cnt].addr_end - 1);
+ liblist_cnt++;
+
+ }
+
+ }
+
+ }
+
+ if (debug) fprintf(stderr, "\n");
+
+#elif defined(__FreeBSD__)
+ int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid()};
+ char * buf, *start, *end;
+ size_t miblen = sizeof(mib) / sizeof(mib[0]);
+ size_t len;
+
+ if (debug) fprintf(stderr, "Library list:\n");
+ if (sysctl(mib, miblen, NULL, &len, NULL, 0) == -1) { return; }
+
+ len = len * 4 / 3;
+
+ buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
+ if (buf == MAP_FAILED) { return; }
+
+ if (sysctl(mib, miblen, buf, &len, NULL, 0) == -1) {
+
+ munmap(buf, len);
+ return;
+
+ }
+
+ start = buf;
+ end = buf + len;
+
+ while (start < end) {
+
+ struct kinfo_vmentry *region = (struct kinfo_vmentry *)start;
+ size_t size = region->kve_structsize;
+
+ if (size == 0) { break; }
+
+ if ((region->kve_protection & KVME_PROT_READ) &&
+ !(region->kve_protection & KVME_PROT_EXEC)) {
+
+ liblist[liblist_cnt].name =
+ region->kve_path[0] != '\0' ? strdup(region->kve_path) : 0;
+ liblist[liblist_cnt].addr_start = region->kve_start;
+ liblist[liblist_cnt].addr_end = region->kve_end;
+
+ if (debug) {
+
+ fprintf(stderr, "%s:%x (%lx-%lx)\n", liblist[liblist_cnt].name,
+ liblist[liblist_cnt].addr_end - liblist[liblist_cnt].addr_start,
+ liblist[liblist_cnt].addr_start,
+ liblist[liblist_cnt].addr_end - 1);
+
+ }
+
+ liblist_cnt++;
+
+ }
+
+ start += size;
+
+ }
+
+#endif
+
+}
+
+library_list_t *find_library(char *name) {
+
+#if defined(__linux__)
+ u32 i;
+
+ for (i = 0; i < liblist_cnt; i++)
+ if (strncmp(liblist[i].name, name, strlen(name)) == 0) return &liblist[i];
+#elif defined(__APPLE__) && defined(__LP64__)
+ kern_return_t err;
+ static library_list_t lib;
+
+ // get the list of all loaded modules from dyld
+ // the task_info mach API will get the address of the dyld all_image_info
+ // struct for the given task from which we can get the names and load
+ // addresses of all modules
+ task_dyld_info_data_t task_dyld_info;
+ mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
+ err = task_info(mach_task_self(), TASK_DYLD_INFO,
+ (task_info_t)&task_dyld_info, &count);
+
+ const struct dyld_all_image_infos *all_image_infos =
+ (const struct dyld_all_image_infos *)task_dyld_info.all_image_info_addr;
+ const struct dyld_image_info *image_infos = all_image_infos->infoArray;
+
+ for (size_t i = 0; i < all_image_infos->infoArrayCount; i++) {
+
+ const char * image_name = image_infos[i].imageFilePath;
+ mach_vm_address_t image_load_address =
+ (mach_vm_address_t)image_infos[i].imageLoadAddress;
+ if (strstr(image_name, name)) {
+
+ lib.name = name;
+ lib.addr_start = (u64)image_load_address;
+ lib.addr_end = 0;
+ return &lib;
+
+ }
+
+ }
+
+#endif
+
+ return NULL;
+
+}
+
+/* for having an easy breakpoint location after loading the shared library */
+// this seems to work for clang too. nice :) requires gcc 4.4+
+#pragma GCC push_options
+#pragma GCC optimize("O0")
+void breakpoint(void) {
+
+ if (debug) fprintf(stderr, "Breakpoint function \"breakpoint\" reached.\n");
+
+}
+
+#pragma GCC pop_options
+
+/* Error reporting to forkserver controller */
+
+void send_forkserver_error(int error) {
+
+ u32 status;
+ if (!error || error > 0xffff) return;
+ status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error));
+ if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return;
+
+}
+
+/* SHM setup. */
+
+static void __afl_map_shm(void) {
+
+ char *id_str = getenv(SHM_ENV_VAR);
+ char *ptr;
+
+ if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) {
+
+ u32 val = atoi(ptr);
+ if (val > 0) __afl_map_size = val;
+
+ }
+
+ if (__afl_map_size > MAP_SIZE) {
+
+ if (__afl_map_size > 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_map_size);
+ if (id_str) {
+
+ send_forkserver_error(FS_ERROR_MAP_SIZE);
+ exit(-1);
+
+ }
+
+ } 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_map_size);
+
+ }
+
+ }
+
+ if (id_str) {
+
+#ifdef USEMMAP
+ const char * shm_file_path = id_str;
+ int shm_fd = -1;
+ unsigned char *shm_base = NULL;
+
+ /* create the shared memory segment as if it was a file */
+ shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
+ if (shm_fd == -1) {
+
+ fprintf(stderr, "shm_open() failed\n");
+ send_forkserver_error(FS_ERROR_SHM_OPEN);
+ exit(1);
+
+ }
+
+ /* map the shared memory segment to the address space of the process */
+ shm_base =
+ mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
+
+ if (shm_base == MAP_FAILED) {
+
+ close(shm_fd);
+ shm_fd = -1;
+
+ fprintf(stderr, "mmap() failed\n");
+ send_forkserver_error(FS_ERROR_MMAP);
+ exit(2);
+
+ }
+
+ __afl_area_ptr = shm_base;
+#else
+ u32 shm_id = atoi(id_str);
+
+ __afl_area_ptr = shmat(shm_id, 0, 0);
+
+#endif
+
+ if (__afl_area_ptr == (void *)-1) {
+
+ send_forkserver_error(FS_ERROR_SHMAT);
+ exit(1);
+
+ }
+
+ /* Write something into the bitmap so that the parent doesn't give up */
+
+ __afl_area_ptr[0] = 1;
+
+ }
+
+}
+
+/* Fork server logic. */
+inline static void __afl_start_forkserver(void) {
+
+ u8 tmp[4] = {0, 0, 0, 0};
+ u32 status = 0;
+
+ if (__afl_map_size <= FS_OPT_MAX_MAPSIZE)
+ status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
+ if (status) status |= (FS_OPT_ENABLED);
+ memcpy(tmp, &status, 4);
+
+ /* Phone home and tell the parent that we're OK. */
+ if (write(FORKSRV_FD + 1, tmp, 4) != 4) do_exit = 1;
+ // fprintf(stderr, "write0 %d\n", do_exit);
+
+}
+
+inline static u32 __afl_next_testcase(u8 *buf, u32 max_len) {
+
+ s32 status;
+
+ /* Wait for parent by reading from the pipe. Abort if read fails. */
+ if (read(FORKSRV_FD, &status, 4) != 4) do_exit = 1;
+ // fprintf(stderr, "read %d\n", do_exit);
+
+ /* we have a testcase - read it if we read from stdin */
+ if (use_stdin) {
+
+ if ((status = read(0, buf, max_len)) <= 0) exit(-1);
+
+ } else
+
+ status = 1;
+ // fprintf(stderr, "stdin: %d %d\n", use_stdin, status);
+
+ /* report that we are starting the target */
+ if (write(FORKSRV_FD + 1, &pid, 4) != 4) do_exit = 1;
+ // fprintf(stderr, "write1 %d\n", do_exit);
+
+ __afl_area_ptr[0] = 1; // put something in the map
+
+ return status;
+
+}
+
+inline static void __afl_end_testcase(int status) {
+
+ if (write(FORKSRV_FD + 1, &status, 4) != 4) do_exit = 1;
+ // fprintf(stderr, "write2 %d\n", do_exit);
+ if (do_exit) exit(0);
+
+}
+
+#ifdef __aarch64__
+ #define SHADOW(addr) \
+ ((uint64_t *)(((uintptr_t)addr & 0xfffffffffffffff8) - \
+ MEMORY_MAP_DECREMENT - \
+ ((uintptr_t)addr & 0x7) * 0x10000000000))
+#else
+ #define SHADOW(addr) \
+ ((uint32_t *)(((uintptr_t)addr & 0xfffffffffffffffc) - \
+ MEMORY_MAP_DECREMENT - \
+ ((uintptr_t)addr & 0x3) * 0x10000000000))
+#endif
+
+void setup_trap_instrumentation(void) {
+
+ library_list_t *lib_base = NULL;
+ size_t lib_size = 0;
+ u8 * lib_addr;
+ char * line = NULL;
+ size_t nread, len = 0;
+ char * filename = getenv("AFL_UNTRACER_FILE");
+ if (!filename) filename = getenv("TRAPFUZZ_FILE");
+ if (!filename) FATAL("AFL_UNTRACER_FILE environment variable not set");
+
+ FILE *patches = fopen(filename, "r");
+ if (!patches) FATAL("Couldn't open AFL_UNTRACER_FILE file %s", filename);
+
+ // Index into the coverage bitmap for the current trap instruction.
+#ifdef __aarch64__
+ uint64_t bitmap_index = 0;
+ #ifdef __APPLE__
+ pthread_jit_write_protect_np(0);
+ #endif
+#else
+ uint32_t bitmap_index = 0;
+#endif
+
+ while ((nread = getline(&line, &len, patches)) != -1) {
+
+ char *end = line + len;
+
+ char *col = strchr(line, ':');
+ if (col) {
+
+ // It's a library:size pair
+ *col++ = 0;
+
+ lib_base = find_library(line);
+ if (!lib_base) FATAL("Library %s does not appear to be loaded", line);
+
+ // we ignore the defined lib_size
+ lib_size = strtoul(col, NULL, 16);
+#if (__linux__)
+ if (lib_size < lib_base->addr_end - lib_base->addr_start)
+ lib_size = lib_base->addr_end - lib_base->addr_start;
+#endif
+ if (lib_size % 0x1000 != 0)
+ WARNF("Invalid library size 0x%zx. Must be multiple of 0x1000",
+ lib_size);
+
+ lib_addr = (u8 *)lib_base->addr_start;
+ // Make library code writable.
+ if (mprotect((void *)lib_addr, lib_size,
+ PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
+ FATAL("Failed to mprotect library %s writable", line);
+
+ // Create shadow memory.
+#ifdef __aarch64__
+ for (int i = 0; i < 8; i++) {
+
+#else
+ for (int i = 0; i < 4; i++) {
+
+#endif
+
+ void *shadow_addr = SHADOW(lib_addr + i);
+ void *shadow = mmap(shadow_addr, lib_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON | MAP_FIXED, 0, 0);
+ if (debug)
+ fprintf(stderr, "Shadow: %s %d = %p-%p for %p\n", line, i, shadow,
+ shadow + lib_size - 1, lib_addr);
+ if (shadow == MAP_FAILED) FATAL("Failed to mmap shadow memory");
+
+ }
+
+ // Done, continue with next line.
+ continue;
+
+ }
+
+ // It's an offset, parse it and do the patching.
+ unsigned long offset = strtoul(line, NULL, 16);
+
+ if (offset > lib_size)
+ FATAL("Invalid offset: 0x%lx. Current library is 0x%zx bytes large",
+ offset, lib_size);
+
+ if (bitmap_index >= __afl_map_size)
+ FATAL("Too many basic blocks to instrument");
+
+#ifdef __arch64__
+ uint64_t
+#else
+ uint32_t
+#endif
+ *shadow = SHADOW(lib_addr + offset);
+ if (*shadow != 0) continue; // skip duplicates
+
+ // Make lookup entry in shadow memory.
+
+#if ((defined(__APPLE__) && defined(__LP64__)) || defined(__x86_64__) || \
+ defined(__i386__))
+
+ // this is for Intel x64
+
+ uint8_t orig_byte = lib_addr[offset];
+ *shadow = (bitmap_index << 8) | orig_byte;
+ lib_addr[offset] = 0xcc; // replace instruction with debug trap
+ if (debug)
+ fprintf(stderr,
+ "Patch entry: %p[%lx] = %p = %02x -> SHADOW(%p) #%d -> %08x\n",
+ lib_addr, offset, lib_addr + offset, orig_byte, shadow,
+ bitmap_index, *shadow);
+
+#elif defined(__aarch64__)
+
+ // this is for aarch64
+
+ uint32_t *patch_bytes = (uint32_t *)(lib_addr + offset);
+ uint32_t orig_bytes = *patch_bytes;
+ *shadow = (bitmap_index << 32) | orig_bytes;
+ *patch_bytes = 0xd4200000; // replace instruction with debug trap
+ if (debug)
+ fprintf(stderr,
+ "Patch entry: %p[%lx] = %p = %02x -> SHADOW(%p) #%d -> %016x\n",
+ lib_addr, offset, lib_addr + offset, orig_bytes, shadow,
+ bitmap_index, *shadow);
+
+#else
+ // this will be ARM and AARCH64
+ // for ARM we will need to identify if the code is in thumb or ARM
+ #error "non x86_64/aarch64 not supported yet"
+ //__arm__:
+ // linux thumb: 0xde01
+ // linux arm: 0xe7f001f0
+ //__aarch64__:
+ // linux aarch64: 0xd4200000
+#endif
+
+ bitmap_index++;
+
+ }
+
+ free(line);
+ fclose(patches);
+
+ // Install signal handler for SIGTRAP.
+ struct sigaction s;
+ s.sa_flags = SA_SIGINFO;
+ s.sa_sigaction = sigtrap_handler;
+ sigemptyset(&s.sa_mask);
+ sigaction(SIGTRAP, &s, 0);
+
+ if (debug) fprintf(stderr, "Patched %u locations.\n", bitmap_index);
+ __afl_map_size = bitmap_index;
+ if (__afl_map_size % 8) __afl_map_size = (((__afl_map_size + 7) >> 3) << 3);
+
+}
+
+/* the signal handler for the traps / debugging interrupts
+ No debug output here because this would cost speed */
+static void sigtrap_handler(int signum, siginfo_t *si, void *context) {
+
+ uint64_t addr;
+ // Must re-execute the instruction, so decrement PC by one instruction.
+ ucontext_t *ctx = (ucontext_t *)context;
+#if defined(__APPLE__) && defined(__LP64__)
+ #if defined(__x86_64__)
+ ctx->uc_mcontext->__ss.__rip -= 1;
+ addr = ctx->uc_mcontext->__ss.__rip;
+ #else
+ ctx->uc_mcontext->__ss.__pc -= 4;
+ addr = ctx->uc_mcontext->__ss.__pc;
+ #endif
+#elif defined(__linux__)
+ #if defined(__x86_64__) || defined(__i386__)
+ ctx->uc_mcontext.gregs[REG_RIP] -= 1;
+ addr = ctx->uc_mcontext.gregs[REG_RIP];
+ #elif defined(__aarch64__)
+ ctx->uc_mcontext.pc -= 4;
+ addr = ctx->uc_mcontext.pc;
+ #else
+ #error "Unsupported processor"
+ #endif
+#elif defined(__FreeBSD__) && defined(__LP64__)
+ ctx->uc_mcontext.mc_rip -= 1;
+ addr = ctx->uc_mcontext.mc_rip;
+#else
+ #error "Unsupported platform"
+#endif
+
+ // fprintf(stderr, "TRAP at context addr = %lx, fault addr = %lx\n", addr,
+ // si->si_addr);
+
+ // If the trap didn't come from our instrumentation, then we probably will
+ // just segfault here
+ uint8_t *faultaddr;
+ if (unlikely(si->si_addr))
+ faultaddr = (u8 *)si->si_addr - 1;
+ else
+ faultaddr = (u8 *)addr;
+ // if (debug) fprintf(stderr, "Shadow location: %p\n", SHADOW(faultaddr));
+ uint32_t shadow = *SHADOW(faultaddr);
+ uint8_t orig_byte = shadow & 0xff;
+ uint32_t index = shadow >> 8;
+
+ // if (debug) fprintf(stderr, "shadow data: %x, orig_byte %02x, index %d\n",
+ // shadow, orig_byte, index);
+
+ // Index zero is invalid so that it is still possible to catch actual trap
+ // instructions in instrumented libraries.
+ if (unlikely(index == 0)) abort();
+
+ // Restore original instruction
+ *faultaddr = orig_byte;
+
+ __afl_area_ptr[index] = 128;
+
+}
+
+/* the MAIN function */
+int main(int argc, char *argv[]) {
+
+#if defined(__linux__)
+ (void)personality(ADDR_NO_RANDOMIZE); // disable ASLR
+#elif defined(__FreeBSD__) && __FreeBSD_version >= 1200000
+ int no_randomize = PROC_ASLR_FORCE_DISABLE;
+ (void)procctl(P_PID, 0, PROC_ASLR_CTL, &no_randomize);
+#endif
+
+ pid = getpid();
+ if (getenv("AFL_DEBUG")) debug = 1;
+
+ /* by default we use stdin, but also a filename can be passed, in this
+ case the input is argv[1] and we have to disable stdin */
+ if (argc > 1) {
+
+ use_stdin = 0;
+ inputfile = argv[1];
+
+ }
+
+ // STEP 2: load the library you want to fuzz and lookup the functions,
+ // inclusive of the cleanup functions
+ // NOTE: above the main() you have to define the functions!
+
+ void *dl = dlopen("./libtestinstr.so", RTLD_LAZY);
+ if (!dl) FATAL("could not find target library");
+ o_function = dlsym(dl, "testinstr");
+ if (!o_function) FATAL("could not resolve target function from library");
+ if (debug) fprintf(stderr, "Function address: %p\n", o_function);
+
+ // END STEP 2
+
+ /* setup instrumentation, shared memory and forkserver */
+ breakpoint();
+ read_library_information();
+ setup_trap_instrumentation();
+ __afl_map_shm();
+ __afl_start_forkserver();
+
+ while (1) {
+
+ // instead of fork() we could also use the snapshot lkm or do our own mini
+ // snapshot feature like in https://github.com/marcinguy/fuzzer
+ // -> snapshot.c
+ if ((pid = fork()) == -1) PFATAL("fork failed");
+
+ if (pid) {
+
+ u32 status;
+ if (waitpid(pid, &status, 0) < 0) exit(1);
+ /* report the test case is done and wait for the next */
+ __afl_end_testcase(status);
+
+ } else {
+
+ pid = getpid();
+ while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) {
+
+ // in this function the fuzz magic happens, this is STEP 3
+ fuzz();
+
+ // we can use _exit which is faster because our target library
+ // was loaded via dlopen and therefore cannot have deconstructors
+ // registered.
+ _exit(0);
+
+ }
+
+ }
+
+ }
+
+ return 0;
+
+}
+
+#ifndef _DEBUG
+inline
+#endif
+ static void
+ fuzz(void) {
+
+ // STEP 3: call the function to fuzz, also the functions you might
+ // need to call to prepare the function and - important! -
+ // to clean everything up
+
+ // in this example we use the input file, not stdin!
+ (*o_function)(buf, len);
+
+ // normally you also need to cleanup
+ //(*o_LibFree)(foo);
+
+ // END STEP 3
+
+}
+
diff --git a/utils/afl_untracer/ghidra_get_patchpoints.java b/utils/afl_untracer/ghidra_get_patchpoints.java
new file mode 100644
index 00000000..2a93642b
--- /dev/null
+++ b/utils/afl_untracer/ghidra_get_patchpoints.java
@@ -0,0 +1,84 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// Find patch points for untracer tools (e.g. afl++ utils/afl_untracer)
+//
+// Copy to ..../Ghidra/Features/Search/ghidra_scripts/
+// Writes the results to ~/Desktop/patches.txt
+//
+// This is my very first Ghidra script. I am sure this could be done better.
+//
+//@category Search
+
+import ghidra.app.script.GhidraScript;
+import ghidra.program.model.address.*;
+import ghidra.program.model.block.*;
+import ghidra.program.model.listing.*;
+import ghidra.program.model.symbol.*;
+import ghidra.program.model.mem.*;
+
+import java.io.*;
+
+public class ghidra_get_patchpoints extends GhidraScript {
+
+ @Override
+ public void run() throws Exception {
+
+ long segment_start = 0;
+ Memory memory = currentProgram.getMemory();
+ MultEntSubModel model = new MultEntSubModel(currentProgram);
+ CodeBlockIterator subIter = model.getCodeBlocks(monitor);
+ BufferedWriter out = new BufferedWriter(new FileWriter(System.getProperty("user.home") + File.separator + "Desktop" + File.separator + "patches.txt"));
+
+ while (subIter.hasNext()) {
+
+ CodeBlock multiEntryBlock = subIter.next();
+ SimpleBlockModel basicBlockModel = new SimpleBlockModel(currentProgram);
+ CodeBlockIterator bbIter = basicBlockModel.getCodeBlocksContaining(multiEntryBlock, monitor);
+
+ while (bbIter.hasNext()) {
+
+ CodeBlock basicBlock = bbIter.next();
+
+ if (segment_start == 0) {
+
+ Address firstAddr = basicBlock.getFirstStartAddress();
+ long firstBlockAddr = firstAddr.getAddressableWordOffset();
+ MemoryBlock mb = memory.getBlock(firstAddr);
+ Address startAddr = mb.getStart();
+ Address endAddr = mb.getEnd();
+ segment_start = startAddr.getAddressableWordOffset();
+ if ((firstBlockAddr - segment_start) >= 0x1000)
+ segment_start += 0x1000;
+ long segment_end = endAddr.getAddressableWordOffset();
+ long segment_size = segment_end - segment_start;
+ if ((segment_size % 0x1000) > 0)
+ segment_size = (((segment_size / 0x1000) + 1) * 0x1000);
+ out.write(currentProgram.getName() + ":0x" + Long.toHexString(segment_size) + "\n");
+ //println("Start: " + Long.toHexString(segment_start));
+ //println("End: " + Long.toHexString(segment_end));
+
+ }
+
+ if (basicBlock.getFirstStartAddress().getAddressableWordOffset() - segment_start > 0)
+ out.write("0x" + Long.toHexString(basicBlock.getFirstStartAddress().getAddressableWordOffset() - segment_start) + "\n");
+
+ }
+ }
+
+ out.close();
+
+ }
+}
diff --git a/utils/afl_untracer/ida_get_patchpoints.py b/utils/afl_untracer/ida_get_patchpoints.py
new file mode 100644
index 00000000..807685b3
--- /dev/null
+++ b/utils/afl_untracer/ida_get_patchpoints.py
@@ -0,0 +1,63 @@
+#
+# IDAPython script for IDA Pro
+# Slightly modified from https://github.com/googleprojectzero/p0tools/blob/master/TrapFuzz/findPatchPoints.py
+#
+
+import idautils
+import idaapi
+import ida_nalt
+import idc
+
+# See https://www.hex-rays.com/products/ida/support/ida74_idapython_no_bc695_porting_guide.shtml
+
+from os.path import expanduser
+
+home = expanduser("~")
+
+patchpoints = set()
+
+max_offset = 0
+for seg_ea in idautils.Segments():
+ name = idc.get_segm_name(seg_ea)
+ # print("Segment: " + name)
+ if name != "__text" and name != ".text":
+ continue
+
+ start = idc.get_segm_start(seg_ea)
+ end = idc.get_segm_end(seg_ea)
+ first = 0
+ subtract_addr = 0
+ # print("Start: " + hex(start) + " End: " + hex(end))
+ for func_ea in idautils.Functions(start, end):
+ f = idaapi.get_func(func_ea)
+ if not f:
+ continue
+ for block in idaapi.FlowChart(f):
+ if start <= block.start_ea < end:
+ if first == 0:
+ if block.start_ea >= 0x1000:
+ subtract_addr = 0x1000
+ first = 1
+
+ max_offset = max(max_offset, block.start_ea)
+ patchpoints.add(block.start_ea - subtract_addr)
+ # else:
+ # print("Warning: broken CFG?")
+
+# Round up max_offset to page size
+size = max_offset
+rem = size % 0x1000
+if rem != 0:
+ size += 0x1000 - rem
+
+print("Writing to " + home + "/Desktop/patches.txt")
+
+with open(home + "/Desktop/patches.txt", "w") as f:
+ f.write(ida_nalt.get_root_filename() + ":" + hex(size) + "\n")
+ f.write("\n".join(map(hex, sorted(patchpoints))))
+ f.write("\n")
+
+print("Done, found {} patchpoints".format(len(patchpoints)))
+
+# For headless script running remove the comment from the next line
+# ida_pro.qexit()
diff --git a/utils/afl_untracer/libtestinstr.c b/utils/afl_untracer/libtestinstr.c
new file mode 100644
index 00000000..a3f5acc8
--- /dev/null
+++ b/utils/afl_untracer/libtestinstr.c
@@ -0,0 +1,35 @@
+/*
+ american fuzzy lop++ - a trivial program to test the build
+ --------------------------------------------------------
+ Originally written by Michal Zalewski
+ Copyright 2014 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+ http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+void testinstr(char *buf, int len) {
+
+ if (len < 1) return;
+ buf[len] = 0;
+
+ // we support three input cases
+ if (buf[0] == '0')
+ printf("Looks like a zero to me!\n");
+ else if (buf[0] == '1')
+ printf("Pretty sure that is a one!\n");
+ else
+ printf("Neither one or zero? How quaint!\n");
+
+}
+
diff --git a/utils/afl_untracer/patches.txt b/utils/afl_untracer/patches.txt
new file mode 100644
index 00000000..7e964249
--- /dev/null
+++ b/utils/afl_untracer/patches.txt
@@ -0,0 +1,34 @@
+libtestinstr.so:0x1000
+0x10
+0x12
+0x20
+0x36
+0x30
+0x40
+0x50
+0x63
+0x6f
+0x78
+0x80
+0xa4
+0xb0
+0xb8
+0x100
+0xc0
+0xc9
+0xd7
+0xe3
+0xe8
+0xf8
+0x105
+0x11a
+0x135
+0x141
+0x143
+0x14e
+0x15a
+0x15c
+0x168
+0x16a
+0x16b
+0x170
diff --git a/utils/aflpp_driver/GNUmakefile b/utils/aflpp_driver/GNUmakefile
new file mode 100644
index 00000000..234a1c31
--- /dev/null
+++ b/utils/aflpp_driver/GNUmakefile
@@ -0,0 +1,52 @@
+ifeq "" "$(LLVM_CONFIG)"
+ LLVM_CONFIG=llvm-config
+endif
+
+ifeq "$(shell uname -s)" "Darwin"
+ # On some odd MacOS system configurations, the Xcode sdk path is not set correctly
+ SDK_LD = -L$(shell xcrun --show-sdk-path)/usr/lib
+ LDFLAGS += $(SDK_LD)
+endif
+
+LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null)
+ifneq "" "$(LLVM_BINDIR)"
+ LLVM_BINDIR := $(LLVM_BINDIR)/
+endif
+
+CFLAGS := -O3 -funroll-loops -g -fPIC
+
+all: libAFLDriver.a libAFLQemuDriver.a aflpp_qemu_driver_hook.so
+
+aflpp_driver.o: aflpp_driver.c
+ -$(LLVM_BINDIR)clang -I. -I../../include $(CFLAGS) -c aflpp_driver.c
+
+libAFLDriver.a: aflpp_driver.o
+ @ar rc 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
+ $(LLVM_BINDIR)clang -I../../include -D_DEBUG=\"1\" -g -funroll-loops -c aflpp_driver.c
+ #$(LLVM_BINDIR)clang -S -emit-llvm -Wno-deprecated -I../../include $(CFLAGS) -D_DEBUG=\"1\" -c -o afl-performance.ll ../../src/afl-performance.c
+ #$(LLVM_BINDIR)clang -S -emit-llvm -I../../include -D_DEBUG=\"1\" -g -funroll-loops -c aflpp_driver.c
+ ar rc libAFLDriver.a afl-performance.o aflpp_driver.o
+
+aflpp_qemu_driver.o: aflpp_qemu_driver.c
+ -$(LLVM_BINDIR)clang $(CFLAGS) -O0 -funroll-loops -c aflpp_qemu_driver.c
+
+libAFLQemuDriver.a: aflpp_qemu_driver.o
+ @-ar rc libAFLQemuDriver.a aflpp_qemu_driver.o
+ @-cp -vf libAFLQemuDriver.a ../../
+
+aflpp_qemu_driver_hook.so: aflpp_qemu_driver_hook.o
+ @-test -e aflpp_qemu_driver_hook.o && $(LLVM_BINDIR)clang $(LDFLAGS) -shared aflpp_qemu_driver_hook.o -o aflpp_qemu_driver_hook.so || echo "Note: Optional aflpp_qemu_driver_hook.so not built."
+
+aflpp_qemu_driver_hook.o: aflpp_qemu_driver_hook.c
+ @-test -e ../../qemu_mode/qemuafl/qemuafl/api.h && $(LLVM_BINDIR)clang $(CFLAGS) -funroll-loops -c aflpp_qemu_driver_hook.c || echo "Note: Optional aflpp_qemu_driver_hook.o not built."
+
+test: debug
+ #clang -S -emit-llvm -D_DEBUG=\"1\" -I../../include -Wl,--allow-multiple-definition -funroll-loops -o aflpp_driver_test.ll aflpp_driver_test.c
+ afl-clang-fast -D_DEBUG=\"1\" -I../../include -Wl,--allow-multiple-definition -funroll-loops -o aflpp_driver_test aflpp_driver_test.c libAFLDriver.a afl-performance.o
+
+clean:
+ rm -f *.o libAFLDriver*.a libAFLQemuDriver.a aflpp_qemu_driver_hook.so *~ core aflpp_driver_test
diff --git a/utils/aflpp_driver/Makefile b/utils/aflpp_driver/Makefile
new file mode 100644
index 00000000..3666a74d
--- /dev/null
+++ b/utils/aflpp_driver/Makefile
@@ -0,0 +1,2 @@
+all:
+ @gmake all || echo please install GNUmake
diff --git a/utils/aflpp_driver/README.md b/utils/aflpp_driver/README.md
new file mode 100644
index 00000000..c547aaea
--- /dev/null
+++ b/utils/aflpp_driver/README.md
@@ -0,0 +1,43 @@
+# AFL++ drivers
+
+## aflpp_driver
+
+aflpp_driver is used to compile directly libfuzzer `LLVMFuzzerTestOneInput()`
+targets.
+
+Just do `afl-clang-fast++ -o fuzz fuzzer_harness.cc libAFLDriver.a [plus
+required linking]`.
+
+You can also sneakily do this little trick: If this is the clang compile command
+to build for libfuzzer: `clang++ -o fuzz -fsanitize=fuzzer fuzzer_harness.cc
+-lfoo`, then just switch `clang++` with `afl-clang-fast++` and our compiler will
+magically insert libAFLDriver.a :)
+
+To use shared-memory test cases, you need nothing to do. To use stdin test
+cases, give `-` as the only command line parameter. To use file input test
+cases, give `@@` as the only command line parameter.
+
+IMPORTANT: if you use `afl-cmin` or `afl-cmin.bash`, then either pass `-` or
+`@@` as command line parameters.
+
+## aflpp_qemu_driver
+
+Note that you can use the driver too for FRIDA mode (`-O`).
+
+aflpp_qemu_driver is used for libfuzzer `LLVMFuzzerTestOneInput()` targets that
+are to be fuzzed in QEMU mode. So compile them with clang/clang++, without
+-fsantize=fuzzer or afl-clang-fast, and link in libAFLQemuDriver.a:
+
+`clang++ -o fuzz fuzzer_harness.cc libAFLQemuDriver.a [plus required linking]`.
+
+Then just do (where the name of the binary is `fuzz`):
+
+```
+AFL_QEMU_PERSISTENT_ADDR=0x$(nm fuzz | grep "T LLVMFuzzerTestOneInput" | awk '{print $1}')
+AFL_QEMU_PERSISTENT_HOOK=/path/to/aflpp_qemu_driver_hook.so afl-fuzz -Q ... -- ./fuzz`
+```
+
+if you use afl-cmin or `afl-showmap -C` with the aflpp_qemu_driver you need to
+set the set same AFL_QEMU_... (or AFL_FRIDA_...) environment variables. If you
+want to use afl-showmap (without -C) or afl-cmin.bash, then you may not set
+these environment variables and rather set `AFL_QEMU_DRIVER_NO_HOOK=1`. \ No newline at end of file
diff --git a/utils/aflpp_driver/aflpp_driver.c b/utils/aflpp_driver/aflpp_driver.c
new file mode 100644
index 00000000..7289c845
--- /dev/null
+++ b/utils/aflpp_driver/aflpp_driver.c
@@ -0,0 +1,374 @@
+//===- afl_driver.cpp - a glue between AFL++ and libFuzzer ------*- C++ -* ===//
+//===----------------------------------------------------------------------===//
+
+/* This file allows to fuzz libFuzzer-style target functions
+ (LLVMFuzzerTestOneInput) with AFL++ using persistent in-memory fuzzing.
+
+Usage:
+################################################################################
+cat << EOF > test_fuzzer.cc
+#include <stddef.h>
+#include <stdint.h>
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+
+ if (size > 0 && data[0] == 'H')
+ if (size > 1 && data[1] == 'I')
+ if (size > 2 && data[2] == '!')
+ __builtin_trap();
+ return 0;
+
+}
+
+EOF
+# Build your target with -fsanitize-coverage=trace-pc-guard using fresh clang.
+clang -c aflpp_driver.c
+# Build afl-compiler-rt.o.c from the AFL distribution.
+clang -c $AFL_HOME/instrumentation/afl-compiler-rt.o.c
+# Build this file, link it with afl-compiler-rt.o.o and the target code.
+afl-clang-fast -o test_fuzzer test_fuzzer.cc afl-compiler-rt.o aflpp_driver.o
+# Run AFL:
+rm -rf IN OUT; mkdir IN OUT; echo z > IN/z;
+$AFL_HOME/afl-fuzz -i IN -o OUT ./a.out
+################################################################################
+*/
+
+#include <assert.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#ifndef __HAIKU__
+ #include <sys/syscall.h>
+#endif
+
+#include "config.h"
+#include "types.h"
+#include "cmplog.h"
+
+#ifdef _DEBUG
+ #include "hash.h"
+#endif
+
+int __afl_sharedmem_fuzzing = 1;
+extern unsigned int * __afl_fuzz_len;
+extern unsigned char *__afl_fuzz_ptr;
+
+// libFuzzer interface is thin, so we don't include any libFuzzer headers.
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
+__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
+
+// Default nop ASan hooks for manual posisoning when not linking the ASan
+// runtime
+// https://github.com/google/sanitizers/wiki/AddressSanitizerManualPoisoning
+__attribute__((weak)) void __asan_poison_memory_region(
+ void const volatile *addr, size_t size) {
+
+ (void)addr;
+ (void)size;
+
+}
+
+__attribute__((weak)) void __asan_unpoison_memory_region(
+ void const volatile *addr, size_t size) {
+
+ (void)addr;
+ (void)size;
+
+}
+
+__attribute__((weak)) void *__asan_region_is_poisoned(void *beg, size_t size);
+
+// Notify AFL about persistent mode.
+static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##";
+int __afl_persistent_loop(unsigned int);
+
+// Notify AFL about deferred forkserver.
+static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##";
+void __afl_manual_init();
+
+// Use this optionally defined function to output sanitizer messages even if
+// user asks to close stderr.
+__attribute__((weak)) void __sanitizer_set_report_fd(void *);
+
+// Keep track of where stderr content is being written to, so that
+// dup_and_close_stderr can use the correct one.
+static FILE *output_file;
+
+// Experimental feature to use afl_driver without AFL's deferred mode.
+// Needs to run before __afl_auto_init.
+__attribute__((constructor(0))) static void __decide_deferred_forkserver(void) {
+
+ if (getenv("AFL_DRIVER_DONT_DEFER")) {
+
+ if (unsetenv("__AFL_DEFER_FORKSRV")) {
+
+ perror("Failed to unset __AFL_DEFER_FORKSRV");
+ abort();
+
+ }
+
+ }
+
+}
+
+// If the user asks us to duplicate stderr, then do it.
+static void maybe_duplicate_stderr() {
+
+ char *stderr_duplicate_filename =
+ getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
+
+ if (!stderr_duplicate_filename) return;
+
+ FILE *stderr_duplicate_stream =
+ freopen(stderr_duplicate_filename, "a+", stderr);
+
+ if (!stderr_duplicate_stream) {
+
+ fprintf(
+ stderr,
+ "Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
+ abort();
+
+ }
+
+ output_file = stderr_duplicate_stream;
+
+}
+
+// Most of these I/O functions were inspired by/copied from libFuzzer's code.
+static void discard_output(int fd) {
+
+ FILE *temp = fopen("/dev/null", "w");
+ if (!temp) abort();
+ dup2(fileno(temp), fd);
+ fclose(temp);
+
+}
+
+static void close_stdout() {
+
+ discard_output(STDOUT_FILENO);
+
+}
+
+// Prevent the targeted code from writing to "stderr" but allow sanitizers and
+// this driver to do so.
+static void dup_and_close_stderr() {
+
+ int output_fileno = fileno(output_file);
+ int output_fd = dup(output_fileno);
+ if (output_fd <= 0) abort();
+ FILE *new_output_file = fdopen(output_fd, "w");
+ if (!new_output_file) abort();
+ if (!__sanitizer_set_report_fd) return;
+ __sanitizer_set_report_fd((void *)(long int)output_fd);
+ discard_output(output_fileno);
+
+}
+
+// Close stdout and/or stderr if user asks for it.
+static void maybe_close_fd_mask() {
+
+ char *fd_mask_str = getenv("AFL_DRIVER_CLOSE_FD_MASK");
+ if (!fd_mask_str) return;
+ int fd_mask = atoi(fd_mask_str);
+ if (fd_mask & 2) dup_and_close_stderr();
+ if (fd_mask & 1) close_stdout();
+
+}
+
+// Define LLVMFuzzerMutate to avoid link failures for targets that use it
+// with libFuzzer's LLVMFuzzerCustomMutator.
+size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
+
+ // assert(false && "LLVMFuzzerMutate should not be called from afl_driver");
+ return 0;
+
+}
+
+// Execute any files provided as parameters.
+static int ExecuteFilesOnyByOne(int argc, char **argv) {
+
+ unsigned char *buf = (unsigned char *)malloc(MAX_FILE);
+
+ __asan_poison_memory_region(buf, MAX_FILE);
+ ssize_t prev_length = 0;
+
+ for (int i = 1; i < argc; i++) {
+
+ int fd = 0;
+
+ if (strcmp(argv[i], "-") != 0) { fd = open(argv[i], O_RDONLY); }
+
+ if (fd == -1) { continue; }
+
+#ifndef __HAIKU__
+ ssize_t length = syscall(SYS_read, fd, buf, MAX_FILE);
+#else
+ ssize_t length = _kern_read(fd, buf, MAX_FILE);
+#endif // HAIKU
+
+ if (length > 0) {
+
+ if (length < prev_length) {
+
+ __asan_poison_memory_region(buf + length, prev_length - length);
+
+ } else {
+
+ __asan_unpoison_memory_region(buf + prev_length, length - prev_length);
+
+ }
+
+ prev_length = length;
+
+ printf("Reading %zu bytes from %s\n", length, argv[i]);
+ LLVMFuzzerTestOneInput(buf, length);
+ printf("Execution successful.\n");
+
+ }
+
+ if (fd > 0) { close(fd); }
+
+ }
+
+ free(buf);
+ return 0;
+
+}
+
+int main(int argc, char **argv) {
+
+ if (argc < 2 || strncmp(argv[1], "-h", 2) == 0)
+ printf(
+ "============================== INFO ================================\n"
+ "This binary is built for afl++.\n"
+ "To run the target function on individual input(s) execute:\n"
+ " %s INPUT_FILE1 [INPUT_FILE2 ... ]\n"
+ "To fuzz with afl-fuzz execute:\n"
+ " afl-fuzz [afl-flags] -- %s [-N]\n"
+ "afl-fuzz will run N iterations before re-spawning the process "
+ "(default: "
+ "INT_MAX)\n"
+ "For stdin input processing, pass '-' as single command line option.\n"
+ "For file input processing, pass '@@' as single command line option.\n"
+ "To use with afl-cmin or afl-cmin.bash pass '-' as single command line "
+ "option\n"
+ "===================================================================\n",
+ argv[0], argv[0]);
+
+ if (getenv("AFL_GDB")) {
+
+ char cmd[64];
+ snprintf(cmd, sizeof(cmd), "cat /proc/%d/maps", getpid());
+ system(cmd);
+ fprintf(stderr, "DEBUG: aflpp_driver pid is %d\n", getpid());
+ sleep(1);
+
+ }
+
+ output_file = stderr;
+ maybe_duplicate_stderr();
+ maybe_close_fd_mask();
+ if (LLVMFuzzerInitialize) {
+
+ fprintf(stderr, "Running LLVMFuzzerInitialize ...\n");
+ LLVMFuzzerInitialize(&argc, &argv);
+ fprintf(stderr, "continue...\n");
+
+ }
+
+ // Do any other expensive one-time initialization here.
+
+ uint8_t dummy_input[64] = {0};
+ memcpy(dummy_input, (void *)AFL_PERSISTENT, sizeof(AFL_PERSISTENT));
+ memcpy(dummy_input + 32, (void *)AFL_DEFER_FORKSVR,
+ sizeof(AFL_DEFER_FORKSVR));
+
+ int N = INT_MAX;
+
+ if (argc == 2 && !strcmp(argv[1], "-")) {
+
+ __afl_sharedmem_fuzzing = 0;
+ __afl_manual_init();
+ return ExecuteFilesOnyByOne(argc, argv);
+
+ } else if (argc == 2 && argv[1][0] == '-') {
+
+ N = atoi(argv[1] + 1);
+
+ } else if (argc == 2 && (N = atoi(argv[1])) > 0) {
+
+ printf("WARNING: using the deprecated call style `%s %d`\n", argv[0], N);
+
+ } else if (argc > 1) {
+
+ __afl_sharedmem_fuzzing = 0;
+
+ if (argc == 2) { __afl_manual_init(); }
+
+ return ExecuteFilesOnyByOne(argc, argv);
+
+ }
+
+ assert(N > 0);
+
+ __afl_manual_init();
+
+ // Call LLVMFuzzerTestOneInput here so that coverage caused by initialization
+ // on the first execution of LLVMFuzzerTestOneInput is ignored.
+ LLVMFuzzerTestOneInput(dummy_input, 4);
+
+ __asan_poison_memory_region(__afl_fuzz_ptr, MAX_FILE);
+ size_t prev_length = 0;
+
+ // for speed only insert asan functions if the target is linked with asan
+ if (__asan_region_is_poisoned) {
+
+ while (__afl_persistent_loop(N)) {
+
+ size_t length = *__afl_fuzz_len;
+
+ if (likely(length)) {
+
+ if (length < prev_length) {
+
+ __asan_poison_memory_region(__afl_fuzz_ptr + length,
+ prev_length - length);
+
+ } else if (length > prev_length) {
+
+ __asan_unpoison_memory_region(__afl_fuzz_ptr + prev_length,
+ length - prev_length);
+
+ }
+
+ prev_length = length;
+ LLVMFuzzerTestOneInput(__afl_fuzz_ptr, length);
+
+ }
+
+ }
+
+ } else {
+
+ while (__afl_persistent_loop(N)) {
+
+ LLVMFuzzerTestOneInput(__afl_fuzz_ptr, *__afl_fuzz_len);
+
+ }
+
+ }
+
+ return 0;
+
+}
+
diff --git a/utils/aflpp_driver/aflpp_driver_test.c b/utils/aflpp_driver/aflpp_driver_test.c
new file mode 100644
index 00000000..527ba57b
--- /dev/null
+++ b/utils/aflpp_driver/aflpp_driver_test.c
@@ -0,0 +1,24 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+void __attribute__((noinline)) crashme(const uint8_t *Data, size_t Size) {
+
+ if (Size < 5) return;
+
+ 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) {
+
+ if (Size) crashme(Data, Size);
+
+ return 0;
+
+}
+
diff --git a/utils/aflpp_driver/aflpp_qemu_driver.c b/utils/aflpp_driver/aflpp_qemu_driver.c
new file mode 100644
index 00000000..e47df1e6
--- /dev/null
+++ b/utils/aflpp_driver/aflpp_qemu_driver.c
@@ -0,0 +1,42 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+// libFuzzer interface is thin, so we don't include any libFuzzer headers.
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
+__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
+
+#define kMaxAflInputSize (1 * 1024 * 1024)
+static uint8_t AflInputBuf[kMaxAflInputSize];
+
+void __attribute__((noinline)) afl_qemu_driver_stdin_input(void) {
+
+ size_t l = read(0, AflInputBuf, kMaxAflInputSize);
+ LLVMFuzzerTestOneInput(AflInputBuf, l);
+
+}
+
+int main(int argc, char **argv) {
+
+ if (LLVMFuzzerInitialize) LLVMFuzzerInitialize(&argc, &argv);
+ // Do any other expensive one-time initialization here.
+
+ if (getenv("AFL_QEMU_DRIVER_NO_HOOK") || getenv("AFL_FRIDA_DRIVER_NO_HOOK")) {
+
+ afl_qemu_driver_stdin_input();
+
+ } else {
+
+ fprintf(stderr,
+ "Using shared-memory testcases. To read via stdin, set "
+ "AFL_QEMU_DRIVER_NO_HOOK=1.\n");
+ uint8_t dummy_input[1024000] = {0};
+ LLVMFuzzerTestOneInput(dummy_input, 1);
+
+ }
+
+ return 0;
+
+}
+
diff --git a/utils/aflpp_driver/aflpp_qemu_driver_hook.c b/utils/aflpp_driver/aflpp_qemu_driver_hook.c
new file mode 100644
index 00000000..2979fadc
--- /dev/null
+++ b/utils/aflpp_driver/aflpp_qemu_driver_hook.c
@@ -0,0 +1,31 @@
+#include "../../qemu_mode/qemuafl/qemuafl/api.h"
+
+#include <stdint.h>
+#include <string.h>
+
+#define g2h(x) ((void *)((unsigned long)(x) + guest_base))
+#define h2g(x) ((uint64_t)(x)-guest_base)
+
+void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base,
+ uint8_t *input_buf, uint32_t input_buf_len) {
+
+ // In this example the register RDI is pointing to the memory location
+ // of the target buffer, and the length of the input is in RSI.
+ // This can be seen with a debugger, e.g. gdb (and "disass main")
+
+ memcpy(g2h(regs->rdi), input_buf, input_buf_len);
+ regs->rsi = input_buf_len;
+
+}
+
+#undef g2h
+#undef h2g
+
+int afl_persistent_hook_init(void) {
+
+ // 1 for shared memory input (faster), 0 for normal input (you have to use
+ // read(), input_buf will be NULL)
+ return 1;
+
+}
+
diff --git a/utils/analysis_scripts/queue2csv.sh b/utils/analysis_scripts/queue2csv.sh
new file mode 100755
index 00000000..2528b438
--- /dev/null
+++ b/utils/analysis_scripts/queue2csv.sh
@@ -0,0 +1,122 @@
+#!/bin/bash
+
+test -z "$1" -o -z "$2" -o "$1" = "-h" -o "$1" = "-hh" -o "$1" = "--help" -o '!' -d "$1" && {
+ echo "Syntax: [-n] $0 out-directory file.csv [\"tools/target --opt @@\"]"
+ echo Option -n will suppress the CSV header.
+ echo If the target execution command is supplied then also edge coverage is gathered.
+ exit 1
+}
+
+function getval() {
+ VAL=""
+ if [ "$file" != "${file/$1/}" ]; then
+ TMP="${file/*$1:/}"
+ VAL="${TMP/,*/}"
+ fi
+}
+
+SKIP=
+if [ "$1" = "-n" ]; then
+ SKIP=1
+ shift
+fi
+
+test -n "$4" && { echo "Error: too many commandline options. Target command and options including @@ have to be passed within \"\"!"; exit 1; }
+
+test -d "$1"/queue && OUT="$1/queue" || OUT="$1"
+
+OK=`ls $OUT/id:000000,time:0,orig:* 2> /dev/null`
+if [ -n "$OK" ]; then
+ LISTCMD="ls $OUT/id:"*
+else
+ LISTCMD="ls -tr $OUT/"
+fi
+
+ID=;SRC=;TIME=;OP=;POS=;REP=;EDGES=;EDGES_TOTAL=;
+DIR="$OUT/../stats"
+rm -rf "$DIR"
+> "$2" || exit 1
+mkdir "$DIR" || exit 1
+> "$DIR/../edges.txt" || exit 1
+
+{
+
+ if [ -z "$SKIP" ]; then
+ echo "time;\"filename\";id;src;new_cov;edges;total_edges;\"op\";pos;rep;unique_edges"
+ fi
+
+ $LISTCMD | grep -v ,sync: | sed 's/.*id:/id:/g' | while read file; do
+
+ if [ -n "$3" ]; then
+
+ TMP=${3/@@/$OUT/$file}
+
+ if [ "$TMP" = "$3" ]; then
+
+ cat "$OUT/$file" | afl-showmap -o "$DIR/$file" -q -- $3 >/dev/null 2>&1
+
+ else
+
+ afl-showmap -o "$DIR/$file" -q -- $TMP >/dev/null 2>&1
+
+ fi
+
+ { cat "$DIR/$file" | sed 's/:.*//' ; cat "$DIR/../edges.txt" ; } | sort -nu > $DIR/../edges.txt.tmp
+ mv $DIR/../edges.txt.tmp $DIR/../edges.txt
+ EDGES=$(cat "$DIR/$file" | wc -l)
+ EDGES_TOTAL=$(cat "$DIR/../edges.txt" | wc -l)
+
+ fi
+
+ getval id; ID="$VAL"
+ getval src; SRC="$VAL"
+ getval time; TIME="$VAL"
+ getval op; OP="$VAL"
+ getval pos; POS="$VAL"
+ getval rep; REP="$VAL"
+ if [ "$file" != "${file/+cov/}" ]; then
+ COV=1
+ else
+ COV=""
+ fi
+
+ if [ -n "$3" -a -s "$DIR/../edges.txt" ]; then
+ echo "$TIME;\"$file\";$ID;$SRC;$COV;$EDGES;$EDGES_TOTAL;\"$OP\";$POS;$REP;UNIQUE$file"
+ else
+ echo "$TIME;\"$file\";$ID;$SRC;$COV;;;\"$OP\";$POS;$REP;"
+ fi
+
+ done
+
+} | tee "$DIR/../queue.csv" > "$2" || exit 1
+
+if [ -n "$3" -a -s "$DIR/../edges.txt" ]; then
+
+ cat "$DIR/"* | sed 's/:.*//' | sort -n | uniq -c | egrep '^[ \t]*1 ' | awk '{print$2}' > $DIR/../unique.txt
+
+ if [ -s "$DIR/../unique.txt" ]; then
+
+ ls "$DIR/id:"* | grep -v ",sync:" |sed 's/.*\/id:/id:/g' | while read file; do
+
+ CNT=$(sed 's/:.*//' "$DIR/$file" | tee "$DIR/../tmp.txt" | wc -l)
+ DIFF=$(diff -u "$DIR/../tmp.txt" "$DIR/../unique.txt" | egrep '^-[0-9]' | wc -l)
+ UNIQUE=$(($CNT - $DIFF))
+ sed -i "s/;UNIQUE$file/;$UNIQUE/" "$DIR/../queue.csv" "$2"
+
+ done
+
+ rm -f "$DIR/../tmp.txt"
+
+ else
+
+ sed -i 's/;UNIQUE.*/;/' "$DIR/../queue.csv" "$2"
+
+ fi
+
+fi
+
+mv "$DIR/../queue.csv" "$DIR/queue.csv"
+if [ -e "$DIR/../edges.txt" ]; then mv "$DIR/../edges.txt" "$DIR/edges.txt"; fi
+if [ -e "$DIR/../unique.txt" ]; then mv "$DIR/../unique.txt" "$DIR/unique.txt"; fi
+
+echo "Created $2"
diff --git a/utils/argv_fuzzing/Makefile b/utils/argv_fuzzing/Makefile
new file mode 100644
index 00000000..183f6bf8
--- /dev/null
+++ b/utils/argv_fuzzing/Makefile
@@ -0,0 +1,58 @@
+#
+# american fuzzy lop++ - argvfuzz
+# --------------------------------
+#
+# Copyright 2019-2022 Kjell Braden <afflux@pentabarf.de>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+
+.PHONY: all install clean
+
+PREFIX ?= /usr/local
+BIN_PATH = $(PREFIX)/bin
+HELPER_PATH = $(PREFIX)/lib/afl
+
+CFLAGS = -fPIC -Wall -Wextra
+LDFLAGS = -shared
+
+UNAME_SAYS_LINUX=$(shell uname | grep -E '^Linux|^GNU' >/dev/null; echo $$?)
+UNAME_SAYS_LINUX:sh=uname | grep -E '^Linux|^GNU' >/dev/null; echo $$?
+
+_LDFLAGS_ADD=$(UNAME_SAYS_LINUX:1=)
+LDFLAGS_ADD=$(_LDFLAGS_ADD:0=-ldl)
+LDFLAGS += $(LDFLAGS_ADD)
+
+# on gcc for arm there is no -m32, but -mbe32
+M32FLAG = -m32
+M64FLAG = -m64
+
+CC_IS_GCC=$(shell $(CC) --version 2>/dev/null | grep -q gcc; echo $$?)
+CC_IS_GCC:sh=$(CC) --version 2>/dev/null | grep -q gcc; echo $$?
+CC_IS_ARMCOMPILER=$(shell $(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?)
+CC_IS_ARMCOMPILER:sh=$(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?
+
+_M32FLAG=$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)
+__M32FLAG=$(_M32FLAG:00=-mbe32)
+___M32FLAG=$(__M32FLAG:$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)=-m32)
+M32FLAG=$(___M32FLAG)
+
+all: argvfuzz32.so argvfuzz64.so
+
+argvfuzz32.so: argvfuzz.c
+ -@$(CC) $(M32FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "argvfuzz32 build failure (that's fine)"
+
+argvfuzz64.so: argvfuzz.c
+ -@$(CC) $(M64FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "argvfuzz64 build failure (that's fine)"
+
+install: argvfuzz32.so argvfuzz64.so
+ install -d -m 755 $(DESTDIR)$(HELPER_PATH)/
+ if [ -f argvfuzz32.so ]; then set -e; install -m 755 argvfuzz32.so $(DESTDIR)$(HELPER_PATH)/; fi
+ if [ -f argvfuzz64.so ]; then set -e; install -m 755 argvfuzz64.so $(DESTDIR)$(HELPER_PATH)/; fi
+
+clean:
+ rm -f argvfuzz32.so argvfuzz64.so
diff --git a/utils/argv_fuzzing/README.md b/utils/argv_fuzzing/README.md
new file mode 100644
index 00000000..e9224995
--- /dev/null
+++ b/utils/argv_fuzzing/README.md
@@ -0,0 +1,16 @@
+# argvfuzz
+
+AFL++ supports fuzzing file inputs or stdin. When source is available,
+`argv-fuzz-inl.h` can be used to change `main()` to build argv from stdin.
+
+`argvfuzz` tries to provide the same functionality for binaries. When loaded
+using `LD_PRELOAD`, it will hook the call to `__libc_start_main` and replace
+argv using the same logic of `argv-fuzz-inl.h`.
+
+A few conditions need to be fulfilled for this mechanism to work correctly:
+
+1. As it relies on hooking the loader, it cannot work on static binaries.
+2. If the target binary does not use the default libc's `_start` implementation
+ (crt1.o), the hook may not run.
+3. The hook will replace argv with pointers to `.data` of `argvfuzz.so`. If the
+ target binary expects argv to be living on the stack, things may go wrong. \ No newline at end of file
diff --git a/utils/argv_fuzzing/argv-fuzz-inl.h b/utils/argv_fuzzing/argv-fuzz-inl.h
new file mode 100644
index 00000000..c15c0271
--- /dev/null
+++ b/utils/argv_fuzzing/argv-fuzz-inl.h
@@ -0,0 +1,90 @@
+/*
+ american fuzzy lop++ - sample argv fuzzing wrapper
+ ------------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Copyright 2015 Google Inc. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ This file shows a simple way to fuzz command-line parameters with stock
+ afl-fuzz. To use, add:
+
+ #include "/path/to/argv-fuzz-inl.h"
+
+ ...to the file containing main(), ideally placing it after all the
+ standard includes. Next, put AFL_INIT_ARGV(); near the very beginning of
+ main().
+
+ This will cause the program to read NUL-delimited input from stdin and
+ put it in argv[]. Two subsequent NULs terminate the array. Empty
+ params are encoded as a lone 0x02. Lone 0x02 can't be generated, but
+ that shouldn't matter in real life.
+
+ If you would like to always preserve argv[0], use this instead:
+ AFL_INIT_SET0("prog_name");
+
+*/
+
+#ifndef _HAVE_ARGV_FUZZ_INL
+#define _HAVE_ARGV_FUZZ_INL
+
+#include <unistd.h>
+
+#define AFL_INIT_ARGV() \
+ do { \
+ \
+ argv = afl_init_argv(&argc); \
+ \
+ } while (0)
+
+#define AFL_INIT_SET0(_p) \
+ do { \
+ \
+ argv = afl_init_argv(&argc); \
+ argv[0] = (_p); \
+ if (!argc) argc = 1; \
+ \
+ } while (0)
+
+#define MAX_CMDLINE_LEN 100000
+#define MAX_CMDLINE_PAR 50000
+
+static char **afl_init_argv(int *argc) {
+
+ static char in_buf[MAX_CMDLINE_LEN];
+ static char *ret[MAX_CMDLINE_PAR];
+
+ char *ptr = in_buf;
+ int rc = 0;
+
+ if (read(0, in_buf, MAX_CMDLINE_LEN - 2) < 0) {}
+
+ while (*ptr && rc < MAX_CMDLINE_PAR) {
+
+ ret[rc] = ptr;
+ if (ret[rc][0] == 0x02 && !ret[rc][1]) ret[rc]++;
+ rc++;
+
+ while (*ptr)
+ ptr++;
+ ptr++;
+
+ }
+
+ *argc = rc;
+
+ return ret;
+
+}
+
+#undef MAX_CMDLINE_LEN
+#undef MAX_CMDLINE_PAR
+
+#endif /* !_HAVE_ARGV_FUZZ_INL */
+
diff --git a/utils/argv_fuzzing/argvfuzz.c b/utils/argv_fuzzing/argvfuzz.c
new file mode 100644
index 00000000..e7cc6b72
--- /dev/null
+++ b/utils/argv_fuzzing/argvfuzz.c
@@ -0,0 +1,49 @@
+/*
+ american fuzzy lop++ - LD_PRELOAD for fuzzing argv in binaries
+ ------------------------------------------------------------
+
+ Copyright 2019-2022 Kjell Braden <afflux@pentabarf.de>
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ */
+
+#define _GNU_SOURCE /* for RTLD_NEXT */
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "argv-fuzz-inl.h"
+
+int __libc_start_main(int (*main)(int, char **, char **), int argc, char **argv,
+ void (*init)(void), void (*fini)(void),
+ void (*rtld_fini)(void), void *stack_end) {
+
+ int (*orig)(int (*main)(int, char **, char **), int argc, char **argv,
+ void (*init)(void), void (*fini)(void), void (*rtld_fini)(void),
+ void *stack_end);
+ int sub_argc;
+ char **sub_argv;
+
+ (void)argc;
+ (void)argv;
+
+ orig = dlsym(RTLD_NEXT, __func__);
+
+ if (!orig) {
+
+ fprintf(stderr, "hook did not find original %s: %s\n", __func__, dlerror());
+ exit(EXIT_FAILURE);
+
+ }
+
+ sub_argv = afl_init_argv(&sub_argc);
+
+ return orig(main, sub_argc, sub_argv, init, fini, rtld_fini, stack_end);
+
+}
+
diff --git a/utils/asan_cgroups/limit_memory.sh b/utils/asan_cgroups/limit_memory.sh
new file mode 100755
index 00000000..1f0f04ad
--- /dev/null
+++ b/utils/asan_cgroups/limit_memory.sh
@@ -0,0 +1,157 @@
+#!/usr/bin/env bash
+#
+# american fuzzy lop++ - limit memory using cgroups
+# -----------------------------------------------
+#
+# Written by Samir Khakimov <samir.hakim@nyu.edu> and
+# David A. Wheeler <dwheeler@ida.org>
+#
+# Edits to bring the script in line with afl-cmin and other companion scripts
+# by Michal Zalewski. All bugs are my fault.
+#
+# Copyright 2015 Institute for Defense Analyses.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# This tool allows the amount of actual memory allocated to a program
+# to be limited on Linux systems using cgroups, instead of the traditional
+# setrlimit() API. This helps avoid the address space problems discussed in
+# docs/notes_for_asan.md.
+#
+# Important: the limit covers *both* afl-fuzz and the fuzzed binary. In some
+# hopefully rare circumstances, afl-fuzz could be killed before the fuzzed
+# task.
+#
+
+echo "cgroup tool for afl-fuzz by <samir.hakim@nyu.edu> and <dwheeler@ida.org>"
+echo
+
+unset NEW_USER
+MEM_LIMIT="50"
+
+while getopts "+u:m:" opt; do
+
+ case "$opt" in
+
+ "u")
+ NEW_USER="$OPTARG"
+ ;;
+
+ "m")
+ MEM_LIMIT="$[OPTARG]"
+ ;;
+
+ "?")
+ exit 1
+ ;;
+
+ esac
+
+done
+
+if [ "$MEM_LIMIT" -lt "5" ]; then
+ echo "[-] Error: malformed or dangerously low value of -m." 1>&2
+ exit 1
+fi
+
+shift $((OPTIND-1))
+
+TARGET_BIN="$1"
+
+if [ "$TARGET_BIN" = "" -o "$NEW_USER" = "" ]; then
+
+ cat 1>&2 <<_EOF_
+Usage: $0 [ options ] -- /path/to/afl-fuzz [ ...afl options... ]
+
+Required parameters:
+
+ -u user - run the fuzzer as a specific user after setting up limits
+
+Optional parameters:
+
+ -m megs - set memory limit to a specified value ($MEM_LIMIT MB)
+
+This tool configures cgroups-based memory limits for a fuzzing job to simplify
+the task of fuzzing ASAN or MSAN binaries. You would normally want to use it in
+conjunction with '-m none' passed to the afl-fuzz binary itself, say:
+
+ $0 -u joe ./afl-fuzz -i input -o output -m none /path/to/target
+
+_EOF_
+
+ exit 1
+
+fi
+
+# Basic sanity checks
+
+if [ ! "`uname -s`" = "Linux" ]; then
+ echo "[-] Error: this tool does not support non-Linux systems." 1>&2
+ exit 1
+fi
+
+if [ ! "`id -u`" = "0" ]; then
+ echo "[-] Error: you need to run this script as root (sorry!)." 1>&2
+ exit 1
+fi
+
+if ! type cgcreate 2>/dev/null 1>&2; then
+
+ echo "[-] Error: you need to install cgroup tools first." 1>&2
+
+ if type apt-get 2>/dev/null 1>&2; then
+ echo " (Perhaps 'apt-get install cgroup-bin' will work.)" 1>&2
+ elif type yum 2>/dev/null 1>&2; then
+ echo " (Perhaps 'yum install libcgroup-tools' will work.)" 1>&2
+ fi
+
+ exit 1
+
+fi
+
+if ! id -u "$NEW_USER" 2>/dev/null 1>&2; then
+ echo "[-] Error: user '$NEW_USER' does not seem to exist." 1>&2
+ exit 1
+fi
+
+# Create a new cgroup path if necessary... We used PID-keyed groups to keep
+# parallel afl-fuzz tasks separate from each other.
+
+CID="afl-$NEW_USER-$$"
+
+CPATH="/sys/fs/cgroup/memory/$CID"
+
+if [ ! -d "$CPATH" ]; then
+
+ cgcreate -a "$NEW_USER" -g memory:"$CID" || exit 1
+
+fi
+
+# Set the appropriate limit...
+
+if [ -f "$CPATH/memory.memsw.limit_in_bytes" ]; then
+
+ echo "${MEM_LIMIT}M" > "$CPATH/memory.limit_in_bytes" 2>/dev/null
+ echo "${MEM_LIMIT}M" > "$CPATH/memory.memsw.limit_in_bytes" || exit 1
+ echo "${MEM_LIMIT}M" > "$CPATH/memory.limit_in_bytes" || exit 1
+
+elif grep -qE 'partition|file' /proc/swaps; then
+
+ echo "[-] Error: your system requires swap to be disabled first (swapoff -a)." 1>&2
+ exit 1
+
+else
+
+ echo "${MEM_LIMIT}M" > "$CPATH/memory.limit_in_bytes" || exit 1
+
+fi
+
+# All right. At this point, we can just run the command.
+
+cgexec -g "memory:$CID" su -c "$*" "$NEW_USER"
+
+cgdelete -g "memory:$CID"
diff --git a/utils/bash_shellshock/shellshock-fuzz.diff b/utils/bash_shellshock/shellshock-fuzz.diff
new file mode 100644
index 00000000..3fa05bf8
--- /dev/null
+++ b/utils/bash_shellshock/shellshock-fuzz.diff
@@ -0,0 +1,59 @@
+This patch shows a very simple way to find post-Shellshock bugs in bash, as
+discussed here:
+
+ http://lcamtuf.blogspot.com/2014/10/bash-bug-how-we-finally-cracked.html
+
+In essence, it shows a way to fuzz environmental variables. Instructions:
+
+1) Download bash 4.3, apply this patch, compile with:
+
+ CC=/path/to/afl-gcc ./configure
+ make clean all
+
+ Note that the harness puts the fuzzed output in $TEST_VARIABLE. With
+ Florian's Shellshock patch (bash43-028), this is no longer passed down
+ to the parser.
+
+2) Create and cd to an empty directory, put the compiled bash binary in
+ there, and run these commands:
+
+ mkdir in_dir
+ echo -n '() { a() { a; }; : >b; }' >in_dir/script.txt
+
+3) Run the fuzzer with:
+
+ /path/to/afl-fuzz -d -i in_dir -o out_dir ./bash -c :
+
+ The -d parameter is advisable only if the tested shell is fairly slow
+ or if you are in a hurry; will cover more ground faster, but
+ less systematically.
+
+4) Watch for crashes in out_dir/crashes/. Also watch for any new files
+ created in cwd if you're interested in non-crash RCEs (files will be
+ created whenever the shell executes "foo>bar" or something like
+ that). You can correlate their creation date with new entries in
+ out_dir/queue/.
+
+ You can also modify the bash binary to directly check for more subtle
+ fault conditions, or use the synthesized entries in out_dir/queue/
+ as a seed for other, possibly slower or more involved testing regimes.
+
+ Expect several hours to get decent coverage.
+
+--- bash-4.3/shell.c.orig 2014-01-14 14:04:32.000000000 +0100
++++ bash-4.3/shell.c 2015-04-30 05:56:46.000000000 +0200
+@@ -371,6 +371,14 @@
+ env = environ;
+ #endif /* __OPENNT */
+
++ {
++
++ static char val[1024 * 16];
++ read(0, val, sizeof(val) - 1);
++ setenv("TEST_VARIABLE", val, 1);
++
++ }
++
+ USE_VAR(argc);
+ USE_VAR(argv);
+ USE_VAR(env);
diff --git a/utils/canvas_harness/canvas_harness.html b/utils/canvas_harness/canvas_harness.html
new file mode 100644
index 00000000..a37b6937
--- /dev/null
+++ b/utils/canvas_harness/canvas_harness.html
@@ -0,0 +1,170 @@
+<html>
+<!--
+
+ american fuzzy lop++ - <canvas> harness
+ -------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Copyright 2013, 2014 Google Inc. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ A simple harness for going through afl-generated test cases, rendering them in
+ the browser environment, and discovering the use of uninitialized memory and
+ similar bugs. This code led to the discovery of a fair number of library and
+ browser security bugs!
+
+ The url_list[] array is a placeholder; for this to work properly, it needs to
+ be initialized with web-reachable paths to individual test cases. This can
+ be done manually or with a simple script.
+
+-->
+
+<body onload="set_images()">
+
+<div id="status"></div>
+
+<div id="image_div"></div>
+
+<canvas height=64 width=64 id=cvs></canvas>
+
+<h2>Results</h2>
+
+<ul id="output"></ul>
+
+<script>
+
+var c = document.getElementById('cvs');
+var ctx = c.getContext('2d');
+
+var url_list = [
+ "images/id:000000,[...].jpg",
+ "images/id:000001,[...].jpg",
+ /* ... */
+ null
+];
+
+var USE_IMAGES = 50;
+var cur_image = 0;
+
+if (location.hash) cur_image = parseInt(location.hash.substr(1));
+
+var loaded = 0;
+var image_obj = [];
+
+var msie_cleanup;
+
+function check_results() {
+
+ var uniques = [];
+
+ clearTimeout(msie_cleanup);
+
+ ctx.clearRect(0, 0, 64, 64);
+
+ uniques.push(image_obj[0].imgdata);
+
+ for (var i = 1; i < USE_IMAGES; i++) {
+
+ if (!image_obj[i].imgdata) continue;
+
+ if (image_obj[0].imgdata != image_obj[i].imgdata) {
+
+ for (var j = 1; j < uniques.length; j++)
+ if (uniques[j] == image_obj[i].imgdata) break;
+
+ if (j == uniques.length) uniques.push(image_obj[i].imgdata);
+
+
+ }
+
+ }
+
+ if (uniques.length > 1) {
+
+ var str = '<li> Image ' + url_list[cur_image] + ' has ' + uniques.length + ' variants: ';
+
+ for (var i = 0; i < uniques.length; i++)
+ str += '<img src="' + uniques[i] + '">';
+
+ document.getElementById('output').innerHTML += str;
+
+ }
+
+ cur_image++;
+ set_images();
+}
+
+
+function count_image() {
+
+ if (!this.complete || this.counted) return;
+
+ this.counted = true;
+
+ loaded++;
+
+ ctx.clearRect(0, 0, 64, 64);
+
+ try {
+ ctx.drawImage(this, 0, 0, 64, 64);
+ } catch (e) { }
+
+ this.imgdata = c.toDataURL();
+
+ if (loaded == USE_IMAGES) check_results();
+}
+
+
+function set_images() {
+
+ loaded = 0;
+
+ document.getElementById('status').innerHTML = 'Now processing ' + cur_image + '...';
+ location.hash = '#' + cur_image;
+
+ if (url_list[cur_image] == null) {
+ alert('Done!');
+ return;
+ }
+
+ restart_images();
+
+ msie_cleanup = setTimeout(check_results, 5000);
+
+ for (var i = 0; i < USE_IMAGES; i++)
+ image_obj[i].src = url_list[cur_image] + '?' + Math.random();
+
+}
+
+
+function restart_images() {
+
+ for (var i = 0; i < USE_IMAGES; i++)
+ if (image_obj[i]) image_obj[i].counted = true;
+
+ document.getElementById('image_div').innerHTML = '';
+ image_obj = [];
+
+ for (var i = 0; i < USE_IMAGES; i++) {
+
+ image_obj[i] = new Image();
+ image_obj[i].height = 64;
+ image_obj[i].width = 64;
+ image_obj[i].onerror = count_image;
+ image_obj[i].onload = count_image;
+
+ document.getElementById('image_div').appendChild(image_obj[i]);
+
+ }
+
+}
+
+</script>
+
+<iframe src='http://www.cnn.com/'></iframe>
diff --git a/utils/clang_asm_normalize/as b/utils/clang_asm_normalize/as
new file mode 100755
index 00000000..45537cae
--- /dev/null
+++ b/utils/clang_asm_normalize/as
@@ -0,0 +1,75 @@
+#!/bin/sh
+#
+# american fuzzy lop++ - clang assembly normalizer
+# ----------------------------------------------
+#
+# Originally written by Michal Zalewski
+# The idea for this wrapper comes from Ryan Govostes.
+#
+# Copyright 2013, 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# This 'as' wrapper should allow you to instrument unruly, hand-written
+# assembly with afl-as.
+#
+# Usage:
+#
+# export AFL_REAL_PATH=/path/to/directory/with/afl-as/
+# AFL_PATH=/path/to/this/directory/ make clean all
+
+if [ "$#" -lt "2" ]; then
+ echo "[-] Error: this utility can't be called directly." 1>&2
+ exit 1
+fi
+
+if [ "$AFL_REAL_PATH" = "" ]; then
+ echo "[-] Error: AFL_REAL_PATH not set!" 1>&2
+ exit 1
+fi
+
+if [ ! -x "$AFL_REAL_PATH/afl-as" ]; then
+ echo "[-] Error: AFL_REAL_PATH does not contain the 'afl-as' binary." 1>&2
+ exit 1
+fi
+
+unset __AFL_AS_CMDLINE __AFL_FNAME
+
+while [ ! "$#" = "0" ]; do
+
+ if [ "$#" = "1" ]; then
+ __AFL_FNAME="$1"
+ else
+ __AFL_AS_CMDLINE="${__AFL_AS_CMDLINE} $1"
+ fi
+
+ shift
+
+done
+
+test "$TMPDIR" = "" && TMPDIR=/tmp
+
+TMPFILE=`mktemp $TMPDIR/.afl-XXXXXXXXXX.s`
+
+test "$TMPFILE" = "" && exit 1
+
+clang -cc1as -filetype asm -output-asm-variant 0 "${__AFL_FNAME}" >"$TMPFILE"
+
+ERR="$?"
+
+if [ ! "$ERR" = "0" ]; then
+ rm -f "$TMPFILE"
+ exit $ERR
+fi
+
+"$AFL_REAL_PATH/afl-as" ${__AFL_AS_CMDLINE} "$TMPFILE"
+
+ERR="$?"
+
+rm -f "$TMPFILE"
+
+exit "$ERR"
diff --git a/utils/crash_triage/triage_crashes.sh b/utils/crash_triage/triage_crashes.sh
new file mode 100755
index 00000000..4d75430e
--- /dev/null
+++ b/utils/crash_triage/triage_crashes.sh
@@ -0,0 +1,118 @@
+#!/bin/sh
+#
+# american fuzzy lop++ - crash triage utility
+# -----------------------------------------
+#
+# Originally written by Michal Zalewski
+#
+# Copyright 2013, 2014, 2017 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Note that this assumes that the targeted application reads from stdin
+# and requires no other cmdline parameters. Modify as needed if this is
+# not the case.
+#
+# Note that on OpenBSD, you may need to install a newer version of gdb
+# (e.g., from ports). You can set GDB=/some/path to point to it if
+# necessary.
+#
+
+echo "crash triage utility for afl-fuzz by Michal Zalewski"
+echo
+
+ulimit -v 100000 2>/dev/null
+ulimit -d 100000 2>/dev/null
+
+if [ "$#" -lt "2" ]; then
+ echo "Usage: $0 /path/to/afl_output_dir /path/to/tested_binary [...target params...]" 1>&2
+ echo 1>&2
+ exit 1
+fi
+
+DIR="$1"
+BIN="$2"
+shift
+shift
+
+if [ "$AFL_ALLOW_TMP" = "" ]; then
+
+ echo "$DIR" | grep -qE '^(/var)?/tmp/'
+ T1="$?"
+
+ echo "$BIN" | grep -qE '^(/var)?/tmp/'
+ T2="$?"
+
+ if [ "$T1" = "0" -o "$T2" = "0" ]; then
+ echo "[-] Error: do not use shared /tmp or /var/tmp directories with this script." 1>&2
+ exit 1
+ fi
+
+fi
+
+if
+ [ "$GDB" = "" ]; then
+ GDB=gdb
+fi
+
+if [ ! -f "$BIN" -o ! -x "$BIN" ]; then
+ echo "[-] Error: binary '$BIN' not found or is not executable." 1>&2
+ exit 1
+fi
+
+if [ ! -d "$DIR/queue" ]; then
+ echo "[-] Error: directory '$DIR' not found or not created by afl-fuzz." 1>&2
+ exit 1
+fi
+
+CCOUNT=$((`ls -- "$DIR/crashes" 2>/dev/null | wc -l`))
+
+if [ "$CCOUNT" = "0" ]; then
+ echo "No crashes recorded in the target directory - nothing to be done."
+ exit 0
+fi
+
+echo
+
+for crash in $DIR/crashes/id:*; do
+
+ id=`basename -- "$crash" | cut -d, -f1 | cut -d: -f2`
+ sig=`basename -- "$crash" | cut -d, -f2 | cut -d: -f2`
+
+ # Grab the args, converting @@ to $crash
+
+ use_args=""
+ use_stdio=1
+
+ for a in $@; do
+
+ case "$a" in
+ *@@*)
+ unset use_stdio
+ use_args="$use_args `printf %s "$a" | sed -e 's<@@<'$crash'<g'`"
+ ;;
+ *)
+ use_args="$use_args $a"
+ ;;
+ esac
+
+ done
+
+ # Strip the trailing space
+ use_args="${use_args# }"
+
+ echo "+++ ID $id, SIGNAL $sig +++"
+ echo
+
+ if [ "$use_stdio" = "1" ]; then
+ $GDB --batch -q --ex "r $use_args <$crash" --ex 'back' --ex 'disass $pc, $pc+16' --ex 'info reg' --ex 'quit' "$BIN" 0</dev/null
+ else
+ $GDB --batch -q --ex "r $use_args" --ex 'back' --ex 'disass $pc, $pc+16' --ex 'info reg' --ex 'quit' "$BIN" 0</dev/null
+ fi
+ echo
+
+done
diff --git a/utils/defork/Makefile b/utils/defork/Makefile
new file mode 100644
index 00000000..e8240dba
--- /dev/null
+++ b/utils/defork/Makefile
@@ -0,0 +1,64 @@
+#
+# american fuzzy lop++ - defork
+# ----------------------------------
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+
+.PHONY: all install clean
+
+PREFIX ?= /usr/local
+BIN_PATH = $(PREFIX)/bin
+HELPER_PATH = $(PREFIX)/lib/afl
+
+CFLAGS = -fPIC -Wall -Wextra
+LDFLAGS = -shared
+
+UNAME_SAYS_LINUX=$(shell uname | grep -E '^Linux|^GNU' >/dev/null; echo $$?)
+UNAME_SAYS_LINUX:sh=uname | grep -E '^Linux|^GNU' >/dev/null; echo $$?
+
+_LDFLAGS_ADD=$(UNAME_SAYS_LINUX:1=)
+LDFLAGS_ADD=$(_LDFLAGS_ADD:0=-ldl)
+LDFLAGS += $(LDFLAGS_ADD)
+
+# on gcc for arm there is no -m32, but -mbe32
+M32FLAG = -m32
+M64FLAG = -m64
+
+CC_IS_GCC=$(shell $(CC) --version 2>/dev/null | grep -q gcc; echo $$?)
+CC_IS_GCC:sh=$(CC) --version 2>/dev/null | grep -q gcc; echo $$?
+CC_IS_ARMCOMPILER=$(shell $(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?)
+CC_IS_ARMCOMPILER:sh=$(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?
+
+_M32FLAG=$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)
+__M32FLAG=$(_M32FLAG:00=-mbe32)
+___M32FLAG=$(__M32FLAG:$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)=-m32)
+M32FLAG=$(___M32FLAG)
+#ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" ""
+# ifneq (,$(findstring arm, "$(shell $(CC) -v 2>&1 >/dev/null)"))
+# M32FLAG = -mbe32
+# endif
+#endif
+
+all: defork32.so defork64.so
+
+defork32.so: defork.c
+ -@$(CC) $(M32FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "defork32 build failure (that's fine)"
+
+defork64.so: defork.c
+ -@$(CC) $(M64FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "defork64 build failure (that's fine)"
+
+install: defork32.so defork64.so
+ install -d -m 755 $(DESTDIR)$(HELPER_PATH)/
+ if [ -f defork32.so ]; then set -e; install -m 755 defork32.so $(DESTDIR)$(HELPER_PATH)/; fi
+ if [ -f defork64.so ]; then set -e; install -m 755 defork64.so $(DESTDIR)$(HELPER_PATH)/; fi
+
+target:
+ ../../afl-clang forking_target.c -o forking_target -Wall -Wextra -Werror
+
+clean:
+ rm -f defork32.so defork64.so forking_target
diff --git a/utils/defork/README.md b/utils/defork/README.md
new file mode 100644
index 00000000..657ef274
--- /dev/null
+++ b/utils/defork/README.md
@@ -0,0 +1,11 @@
+# defork
+
+when the target forks, this breaks all normal fuzzing runs.
+Sometimes, though, it is enough to just run the child process.
+If this is the case, then this LD_PRELOAD library will always return 0 on fork,
+the target will belive it is running as the child, post-fork.
+
+This is defork.c from the amazing preeny project
+https://github.com/zardus/preeny
+
+It is altered for AFL++ to work with its fork-server: the initial fork will go through, the second fork will be blocked.
diff --git a/utils/defork/defork.c b/utils/defork/defork.c
new file mode 100644
index 00000000..c9be3283
--- /dev/null
+++ b/utils/defork/defork.c
@@ -0,0 +1,51 @@
+#define _GNU_SOURCE
+#include <dlfcn.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdbool.h>
+
+#include "../../include/config.h"
+#include "../../include/types.h"
+
+/* we want to fork once (for the afl++ forkserver),
+ then immediately return as child on subsequent forks. */
+static bool forked = 0;
+
+pid_t (*original_fork)(void);
+
+/* In case we are not running in afl, we use a dummy original_fork */
+static pid_t nop(void) {
+
+ return 0;
+
+}
+
+__attribute__((constructor)) void preeny_fork_orig() {
+
+ if (getenv(SHM_ENV_VAR)) {
+
+ printf("defork: running in AFL++. Allowing forkserver.\n");
+ original_fork = dlsym(RTLD_NEXT, "socket");
+
+ } else {
+
+ printf("defork: no AFL++ detected. Disabling fork from the start.\n");
+ original_fork = &nop;
+
+ }
+
+}
+
+pid_t fork(void) {
+
+ /* If we forked before, or if we're in the child (pid==0),
+ we don't want to fork anymore, else, we are still in the forkserver.
+ The forkserver parent needs to fork infinite times, each child should never
+ fork again. This can be written without branches and I hate myself for it.
+ */
+ pid_t ret = !forked && original_fork();
+ forked = !ret;
+ return ret;
+
+}
+
diff --git a/utils/defork/forking_target.c b/utils/defork/forking_target.c
new file mode 100644
index 00000000..628d23c9
--- /dev/null
+++ b/utils/defork/forking_target.c
@@ -0,0 +1,49 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+/* This is an example target for defork.c - fuzz using
+```
+mkdir in; echo a > ./in/a
+AFL_PRELOAD=./defork64.so ../../afl-fuzz -i in -o out -- ./forking_target @@
+```
+*/
+
+int main(int argc, char **argv) {
+
+ if (argc < 2) {
+
+ printf("Example tool to test defork.\nUsage ./forking_target <input>\n");
+ return -1;
+
+ }
+
+ pid_t pid = fork();
+ if (pid == 0) {
+
+ printf("We're in the child.\n");
+ FILE *f = fopen(argv[1], "r");
+ char buf[4096];
+ fread(buf, 1, 4096, f);
+ fclose(f);
+ uint32_t offset = buf[100] + (buf[101] << 8);
+ char test_val = buf[offset];
+ return test_val < 100;
+
+ } else if (pid < 0) {
+
+ perror("fork");
+ return -1;
+
+ } else {
+
+ printf("We are in the parent - defork didn't work! :( (pid=%d)\n",
+ (int)pid);
+
+ }
+
+ return 0;
+
+}
+
diff --git a/utils/distributed_fuzzing/sync_script.sh b/utils/distributed_fuzzing/sync_script.sh
new file mode 100755
index 00000000..251ae4e6
--- /dev/null
+++ b/utils/distributed_fuzzing/sync_script.sh
@@ -0,0 +1,97 @@
+#!/bin/sh
+#
+# american fuzzy lop++ - fuzzer synchronization tool
+# --------------------------------------------------
+#
+# Originally written by Michal Zalewski
+#
+# Copyright 2014 Google Inc. All rights reserved.
+# Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# To make this script work:
+#
+# - Edit FUZZ_HOSTS, FUZZ_DOMAIN, FUZZ_USER, and SYNC_DIR to reflect your
+# environment.
+#
+# - Make sure that the system you are running this on can log into FUZZ_HOSTS
+# without a password (authorized_keys or otherwise).
+#
+# - Make sure that every fuzzer is running with -o pointing to SYNC_DIR and -S
+# that consists of its local host name, followed by an underscore, and then
+# by some host-local fuzzer ID.
+#
+
+# Hosts to synchronize the data across.
+FUZZ_HOSTS='host1 host2 host3 host4'
+
+# Domain for all hosts
+FUZZ_DOMAIN='example.com'
+
+# Remote user for SSH
+FUZZ_USER=bob
+
+# Directory to synchronize
+SYNC_DIR='/home/bob/sync_dir'
+
+# We only capture -M main nodes, set the name to your chosen naming scheme
+MAIN_NAME='main'
+
+# Interval (seconds) between sync attempts (eg one hour)
+SYNC_INTERVAL=$((60 * 60))
+
+if [ "$AFL_ALLOW_TMP" = "" ]; then
+
+ if [ "$PWD" = "/tmp" -o "$PWD" = "/var/tmp" ]; then
+ echo "[-] Error: do not use shared /tmp or /var/tmp directories with this script." 1>&2
+ exit 1
+ fi
+
+fi
+
+rm -rf .sync_tmp 2>/dev/null
+mkdir .sync_tmp || exit 1
+
+while :; do
+
+ # Pull data in...
+
+ for host in $FUZZ_HOSTS; do
+
+ echo "[*] Retrieving data from ${host}.${FUZZ_DOMAIN}..."
+
+ ssh -o 'passwordauthentication no' ${FUZZ_USER}@${host}.$FUZZ_DOMAIN \
+ "cd '$SYNC_DIR' && tar -czf - ${host}_${MAIN_NAME}*/" > ".sync_tmp/${host}.tgz"
+
+ done
+
+ # Distribute data. For large fleets, see tips in the docs/ directory.
+
+ for dst_host in $FUZZ_HOSTS; do
+
+ echo "[*] Distributing data to ${dst_host}.${FUZZ_DOMAIN}..."
+
+ for src_host in $FUZZ_HOSTS; do
+
+ test "$src_host" = "$dst_host" && continue
+
+ echo " Sending fuzzer data from ${src_host}.${FUZZ_DOMAIN}..."
+
+ ssh -o 'passwordauthentication no' ${FUZZ_USER}@$dst_host \
+ "cd '$SYNC_DIR' && tar -xkzf - " < ".sync_tmp/${src_host}.tgz"
+
+ done
+
+ done
+
+ echo "[+] Done. Sleeping for $SYNC_INTERVAL seconds (Ctrl-C to quit)."
+
+ sleep $SYNC_INTERVAL
+
+done
+
diff --git a/utils/libdislocator/Makefile b/utils/libdislocator/Makefile
new file mode 100644
index 00000000..6bfb79ec
--- /dev/null
+++ b/utils/libdislocator/Makefile
@@ -0,0 +1,44 @@
+#
+# american fuzzy lop++ - libdislocator
+# ----------------------------------
+#
+# Originally written by Michal Zalewski
+#
+# Copyright 2016 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+
+PREFIX ?= /usr/local
+HELPER_PATH = $(PREFIX)/lib/afl
+
+VERSION = $(shell grep '^\#define VERSION ' ../../config.h | cut -d '"' -f2)
+
+CFLAGS ?= -O3 -funroll-loops -D_FORTIFY_SOURCE=2
+CFLAGS += -I ../../include/ -Wall -g -Wno-pointer-sign
+
+CFLAGS_ADD=$(USEHUGEPAGE:1=-DUSEHUGEPAGE)
+CFLAGS_ADD += $(USENAMEDPAGE:1=-DUSENAMEDPAGE)
+CFLAGS += $(CFLAGS_ADD)
+
+all: libdislocator.so
+
+libdislocator.so: libdislocator.so.c ../../config.h
+ $(CC) $(CFLAGS) $(CPPFLAGS) -shared -fPIC libdislocator.so.c -o $@ $(LDFLAGS)
+ cp -fv libdislocator.so ../../
+
+.NOTPARALLEL: clean
+
+clean:
+ rm -f *.o *.so *~ a.out core core.[1-9][0-9]*
+ rm -f ../../libdislocator.so
+
+install: all
+ install -m 755 -d $${DESTDIR}$(HELPER_PATH)
+ install -m 755 ../../libdislocator.so $${DESTDIR}$(HELPER_PATH)
+ install -m 644 -T README.md $${DESTDIR}$(HELPER_PATH)/README.dislocator.md
+
diff --git a/utils/libdislocator/README.md b/utils/libdislocator/README.md
new file mode 100644
index 00000000..e4934b5d
--- /dev/null
+++ b/utils/libdislocator/README.md
@@ -0,0 +1,70 @@
+# libdislocator, an abusive allocator
+
+For the general instruction manual, see [docs/README.md](../../docs/README.md).
+
+This is a companion library that can be used as a drop-in replacement for the
+libc allocator in the fuzzed binaries. It improves the odds of bumping into
+heap-related security bugs in several ways:
+
+ - It allocates all buffers so that they are immediately adjacent to a
+ subsequent PROT_NONE page, causing most off-by-one reads and writes to
+ immediately segfault,
+
+ - It adds a canary immediately below the allocated buffer, to catch writes to
+ negative offsets (won't catch reads, though),
+
+ - It sets the memory returned by malloc() to garbage values, improving the
+ odds of crashing when the target accesses uninitialized data,
+
+ - It sets freed memory to PROT_NONE and does not actually reuse it, causing
+ most use-after-free bugs to segfault right away,
+
+ - It forces all realloc() calls to return a new address - and sets PROT_NONE
+ on the original block. This catches use-after-realloc bugs,
+
+ - It checks for calloc() overflows and can cause soft or hard failures of
+ alloc requests past a configurable memory limit (AFL_LD_LIMIT_MB,
+ AFL_LD_HARD_FAIL).
+
+ - Optionally, in platforms supporting it, huge pages can be used by passing
+ `USEHUGEPAGE=1` to make.
+
+ - Optionally, in platforms supporting it, `named` pages can be used by passing
+ `USENAMEDPAGE=1` to make.
+
+ - Size alignment to `max_align_t` can be enforced with `AFL_ALIGNED_ALLOC=1`. In
+ this case, a tail canary is inserted in the padding bytes at the end of the
+ allocated zone. This reduce the ability of libdislocator to detect
+ off-by-one bugs but also it make slibdislocator compliant to the C standard.
+
+Basically, it is inspired by some of the non-default options available for the
+OpenBSD allocator - see malloc.conf(5) on that platform for reference. It is
+also somewhat similar to several other debugging libraries, such as gmalloc and
+DUMA - but is simple, plug-and-play, and designed specifically for fuzzing jobs.
+
+Note that it does nothing for stack-based memory handling errors. The
+-fstack-protector-all setting for GCC / clang, enabled when using AFL_HARDEN,
+can catch some subset of that.
+
+The allocator is slow and memory-intensive (even the tiniest allocation uses up
+4 kB of physical memory and 8 kB of virtual mem), making it completely
+unsuitable for "production" uses; but it can be faster and more hassle-free than
+ASAN / MSAN when fuzzing small, self-contained binaries.
+
+To use this library, run AFL++ like so:
+
+```
+AFL_PRELOAD=/path/to/libdislocator.so ./afl-fuzz [...other params...]
+```
+
+You *have* to specify path, even if it's just ./libdislocator.so or
+$PWD/libdislocator.so.
+
+Similarly to afl-tmin, the library is not "proprietary" and can be used with
+other fuzzers or testing tools without the need for any code tweaks. It does not
+require AFL-instrumented binaries to work.
+
+Note that the AFL_PRELOAD approach (which AFL++ internally maps to LD_PRELOAD or
+DYLD_INSERT_LIBRARIES, depending on the OS) works only if the target binary is
+dynamically linked. Otherwise, attempting to use the library will have no
+effect.
diff --git a/utils/libdislocator/libdislocator.so.c b/utils/libdislocator/libdislocator.so.c
new file mode 100644
index 00000000..bd08a678
--- /dev/null
+++ b/utils/libdislocator/libdislocator.so.c
@@ -0,0 +1,572 @@
+/*
+
+ american fuzzy lop++ - dislocator, an abusive allocator
+ -----------------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Copyright 2016 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ This is a companion library that can be used as a drop-in replacement
+ for the libc allocator in the fuzzed binaries. See README.dislocator.md for
+ more info.
+
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+#include <sys/mman.h>
+
+#ifdef __APPLE__
+ #include <mach/vm_statistics.h>
+#endif
+
+#ifdef __FreeBSD__
+ #include <sys/param.h>
+#endif
+
+#if (defined(__linux__) && !defined(__ANDROID__)) || defined(__HAIKU__)
+ #include <unistd.h>
+ #include <sys/prctl.h>
+ #ifdef __linux__
+ #include <sys/syscall.h>
+ #include <malloc.h>
+ #endif
+ #ifdef __NR_getrandom
+ #define arc4random_buf(p, l) \
+ do { \
+ \
+ ssize_t rd = syscall(__NR_getrandom, p, l, 0); \
+ if (rd != l) DEBUGF("getrandom failed"); \
+ \
+ } while (0)
+
+ #else
+ #include <time.h>
+ #define arc4random_buf(p, l) \
+ do { \
+ \
+ srand(time(NULL)); \
+ u32 i; \
+ u8 *ptr = (u8 *)p; \
+ for (i = 0; i < l; i++) \
+ ptr[i] = rand() % INT_MAX; \
+ \
+ } while (0)
+
+ #endif
+ #ifndef PR_SET_VMA
+ #define PR_SET_VMA 0x53564d41
+ #define PR_SET_VMA_ANON_NAME 0
+ #endif
+#endif
+
+#include "config.h"
+#include "types.h"
+
+#if __STDC_VERSION__ < 201112L || \
+ (defined(__FreeBSD__) && __FreeBSD_version < 1200000)
+// use this hack if not C11
+typedef struct {
+
+ long long __ll;
+ long double __ld;
+
+} max_align_t;
+
+#endif
+
+#define ALLOC_ALIGN_SIZE (_Alignof(max_align_t))
+
+#ifndef PAGE_SIZE
+ #define PAGE_SIZE 4096
+#endif /* !PAGE_SIZE */
+
+#ifndef MAP_ANONYMOUS
+ #define MAP_ANONYMOUS MAP_ANON
+#endif /* !MAP_ANONYMOUS */
+
+#define SUPER_PAGE_SIZE 1 << 21
+
+/* Error / message handling: */
+
+#define DEBUGF(_x...) \
+ do { \
+ \
+ if (alloc_verbose) { \
+ \
+ if (++call_depth == 1) { \
+ \
+ fprintf(stderr, "[AFL] " _x); \
+ fprintf(stderr, "\n"); \
+ \
+ } \
+ call_depth--; \
+ \
+ } \
+ \
+ } while (0)
+
+#define FATAL(_x...) \
+ do { \
+ \
+ if (++call_depth == 1) { \
+ \
+ fprintf(stderr, "*** [AFL] " _x); \
+ fprintf(stderr, " ***\n"); \
+ abort(); \
+ \
+ } \
+ call_depth--; \
+ \
+ } while (0)
+
+/* Macro to count the number of pages needed to store a buffer: */
+
+#define PG_COUNT(_l) (((_l) + (PAGE_SIZE - 1)) / PAGE_SIZE)
+
+/* Canary & clobber bytes: */
+
+#define ALLOC_CANARY 0xAACCAACC
+#define ALLOC_CLOBBER 0xCC
+
+#define TAIL_ALLOC_CANARY 0xAC
+
+#define PTR_C(_p) (((u32 *)(_p))[-1])
+#define PTR_L(_p) (((u32 *)(_p))[-2])
+
+/* Configurable stuff (use AFL_LD_* to set): */
+
+static size_t max_mem = MAX_ALLOC; /* Max heap usage to permit */
+static u8 alloc_verbose, /* Additional debug messages */
+ hard_fail, /* abort() when max_mem exceeded? */
+ no_calloc_over, /* abort() on calloc() overflows? */
+ align_allocations; /* Force alignment to sizeof(void*) */
+
+#if defined __OpenBSD__ || defined __APPLE__
+ #define __thread
+ #warning no thread support available
+#endif
+static _Atomic size_t total_mem; /* Currently allocated mem */
+
+static __thread u32 call_depth; /* To avoid recursion via fprintf() */
+static u32 alloc_canary;
+
+/* This is the main alloc function. It allocates one page more than necessary,
+ sets that tailing page to PROT_NONE, and then increments the return address
+ so that it is right-aligned to that boundary. Since it always uses mmap(),
+ the returned memory will be zeroed. */
+
+static void *__dislocator_alloc(size_t len) {
+
+ u8 * ret, *base;
+ size_t tlen;
+ int flags, protflags, fd, sp;
+
+ if (total_mem + len > max_mem || total_mem + len < total_mem) {
+
+ if (hard_fail) FATAL("total allocs exceed %zu MB", max_mem / 1024 / 1024);
+
+ DEBUGF("total allocs exceed %zu MB, returning NULL", max_mem / 1024 / 1024);
+
+ return NULL;
+
+ }
+
+ size_t rlen;
+ if (align_allocations && (len & (ALLOC_ALIGN_SIZE - 1)))
+ rlen = (len & ~(ALLOC_ALIGN_SIZE - 1)) + ALLOC_ALIGN_SIZE;
+ else
+ rlen = len;
+
+ /* We will also store buffer length and a canary below the actual buffer, so
+ let's add 8 bytes for that. */
+
+ base = NULL;
+ tlen = (1 + PG_COUNT(rlen + 8)) * PAGE_SIZE;
+ protflags = PROT_READ | PROT_WRITE;
+ flags = MAP_PRIVATE | MAP_ANONYMOUS;
+ fd = -1;
+#if defined(PROT_MAX)
+ // apply when sysctl vm.imply_prot_max is set to 1
+ // no-op otherwise
+ protflags |= PROT_MAX(PROT_READ | PROT_WRITE);
+#endif
+#if defined(USEHUGEPAGE)
+ sp = (rlen >= SUPER_PAGE_SIZE && !(rlen % SUPER_PAGE_SIZE));
+
+ #if defined(__APPLE__)
+ if (sp) fd = VM_FLAGS_SUPERPAGE_SIZE_2MB;
+ #elif defined(__linux__)
+ if (sp) flags |= MAP_HUGETLB;
+ #elif defined(__FreeBSD__)
+ if (sp) flags |= MAP_ALIGNED_SUPER;
+ #elif defined(__sun)
+ if (sp) {
+
+ base = (void *)(caddr_t)(1 << 21);
+ flags |= MAP_ALIGN;
+
+ }
+
+ #endif
+#else
+ (void)sp;
+#endif
+
+ ret = (u8 *)mmap(base, tlen, protflags, flags, fd, 0);
+#if defined(USEHUGEPAGE)
+ /* We try one more time with regular call */
+ if (ret == MAP_FAILED) {
+
+ #if defined(__APPLE__)
+ fd = -1;
+ #elif defined(__linux__)
+ flags &= -MAP_HUGETLB;
+ #elif defined(__FreeBSD__)
+ flags &= -MAP_ALIGNED_SUPER;
+ #elif defined(__sun)
+ flags &= -MAP_ALIGN;
+ #endif
+ ret = (u8 *)mmap(NULL, tlen, protflags, flags, fd, 0);
+
+ }
+
+#endif
+
+ if (ret == MAP_FAILED) {
+
+ if (hard_fail) FATAL("mmap() failed on alloc (OOM?)");
+
+ DEBUGF("mmap() failed on alloc (OOM?)");
+
+ return NULL;
+
+ }
+
+#if defined(USENAMEDPAGE)
+ #if defined(__linux__)
+ // in the /proc/<pid>/maps file, the anonymous page appears as
+ // `<start>-<end> ---p 00000000 00:00 0 [anon:libdislocator]`
+ if (prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, (unsigned long)ret, tlen,
+ (unsigned long)"libdislocator") < 0) {
+
+ DEBUGF("prctl() failed");
+
+ }
+
+ #endif
+#endif
+
+ /* Set PROT_NONE on the last page. */
+
+ if (mprotect(ret + PG_COUNT(rlen + 8) * PAGE_SIZE, PAGE_SIZE, PROT_NONE))
+ FATAL("mprotect() failed when allocating memory");
+
+ /* Offset the return pointer so that it's right-aligned to the page
+ boundary. */
+
+ ret += PAGE_SIZE * PG_COUNT(rlen + 8) - rlen - 8;
+
+ /* Store allocation metadata. */
+
+ ret += 8;
+
+ PTR_L(ret) = len;
+ PTR_C(ret) = alloc_canary;
+
+ total_mem += len;
+
+ if (rlen != len) {
+
+ size_t i;
+ for (i = len; i < rlen; ++i)
+ ret[i] = TAIL_ALLOC_CANARY;
+
+ }
+
+ return ret;
+
+}
+
+/* The "user-facing" wrapper for calloc(). This just checks for overflows and
+ displays debug messages if requested. */
+
+void *calloc(size_t elem_len, size_t elem_cnt) {
+
+ void *ret;
+
+ size_t len = elem_len * elem_cnt;
+
+ /* Perform some sanity checks to detect obvious issues... */
+
+ if (elem_cnt && len / elem_cnt != elem_len) {
+
+ if (no_calloc_over) {
+
+ DEBUGF("calloc(%zu, %zu) would overflow, returning NULL", elem_len,
+ elem_cnt);
+ return NULL;
+
+ }
+
+ FATAL("calloc(%zu, %zu) would overflow", elem_len, elem_cnt);
+
+ }
+
+ ret = __dislocator_alloc(len);
+
+ DEBUGF("calloc(%zu, %zu) = %p [%zu total]", elem_len, elem_cnt, ret,
+ total_mem);
+
+ return ret;
+
+}
+
+/* The wrapper for malloc(). Roughly the same, also clobbers the returned
+ memory (unlike calloc(), malloc() is not guaranteed to return zeroed
+ memory). */
+
+void *malloc(size_t len) {
+
+ void *ret;
+
+ ret = __dislocator_alloc(len);
+
+ DEBUGF("malloc(%zu) = %p [%zu total]", len, ret, total_mem);
+
+ if (ret && len) memset(ret, ALLOC_CLOBBER, len);
+
+ return ret;
+
+}
+
+/* The wrapper for free(). This simply marks the entire region as PROT_NONE.
+ If the region is already freed, the code will segfault during the attempt to
+ read the canary. Not very graceful, but works, right? */
+
+void free(void *ptr) {
+
+ u32 len;
+
+ DEBUGF("free(%p)", ptr);
+
+ if (!ptr) return;
+
+ if (PTR_C(ptr) != alloc_canary) FATAL("bad allocator canary on free()");
+
+ len = PTR_L(ptr);
+
+ total_mem -= len;
+ u8 *ptr_ = ptr;
+
+ if (align_allocations && (len & (ALLOC_ALIGN_SIZE - 1))) {
+
+ size_t rlen = (len & ~(ALLOC_ALIGN_SIZE - 1)) + ALLOC_ALIGN_SIZE;
+ for (; len < rlen; ++len)
+ if (ptr_[len] != TAIL_ALLOC_CANARY)
+ FATAL("bad tail allocator canary on free()");
+
+ }
+
+ /* Protect everything. Note that the extra page at the end is already
+ set as PROT_NONE, so we don't need to touch that. */
+
+ ptr_ -= PAGE_SIZE * PG_COUNT(len + 8) - len - 8;
+
+ if (mprotect(ptr_ - 8, PG_COUNT(len + 8) * PAGE_SIZE, PROT_NONE))
+ FATAL("mprotect() failed when freeing memory");
+
+ ptr = ptr_;
+
+ /* Keep the mapping; this is wasteful, but prevents ptr reuse. */
+
+}
+
+/* Realloc is pretty straightforward, too. We forcibly reallocate the buffer,
+ move data, and then free (aka mprotect()) the original one. */
+
+void *realloc(void *ptr, size_t len) {
+
+ void *ret;
+
+ ret = malloc(len);
+
+ if (ret && ptr) {
+
+ if (PTR_C(ptr) != alloc_canary) FATAL("bad allocator canary on realloc()");
+ // Here the tail canary check is delayed to free()
+
+ memcpy(ret, ptr, MIN(len, PTR_L(ptr)));
+ free(ptr);
+
+ }
+
+ DEBUGF("realloc(%p, %zu) = %p [%zu total]", ptr, len, ret, total_mem);
+
+ return ret;
+
+}
+
+/* posix_memalign we mainly check the proper alignment argument
+ if the requested size fits within the alignment we do
+ a normal request */
+
+int posix_memalign(void **ptr, size_t align, size_t len) {
+
+ // if (*ptr == NULL) return EINVAL; // (andrea) Why? I comment it out for now
+ if ((align % 2) || (align % sizeof(void *))) return EINVAL;
+ if (len == 0) {
+
+ *ptr = NULL;
+ return 0;
+
+ }
+
+ size_t rem = len % align;
+ if (rem) len += align - rem;
+
+ *ptr = __dislocator_alloc(len);
+
+ if (*ptr && len) memset(*ptr, ALLOC_CLOBBER, len);
+
+ DEBUGF("posix_memalign(%p %zu, %zu) [*ptr = %p]", ptr, align, len, *ptr);
+
+ return 0;
+
+}
+
+/* just the non-posix fashion */
+
+void *memalign(size_t align, size_t len) {
+
+ void *ret = NULL;
+
+ if (posix_memalign(&ret, align, len)) {
+
+ DEBUGF("memalign(%zu, %zu) failed", align, len);
+
+ }
+
+ return ret;
+
+}
+
+/* sort of C11 alias of memalign only more severe, alignment-wise */
+
+void *aligned_alloc(size_t align, size_t len) {
+
+ void *ret = NULL;
+
+ if ((len % align)) return NULL;
+
+ if (posix_memalign(&ret, align, len)) {
+
+ DEBUGF("aligned_alloc(%zu, %zu) failed", align, len);
+
+ }
+
+ return ret;
+
+}
+
+/* specific BSD api mainly checking possible overflow for the size */
+
+void *reallocarray(void *ptr, size_t elem_len, size_t elem_cnt) {
+
+ const size_t elem_lim = 1UL << (sizeof(size_t) * 4);
+ const size_t elem_tot = elem_len * elem_cnt;
+ void * ret = NULL;
+
+ if ((elem_len >= elem_lim || elem_cnt >= elem_lim) && elem_len > 0 &&
+ elem_cnt > (SIZE_MAX / elem_len)) {
+
+ DEBUGF("reallocarray size overflow (%zu)", elem_tot);
+
+ } else {
+
+ ret = realloc(ptr, elem_tot);
+
+ }
+
+ return ret;
+
+}
+
+#if !defined(__ANDROID__)
+size_t malloc_usable_size(void *ptr) {
+
+#else
+size_t malloc_usable_size(const void *ptr) {
+
+#endif
+
+ return ptr ? PTR_L(ptr) : 0;
+
+}
+
+__attribute__((constructor)) void __dislocator_init(void) {
+
+ char *tmp = getenv("AFL_LD_LIMIT_MB");
+
+ if (tmp) {
+
+ char * tok;
+ unsigned long long mmem = strtoull(tmp, &tok, 10);
+ if (*tok != '\0' || errno == ERANGE || mmem > SIZE_MAX / 1024 / 1024)
+ FATAL("Bad value for AFL_LD_LIMIT_MB");
+ max_mem = mmem * 1024 * 1024;
+
+ }
+
+ alloc_canary = ALLOC_CANARY;
+ tmp = getenv("AFL_RANDOM_ALLOC_CANARY");
+
+ if (tmp) arc4random_buf(&alloc_canary, sizeof(alloc_canary));
+
+ alloc_verbose = !!getenv("AFL_LD_VERBOSE");
+ hard_fail = !!getenv("AFL_LD_HARD_FAIL");
+ no_calloc_over = !!getenv("AFL_LD_NO_CALLOC_OVER");
+ align_allocations = !!getenv("AFL_ALIGNED_ALLOC");
+
+}
+
+/* NetBSD fault handler specific api subset */
+
+void (*esetfunc(void (*fn)(int, const char *, ...)))(int, const char *, ...) {
+
+ /* Might not be meaningful to implement; upper calls already report errors */
+ return NULL;
+
+}
+
+void *emalloc(size_t len) {
+
+ return malloc(len);
+
+}
+
+void *ecalloc(size_t elem_len, size_t elem_cnt) {
+
+ return calloc(elem_len, elem_cnt);
+
+}
+
+void *erealloc(void *ptr, size_t len) {
+
+ return realloc(ptr, len);
+
+}
+
diff --git a/utils/libpng_no_checksum/libpng-nocrc.patch b/utils/libpng_no_checksum/libpng-nocrc.patch
new file mode 100644
index 00000000..0a3793a0
--- /dev/null
+++ b/utils/libpng_no_checksum/libpng-nocrc.patch
@@ -0,0 +1,15 @@
+--- pngrutil.c.orig 2014-06-12 03:35:16.000000000 +0200
++++ pngrutil.c 2014-07-01 05:08:31.000000000 +0200
+@@ -268,7 +268,11 @@
+ if (need_crc != 0)
+ {
+ crc = png_get_uint_32(crc_bytes);
+- return ((int)(crc != png_ptr->crc));
++
++ if (crc != png_ptr->crc)
++ fprintf(stderr, "NOTE: CRC in the file is 0x%08x, change to 0x%08x\n", crc, png_ptr->crc);
++
++ return ((int)(1 != 1));
+ }
+
+ else
diff --git a/utils/libtokencap/Makefile b/utils/libtokencap/Makefile
new file mode 100644
index 00000000..b81e1729
--- /dev/null
+++ b/utils/libtokencap/Makefile
@@ -0,0 +1,94 @@
+#
+# american fuzzy lop++ - libtokencap
+# --------------------------------
+#
+# Originally written by Michal Zalewski
+#
+# Copyright 2016 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+
+PREFIX ?= /usr/local
+HELPER_PATH = $(PREFIX)/lib/afl
+DOC_PATH ?= $(PREFIX)/share/doc/afl
+MAN_PATH ?= $(PREFIX)/share/man/man8
+
+VERSION = $(shell grep '^\#define VERSION ' ../../config.h | cut -d '"' -f2)
+
+CFLAGS ?= -O3 -funroll-loops -D_FORTIFY_SOURCE=2
+override CFLAGS += -I ../../include/ -Wall -g -Wno-pointer-sign
+
+
+UNAME_S =$(shell uname -s)# GNU make
+UNAME_S:sh=uname -s # BSD make
+_UNIQ=_QINU_
+
+ _OS_DL = $(_UNIQ)$(UNAME_S)
+ __OS_DL = $(_OS_DL:$(_UNIQ)Linux=$(_UNIQ))
+ ___OS_DL = $(__OS_DL:$(_UNIQ)Darwin=$(_UNIQ))
+ ____OS_DL = $(___OS_DL:$(_UNIQ)$(UNAME_S)=)
+_____OS_DL = $(____OS_DL:$(_UNIQ)="-ldl")
+
+ _OS_TARGET = $(___OS_DL:$(_UNIQ)FreeBSD=$(_UNIQ))
+ __OS_TARGET = $(_OS_TARGET:$(_UNIQ)OpenBSD=$(_UNIQ))
+ ___OS_TARGET = $(__OS_TARGET:$(_UNIQ)NetBSD=$(_UNIQ))
+ ____OS_TARGET = $(___OS_TARGET:$(_UNIQ)Haiku=$(_UNIQ))
+ _____OS_TARGET = $(____OS_TARGET:$(_UNIQ)SunOS=$(_UNIQ))
+______OS_TARGET = $(_____OS_TARGET:$(_UNIQ)$(UNAME_S)=)
+
+TARGETS = $(______OS_TARGET:$(_UNIQ)=libtokencap.so)
+
+LDFLAGS += $(_____OS_DL)
+
+#ifeq "$(shell uname)" "Linux"
+# TARGETS = libtokencap.so
+# LDFLAGS += -ldl
+#endif
+#ifeq "$(shell uname)" "Darwin"
+# TARGETS = libtokencap.so
+# LDFLAGS += -ldl
+#endif
+#ifeq "$(shell uname)" "FreeBSD"
+# TARGETS = libtokencap.so
+#endif
+#ifeq "$(shell uname)" "OpenBSD"
+# TARGETS = libtokencap.so
+#endif
+#ifeq "$(shell uname)" "NetBSD"
+# TARGETS = libtokencap.so
+#endif
+#ifeq "$(shell uname)" "DragonFly"
+# TARGETS = libtokencap.so
+# LDFLAGS += -ldl
+#endif
+all: $(TARGETS)
+
+libtokencap.so: libtokencap.so.c ../../config.h
+ $(CC) $(CFLAGS) $(CPPFLAGS) -shared -fPIC $< -o $@ $(LDFLAGS)
+ cp -f libtokencap.so ../../
+
+.NOTPARALLEL: clean
+
+debug:
+ @echo $(UNAME_S)$(_UNIQ) | hexdump -C
+ @echo from $(____OS_DL) : $(_UNIQ)$(UNAME_S) = -\> $(_____OS_DL)
+ @echo from $(_____OS_DL) : $(_UNIQ) = -ldl -\> $(______OS_DL)
+ @echo from $(____OS_DL) : $(_UNIQ)FreeBSD = $(_UNIQ) -\> $(_OS_TARGET)
+ @echo from $(_OS_TARGET) : $(_UNIQ)OpenBSD = $(_UNIQ) -\> $(__OS_TARGET)
+ @echo from $(__OS_TARGET) : $(_UNIQ)NetBSD = $(_UNIQ) -\> $(___OS_TARGET)
+ @echo from $(___OS_TARGET) : $(_UNIQ)$(_UNIQ) = -\> $(____OS_TARGET)
+ @echo from $(____OS_TARGET) : $(_UNIQ) = libtokencap.so -\> $(TARGETS)
+
+clean:
+ rm -f *.o *.so *~ a.out core core.[1-9][0-9]*
+ rm -fv ../../libtokencap.so
+
+install: all
+ install -m 755 -d $${DESTDIR}$(HELPER_PATH)
+ install -m 755 ../../libtokencap.so $${DESTDIR}$(HELPER_PATH)
+ install -m 644 -T README.md $${DESTDIR}$(DOC_PATH)/README.tokencap.md
diff --git a/utils/libtokencap/README.md b/utils/libtokencap/README.md
new file mode 100644
index 00000000..50104291
--- /dev/null
+++ b/utils/libtokencap/README.md
@@ -0,0 +1,69 @@
+# strcmp() / memcmp() token capture library
+
+ NOTE: libtokencap is only recommended for binary-only targets or targets that
+ do not compile with afl-clang-fast/afl-clang-lto.
+ The afl-clang-fast AFL_LLVM_DICT2FILE feature is much better, afl-clang-lto
+ has that feature automatically integrated.
+
+For the general instruction manual, see [docs/README.md](../../docs/README.md).
+
+This companion library allows you to instrument `strcmp()`, `memcmp()`,
+and related functions to automatically extract syntax tokens passed to any of
+these libcalls. The resulting list of tokens may be then given as a starting
+dictionary to afl-fuzz (the -x option) to improve coverage on subsequent
+fuzzing runs.
+
+This may help improving coverage in some targets, and do precisely nothing in
+others. In some cases, it may even make things worse: if libtokencap picks up
+syntax tokens that are not used to process the input data, but that are a part
+of - say - parsing a config file... well, you're going to end up wasting a lot
+of CPU time on trying them out in the input stream. In other words, use this
+feature with care. Manually screening the resulting dictionary is almost
+always a necessity.
+
+As for the actual operation: the library stores tokens, without any deduping,
+by appending them to a file specified via AFL_TOKEN_FILE. If the variable is not
+set, the tool uses stderr (which is probably not what you want).
+
+Similarly to afl-tmin, the library is not "proprietary" and can be used with
+other fuzzers or testing tools without the need for any code tweaks. It does not
+require AFL-instrumented binaries to work.
+
+To use the library, you *need* to make sure that your fuzzing target is compiled
+with -fno-builtin and is linked dynamically. If you wish to automate the first
+part without mucking with CFLAGS in Makefiles, you can set `AFL_NO_BUILTIN=1`
+when using afl-gcc. This setting specifically adds the following flags:
+
+```
+ -fno-builtin-strcmp -fno-builtin-strncmp -fno-builtin-strcasecmp
+ -fno-builtin-strcasencmp -fno-builtin-memcmp -fno-builtin-strstr
+ -fno-builtin-strcasestr
+```
+
+The next step is to load this library via LD_PRELOAD. The optimal usage pattern
+is to allow afl-fuzz to fuzz normally for a while and build up a corpus, and
+then fire off the target binary, with libtokencap.so loaded, on every file found
+by AFL++ in that earlier run. This demonstrates the basic principle:
+
+```
+ export AFL_TOKEN_FILE=$PWD/temp_output.txt
+
+ for i in <out_dir>/queue/id*; do
+ LD_PRELOAD=/path/to/libtokencap.so \
+ /path/to/target/program [...params, including $i...]
+ done
+
+ sort -u temp_output.txt >afl_dictionary.txt
+```
+
+If you don't get any results, the target library is probably not using strcmp()
+and memcmp() to parse input; or you haven't compiled it with -fno-builtin; or
+the whole thing isn't dynamically linked, and LD_PRELOAD is having no effect.
+
+Portability hints: There is probably no particularly portable and non-invasive
+way to distinguish between read-only and read-write memory mappings.
+The `__tokencap_load_mappings()` function is the only thing that would
+need to be changed for other OSes.
+
+Current supported OSes are: Linux, Darwin, FreeBSD (thanks to @devnexen)
+
diff --git a/utils/libtokencap/libtokencap.so.c b/utils/libtokencap/libtokencap.so.c
new file mode 100644
index 00000000..71c30eed
--- /dev/null
+++ b/utils/libtokencap/libtokencap.so.c
@@ -0,0 +1,798 @@
+/*
+
+ american fuzzy lop++ - extract tokens passed to strcmp / memcmp
+ -------------------------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Copyright 2016 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ This Linux-only companion library allows you to instrument strcmp(),
+ memcmp(), and related functions to automatically extract tokens.
+ See README.tokencap.md for more info.
+
+ */
+
+#ifndef _GNU_SOURCE
+ #define _GNU_SOURCE
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdbool.h>
+
+#include "../types.h"
+#include "../config.h"
+
+#include "debug.h"
+
+#if !defined __linux__ && !defined __APPLE__ && !defined __FreeBSD__ && \
+ !defined __OpenBSD__ && !defined __NetBSD__ && !defined __DragonFly__ && \
+ !defined(__HAIKU__) && !defined(__sun)
+ #error "Sorry, this library is unsupported in this platform for now!"
+#endif /* !__linux__ && !__APPLE__ && ! __FreeBSD__ && ! __OpenBSD__ && \
+ !__NetBSD__*/
+
+#if defined __APPLE__
+ #include <mach/vm_map.h>
+ #include <mach/mach_init.h>
+#elif defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__
+ #include <sys/types.h>
+ #include <sys/sysctl.h>
+ #if !defined __NetBSD__
+ #include <sys/user.h>
+ #endif
+ #include <sys/mman.h>
+#elif defined __HAIKU__
+ #include <kernel/image.h>
+#elif defined __sun
+ /* For map addresses the old struct is enough */
+ #include <sys/procfs.h>
+ #include <limits.h>
+#endif
+
+#include <dlfcn.h>
+
+#ifdef RTLD_NEXT
+/* The libc functions are a magnitude faster than our replacements.
+ Use them when RTLD_NEXT is available. */
+int (*__libc_strcmp)(const char *str1, const char *str2);
+int (*__libc_strncmp)(const char *str1, const char *str2, size_t len);
+int (*__libc_strcasecmp)(const char *str1, const char *str2);
+int (*__libc_strncasecmp)(const char *str1, const char *str2, size_t len);
+int (*__libc_memcmp)(const void *mem1, const void *mem2, size_t len);
+int (*__libc_bcmp)(const void *mem1, const void *mem2, size_t len);
+char *(*__libc_strstr)(const char *haystack, const char *needle);
+char *(*__libc_strcasestr)(const char *haystack, const char *needle);
+void *(*__libc_memmem)(const void *haystack, size_t haystack_len,
+ const void *needle, size_t needle_len);
+#endif
+
+/* Mapping data and such */
+
+#define MAX_MAPPINGS 1024
+
+static struct mapping { void *st, *en; } __tokencap_ro[MAX_MAPPINGS];
+
+static u32 __tokencap_ro_cnt;
+static u8 __tokencap_ro_loaded;
+static int __tokencap_out_file = -1;
+static pid_t __tokencap_pid = -1;
+
+/* Identify read-only regions in memory. Only parameters that fall into these
+ ranges are worth dumping when passed to strcmp() and so on. Read-write
+ regions are far more likely to contain user input instead. */
+
+static void __tokencap_load_mappings(void) {
+
+#if defined __linux__
+
+ u8 buf[MAX_LINE];
+ FILE *f = fopen("/proc/self/maps", "r");
+
+ __tokencap_ro_loaded = 1;
+
+ if (!f) return;
+
+ while (fgets(buf, MAX_LINE, f)) {
+
+ u8 rf, wf;
+ void *st, *en;
+
+ if (sscanf(buf, "%p-%p %c%c", &st, &en, &rf, &wf) != 4) continue;
+ if (wf == 'w' || rf != 'r') continue;
+
+ __tokencap_ro[__tokencap_ro_cnt].st = (void *)st;
+ __tokencap_ro[__tokencap_ro_cnt].en = (void *)en;
+
+ if (++__tokencap_ro_cnt == MAX_MAPPINGS) break;
+
+ }
+
+ fclose(f);
+
+#elif defined __APPLE__
+
+ struct vm_region_submap_info_64 region;
+ mach_msg_type_number_t cnt = VM_REGION_SUBMAP_INFO_COUNT_64;
+ vm_address_t base = 0;
+ vm_size_t size = 0;
+ natural_t depth = 0;
+
+ __tokencap_ro_loaded = 1;
+
+ while (1) {
+
+ if (vm_region_recurse_64(mach_task_self(), &base, &size, &depth,
+ (vm_region_info_64_t)&region,
+ &cnt) != KERN_SUCCESS)
+ break;
+
+ if (region.is_submap) {
+
+ depth++;
+
+ } else {
+
+ /* We only care of main map addresses and the read only kinds */
+ if ((region.protection & VM_PROT_READ) &&
+ !(region.protection & VM_PROT_WRITE)) {
+
+ __tokencap_ro[__tokencap_ro_cnt].st = (void *)base;
+ __tokencap_ro[__tokencap_ro_cnt].en = (void *)(base + size);
+
+ if (++__tokencap_ro_cnt == MAX_MAPPINGS) break;
+
+ }
+
+ base += size;
+ size = 0;
+
+ }
+
+ }
+
+#elif defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__
+
+ #if defined __FreeBSD__
+ int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, __tokencap_pid};
+ #elif defined __OpenBSD__
+ int mib[] = {CTL_KERN, KERN_PROC_VMMAP, __tokencap_pid};
+ #elif defined __NetBSD__
+ int mib[] = {CTL_VM, VM_PROC, VM_PROC_MAP, __tokencap_pid,
+ sizeof(struct kinfo_vmentry)};
+ #endif
+ char * buf, *low, *high;
+ size_t miblen = sizeof(mib) / sizeof(mib[0]);
+ size_t len;
+
+ if (sysctl(mib, miblen, NULL, &len, NULL, 0) == -1) return;
+
+ #if defined __FreeBSD__ || defined __NetBSD__
+ len = len * 4 / 3;
+ #elif defined __OpenBSD__
+ len -= len % sizeof(struct kinfo_vmentry);
+ #endif
+
+ buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
+ if (buf == MAP_FAILED) return;
+
+ if (sysctl(mib, miblen, buf, &len, NULL, 0) == -1) {
+
+ munmap(buf, len);
+ return;
+
+ }
+
+ low = buf;
+ high = low + len;
+
+ __tokencap_ro_loaded = 1;
+
+ while (low < high) {
+
+ struct kinfo_vmentry *region = (struct kinfo_vmentry *)low;
+
+ #if defined __FreeBSD__ || defined __NetBSD__
+
+ #if defined __FreeBSD__
+ size_t size = region->kve_structsize;
+
+ if (size == 0) break;
+ #elif defined __NetBSD__
+ size_t size = sizeof(*region);
+ #endif
+
+ /* We go through the whole mapping of the process and track read-only
+ * addresses */
+ if ((region->kve_protection & KVME_PROT_READ) &&
+ !(region->kve_protection & KVME_PROT_WRITE)) {
+
+ #elif defined __OpenBSD__
+
+ size_t size = sizeof(*region);
+
+ /* We go through the whole mapping of the process and track read-only
+ * addresses */
+ if ((region->kve_protection & KVE_PROT_READ) &&
+ !(region->kve_protection & KVE_PROT_WRITE)) {
+
+ #endif
+ __tokencap_ro[__tokencap_ro_cnt].st = (void *)region->kve_start;
+ __tokencap_ro[__tokencap_ro_cnt].en = (void *)region->kve_end;
+
+ if (++__tokencap_ro_cnt == MAX_MAPPINGS) break;
+
+ }
+
+ low += size;
+
+ }
+
+ munmap(buf, len);
+#elif defined __HAIKU__
+ image_info ii;
+ int32_t group = 0;
+
+ __tokencap_ro_loaded = 1;
+
+ while (get_next_image_info(0, &group, &ii) == B_OK) {
+
+ __tokencap_ro[__tokencap_ro_cnt].st = ii.text;
+ __tokencap_ro[__tokencap_ro_cnt].en = ((char *)ii.text) + ii.text_size;
+
+ if (++__tokencap_ro_cnt == MAX_MAPPINGS) break;
+
+ }
+
+#elif defined __sun
+ prmap_t *c, *map;
+ char path[PATH_MAX];
+ ssize_t r;
+ size_t hint;
+ int fd;
+
+ snprintf(path, sizeof(path), "/proc/%ld/map", getpid());
+ fd = open(path, O_RDONLY);
+ hint = (1 << 20);
+ map = malloc(hint);
+
+ __tokencap_ro_loaded = 1;
+
+ for (; (r = pread(fd, map, hint, 0)) == hint;) {
+
+ hint <<= 1;
+ map = realloc(map, hint);
+
+ }
+
+ for (c = map; r > 0; c++, r -= sizeof(prmap_t)) {
+
+ __tokencap_ro[__tokencap_ro_cnt].st = (void *)c->pr_vaddr;
+ __tokencap_ro[__tokencap_ro_cnt].en = (void *)(c->pr_vaddr + c->pr_size);
+
+ if (++__tokencap_ro_cnt == MAX_MAPPINGS) break;
+
+ }
+
+ free(map);
+ close(fd);
+#endif
+
+}
+
+/* Check an address against the list of read-only mappings. */
+
+static u8 __tokencap_is_ro(const void *ptr) {
+
+ u32 i;
+
+ if (!__tokencap_ro_loaded) __tokencap_load_mappings();
+
+ for (i = 0; i < __tokencap_ro_cnt; i++)
+ if (ptr >= __tokencap_ro[i].st && ptr <= __tokencap_ro[i].en) return 1;
+
+ return 0;
+
+}
+
+/* Dump an interesting token to output file, quoting and escaping it
+ properly. */
+
+static void __tokencap_dump(const u8 *ptr, size_t len, u8 is_text) {
+
+ u8 buf[MAX_AUTO_EXTRA * 4 + 1];
+ u32 i;
+ u32 pos = 0;
+
+ if (len < MIN_AUTO_EXTRA || len > MAX_AUTO_EXTRA || __tokencap_out_file == -1)
+ return;
+
+ for (i = 0; i < len; i++) {
+
+ if (is_text && !ptr[i]) break;
+
+ switch (ptr[i]) {
+
+ case 0 ... 31:
+ case 127 ... 255:
+ case '\"':
+ case '\\':
+
+ sprintf(buf + pos, "\\x%02x", ptr[i]);
+ pos += 4;
+ break;
+
+ default:
+ buf[pos++] = ptr[i];
+
+ }
+
+ }
+
+ buf[pos] = 0;
+
+ int wrt_ok = (1 == write(__tokencap_out_file, "\"", 1));
+ wrt_ok &= (pos == write(__tokencap_out_file, buf, pos));
+ wrt_ok &= (2 == write(__tokencap_out_file, "\"\n", 2));
+
+ if (!wrt_ok) { DEBUGF("%s", "writing to the token file failed\n"); }
+
+}
+
+/* Replacements for strcmp(), memcmp(), and so on. Note that these will be used
+ only if the target is compiled with -fno-builtins and linked dynamically. */
+
+#undef strcmp
+
+int strcmp(const char *str1, const char *str2) {
+
+ if (__tokencap_is_ro(str1)) __tokencap_dump(str1, strlen(str1), 1);
+ if (__tokencap_is_ro(str2)) __tokencap_dump(str2, strlen(str2), 1);
+
+#ifdef RTLD_NEXT
+ if (__libc_strcmp) return __libc_strcmp(str1, str2);
+#endif
+
+ while (1) {
+
+ const unsigned char c1 = *str1, c2 = *str2;
+
+ if (c1 != c2) return (c1 > c2) ? 1 : -1;
+ if (!c1) return 0;
+ str1++;
+ str2++;
+
+ }
+
+}
+
+#undef strncmp
+
+int strncmp(const char *str1, const char *str2, size_t len) {
+
+ if (__tokencap_is_ro(str1)) __tokencap_dump(str1, len, 1);
+ if (__tokencap_is_ro(str2)) __tokencap_dump(str2, len, 1);
+
+#ifdef RTLD_NEXT
+ if (__libc_strncmp) return __libc_strncmp(str1, str2, len);
+#endif
+
+ while (len--) {
+
+ unsigned char c1 = *str1, c2 = *str2;
+
+ if (c1 != c2) return (c1 > c2) ? 1 : -1;
+ if (!c1) return 0;
+ str1++;
+ str2++;
+
+ }
+
+ return 0;
+
+}
+
+#undef strcasecmp
+
+int strcasecmp(const char *str1, const char *str2) {
+
+ if (__tokencap_is_ro(str1)) __tokencap_dump(str1, strlen(str1), 1);
+ if (__tokencap_is_ro(str2)) __tokencap_dump(str2, strlen(str2), 1);
+
+#ifdef RTLD_NEXT
+ if (__libc_strcasecmp) return __libc_strcasecmp(str1, str2);
+#endif
+
+ while (1) {
+
+ const unsigned char c1 = tolower((int)*str1), c2 = tolower((int)*str2);
+
+ if (c1 != c2) return (c1 > c2) ? 1 : -1;
+ if (!c1) return 0;
+ str1++;
+ str2++;
+
+ }
+
+}
+
+#undef strncasecmp
+
+int strncasecmp(const char *str1, const char *str2, size_t len) {
+
+ if (__tokencap_is_ro(str1)) __tokencap_dump(str1, len, 1);
+ if (__tokencap_is_ro(str2)) __tokencap_dump(str2, len, 1);
+
+#ifdef RTLD_NEXT
+ if (__libc_strncasecmp) return __libc_strncasecmp(str1, str2, len);
+#endif
+
+ while (len--) {
+
+ const unsigned char c1 = tolower((int)*str1), c2 = tolower((int)*str2);
+
+ if (c1 != c2) return (c1 > c2) ? 1 : -1;
+ if (!c1) return 0;
+ str1++;
+ str2++;
+
+ }
+
+ return 0;
+
+}
+
+#undef memcmp
+
+int memcmp(const void *mem1, const void *mem2, size_t len) {
+
+ if (__tokencap_is_ro(mem1)) __tokencap_dump(mem1, len, 0);
+ if (__tokencap_is_ro(mem2)) __tokencap_dump(mem2, len, 0);
+
+#ifdef RTLD_NEXT
+ if (__libc_memcmp) return __libc_memcmp(mem1, mem2, len);
+#endif
+
+ const char *strmem1 = (const char *)mem1;
+ const char *strmem2 = (const char *)mem2;
+
+ while (len--) {
+
+ const unsigned char c1 = *strmem1, c2 = *strmem2;
+ if (c1 != c2) return (c1 > c2) ? 1 : -1;
+ strmem1++;
+ strmem2++;
+
+ }
+
+ return 0;
+
+}
+
+#undef bcmp
+
+int bcmp(const void *mem1, const void *mem2, size_t len) {
+
+ if (__tokencap_is_ro(mem1)) __tokencap_dump(mem1, len, 0);
+ if (__tokencap_is_ro(mem2)) __tokencap_dump(mem2, len, 0);
+
+#ifdef RTLD_NEXT
+ if (__libc_bcmp) return __libc_bcmp(mem1, mem2, len);
+#endif
+
+ const char *strmem1 = (const char *)mem1;
+ const char *strmem2 = (const char *)mem2;
+
+ while (len--) {
+
+ int diff = *strmem1 ^ *strmem2;
+ if (diff != 0) return 1;
+ strmem1++;
+ strmem2++;
+
+ }
+
+ return 0;
+
+}
+
+#undef strstr
+
+char *strstr(const char *haystack, const char *needle) {
+
+ if (__tokencap_is_ro(haystack))
+ __tokencap_dump(haystack, strlen(haystack), 1);
+
+ if (__tokencap_is_ro(needle)) __tokencap_dump(needle, strlen(needle), 1);
+
+#ifdef RTLD_NEXT
+ if (__libc_strstr) return __libc_strstr(haystack, needle);
+#endif
+
+ do {
+
+ const char *n = needle;
+ const char *h = haystack;
+
+ while (*n && *h && *n == *h)
+ n++, h++;
+
+ if (!*n) return (char *)haystack;
+
+ } while (*(haystack++));
+
+ return 0;
+
+}
+
+#undef strcasestr
+
+char *strcasestr(const char *haystack, const char *needle) {
+
+ if (__tokencap_is_ro(haystack))
+ __tokencap_dump(haystack, strlen(haystack), 1);
+
+ if (__tokencap_is_ro(needle)) __tokencap_dump(needle, strlen(needle), 1);
+
+#ifdef RTLD_NEXT
+ if (__libc_strcasestr) return __libc_strcasestr(haystack, needle);
+#endif
+
+ do {
+
+ const char *n = needle;
+ const char *h = haystack;
+
+ while (*n && *h && tolower((int)*n) == tolower((int)*h))
+ n++, h++;
+
+ if (!*n) return (char *)haystack;
+
+ } while (*(haystack++));
+
+ return 0;
+
+}
+
+#undef memmem
+
+void *memmem(const void *haystack, size_t haystack_len, const void *needle,
+ size_t needle_len) {
+
+ if (__tokencap_is_ro(haystack)) __tokencap_dump(haystack, haystack_len, 1);
+
+ if (__tokencap_is_ro(needle)) __tokencap_dump(needle, needle_len, 1);
+
+#ifdef RTLD_NEXT
+ if (__libc_memmem)
+ return __libc_memmem(haystack, haystack_len, needle, needle_len);
+#endif
+
+ const char *n = (const char *)needle;
+ const char *h = (const char *)haystack;
+ if (haystack_len < needle_len) return 0;
+ if (needle_len == 0) return (void *)haystack;
+ if (needle_len == 1) return memchr(haystack, *n, haystack_len);
+
+ const char *end = h + (haystack_len - needle_len);
+
+ do {
+
+ if (*h == *n) {
+
+ if (memcmp(h, n, needle_len) == 0) return (void *)h;
+
+ }
+
+ } while (h++ <= end);
+
+ return 0;
+
+}
+
+/* Common libraries wrappers (from honggfuzz) */
+
+/*
+ * Apache's httpd wrappers
+ */
+int ap_cstr_casecmp(const char *s1, const char *s2) {
+
+ return strcasecmp(s1, s2);
+
+}
+
+int ap_cstr_casecmpn(const char *s1, const char *s2, size_t n) {
+
+ return strncasecmp(s1, s2, n);
+
+}
+
+const char *ap_strcasestr(const char *s1, const char *s2) {
+
+ return strcasestr(s1, s2);
+
+}
+
+int apr_cstr_casecmp(const char *s1, const char *s2) {
+
+ return strcasecmp(s1, s2);
+
+}
+
+int apr_cstr_casecmpn(const char *s1, const char *s2, size_t n) {
+
+ return strncasecmp(s1, s2, n);
+
+}
+
+/*
+ * *SSL wrappers
+ */
+int CRYPTO_memcmp(const void *m1, const void *m2, size_t len) {
+
+ return memcmp(m1, m2, len);
+
+}
+
+int OPENSSL_memcmp(const void *m1, const void *m2, size_t len) {
+
+ return memcmp(m1, m2, len);
+
+}
+
+int OPENSSL_strcasecmp(const char *s1, const char *s2) {
+
+ return strcasecmp(s1, s2);
+
+}
+
+int OPENSSL_strncasecmp(const char *s1, const char *s2, size_t len) {
+
+ return strncasecmp(s1, s2, len);
+
+}
+
+int32_t memcmpct(const void *s1, const void *s2, size_t len) {
+
+ return memcmp(s1, s2, len);
+
+}
+
+/*
+ * libXML wrappers
+ */
+int xmlStrncmp(const char *s1, const char *s2, int len) {
+
+ if (len <= 0) { return 0; }
+ if (s1 == s2) { return 0; }
+ if (s1 == NULL) { return -1; }
+ if (s2 == NULL) { return 1; }
+ return strncmp(s1, s2, (size_t)len);
+
+}
+
+int xmlStrcmp(const char *s1, const char *s2) {
+
+ if (s1 == s2) { return 0; }
+ if (s1 == NULL) { return -1; }
+ if (s2 == NULL) { return 1; }
+ return strcmp(s1, s2);
+
+}
+
+int xmlStrEqual(const char *s1, const char *s2) {
+
+ if (s1 == s2) { return 1; }
+ if (s1 == NULL) { return 0; }
+ if (s2 == NULL) { return 0; }
+ if (strcmp(s1, s2) == 0) { return 1; }
+ return 0;
+
+}
+
+int xmlStrcasecmp(const char *s1, const char *s2) {
+
+ if (s1 == s2) { return 0; }
+ if (s1 == NULL) { return -1; }
+ if (s2 == NULL) { return 1; }
+ return strcasecmp(s1, s2);
+
+}
+
+int xmlStrncasecmp(const char *s1, const char *s2, int len) {
+
+ if (len <= 0) { return 0; }
+ if (s1 == s2) { return 0; }
+ if (s1 == NULL) { return -1; }
+ if (s2 == NULL) { return 1; }
+ return strncasecmp(s1, s2, (size_t)len);
+
+}
+
+const char *xmlStrstr(const char *haystack, const char *needle) {
+
+ if (haystack == NULL) { return NULL; }
+ if (needle == NULL) { return NULL; }
+ return strstr(haystack, needle);
+
+}
+
+const char *xmlStrcasestr(const char *haystack, const char *needle) {
+
+ if (haystack == NULL) { return NULL; }
+ if (needle == NULL) { return NULL; }
+ return strcasestr(haystack, needle);
+
+}
+
+/*
+ * Samba wrappers
+ */
+int memcmp_const_time(const void *s1, const void *s2, size_t n) {
+
+ return memcmp(s1, s2, n);
+
+}
+
+bool strcsequal(const void *s1, const void *s2) {
+
+ if (s1 == s2) { return true; }
+ if (!s1 || !s2) { return false; }
+ return (strcmp(s1, s2) == 0);
+
+}
+
+/* bcmp/memcmp BSD flavors, similar to CRYPTO_memcmp */
+
+int timingsafe_bcmp(const void *mem1, const void *mem2, size_t len) {
+
+ return bcmp(mem1, mem2, len);
+
+}
+
+int timingsafe_memcmp(const void *mem1, const void *mem2, size_t len) {
+
+ return memcmp(mem1, mem2, len);
+
+}
+
+/* Init code to open the output file (or default to stderr). */
+
+__attribute__((constructor)) void __tokencap_init(void) {
+
+ u8 *fn = getenv("AFL_TOKEN_FILE");
+ if (fn) __tokencap_out_file = open(fn, O_RDWR | O_CREAT | O_APPEND, 0655);
+ if (__tokencap_out_file == -1) __tokencap_out_file = STDERR_FILENO;
+ __tokencap_pid = getpid();
+
+#ifdef RTLD_NEXT
+ __libc_strcmp = dlsym(RTLD_NEXT, "strcmp");
+ __libc_strncmp = dlsym(RTLD_NEXT, "strncmp");
+ __libc_strcasecmp = dlsym(RTLD_NEXT, "strcasecmp");
+ __libc_strncasecmp = dlsym(RTLD_NEXT, "strncasecmp");
+ __libc_memcmp = dlsym(RTLD_NEXT, "memcmp");
+ __libc_bcmp = dlsym(RTLD_NEXT, "bcmp");
+ __libc_strstr = dlsym(RTLD_NEXT, "strstr");
+ __libc_strcasestr = dlsym(RTLD_NEXT, "strcasestr");
+ __libc_memmem = dlsym(RTLD_NEXT, "memmem");
+#endif
+
+}
+
+/* closing as best as we can the tokens file */
+__attribute__((destructor)) void __tokencap_shutdown(void) {
+
+ if (__tokencap_out_file != STDERR_FILENO) close(__tokencap_out_file);
+
+}
+
diff --git a/utils/persistent_mode/Makefile b/utils/persistent_mode/Makefile
new file mode 100644
index 00000000..e348c46c
--- /dev/null
+++ b/utils/persistent_mode/Makefile
@@ -0,0 +1,10 @@
+all:
+ ../../afl-clang-fast -o persistent_demo persistent_demo.c
+ ../../afl-clang-fast -o persistent_demo_new persistent_demo_new.c
+ AFL_DONT_OPTIMIZE=1 ../../afl-clang-fast -o test-instr test-instr.c
+
+document:
+ AFL_DONT_OPTIMIZE=1 ../../afl-clang-fast -D_AFL_DOCUMENT_MUTATIONS -o test-instr test-instr.c
+
+clean:
+ rm -f persistent_demo persistent_demo_new test-instr
diff --git a/utils/persistent_mode/persistent_demo.c b/utils/persistent_mode/persistent_demo.c
new file mode 100644
index 00000000..f5e43728
--- /dev/null
+++ b/utils/persistent_mode/persistent_demo.c
@@ -0,0 +1,118 @@
+/*
+ american fuzzy lop++ - persistent mode example
+ --------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Copyright 2015 Google Inc. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ This file demonstrates the high-performance "persistent mode" that may be
+ suitable for fuzzing certain fast and well-behaved libraries, provided that
+ they are stateless or that their internal state can be easily reset
+ across runs.
+
+ To make this work, the library and this shim need to be compiled in LLVM
+ mode using afl-clang-fast (other compiler wrappers will *not* work).
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <limits.h>
+
+/* Main entry point. */
+
+/* To ensure checks are not optimized out it is recommended to disable
+ code optimization for the fuzzer harness main() */
+#pragma clang optimize off
+#pragma GCC optimize("O0")
+
+int main(int argc, char **argv) {
+
+ ssize_t len; /* how much input did we read? */
+ char buf[100]; /* Example-only buffer, you'd replace it with other global or
+ local variables appropriate for your use case. */
+
+ /* The number passed to __AFL_LOOP() controls the maximum number of
+ iterations before the loop exits and the program is allowed to
+ terminate normally. This limits the impact of accidental memory leaks
+ and similar hiccups. */
+
+ __AFL_INIT();
+ while (__AFL_LOOP(UINT_MAX)) {
+
+ /*** PLACEHOLDER CODE ***/
+
+ /* STEP 1: Fully re-initialize all critical variables. In our example, this
+ involves zeroing buf[], our input buffer. */
+
+ memset(buf, 0, 100);
+
+ /* STEP 2: Read input data. When reading from stdin, no special preparation
+ is required. When reading from a named file, you need to close
+ the old descriptor and reopen the file first!
+
+ Beware of reading from buffered FILE* objects such as stdin. Use
+ raw file descriptors or call fopen() / fdopen() in every pass. */
+
+ len = read(0, buf, 100);
+
+ /* STEP 3: This is where we'd call the tested library on the read data.
+ We just have some trivial inline code that faults on 'foo!'. */
+
+ /* do we have enough data? */
+ if (len < 8) continue;
+
+ if (buf[0] == 'f') {
+
+ printf("one\n");
+ if (buf[1] == 'o') {
+
+ printf("two\n");
+ if (buf[2] == 'o') {
+
+ printf("three\n");
+ if (buf[3] == '!') {
+
+ printf("four\n");
+ if (buf[4] == '!') {
+
+ printf("five\n");
+ if (buf[5] == '!') {
+
+ printf("six\n");
+ abort();
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ /*** END PLACEHOLDER CODE ***/
+
+ }
+
+ /* Once the loop is exited, terminate normally - AFL will restart the process
+ when this happens, with a clean slate when it comes to allocated memory,
+ leftover file descriptors, etc. */
+
+ return 0;
+
+}
+
diff --git a/utils/persistent_mode/persistent_demo_new.c b/utils/persistent_mode/persistent_demo_new.c
new file mode 100644
index 00000000..285f50aa
--- /dev/null
+++ b/utils/persistent_mode/persistent_demo_new.c
@@ -0,0 +1,123 @@
+/*
+ american fuzzy lop++ - persistent mode example
+ --------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Copyright 2015 Google Inc. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ This file demonstrates the high-performance "persistent mode" that may be
+ suitable for fuzzing certain fast and well-behaved libraries, provided that
+ they are stateless or that their internal state can be easily reset
+ across runs.
+
+ To make this work, the library and this shim need to be compiled in LLVM
+ mode using afl-clang-fast (other compiler wrappers will *not* work).
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <limits.h>
+
+/* this lets the source compile without afl-clang-fast/lto */
+#ifndef __AFL_FUZZ_TESTCASE_LEN
+
+ssize_t fuzz_len;
+unsigned char fuzz_buf[1024000];
+
+ #define __AFL_FUZZ_TESTCASE_LEN fuzz_len
+ #define __AFL_FUZZ_TESTCASE_BUF fuzz_buf
+ #define __AFL_FUZZ_INIT() void sync(void);
+ #define __AFL_LOOP(x) \
+ ((fuzz_len = read(0, fuzz_buf, sizeof(fuzz_buf))) > 0 ? 1 : 0)
+ #define __AFL_INIT() sync()
+
+#endif
+
+__AFL_FUZZ_INIT();
+
+/* Main entry point. */
+
+/* To ensure checks are not optimized out it is recommended to disable
+ code optimization for the fuzzer harness main() */
+#pragma clang optimize off
+#pragma GCC optimize("O0")
+
+int main(int argc, char **argv) {
+
+ ssize_t len; /* how much input did we read? */
+ unsigned char *buf; /* test case buffer pointer */
+
+ /* The number passed to __AFL_LOOP() controls the maximum number of
+ iterations before the loop exits and the program is allowed to
+ terminate normally. This limits the impact of accidental memory leaks
+ and similar hiccups. */
+
+ __AFL_INIT();
+ buf = __AFL_FUZZ_TESTCASE_BUF; // this must be assigned before __AFL_LOOP!
+
+ while (__AFL_LOOP(UINT_MAX)) { // increase if you have good stability
+
+ len = __AFL_FUZZ_TESTCASE_LEN; // do not use the macro directly in a call!
+
+ // fprintf(stderr, "input: %zd \"%s\"\n", len, buf);
+
+ /* do we have enough data? */
+ if (len < 8) continue;
+
+ if (strcmp((char *)buf, "thisisateststring") == 0) printf("teststring\n");
+
+ if (buf[0] == 'f') {
+
+ printf("one\n");
+ if (buf[1] == 'o') {
+
+ printf("two\n");
+ if (buf[2] == 'o') {
+
+ printf("three\n");
+ if (buf[3] == '!') {
+
+ printf("four\n");
+ if (buf[4] == '!') {
+
+ printf("five\n");
+ if (buf[5] == '!') {
+
+ printf("six\n");
+ abort();
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ /*** END PLACEHOLDER CODE ***/
+
+ }
+
+ /* Once the loop is exited, terminate normally - AFL will restart the process
+ when this happens, with a clean slate when it comes to allocated memory,
+ leftover file descriptors, etc. */
+
+ return 0;
+
+}
+
diff --git a/utils/persistent_mode/test-instr.c b/utils/persistent_mode/test-instr.c
new file mode 100644
index 00000000..168aa429
--- /dev/null
+++ b/utils/persistent_mode/test-instr.c
@@ -0,0 +1,75 @@
+/*
+ american fuzzy lop++ - a trivial program to test the build
+ --------------------------------------------------------
+ Originally written by Michal Zalewski
+ Copyright 2014 Google Inc. All rights reserved.
+ Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+ http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <limits.h>
+
+__AFL_FUZZ_INIT();
+
+/* To ensure checks are not optimized out it is recommended to disable
+ code optimization for the fuzzer harness main() */
+#pragma clang optimize off
+#pragma GCC optimize("O0")
+
+int main(int argc, char **argv) {
+
+ __AFL_INIT();
+ unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF;
+
+ while (__AFL_LOOP(UINT_MAX)) { // if you have 100% stability
+
+ unsigned int len = __AFL_FUZZ_TESTCASE_LEN;
+
+#ifdef _AFL_DOCUMENT_MUTATIONS
+ static unsigned int counter = 0;
+ char fn[32];
+ sprintf(fn, "%09u:test-instr", counter);
+ int fd_doc = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ if (fd_doc >= 0) {
+
+ if (write(fd_doc, buf, len) != __afl_fuzz_len) {
+
+ fprintf(stderr, "write of mutation file failed: %s\n", fn);
+ unlink(fn);
+
+ }
+
+ close(fd_doc);
+
+ }
+
+ counter++;
+#endif
+
+ // fprintf(stderr, "len: %u\n", len);
+
+ if (!len) continue;
+
+ if (buf[0] == '0')
+ printf("Looks like a zero to me!\n");
+ else if (buf[0] == '1')
+ printf("Pretty sure that is a one!\n");
+ else
+ printf("Neither one or zero? How quaint!\n");
+
+ }
+
+ return 0;
+
+}
+
diff --git a/utils/plot_ui/Makefile b/utils/plot_ui/Makefile
new file mode 100644
index 00000000..b2013248
--- /dev/null
+++ b/utils/plot_ui/Makefile
@@ -0,0 +1,10 @@
+CFLAGS=`pkg-config --cflags gtk+-3.0`
+LDFLAGS=`pkg-config --libs gtk+-3.0`
+
+all: afl-plot-ui
+
+afl-plot-ui: afl-plot-ui.c
+ $(CC) $(CFLAGS) -o afl-plot-ui afl-plot-ui.c $(LDFLAGS)
+
+clean:
+ rm -f afl-plot-ui
diff --git a/utils/plot_ui/README.md b/utils/plot_ui/README.md
new file mode 100644
index 00000000..145ec219
--- /dev/null
+++ b/utils/plot_ui/README.md
@@ -0,0 +1,15 @@
+# afl-plot-ui
+
+`afl-plot-ui` is a helper utility for rendering the GNUplot graphs in a GTK window. This allows to real time resizing, scrolling, and cursor positioning features while viewing the graph. This utility also provides options to hide graphs using check buttons.
+
+Currently, this utility is not built by default.
+You can manually build and install `afl-plot-ui` as follows
+
+```shell
+sudo apt install libgtk-3-0 libgtk-3-dev pkg-config
+make
+cd ../../
+sudo make install
+```
+
+*NOTE:* This utility is not meant to be used standalone. Never run this utility directly. Always run [`afl-plot`](../../afl-plot), which will, in turn, invoke this utility (when run using `-g` or `--graphical` flag). \ No newline at end of file
diff --git a/utils/plot_ui/afl-plot-ui.c b/utils/plot_ui/afl-plot-ui.c
new file mode 100644
index 00000000..56f0c006
--- /dev/null
+++ b/utils/plot_ui/afl-plot-ui.c
@@ -0,0 +1,173 @@
+#include <gtk/gtk.h>
+#include <gtk/gtkx.h>
+#include <stdio.h>
+#include <string.h>
+
+char USAGE[] =
+ "is a helper utility for rendering the GNUplot graphs in a GTK window. This allows to real time resizing, scrolling, and cursor positioning features while viewing the graph. This utility also provides options to hide graphs using check buttons.\n \
+\n \
+Usage:\n \
+ -h, --help Show this help menu\n \
+\n \
+NOTE: This utility is not meant to be used standalone. Never run this utility directly. Always run afl-plot, which will, in turn, invoke this utility (when run using `-g` or `--graphical` flag).\n \
+";
+
+static void plot_toggled(GtkWidget *caller, gpointer data);
+
+int main(int argc, char **argv) {
+
+ if (argc == 2 && (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "-help"))) {
+
+ printf("%s %s", argv[0], USAGE);
+ return EXIT_SUCCESS;
+
+ }
+
+ GtkWidget *window;
+ GtkWidget *main_vbox;
+
+ GtkWidget *cbuttons_frame;
+ GtkWidget *cbuttons_hbox;
+
+ GtkWidget *separator_top;
+ GtkWidget *pane1, *pane2, *pane3;
+
+ GtkWidget *plots_vbox;
+ GtkWidget *plot_edges_frame, *plot_exec_speed_frame, *plot_high_freq_frame,
+ *plot_low_freq_frame;
+ GtkWidget *plot_edges, *plot_exec_speed, *plot_high_freq, *plot_low_freq;
+
+ gtk_init(&argc, &argv);
+
+ window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title(GTK_WINDOW(window), "Graph drawing");
+ gtk_container_set_border_width(GTK_CONTAINER(window), 10);
+
+ main_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
+
+ cbuttons_frame = gtk_frame_new("Select the plots");
+ gtk_container_set_border_width(GTK_CONTAINER(cbuttons_frame), 5);
+
+ cbuttons_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 1);
+
+ GtkWidget *cbutton_edges, *cbutton_exec_speed, *cbutton_high_freq,
+ *cbutton_low_freq;
+
+ cbutton_edges = gtk_check_button_new_with_label("Edges");
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cbutton_edges), TRUE);
+ g_signal_connect(cbutton_edges, "toggled", G_CALLBACK(plot_toggled),
+ &plot_edges_frame);
+
+ cbutton_exec_speed = gtk_check_button_new_with_label("Execution Speed");
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cbutton_exec_speed), TRUE);
+ g_signal_connect(cbutton_exec_speed, "toggled", G_CALLBACK(plot_toggled),
+ &plot_exec_speed_frame);
+
+ cbutton_high_freq = gtk_check_button_new_with_label("High Frequency");
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cbutton_high_freq), TRUE);
+ g_signal_connect(cbutton_high_freq, "toggled", G_CALLBACK(plot_toggled),
+ &plot_high_freq_frame);
+
+ cbutton_low_freq = gtk_check_button_new_with_label("Low Frequency");
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cbutton_low_freq), TRUE);
+ g_signal_connect(cbutton_low_freq, "toggled", G_CALLBACK(plot_toggled),
+ &plot_low_freq_frame);
+
+ gtk_box_pack_start(GTK_BOX(cbuttons_hbox), cbutton_edges, TRUE, TRUE, 1);
+ gtk_box_pack_start(GTK_BOX(cbuttons_hbox), cbutton_exec_speed, TRUE, TRUE, 1);
+ gtk_box_pack_start(GTK_BOX(cbuttons_hbox), cbutton_high_freq, TRUE, TRUE, 1);
+ gtk_box_pack_start(GTK_BOX(cbuttons_hbox), cbutton_low_freq, TRUE, TRUE, 1);
+
+ gtk_container_add(GTK_CONTAINER(cbuttons_frame), cbuttons_hbox);
+ gtk_box_pack_start(GTK_BOX(main_vbox), cbuttons_frame, FALSE, TRUE, 1);
+
+ separator_top = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
+ gtk_box_pack_start(GTK_BOX(main_vbox), separator_top, FALSE, TRUE, 1);
+
+ plots_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
+
+ plot_edges_frame = gtk_frame_new("Edges");
+ gtk_frame_set_shadow_type(GTK_FRAME(plot_edges_frame), GTK_SHADOW_IN);
+ gtk_container_set_border_width(GTK_CONTAINER(plot_edges_frame), 10);
+ plot_edges = gtk_socket_new();
+ gtk_widget_set_size_request(plot_edges, -1, 100);
+ gtk_container_add(GTK_CONTAINER(plot_edges_frame), plot_edges);
+
+ plot_exec_speed_frame = gtk_frame_new("Exec Speed");
+ gtk_frame_set_shadow_type(GTK_FRAME(plot_exec_speed_frame), GTK_SHADOW_IN);
+ gtk_container_set_border_width(GTK_CONTAINER(plot_exec_speed_frame), 10);
+ plot_exec_speed = gtk_socket_new();
+ gtk_widget_set_size_request(plot_exec_speed, -1, 100);
+ gtk_container_add(GTK_CONTAINER(plot_exec_speed_frame), plot_exec_speed);
+
+ plot_high_freq_frame = gtk_frame_new("High Frequency");
+ gtk_frame_set_shadow_type(GTK_FRAME(plot_high_freq_frame), GTK_SHADOW_IN);
+ gtk_container_set_border_width(GTK_CONTAINER(plot_high_freq_frame), 10);
+ plot_high_freq = gtk_socket_new();
+ gtk_widget_set_size_request(plot_high_freq, -1, 100);
+ gtk_container_add(GTK_CONTAINER(plot_high_freq_frame), plot_high_freq);
+
+ plot_low_freq_frame = gtk_frame_new("Low Frequency");
+ gtk_frame_set_shadow_type(GTK_FRAME(plot_low_freq_frame), GTK_SHADOW_IN);
+ gtk_container_set_border_width(GTK_CONTAINER(plot_low_freq_frame), 10);
+ plot_low_freq = gtk_socket_new();
+ gtk_widget_set_size_request(plot_low_freq, -1, 100);
+ gtk_container_add(GTK_CONTAINER(plot_low_freq_frame), plot_low_freq);
+
+ pane1 = gtk_paned_new(GTK_ORIENTATION_VERTICAL);
+ pane2 = gtk_paned_new(GTK_ORIENTATION_VERTICAL);
+ pane3 = gtk_paned_new(GTK_ORIENTATION_VERTICAL);
+
+ gtk_paned_pack1(GTK_PANED(pane1), plot_edges_frame, TRUE, FALSE);
+ gtk_paned_pack2(GTK_PANED(pane1), plot_exec_speed_frame, TRUE, FALSE);
+
+ gtk_paned_pack1(GTK_PANED(pane2), pane1, TRUE, FALSE);
+ gtk_paned_pack2(GTK_PANED(pane2), plot_high_freq_frame, TRUE, FALSE);
+
+ gtk_paned_pack1(GTK_PANED(pane3), pane2, TRUE, FALSE);
+ gtk_paned_pack2(GTK_PANED(pane3), plot_low_freq_frame, TRUE, FALSE);
+
+ gtk_box_pack_start(GTK_BOX(plots_vbox), pane3, TRUE, TRUE, 0);
+
+ gtk_box_pack_start(GTK_BOX(main_vbox), plots_vbox, TRUE, TRUE, 1);
+
+ gtk_container_add(GTK_CONTAINER(window), main_vbox);
+
+ guint id_edges = gtk_socket_get_id(GTK_SOCKET(plot_edges));
+ guint id_exec_speed = gtk_socket_get_id(GTK_SOCKET(plot_exec_speed));
+ guint id_high_freq = gtk_socket_get_id(GTK_SOCKET(plot_high_freq));
+ guint id_low_freq = gtk_socket_get_id(GTK_SOCKET(plot_low_freq));
+
+ printf("%x\n%x\n%x\n%x\n", id_edges, id_exec_speed, id_high_freq,
+ id_low_freq);
+
+ fclose(stdout);
+
+ g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit),
+ NULL);
+ gtk_widget_show_all(window);
+ gtk_window_maximize(GTK_WINDOW(window));
+ gtk_main();
+
+ return EXIT_SUCCESS;
+
+}
+
+static void plot_toggled(GtkWidget *caller, gpointer data) {
+
+ gboolean state = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(caller));
+
+ GtkWidget *widget = *(GtkWidget **)data;
+
+ if (state) {
+
+ gtk_widget_show(widget);
+
+ } else {
+
+ gtk_widget_hide(widget);
+
+ }
+
+}
+
diff --git a/utils/qbdi_mode/README.md b/utils/qbdi_mode/README.md
new file mode 100755
index 00000000..08558017
--- /dev/null
+++ b/utils/qbdi_mode/README.md
@@ -0,0 +1,206 @@
+# qbdi-based binary-only instrumentation for afl-fuzz
+
+NOTE: this code is outdated and first would need to be adapted to the current
+AFL++ versions.
+Try FRIDA mode or fpicker [https://github.com/ttdennis/fpicker/](https://github.com/ttdennis/fpicker/) first, maybe they suite your need.
+
+## 1) Introduction
+
+The code in ./qbdi_mode allows you to build a standalone feature that
+using the QBDI framework to fuzz android native library.
+
+## 2) Build
+
+First download the Android NDK
+
+```
+https://developer.android.com/ndk/downloads
+https://dl.google.com/android/repository/android-ndk-r20-linux-x86_64.zip
+```
+
+Then unzip it and build the standalone-toolchain
+For x86_64 standalone-toolchain
+
+```
+unzip android-ndk-r20-linux-x86_64.zip
+cd android-ndk-r20/
+./build/tools/make_standalone_toolchain.py --arch x86_64 --api 21 --install-dir ../android-standalone-toolchain-x86_64
+```
+
+For x86 standalone-toolchain
+
+```
+./build/tools/make_standalone_toolchain.py --arch x86 --api 21 --install-dir ../android-standalone-toolchain-x86
+```
+
+In alternative you can also use the pre-built toolchain, in that case make sure
+to set the proper CC and CXX environment variables because there are many
+different compilers for each API version in the pre-built toolchain.
+
+For example:
+
+```
+export STANDALONE_TOOLCHAIN_PATH=~/Android/Sdk/ndk/20.1.5948944/toolchains/llvm/prebuilt/linux-x86_64/
+export CC=x86_64-linux-android21-clang
+export CXX=x86_64-linux-android21-clang++
+```
+
+Then download the QBDI SDK from website
+
+```
+https://qbdi.quarkslab.com/
+```
+
+For Android x86_64
+
+```
+https://github.com/QBDI/QBDI/releases/download/v0.7.0/QBDI-0.7.0-android-X86_64.tar.gz
+```
+
+Then decompress the sdk
+
+```
+mkdir android-qbdi-sdk-x86_64
+cp QBDI-0.7.0-android-X86_64.tar.gz android-qbdi-sdk-x86_64/
+cd android-qbdi-sdk-x86_64/
+tar xvf QBDI-0.7.0-android-X86_64.tar.gz
+```
+
+Now set the `STANDALONE_TOOLCHAIN_PATH` to the path of standalone-toolchain
+
+```
+export STANDALONE_TOOLCHAIN_PATH=/home/hac425/workspace/android-standalone-toolchain-x86_64
+```
+
+set the `QBDI_SDK_PATH` to the path of QBDI SDK
+
+```
+export QBDI_SDK_PATH=/home/hac425/workspace/AFLplusplus/qbdi_mode/android-qbdi-sdk-x86_64/
+```
+
+Then run the build.sh
+
+```
+./build.sh x86_64
+```
+
+this could build the afl-fuzz and also the qbdi template for android x86_64
+
+### Example
+
+The demo-so.c is an vulnerable library, it has a function for test
+
+```c
+int target_func(char *buf, int size) {
+
+ printf("buffer:%p, size:%p\n", buf, size);
+ switch (buf[0]) {
+
+ case 1:
+ puts("222");
+ if (buf[1] == '\x44') {
+
+ puts("null ptr deference");
+ *(char *)(0) = 1;
+
+ }
+
+ break;
+ case 0xff:
+ if (buf[2] == '\xff') {
+
+ if (buf[1] == '\x44') {
+
+ puts("crash....");
+ *(char *)(0xdeadbeef) = 1;
+
+ }
+
+ }
+
+ break;
+ default: puts("default action"); break;
+
+ }
+
+ return 1;
+
+}
+```
+
+This could be built to `libdemo.so`.
+
+Then load the library in template.cpp and find the `target` function address:
+
+```c
+ void *handle = dlopen(lib_path, RTLD_LAZY);
+ ..........................................
+ ..........................................
+ ..........................................
+ p_target_func = (target_func)dlsym(handle, "target_func");
+```
+
+Then read the data from file and call the function in `fuzz_func`:
+
+```c
+QBDI_NOINLINE int fuzz_func() {
+
+ if (afl_setup()) { afl_forkserver(); }
+
+ /* Read the input from file */
+ unsigned long len = 0;
+ char * data = read_file(input_pathname, &len);
+
+ /* Call the target function with the input data */
+ p_target_func(data, len);
+ return 1;
+
+}
+```
+
+Just compile it
+
+```
+./build.sh x86_64
+```
+
+Then push the `afl-fuzz`, `loader`, `libdemo.so`, the `libQBDI.so` from the QBDI SDK and the `libc++_shared.so` from android-standalone-toolchain to android device
+
+```
+adb push afl-fuzz /data/local/tmp
+adb push libdemo.so /data/local/tmp
+adb push loader /data/local/tmp
+adb push android-qbdi-sdk-x86_64/usr/local/lib/libQBDI.so /data/local/tmp
+adb push ../../android-standalone-toolchain-x86_64/sysroot/usr/lib/x86_64-linux-android/libc++_shared.so
+/data/local/tmp
+```
+
+In android adb shell, run the loader to test if it runs
+
+```
+cd /data/local/tmp
+export LD_LIBRARY_PATH=/data/local/tmp
+mkdir in
+echo 0000 > in/1
+./loader libdemo.so in/1
+p_target_func:0x716d96a98600
+ offset:0x600
+ offset:0x580
+buffer:0x716d96609050, size:0x5
+ offset:0x628
+ offset:0x646
+ offset:0x64b
+ offset:0x65c
+ offset:0x6df
+ offset:0x590
+default action
+ offset:0x6eb
+```
+
+Now run `afl-fuzz` to fuzz the demo library
+
+```
+./afl-fuzz -i in -o out -- ./loader /data/local/tmp/libdemo.so @@
+```
+
+![screen1](assets/screen1.png) \ No newline at end of file
diff --git a/utils/qbdi_mode/assets/screen1.png b/utils/qbdi_mode/assets/screen1.png
new file mode 100644
index 00000000..3cf1cb76
--- /dev/null
+++ b/utils/qbdi_mode/assets/screen1.png
Binary files differ
diff --git a/utils/qbdi_mode/build.sh b/utils/qbdi_mode/build.sh
new file mode 100755
index 00000000..29fe0ee4
--- /dev/null
+++ b/utils/qbdi_mode/build.sh
@@ -0,0 +1,57 @@
+
+if [ -z ${STANDALONE_TOOLCHAIN_PATH} ]; then
+ echo "please set the android-standalone-toolchain path in STANDALONE_TOOLCHAIN_PATH environmental variable"
+ echo "for example: "
+ echo " export STANDALONE_TOOLCHAIN_PATH=/home/android-standalone-toolchain-21/"
+ exit
+fi
+
+if [ -z ${QBDI_SDK_PATH} ]; then
+ echo "please set the qbdi sdk path in QBDI_SDK_PATH environmental variable"
+ echo "for example: "
+ echo " export QBDI_SDK_PATH=/home/QBDI-Android/"
+ exit
+fi
+
+
+
+if [ "$1" = "x86" ]; then
+ echo "build x86 qbdi"
+ compiler_prefix="${STANDALONE_TOOLCHAIN_PATH}/bin/"
+ if [ -z ${CC} ]; then
+ export CC=i686-linux-android-gcc
+ fi
+ if [ -z ${CXX} ]; then
+ export CXX=i686-linux-android-g++
+ fi
+elif [ "$1" = "x86_64" ]; then
+ echo "build x86_64 qbdi"
+ compiler_prefix="${STANDALONE_TOOLCHAIN_PATH}/bin/"
+ if [ -z ${CC} ]; then
+ export CC=x86_64-linux-android-gcc
+ fi
+ if [ -z ${CXX} ]; then
+ export CXX=x86_64-linux-android-g++
+ fi
+else
+ echo "usage: ./build.sh arch[x86, x86_64]"
+ exit
+fi
+
+
+CFLAGS="-I${QBDI_SDK_PATH}/usr/local/include/ -L${QBDI_SDK_PATH}/usr/local/lib/"
+
+echo "[+] Building the QBDI template"
+# build the qbdi template
+${compiler_prefix}${CXX} -o loader template.cpp -lQBDI -ldl -w -g ${CFLAGS}
+
+echo "[+] Building the demo library"
+# build the demo share library
+${compiler_prefix}${CC} -shared -o libdemo.so demo-so.c -w -g
+
+echo "[+] Building afl-fuzz for Android"
+# build afl-fuzz
+cd ../..
+${compiler_prefix}${CC} -DANDROID_DISABLE_FANCY=1 -O3 -funroll-loops -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign -I include/ -DAFL_PATH=\"/usr/local/lib/afl\" -DBIN_PATH=\"/usr/local/bin\" -DDOC_PATH=\"/usr/local/share/doc/afl\" -Wno-unused-function src/afl-fuzz*.c src/afl-common.c src/afl-sharedmem.c src/afl-forkserver.c src/afl-performance.c -o utils/qbdi_mode/afl-fuzz -ldl -lm -w
+
+echo "[+] All done. Enjoy!"
diff --git a/utils/qbdi_mode/demo-so.c b/utils/qbdi_mode/demo-so.c
new file mode 100755
index 00000000..dd367036
--- /dev/null
+++ b/utils/qbdi_mode/demo-so.c
@@ -0,0 +1,41 @@
+#include <stdio.h>
+
+// gcc -shared -o libdemo.so demo-so.c -w
+int target_func(char *buf, int size) {
+
+ printf("buffer:%p, size:%p\n", buf, size);
+ switch (buf[0]) {
+
+ case 1:
+ puts("222");
+ if (buf[1] == '\x44') {
+
+ puts("null ptr deference");
+ *(char *)(0) = 1;
+
+ }
+
+ break;
+ case 0xff:
+ if (buf[2] == '\xff') {
+
+ if (buf[1] == '\x44') {
+
+ puts("crash....");
+ *(char *)(0xdeadbeef) = 1;
+
+ }
+
+ }
+
+ break;
+ default:
+ puts("default action");
+ break;
+
+ }
+
+ return 1;
+
+}
+
diff --git a/utils/qbdi_mode/template.cpp b/utils/qbdi_mode/template.cpp
new file mode 100755
index 00000000..182a014b
--- /dev/null
+++ b/utils/qbdi_mode/template.cpp
@@ -0,0 +1,251 @@
+#include <iostream>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <dlfcn.h>
+
+#ifdef __ANDROID__
+ #include "../include/android-ashmem.h"
+#endif
+
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include "../config.h"
+
+#include <QBDI.h>
+
+/* NeverZero */
+
+#if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO)
+ #define INC_AFL_AREA(loc) \
+ asm volatile( \
+ "addb $1, (%0, %1, 1)\n" \
+ "adcb $0, (%0, %1, 1)\n" \
+ : /* no out */ \
+ : "r"(afl_area_ptr), "r"(loc) \
+ : "memory", "eax")
+#else
+ #define INC_AFL_AREA(loc) afl_area_ptr[loc]++
+#endif
+
+using namespace QBDI;
+
+typedef int (*target_func)(char *buf, int size);
+
+static const size_t STACK_SIZE = 0x100000; // 1MB
+static const QBDI::rword FAKE_RET_ADDR = 0x40000;
+target_func p_target_func = NULL;
+rword module_base = 0;
+rword module_end = 0;
+static unsigned char
+ dummy[MAP_SIZE]; /* costs MAP_SIZE but saves a few instructions */
+unsigned char *afl_area_ptr = NULL; /* Exported for afl_gen_trace */
+
+unsigned long afl_prev_loc = 0;
+
+char input_pathname[PATH_MAX];
+
+/* Set up SHM region and initialize other stuff. */
+
+int afl_setup(void) {
+
+ char *id_str = getenv(SHM_ENV_VAR);
+ int shm_id;
+ if (id_str) {
+
+ shm_id = atoi(id_str);
+ afl_area_ptr = (unsigned char *)shmat(shm_id, NULL, 0);
+ if (afl_area_ptr == (void *)-1) return 0;
+ memset(afl_area_ptr, 0, MAP_SIZE);
+
+ }
+
+ return 1;
+
+}
+
+/* Fork server logic, invoked once we hit _start. */
+static void afl_forkserver() {
+
+ static unsigned char tmp[4];
+ pid_t child_pid;
+
+ if (write(FORKSRV_FD + 1, tmp, 4) != 4) return;
+
+ while (1) {
+
+ int status;
+ u32 was_killed;
+ // wait for afl-fuzz
+ if (read(FORKSRV_FD, &was_killed, 4) != 4) exit(2);
+
+ child_pid = fork();
+ if (child_pid < 0) exit(4);
+
+ if (!child_pid) {
+
+ // child return to execute code
+ close(FORKSRV_FD);
+ close(FORKSRV_FD + 1);
+ return;
+
+ }
+
+ // write child pid to afl-fuzz
+ if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) exit(5);
+
+ // wait child stop
+ if (waitpid(child_pid, &status, 0) < 0) exit(6);
+
+ // send child stop status to afl-fuzz
+ if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(7);
+
+ }
+
+}
+
+void afl_maybe_log(unsigned long cur_loc) {
+
+ if (afl_area_ptr == NULL) { return; }
+ unsigned long afl_idx = cur_loc ^ afl_prev_loc;
+ afl_idx &= MAP_SIZE - 1;
+ INC_AFL_AREA(afl_idx);
+ afl_prev_loc = cur_loc >> 1;
+
+}
+
+char *read_file(char *path, unsigned long *length) {
+
+ unsigned long len;
+ char * buf;
+
+ FILE *fp = fopen(path, "rb");
+ fseek(fp, 0, SEEK_END);
+ len = ftell(fp);
+ buf = (char *)malloc(len);
+ rewind(fp);
+ fread(buf, 1, len, fp);
+ fclose(fp);
+ *length = len;
+ return buf;
+
+}
+
+QBDI_NOINLINE int fuzz_func() {
+
+ if (afl_setup()) { afl_forkserver(); }
+
+ unsigned long len = 0;
+ char * data = read_file(input_pathname, &len);
+
+ // printf("In fuzz_func\n");
+ p_target_func(data, len);
+ return 1;
+
+}
+
+static QBDI::VMAction bbcallback(QBDI::VMInstanceRef vm,
+ const QBDI::VMState *state,
+ QBDI::GPRState * gprState,
+ QBDI::FPRState *fprState, void *data) {
+
+ // errno = SAVED_ERRNO;
+
+#ifdef __x86_64__
+ unsigned long pc = gprState->rip;
+#elif defined(i386)
+ unsigned long pc = gprState->eip;
+#elif defined(__arm__)
+ unsigned long pc = gprState->pc;
+#endif
+
+ // just log the module path
+ if (pc >= module_base && pc <= module_end) {
+
+ unsigned long offset = pc - module_base;
+ printf("\toffset:%p\n", offset);
+ afl_maybe_log(offset);
+
+ }
+
+ return QBDI::VMAction::CONTINUE;
+
+}
+
+int main(int argc, char **argv) {
+
+ if (argc < 3) {
+
+ puts("usage: ./loader library_path input_file_path");
+ exit(0);
+
+ }
+
+ const char *lib_path;
+ lib_path = argv[1];
+ strcpy(input_pathname, argv[2]);
+ void *handle = dlopen(lib_path, RTLD_LAZY);
+
+ if (handle == nullptr) {
+
+ perror("Cannot load library");
+ exit(EXIT_FAILURE);
+
+ }
+
+ const char *lib_name = lib_path;
+ if (strrchr(lib_name, '/') != nullptr) lib_name = strrchr(lib_name, '/') + 1;
+
+ // printf("library name:%s\n", lib_name);
+ // load library module address for log path
+ for (MemoryMap &map : getCurrentProcessMaps()) {
+
+ // printf("module:%s\n", map.name.c_str());
+ if ((map.permission & PF_EXEC) &&
+ strstr(map.name.c_str(), lib_name) != NULL) {
+
+ module_base = map.range.start;
+ module_end = map.range.end;
+
+ }
+
+ }
+
+ if (module_base == 0) {
+
+ std::cerr << "Fail to find base address" << std::endl;
+ return -1;
+
+ }
+
+ // printf("module base:%p, module end:%p\n", module_base, module_end);
+ p_target_func = (target_func)dlsym(handle, "target_func");
+ // p_target_func = (target_func)(module_base + 0x61a);
+ printf("p_target_func:%p\n", p_target_func);
+
+ VM vm;
+ uint8_t *fakestack = nullptr;
+
+ GPRState *state = vm.getGPRState();
+ allocateVirtualStack(state, STACK_SIZE, &fakestack);
+ vm.addInstrumentedModuleFromAddr(module_base);
+ vm.addInstrumentedModuleFromAddr((rword)&main);
+
+ vm.addVMEventCB(BASIC_BLOCK_ENTRY, bbcallback, nullptr);
+
+ // QBDI::simulateCall(state, FAKE_RET_ADDR);
+ // vm.run((rword)&fuzz_func, (rword)FAKE_RET_ADDR);
+
+ rword ret;
+ vm.call(&ret, (rword)&fuzz_func, {});
+
+ return 0;
+
+}
+
diff --git a/utils/qemu_persistent_hook/Makefile b/utils/qemu_persistent_hook/Makefile
new file mode 100644
index 00000000..85db1b46
--- /dev/null
+++ b/utils/qemu_persistent_hook/Makefile
@@ -0,0 +1,6 @@
+all:
+ $(CC) -no-pie test.c -o test
+ $(CC) -fPIC -shared read_into_rdi.c -o read_into_rdi.so
+
+clean:
+ rm -rf in out test read_into_rdi.so
diff --git a/utils/qemu_persistent_hook/README.md b/utils/qemu_persistent_hook/README.md
new file mode 100644
index 00000000..3bbaef6b
--- /dev/null
+++ b/utils/qemu_persistent_hook/README.md
@@ -0,0 +1,19 @@
+# QEMU persistent hook example
+
+Compile the test binary and the library:
+
+```
+make
+```
+
+Fuzz with:
+
+```
+export AFL_QEMU_PERSISTENT_ADDR=0x$(nm test | grep "T target_func" | awk '{print $1}')
+export AFL_QEMU_PERSISTENT_HOOK=./read_into_rdi.so
+
+mkdir in
+echo 0000 > in/in
+
+../../afl-fuzz -Q -i in -o out -- ./test
+``` \ No newline at end of file
diff --git a/utils/qemu_persistent_hook/read_into_rdi.c b/utils/qemu_persistent_hook/read_into_rdi.c
new file mode 100644
index 00000000..14b2ed85
--- /dev/null
+++ b/utils/qemu_persistent_hook/read_into_rdi.c
@@ -0,0 +1,34 @@
+#include "../../qemu_mode/qemuafl/qemuafl/api.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#define g2h(x) ((void *)((unsigned long)(x) + guest_base))
+#define h2g(x) ((uint64_t)(x)-guest_base)
+
+void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base,
+ uint8_t *input_buf, uint32_t input_buf_len) {
+
+ // In this example the register RDI is pointing to the memory location
+ // of the target buffer, and the length of the input is in RSI.
+ // This can be seen with a debugger, e.g. gdb (and "disass main")
+
+ printf("Placing input into 0x%lx\n", regs->rdi);
+
+ if (input_buf_len > 1024) input_buf_len = 1024;
+ memcpy(g2h(regs->rdi), input_buf, input_buf_len);
+ regs->rsi = input_buf_len;
+
+}
+
+#undef g2h
+#undef h2g
+
+int afl_persistent_hook_init(void) {
+
+ // 1 for shared memory input (faster), 0 for normal input (you have to use
+ // read(), input_buf will be NULL)
+ return 1;
+
+}
+
diff --git a/utils/qemu_persistent_hook/test.c b/utils/qemu_persistent_hook/test.c
new file mode 100644
index 00000000..a0e815dc
--- /dev/null
+++ b/utils/qemu_persistent_hook/test.c
@@ -0,0 +1,35 @@
+#include <stdio.h>
+
+int target_func(unsigned char *buf, int size) {
+
+ printf("buffer:%p, size:%d\n", buf, size);
+ switch (buf[0]) {
+
+ case 1:
+ if (buf[1] == '\x44') { puts("a"); }
+ break;
+ case 0xff:
+ if (buf[2] == '\xff') {
+
+ if (buf[1] == '\x44') { puts("b"); }
+
+ }
+
+ break;
+ default:
+ break;
+
+ }
+
+ return 1;
+
+}
+
+char data[1024];
+
+int main() {
+
+ target_func(data, 1024);
+
+}
+
diff --git a/utils/socket_fuzzing/Makefile b/utils/socket_fuzzing/Makefile
new file mode 100644
index 00000000..9476e2d5
--- /dev/null
+++ b/utils/socket_fuzzing/Makefile
@@ -0,0 +1,61 @@
+#
+# american fuzzy lop++ - socket_fuzz
+# ----------------------------------
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+
+.PHONY: all install clean
+
+PREFIX ?= /usr/local
+BIN_PATH = $(PREFIX)/bin
+HELPER_PATH = $(PREFIX)/lib/afl
+
+CFLAGS = -fPIC -Wall -Wextra
+LDFLAGS = -shared
+
+UNAME_SAYS_LINUX=$(shell uname | grep -E '^Linux|^GNU' >/dev/null; echo $$?)
+UNAME_SAYS_LINUX:sh=uname | grep -E '^Linux|^GNU' >/dev/null; echo $$?
+
+_LDFLAGS_ADD=$(UNAME_SAYS_LINUX:1=)
+LDFLAGS_ADD=$(_LDFLAGS_ADD:0=-ldl)
+LDFLAGS += $(LDFLAGS_ADD)
+
+# on gcc for arm there is no -m32, but -mbe32
+M32FLAG = -m32
+M64FLAG = -m64
+
+CC_IS_GCC=$(shell $(CC) --version 2>/dev/null | grep -q gcc; echo $$?)
+CC_IS_GCC:sh=$(CC) --version 2>/dev/null | grep -q gcc; echo $$?
+CC_IS_ARMCOMPILER=$(shell $(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?)
+CC_IS_ARMCOMPILER:sh=$(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?
+
+_M32FLAG=$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)
+__M32FLAG=$(_M32FLAG:00=-mbe32)
+___M32FLAG=$(__M32FLAG:$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)=-m32)
+M32FLAG=$(___M32FLAG)
+#ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" ""
+# ifneq (,$(findstring arm, "$(shell $(CC) -v 2>&1 >/dev/null)"))
+# M32FLAG = -mbe32
+# endif
+#endif
+
+all: socketfuzz32.so socketfuzz64.so
+
+socketfuzz32.so: socketfuzz.c
+ -@$(CC) $(M32FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "socketfuzz32 build failure (that's fine)"
+
+socketfuzz64.so: socketfuzz.c
+ -@$(CC) $(M64FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "socketfuzz64 build failure (that's fine)"
+
+install: socketfuzz32.so socketfuzz64.so
+ install -d -m 755 $(DESTDIR)$(HELPER_PATH)/
+ if [ -f socketfuzz32.so ]; then set -e; install -m 755 socketfuzz32.so $(DESTDIR)$(HELPER_PATH)/; fi
+ if [ -f socketfuzz64.so ]; then set -e; install -m 755 socketfuzz64.so $(DESTDIR)$(HELPER_PATH)/; fi
+
+clean:
+ rm -f socketfuzz32.so socketfuzz64.so
diff --git a/utils/socket_fuzzing/README.md b/utils/socket_fuzzing/README.md
new file mode 100644
index 00000000..2805fa22
--- /dev/null
+++ b/utils/socket_fuzzing/README.md
@@ -0,0 +1,11 @@
+# socketfuzz
+
+when you want to fuzz a network service and you can not/do not want to modify
+the source (or just have a binary), then this LD_PRELOAD library will allow
+for sending input to stdin which the target binary will think is coming from
+a network socket.
+
+This is desock_dup.c from the amazing preeny project
+[https://github.com/zardus/preeny](https://github.com/zardus/preeny)
+
+It is packaged in AFL++ to have it at hand if needed
diff --git a/utils/socket_fuzzing/socketfuzz.c b/utils/socket_fuzzing/socketfuzz.c
new file mode 100644
index 00000000..3ec8383b
--- /dev/null
+++ b/utils/socket_fuzzing/socketfuzz.c
@@ -0,0 +1,110 @@
+/*
+ * This is desock_dup.c from the amazing preeny project
+ * https://github.com/zardus/preeny
+ *
+ * It is packaged in afl++ to have it at hand if needed
+ *
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h> //
+#include <sys/socket.h> //
+#include <sys/stat.h> //
+#include <fcntl.h> //
+#include <netinet/in.h>
+#include <pthread.h>
+#include <signal.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <stdio.h>
+#include <poll.h>
+//#include "logging.h" // switche from preeny_info() to fprintf(stderr, "Info: "
+
+//
+// originals
+//
+int (*original_close)(int);
+int (*original_dup2)(int, int);
+__attribute__((constructor)) void preeny_desock_dup_orig() {
+
+ original_close = dlsym(RTLD_NEXT, "close");
+ original_dup2 = dlsym(RTLD_NEXT, "dup2");
+
+}
+
+int close(int sockfd) {
+
+ if (sockfd <= 2) {
+
+ fprintf(stderr, "Info: Disabling close on %d\n", sockfd);
+ return 0;
+
+ } else {
+
+ return original_close(sockfd);
+
+ }
+
+}
+
+int dup2(int old, int new) {
+
+ if (new <= 2) {
+
+ fprintf(stderr, "Info: Disabling dup from %d to %d\n", old, new);
+ return 0;
+
+ } else {
+
+ return original_dup2(old, new);
+
+ }
+
+}
+
+int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
+
+ (void)sockfd;
+ (void)addr;
+ (void)addrlen;
+ fprintf(stderr, "Info: Emulating accept on %d\n", sockfd);
+ return 0;
+
+}
+
+int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
+
+ (void)sockfd;
+ (void)addr;
+ (void)addrlen;
+ fprintf(stderr, "Info: Emulating bind on port %d\n",
+ ntohs(((struct sockaddr_in *)addr)->sin_port));
+ return 0;
+
+}
+
+int listen(int sockfd, int backlog) {
+
+ (void)sockfd;
+ (void)backlog;
+ return 0;
+
+}
+
+int setsockopt(int sockfd, int level, int optid, const void *optdata,
+ socklen_t optdatalen) {
+
+ (void)sockfd;
+ (void)level;
+ (void)optid;
+ (void)optdata;
+ (void)optdatalen;
+ return 0;
+
+}
+