about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAndrea Fioraldi <andreafioraldi@gmail.com>2019-10-25 20:04:16 +0200
committerAndrea Fioraldi <andreafioraldi@gmail.com>2019-10-25 20:04:16 +0200
commit4ec4e5b394dfa4e40a26574e3053a9bd7eaa8d37 (patch)
tree4ae76859d96fb31b3635a12f8632771cdaa9664f
parente7871b2c7675e0f6df4fbe1a8f53a23ed5d2024f (diff)
downloadafl++-4ec4e5b394dfa4e40a26574e3053a9bd7eaa8d37.tar.gz
floating point compcov
-rwxr-xr-xqemu_mode/build_qemu_support.sh3
-rw-r--r--qemu_mode/patches/afl-qemu-common.h12
-rw-r--r--qemu_mode/patches/afl-qemu-floats.h217
-rw-r--r--qemu_mode/patches/i386-fpu_helper.diff54
-rw-r--r--qemu_mode/patches/i386-ops_sse.diff61
-rw-r--r--qemu_mode/patches/softfloat.diff10
6 files changed, 357 insertions, 0 deletions
diff --git a/qemu_mode/build_qemu_support.sh b/qemu_mode/build_qemu_support.sh
index f18cbdf3..6b9f91f9 100755
--- a/qemu_mode/build_qemu_support.sh
+++ b/qemu_mode/build_qemu_support.sh
@@ -150,6 +150,9 @@ patch -p1 <../patches/translate-all.diff || exit 1
 patch -p1 <../patches/tcg.diff || exit 1
 patch -p1 <../patches/i386-translate.diff || exit 1
 patch -p1 <../patches/arm-translate.diff || exit 1
+patch -p1 <../patches/i386-ops_sse.diff || exit 1
+patch -p1 <../patches/i386-fpu_helper.diff || exit 1
+patch -p1 <../patches/softfloat.diff || exit 1
 
 echo "[+] Patching done."
 
diff --git a/qemu_mode/patches/afl-qemu-common.h b/qemu_mode/patches/afl-qemu-common.h
index 409a7eab..d4024353 100644
--- a/qemu_mode/patches/afl-qemu-common.h
+++ b/qemu_mode/patches/afl-qemu-common.h
@@ -31,6 +31,9 @@
 
  */
 
+#ifndef __AFL_QEMU_COMMON
+#define __AFL_QEMU_COMMON
+
 #include "../../config.h"
 
 #ifndef CPU_NB_REGS
@@ -81,6 +84,12 @@ void tcg_gen_afl_compcov_log_call(void *func, target_ulong cur_loc,
 
 void tcg_gen_afl_maybe_log_call(target_ulong cur_loc);
 
+void afl_float_compcov_log_32(target_ulong cur_loc, float32 arg1, float32 arg2,
+                              void *status);
+void afl_float_compcov_log_64(target_ulong cur_loc, float64 arg1, float64 arg2,
+                              void *status);
+void afl_float_compcov_log_80(target_ulong cur_loc, floatx80 arg1,
+                              floatx80 arg2);
 
 /* Check if an address is valid in the current mapping */
 
@@ -99,3 +108,6 @@ static inline int is_valid_addr(target_ulong addr) {
   return 1;
 
 }
+
+#endif
+
diff --git a/qemu_mode/patches/afl-qemu-floats.h b/qemu_mode/patches/afl-qemu-floats.h
new file mode 100644
index 00000000..765deb74
--- /dev/null
+++ b/qemu_mode/patches/afl-qemu-floats.h
@@ -0,0 +1,217 @@
+/*
+   american fuzzy lop++ - high-performance binary-only instrumentation
+   -------------------------------------------------------------------
+
+   Originally written by Andrew Griffiths <agriffiths@google.com> and
+                         Michal Zalewski
+
+   TCG instrumentation and block chaining support by Andrea Biondo
+                                      <andrea.biondo965@gmail.com>
+
+   QEMU 3.1.1 port, TCG thread-safety, CompareCoverage and NeverZero
+   counters by Andrea Fioraldi <andreafioraldi@gmail.com>
+
+   Copyright 2015, 2016, 2017 Google Inc. All rights reserved.
+   Copyright 2019 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 code is a shim patched into the separately-distributed source
+   code of QEMU 3.1.0. It leverages the built-in QEMU tracing functionality
+   to implement AFL-style instrumentation and to take care of the remaining
+   parts of the AFL fork server logic.
+
+   The resulting QEMU binary is essentially a standalone instrumentation
+   tool; for an example of how to leverage it for other purposes, you can
+   have a look at afl-showmap.c.
+
+ */
+
+#include "tcg.h"
+#include "afl-qemu-common.h"
+
+union afl_float32 {
+  float64 f;
+  struct {
+    u64 sign :  1;
+    u64 exp  :  7;
+    u64 frac : 24;
+  };
+};
+
+
+union afl_float64 {
+  float64 f;
+  struct {
+    u64 sign :  1;
+    u64 exp  : 11;
+    u64 frac : 52;
+  };
+};
+
+
+// TODO 16 and 128 bits floats
+// TODO figure out why float*_unpack_canonical does not work
+
+void afl_float_compcov_log_32(target_ulong cur_loc, float32 arg1, float32 arg2,
+                              void* status) {
+
+  cur_loc = (cur_loc >> 4) ^ (cur_loc << 8);
+  cur_loc &= MAP_SIZE - 7;
+
+  if (cur_loc >= afl_inst_rms) return;
+
+  //float_status* s = (float_status*)status;
+  //FloatParts    a = float32_unpack_canonical(arg1, s);
+  //FloatParts    b = float32_unpack_canonical(arg2, s);
+  union afl_float32 a = { .f = arg1 };
+  union afl_float32 b = { .f = arg2 };
+
+  // if (is_nan(a.cls) || is_nan(b.cls)) return;
+
+  register uintptr_t idx = cur_loc;
+
+  if (a.sign != b.sign) return;
+  INC_AFL_AREA(idx);
+  if (a.exp != b.exp) return;
+  INC_AFL_AREA(idx + 1);
+
+  if ((a.frac & 0xff0000) == (b.frac & 0xff0000)) {
+
+    INC_AFL_AREA(idx + 2);
+    if ((a.frac & 0xff00) == (b.frac & 0xff00)) { INC_AFL_AREA(idx + 3); }
+
+  }
+
+}
+
+void afl_float_compcov_log_64(target_ulong cur_loc, float64 arg1, float64 arg2,
+                              void* status) {
+
+  cur_loc = (cur_loc >> 4) ^ (cur_loc << 8);
+  cur_loc &= MAP_SIZE - 7;
+
+  if (cur_loc >= afl_inst_rms) return;
+
+  //float_status* s = (float_status*)status;
+  //FloatParts    a = float64_unpack_canonical(arg1, s);
+  //FloatParts    b = float64_unpack_canonical(arg2, s);
+  union afl_float64 a = { .f = arg1 };
+  union afl_float64 b = { .f = arg2 };
+
+  // if (is_nan(a.cls) || is_nan(b.cls)) return;
+
+  register uintptr_t idx = cur_loc;
+
+  if (a.sign == b.sign) INC_AFL_AREA(idx);
+  if ((a.exp & 0xff00) == (b.exp & 0xff00)) {
+
+    INC_AFL_AREA(idx + 1);
+    if ((a.exp & 0xff) == (b.exp & 0xff)) INC_AFL_AREA(idx + 2);
+
+  }
+
+  if ((a.frac & 0xff000000000000) == (b.frac & 0xff000000000000)) {
+
+    INC_AFL_AREA(idx + 3);
+    if ((a.frac & 0xff0000000000) == (b.frac & 0xff0000000000)) {
+
+      INC_AFL_AREA(idx + 4);
+      if ((a.frac & 0xff00000000) == (b.frac & 0xff00000000)) {
+
+        INC_AFL_AREA(idx + 5);
+        if ((a.frac & 0xff000000) == (b.frac & 0xff000000)) {
+
+          INC_AFL_AREA(idx + 6);
+          if ((a.frac & 0xff0000) == (b.frac & 0xff0000)) {
+
+            INC_AFL_AREA(idx + 7);
+            if ((a.frac & 0xff00) == (b.frac & 0xff00)) INC_AFL_AREA(idx + 8);
+
+          }
+
+        }
+
+      }
+
+    }
+
+  }
+
+}
+
+void afl_float_compcov_log_80(target_ulong cur_loc, floatx80 arg1,
+                              floatx80 arg2) {
+
+  cur_loc = (cur_loc >> 4) ^ (cur_loc << 8);
+  cur_loc &= MAP_SIZE - 7;
+
+  if (cur_loc >= afl_inst_rms) return;
+
+  if (floatx80_invalid_encoding(arg1) || floatx80_invalid_encoding(arg2))
+    return;
+
+  flag a_sign = extractFloatx80Sign(arg1);
+  flag b_sign = extractFloatx80Sign(arg2);
+
+  /*if (((extractFloatx80Exp(arg1) == 0x7fff) &&
+       (extractFloatx80Frac(arg1) << 1)) ||
+      ((extractFloatx80Exp(arg2) == 0x7fff) &&
+       (extractFloatx80Frac(arg2) << 1)))
+    return;*/
+
+  register uintptr_t idx = cur_loc;
+
+  if (a_sign == b_sign) INC_AFL_AREA(idx);
+
+  if ((arg1.high & 0x7f00) == (arg2.high & 0x7f00)) {
+
+    INC_AFL_AREA(idx + 1);
+    if ((arg1.high & 0xff) == (arg2.high & 0xff)) INC_AFL_AREA(idx + 2);
+
+  }
+
+  if ((arg1.low & 0xff00000000000000) == (arg2.low & 0xff00000000000000)) {
+
+    INC_AFL_AREA(idx + 3);
+    if ((arg1.low & 0xff000000000000) == (arg2.low & 0xff000000000000)) {
+
+      INC_AFL_AREA(idx + 4);
+      if ((arg1.low & 0xff0000000000) == (arg2.low & 0xff0000000000)) {
+
+        INC_AFL_AREA(idx + 5);
+        if ((arg1.low & 0xff00000000) == (arg2.low & 0xff00000000)) {
+
+          INC_AFL_AREA(idx + 6);
+          if ((arg1.low & 0xff000000) == (arg2.low & 0xff000000)) {
+
+            INC_AFL_AREA(idx + 7);
+            if ((arg1.low & 0xff0000) == (arg2.low & 0xff0000)) {
+
+              INC_AFL_AREA(idx + 8);
+              if ((arg1.low & 0xff00) == (arg2.low & 0xff00)) {
+
+                INC_AFL_AREA(idx + 9);
+                //if ((arg1.low & 0xff) == (arg2.low & 0xff))
+                //  INC_AFL_AREA(idx + 10);
+
+              }
+
+            }
+
+          }
+
+        }
+
+      }
+
+    }
+
+  }
+
+}
+
diff --git a/qemu_mode/patches/i386-fpu_helper.diff b/qemu_mode/patches/i386-fpu_helper.diff
new file mode 100644
index 00000000..3bd09d9c
--- /dev/null
+++ b/qemu_mode/patches/i386-fpu_helper.diff
@@ -0,0 +1,54 @@
+diff --git a/target/i386/fpu_helper.c b/target/i386/fpu_helper.c
+index ea5a0c48..89901315 100644
+--- a/target/i386/fpu_helper.c
++++ b/target/i386/fpu_helper.c
+@@ -384,10 +384,16 @@ void helper_fxchg_ST0_STN(CPUX86State *env, int st_index)
+ 
+ static const int fcom_ccval[4] = {0x0100, 0x4000, 0x0000, 0x4500};
+ 
++#include "../patches/afl-qemu-common.h"
++
+ void helper_fcom_ST0_FT0(CPUX86State *env)
+ {
+     int ret;
+ 
++    if (afl_compcov_level > 2 && env->eip < afl_end_code &&
++        env->eip >= afl_start_code)
++      afl_float_compcov_log_80(env->eip, ST0, FT0);
++
+     ret = floatx80_compare(ST0, FT0, &env->fp_status);
+     env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1];
+ }
+@@ -396,6 +402,10 @@ void helper_fucom_ST0_FT0(CPUX86State *env)
+ {
+     int ret;
+ 
++    if (afl_compcov_level > 2 && env->eip < afl_end_code &&
++        env->eip >= afl_start_code)
++      afl_float_compcov_log_80(env->eip, ST0, FT0);
++
+     ret = floatx80_compare_quiet(ST0, FT0, &env->fp_status);
+     env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1];
+ }
+@@ -407,6 +417,10 @@ void helper_fcomi_ST0_FT0(CPUX86State *env)
+     int eflags;
+     int ret;
+ 
++    if (afl_compcov_level > 2 && env->eip < afl_end_code &&
++        env->eip >= afl_start_code)
++      afl_float_compcov_log_80(env->eip, ST0, FT0);
++
+     ret = floatx80_compare(ST0, FT0, &env->fp_status);
+     eflags = cpu_cc_compute_all(env, CC_OP);
+     eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
+@@ -418,6 +432,10 @@ void helper_fucomi_ST0_FT0(CPUX86State *env)
+     int eflags;
+     int ret;
+ 
++    if (afl_compcov_level > 2 && env->eip < afl_end_code &&
++        env->eip >= afl_start_code)
++      afl_float_compcov_log_80(env->eip, ST0, FT0);
++
+     ret = floatx80_compare_quiet(ST0, FT0, &env->fp_status);
+     eflags = cpu_cc_compute_all(env, CC_OP);
+     eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
diff --git a/qemu_mode/patches/i386-ops_sse.diff b/qemu_mode/patches/i386-ops_sse.diff
new file mode 100644
index 00000000..d2779ea8
--- /dev/null
+++ b/qemu_mode/patches/i386-ops_sse.diff
@@ -0,0 +1,61 @@
+diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h
+index ed059897..a5296caa 100644
+--- a/target/i386/ops_sse.h
++++ b/target/i386/ops_sse.h
+@@ -997,6 +997,8 @@ SSE_HELPER_CMP(cmpord, FPU_CMPORD)
+ 
+ static const int comis_eflags[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C};
+ 
++#include "../patches/afl-qemu-common.h"
++
+ void helper_ucomiss(CPUX86State *env, Reg *d, Reg *s)
+ {
+     int ret;
+@@ -1004,6 +1006,11 @@ void helper_ucomiss(CPUX86State *env, Reg *d, Reg *s)
+ 
+     s0 = d->ZMM_S(0);
+     s1 = s->ZMM_S(0);
++
++   if (afl_compcov_level > 2 && env->eip < afl_end_code &&
++        env->eip >= afl_start_code)
++      afl_float_compcov_log_32(env->eip, s0, s1, &env->sse_status);
++
+     ret = float32_compare_quiet(s0, s1, &env->sse_status);
+     CC_SRC = comis_eflags[ret + 1];
+ }
+@@ -1015,6 +1022,11 @@ void helper_comiss(CPUX86State *env, Reg *d, Reg *s)
+ 
+     s0 = d->ZMM_S(0);
+     s1 = s->ZMM_S(0);
++
++   if (afl_compcov_level > 2 && env->eip < afl_end_code &&
++        env->eip >= afl_start_code)
++      afl_float_compcov_log_32(env->eip, s0, s1, &env->sse_status);
++
+     ret = float32_compare(s0, s1, &env->sse_status);
+     CC_SRC = comis_eflags[ret + 1];
+ }
+@@ -1026,6 +1038,11 @@ void helper_ucomisd(CPUX86State *env, Reg *d, Reg *s)
+ 
+     d0 = d->ZMM_D(0);
+     d1 = s->ZMM_D(0);
++
++   if (afl_compcov_level > 2 && env->eip < afl_end_code &&
++        env->eip >= afl_start_code)
++      afl_float_compcov_log_64(env->eip, d0, d1, &env->sse_status);
++
+     ret = float64_compare_quiet(d0, d1, &env->sse_status);
+     CC_SRC = comis_eflags[ret + 1];
+ }
+@@ -1037,6 +1054,11 @@ void helper_comisd(CPUX86State *env, Reg *d, Reg *s)
+ 
+     d0 = d->ZMM_D(0);
+     d1 = s->ZMM_D(0);
++
++   if (afl_compcov_level > 2 && env->eip < afl_end_code &&
++        env->eip >= afl_start_code)
++      afl_float_compcov_log_64(env->eip, d0, d1, &env->sse_status);
++
+     ret = float64_compare(d0, d1, &env->sse_status);
+     CC_SRC = comis_eflags[ret + 1];
+ }
diff --git a/qemu_mode/patches/softfloat.diff b/qemu_mode/patches/softfloat.diff
new file mode 100644
index 00000000..86ffb97f
--- /dev/null
+++ b/qemu_mode/patches/softfloat.diff
@@ -0,0 +1,10 @@
+diff --git a/fpu/softfloat.c b/fpu/softfloat.c
+index e1eef954..2f8d0d62 100644
+--- a/fpu/softfloat.c
++++ b/fpu/softfloat.c
+@@ -7205,3 +7205,5 @@ float128 float128_scalbn(float128 a, int n, float_status *status)
+                                          , status);
+ 
+ }
++
++#include "../../patches/afl-qemu-floats.h"