diff options
-rw-r--r-- | frida_mode/src/instrument/instrument_x64.c | 222 | ||||
-rw-r--r-- | frida_mode/test/libxml/GNUmakefile | 172 | ||||
-rw-r--r-- | frida_mode/test/libxml/Makefile | 13 | ||||
-rwxr-xr-x | frida_mode/test/libxml/get_symbol_addr.py | 36 | ||||
-rw-r--r-- | instrumentation/split-compares-pass.so.cc | 139 | ||||
-rwxr-xr-x | test/test-fpExtra.sh | 39 | ||||
-rw-r--r-- | test/test-fp_Infcases.c | 124 | ||||
-rw-r--r-- | test/test-fp_NaNcases.c | 86 | ||||
-rw-r--r-- | test/test-fp_minusZerocases.c | 35 |
9 files changed, 786 insertions, 80 deletions
diff --git a/frida_mode/src/instrument/instrument_x64.c b/frida_mode/src/instrument/instrument_x64.c index 41162f2a..b51cb697 100644 --- a/frida_mode/src/instrument/instrument_x64.c +++ b/frida_mode/src/instrument/instrument_x64.c @@ -45,7 +45,9 @@ static gboolean instrument_coverage_in_range(gssize offset) { } - #pragma pack(push, 1) + #ifdef __APPLE__ + #pragma pack(push, 1) + typedef struct { // cur_location = (block_address >> 4) ^ (block_address << 8); @@ -58,7 +60,7 @@ typedef struct { // mov QWORD PTR [rsp-0x90],rbx // mov eax,DWORD PTR [rip+0x333d5a] # 0x7ffff6ff2740 // mov DWORD PTR [rip+0x333d3c],0x9fbb # 0x7ffff6ff2740 - // xor eax,0x103f77 + // lea rax,[rip + 0x103f77] // mov bl,BYTE PTR [rax] // add bl,0x1 // adc bl,0x0 @@ -76,7 +78,7 @@ typedef struct { uint8_t mov_eax_prev_loc[6]; uint8_t mov_prev_loc_curr_loc_shr1[10]; - uint8_t xor_eax_curr_loc[5]; + uint8_t leax_eax_curr_loc[7]; uint8_t mov_rbx_ptr_rax[2]; uint8_t add_bl_1[3]; @@ -90,14 +92,81 @@ typedef struct { } afl_log_code_asm_t; - #pragma pack(pop) + #pragma pack(pop) -typedef union { +static const afl_log_code_asm_t template = + { - afl_log_code_asm_t code; - uint8_t bytes[0]; + .mov_rax_rsp_88 = {0x48, 0x89, 0x84, 0x24, 0x78, 0xFF, 0xFF, 0xFF}, + .lahf = 0x9f, + .mov_rax_rsp_90 = {0x48, 0x89, 0x84, 0x24, 0x70, 0xFF, 0xFF, 0xFF}, + .mov_rbx_rsp_98 = {0x48, 0x89, 0x9C, 0x24, 0x68, 0xFF, 0xFF, 0xFF}, -} afl_log_code; + .mov_eax_prev_loc = {0x8b, 0x05}, + .mov_prev_loc_curr_loc_shr1 = {0xc7, 0x05}, + + .leax_eax_curr_loc = {0x48, 0x8d, 0x05}, + .mov_rbx_ptr_rax = {0x8a, 0x18}, + .add_bl_1 = {0x80, 0xc3, 0x01}, + .adc_bl_0 = {0x80, 0xd3, 0x00}, + .mov_ptr_rax_rbx = {0x88, 0x18}, + + .mov_rsp_98_rbx = {0x48, 0x8B, 0x9C, 0x24, 0x68, 0xFF, 0xFF, 0xFF}, + .mov_rsp_90_rax = {0x48, 0x8B, 0x84, 0x24, 0x70, 0xFF, 0xFF, 0xFF}, + .sahf = 0x9e, + .mov_rsp_88_rax = {0x48, 0x8B, 0x84, 0x24, 0x78, 0xFF, 0xFF, 0xFF}, + +} + +; + + #else + #pragma pack(push, 1) +typedef struct { + + // cur_location = (block_address >> 4) ^ (block_address << 8); + // shared_mem[cur_location ^ prev_location]++; + // prev_location = cur_location >> 1; + + // mov QWORD PTR [rsp-0x80],rax + // lahf + // mov QWORD PTR [rsp-0x88],rax + // mov QWORD PTR [rsp-0x90],rbx + // mov eax,DWORD PTR [rip+0x333d5a] # 0x7ffff6ff2740 + // mov DWORD PTR [rip+0x333d3c],0x9fbb # 0x7ffff6ff2740 + // xor eax,0x103f77 + // mov bl,BYTE PTR [rax] + // add bl,0x1 + // adc bl,0x0 + // mov BYTE PTR [rax],bl + // mov rbx,QWORD PTR [rsp-0x90] + // mov rax,QWORD PTR [rsp-0x88] + // sahf + // mov rax,QWORD PTR [rsp-0x80] + + uint8_t mov_rax_rsp_88[8]; + uint8_t lahf; + uint8_t mov_rax_rsp_90[8]; + uint8_t mov_rbx_rsp_98[8]; + + uint8_t mov_eax_prev_loc[6]; + uint8_t mov_prev_loc_curr_loc_shr1[10]; + + uint8_t xor_eax_curr_loc[5]; + + uint8_t mov_rbx_ptr_rax[2]; + uint8_t add_bl_1[3]; + uint8_t adc_bl_0[3]; + uint8_t mov_ptr_rax_rbx[2]; + + uint8_t mov_rsp_98_rbx[8]; + uint8_t mov_rsp_90_rax[8]; + uint8_t sahf; + uint8_t mov_rsp_88_rax[8]; + +} afl_log_code_asm_t; + + #pragma pack(pop) static const afl_log_code_asm_t template = { @@ -124,6 +193,22 @@ static const afl_log_code_asm_t template = } ; + #endif + +typedef union { + + afl_log_code_asm_t code; + uint8_t bytes[0]; + +} afl_log_code; + + #ifdef __APPLE__ + +void instrument_coverage_optimize_init(void) { + +} + + #else static gboolean instrument_coverage_find_low(const GumRangeDetails *details, gpointer user_data) { @@ -181,10 +266,10 @@ static void instrument_coverage_optimize_map_mmap(char * shm_file_path, __afl_area_ptr = NULL; - #if !defined(__ANDROID__) + #if !defined(__ANDROID__) shm_fd = shm_open(shm_file_path, O_RDWR, DEFAULT_PERMISSION); if (shm_fd == -1) { FATAL("shm_open() failed\n"); } - #else + #else shm_fd = open("/dev/ashmem", O_RDWR); if (shm_fd == -1) { FATAL("open() failed\n"); } if (ioctl(shm_fd, ASHMEM_SET_NAME, shm_file_path) == -1) { @@ -199,7 +284,7 @@ static void instrument_coverage_optimize_map_mmap(char * shm_file_path, } - #endif + #endif __afl_area_ptr = mmap(address, __afl_map_size, PROT_READ | PROT_WRITE, MAP_FIXED_NOREPLACE | MAP_SHARED, shm_fd, 0); @@ -231,51 +316,6 @@ static void instrument_coverage_optimize_map_shm(guint64 shm_env_val, } -static void instrument_coverage_switch(GumStalkerObserver *self, - gpointer start_address, - const cs_insn * from_insn, - gpointer * target) { - - UNUSED_PARAMETER(self); - UNUSED_PARAMETER(start_address); - - cs_x86 * x86; - cs_x86_op *op; - if (from_insn == NULL) { return; } - - x86 = &from_insn->detail->x86; - op = x86->operands; - - if (!g_hash_table_contains(coverage_blocks, GSIZE_TO_POINTER(*target))) { - - return; - - } - - switch (from_insn->id) { - - case X86_INS_CALL: - case X86_INS_JMP: - if (x86->op_count != 1) { - - FATAL("Unexpected operand count: %d", x86->op_count); - - } - - if (op[0].type != X86_OP_IMM) { return; } - - break; - case X86_INS_RET: - break; - default: - return; - - } - - *target = (guint8 *)*target + sizeof(afl_log_code); - -} - void instrument_coverage_optimize_init(void) { gpointer low_address = NULL; @@ -324,6 +364,53 @@ void instrument_coverage_optimize_init(void) { } + #endif + +static void instrument_coverage_switch(GumStalkerObserver *self, + gpointer start_address, + const cs_insn * from_insn, + gpointer * target) { + + UNUSED_PARAMETER(self); + UNUSED_PARAMETER(start_address); + + cs_x86 * x86; + cs_x86_op *op; + if (from_insn == NULL) { return; } + + x86 = &from_insn->detail->x86; + op = x86->operands; + + if (!g_hash_table_contains(coverage_blocks, GSIZE_TO_POINTER(*target))) { + + return; + + } + + switch (from_insn->id) { + + case X86_INS_CALL: + case X86_INS_JMP: + if (x86->op_count != 1) { + + FATAL("Unexpected operand count: %d", x86->op_count); + + } + + if (op[0].type != X86_OP_IMM) { return; } + + break; + case X86_INS_RET: + break; + default: + return; + + } + + *target = (guint8 *)*target + sizeof(afl_log_code); + +} + static void instrument_coverage_suppress_init(void) { static gboolean initialized = false; @@ -405,12 +492,35 @@ void instrument_coverage_optimize(const cs_insn * instr, *((gint *)&code.bytes[prev_loc_value_offset2]) = (gint)prev_loc_value2; + #ifdef __APPLE__ + + gssize xor_curr_loc_offset = offsetof(afl_log_code, code.leax_eax_curr_loc) + + sizeof(code.code.leax_eax_curr_loc) - + sizeof(guint32); + + gssize xor_curr_loc_value = + ((GPOINTER_TO_SIZE(__afl_area_ptr) | area_offset) - + (code_addr + offsetof(afl_log_code, code.mov_eax_prev_loc) + + sizeof(code.code.mov_eax_prev_loc))); + + if (!instrument_coverage_in_range(xor_curr_loc_value)) { + + FATAL("Patch out of range (xor_curr_loc_value): 0x%016lX", + xor_curr_loc_value); + + } + + *((guint32 *)&code.bytes[xor_curr_loc_offset]) = xor_curr_loc_value; + + #else + gssize xor_curr_loc_offset = offsetof(afl_log_code, code.xor_eax_curr_loc) + sizeof(code.code.xor_eax_curr_loc) - sizeof(guint32); *((guint32 *)&code.bytes[xor_curr_loc_offset]) = (guint32)(GPOINTER_TO_SIZE(__afl_area_ptr) | area_offset); + #endif gum_x86_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code)); diff --git a/frida_mode/test/libxml/GNUmakefile b/frida_mode/test/libxml/GNUmakefile new file mode 100644 index 00000000..1d675187 --- /dev/null +++ b/frida_mode/test/libxml/GNUmakefile @@ -0,0 +1,172 @@ +PWD:=$(shell pwd)/ +ROOT:=$(PWD)../../../ +BUILD_DIR:=$(PWD)build/ + +AFLPP_FRIDA_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/frida_hook.so +AFLPP_QEMU_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/qemu_hook.so + +LIBXML_GIT_REPO:=https://gitlab.gnome.org/GNOME/libxml2.git +LIBXML_DIR:=$(BUILD_DIR)libxml/ +LIBXML_BIN:=$(LIBXML_DIR).libs/libxml2.a + +TARGET_URL:=https://raw.githubusercontent.com/google/fuzzbench/master/benchmarks/libxml2-v2.9.2/target.cc +TARGET_SRC:=$(BUILD_DIR)target.cc +TARGET_OBJ:=$(BUILD_DIR)target.o + +HARNESS_URL:="https://raw.githubusercontent.com/llvm/llvm-project/main/compiler-rt/lib/fuzzer/standalone/StandaloneFuzzTargetMain.c" +HARNESS_SRC:=$(BUILD_DIR)StandaloneFuzzTargetMain.c +HARNESS_OBJ:=$(BUILD_DIR)StandaloneFuzzTargetMain.o + +TEST_BIN:=$(BUILD_DIR)test + +ifeq "$(shell uname)" "Darwin" +TEST_BIN_LDFLAGS:=-undefined dynamic_lookup -Wl,-no_pie +endif + +TEST_DATA_DIR:=$(BUILD_DIR)in/ +TEST_DATA_FILE:=$(TEST_DATA_DIR)default_seed +DUMMY_DATA_FILE:=$(BUILD_DIR)dummy.dat + +FRIDA_OUT:=$(BUILD_DIR)frida-out +QEMU_OUT:=$(BUILD_DIR)qemu-out + +ifndef ARCH + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + ARCH:=arm64 +endif + +ifeq "$(ARCH)" "i686" + ARCH:=x86 +endif +endif + +GET_SYMBOL_ADDR:=$(ROOT)frida_mode/util/get_symbol_addr.sh + +AFL_QEMU_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput 0x4000000000) + +ifeq "$(ARCH)" "aarch64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput 0x0000aaaaaaaaa000) +endif + +ifeq "$(ARCH)" "x86_64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput 0x0000555555554000) +endif + +ifeq "$(ARCH)" "x86" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput 0x56555000) +endif + +.PHONY: all clean frida hook + +all: $(TEST_BIN) + make -C $(ROOT)frida_mode/ + +32: + CXXFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + +$(BUILD_DIR): + mkdir -p $@ + +########## LIBXML ####### + +$(LIBXML_DIR): | $(BUILD_DIR) + git clone --depth 1 $(LIBXML_GIT_REPO) $@ + +$(LIBXML_BIN): | $(LIBXML_DIR) + cd $(LIBXML_DIR) && git fetch --tags + cd $(LIBXML_DIR) && git checkout -f v2.9.2 + cd $(LIBXML_DIR) && ./autogen.sh + cd $(LIBXML_DIR) && CCLD="$CXX $CXXFLAGS" ./configure --without-python --with-threads=no \ + --with-zlib=no --with-lzma=no + cd $(LIBXML_DIR) && make + +libxml: $(LIBXML_BIN) + +########## TARGET ####### + +$(TARGET_SRC): + wget -O $@ $(TARGET_URL) + +$(TARGET_OBJ): $(TARGET_SRC) $(LIBXML_BIN) + $(CXX) \ + $(CXXFLAGS) \ + -std=c++11 \ + -I $(LIBXML_DIR)include \ + -c $< \ + -o $@ + +target: $(TARGET_OBJ) + + +######### HARNESS ######## +$(HARNESS_SRC): | $(BUILD_DIR) + wget -O $@ $(HARNESS_URL) + +$(HARNESS_OBJ): $(HARNESS_SRC) + $(CC) $(CXXFLAGS) $(LDFLAGS) -o $@ -c $< + +harness: $(HARNESS_OBJ) + +######### TEST ######## + +$(TEST_BIN): $(HARNESS_OBJ) $(TARGET_OBJ) $(LIBXML_BIN) + $(CXX) \ + $(CFLAGS) \ + -o $@ \ + $(HARNESS_OBJ) \ + $(TARGET_OBJ) \ + $(LIBXML_BIN) \ + $(LDFLAGS) \ + $(TEST_BIN_LDFLAGS) \ + +test: $(TEST_BIN) + +########## DUMMY ####### + +$(DUMMY_DATA_FILE): | $(BUILD_DIR) + dd if=/dev/zero bs=1048576 count=1 of=$@ + +###### TEST DATA ####### + +$(TEST_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(TEST_DATA_FILE): | $(TEST_DATA_DIR) + dd if=/dev/zero bs=1048576 count=1 of=$@ + +###### ####### + +clean: + rm -rf $(BUILD_DIR) + +frida: $(TEST_BIN) $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) $(TEST_DATA_FILE) $(DUMMY_DATA_FILE) + AFL_FRIDA_PERSISTENT_CNT=1000000 \ + AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_FRIDA_DRIVER_HOOK_OBJ) \ + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + AFL_ENTRYPOINT=$(AFL_FRIDA_PERSISTENT_ADDR) \ + $(ROOT)afl-fuzz \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -m none \ + -d \ + -O \ + -V 30 \ + -- \ + $(TEST_BIN) $(DUMMY_DATA_FILE) + +qemu: $(TEST_BIN) $(AFLPP_QEMU_DRIVER_HOOK_OBJ) $(TEST_DATA_FILE) $(DUMMY_DATA_FILE) + AFL_QEMU_PERSISTENT_CNT=1000000 \ + AFL_QEMU_PERSISTENT_HOOK=$(AFLPP_QEMU_DRIVER_HOOK_OBJ) \ + AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \ + AFL_ENTRYPOINT=$(AFL_QEMU_PERSISTENT_ADDR) \ + $(ROOT)afl-fuzz \ + -i $(TEST_DATA_DIR) \ + -o $(QEMU_OUT) \ + -m none \ + -d \ + -Q \ + -V 30 \ + -- \ + $(TEST_BIN) $(DUMMY_DATA_FILE) diff --git a/frida_mode/test/libxml/Makefile b/frida_mode/test/libxml/Makefile new file mode 100644 index 00000000..07b139e9 --- /dev/null +++ b/frida_mode/test/libxml/Makefile @@ -0,0 +1,13 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + +clean: + @gmake clean + +frida: + @gmake frida diff --git a/frida_mode/test/libxml/get_symbol_addr.py b/frida_mode/test/libxml/get_symbol_addr.py new file mode 100755 index 00000000..1c46e010 --- /dev/null +++ b/frida_mode/test/libxml/get_symbol_addr.py @@ -0,0 +1,36 @@ +#!/usr/bin/python3 +import argparse +from elftools.elf.elffile import ELFFile + +def process_file(file, symbol, base): + with open(file, 'rb') as f: + elf = ELFFile(f) + symtab = elf.get_section_by_name('.symtab') + mains = symtab.get_symbol_by_name(symbol) + if len(mains) != 1: + print ("Failed to find main") + return 1 + + main_addr = mains[0]['st_value'] + main = base + main_addr + print ("0x%016x" % main) + return 0 + +def hex_value(x): + return int(x, 16) + +def main(): + parser = argparse.ArgumentParser(description='Process some integers.') + parser.add_argument('-f', '--file', dest='file', type=str, + help='elf file name', required=True) + parser.add_argument('-s', '--symbol', dest='symbol', type=str, + help='symbol name', required=True) + parser.add_argument('-b', '--base', dest='base', type=hex_value, + help='elf base address', required=True) + + args = parser.parse_args() + return process_file (args.file, args.symbol, args.base) + +if __name__ == "__main__": + ret = main() + exit(ret) diff --git a/instrumentation/split-compares-pass.so.cc b/instrumentation/split-compares-pass.so.cc index 95485be9..c06118c0 100644 --- a/instrumentation/split-compares-pass.so.cc +++ b/instrumentation/split-compares-pass.so.cc @@ -882,6 +882,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { // 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 @@ -913,14 +914,99 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(FcmpInst)); /* create the integers from floats directly */ - Instruction *b_op0, *b_op1; - b_op0 = CastInst::Create(Instruction::BitCast, op0, + Instruction *bpre_op0, *bpre_op1; + bpre_op0 = CastInst::Create(Instruction::BitCast, op0, IntegerType::get(C, op_size)); - bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), b_op0); + bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), bpre_op0); - b_op1 = CastInst::Create(Instruction::BitCast, op1, + bpre_op1 = CastInst::Create(Instruction::BitCast, op1, IntegerType::get(C, op_size)); - bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), b_op1); + 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 */ @@ -931,21 +1017,21 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { s_s0 = BinaryOperator::Create(Instruction::LShr, b_op0, ConstantInt::get(b_op0->getType(), op_size - 1)); - bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), s_s0); + nonan_bb->getInstList().insert(BasicBlock::iterator(nonan_bb->getTerminator()), s_s0); t_s0 = new TruncInst(s_s0, Int1Ty); - bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), t_s0); + 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)); - bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), s_s1); + nonan_bb->getInstList().insert(BasicBlock::iterator(nonan_bb->getTerminator()), s_s1); t_s1 = new TruncInst(s_s1, Int1Ty); - bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), t_s1); + 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); - bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), + 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 @@ -962,9 +1048,9 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { BranchInst::Create(end_bb, middle_bb); - auto term = bb->getTerminator(); + 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, bb); + BranchInst::Create(signequal_bb, end_bb, icmp_sign_bit, nonan_bb); term->eraseFromParent(); /* insert code for equal signs */ @@ -1261,7 +1347,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { } - PHINode *PN = PHINode::Create(Int1Ty, 3, ""); + PHINode *PN = PHINode::Create(Int1Ty, 4, ""); switch (FcmpInst->getPredicate()) { @@ -1269,37 +1355,45 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { case CmpInst::FCMP_OEQ: /* unequal signs cannot be equal values */ /* goto false branch */ - PN->addIncoming(ConstantInt::get(Int1Ty, 0), bb); + 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), bb); + 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, bb); + 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, bb); + 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; @@ -1341,18 +1435,15 @@ bool SplitComparesTransform::runOnModule(Module &M) { if (enableFPSplit) { + simplifyFPCompares(M); count = splitFPCompares(M); - /* - if (!be_quiet) { + if (!be_quiet && !debug) { errs() << "Split-floatingpoint-compare-pass: " << count - << " FP comparisons split\n"; + << " FP comparisons splitted\n"; - } - - */ - simplifyFPCompares(M); + } } 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..88a89ead --- /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..78d32711 --- /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_minusZerocases.c b/test/test-fp_minusZerocases.c new file mode 100644 index 00000000..00beef2e --- /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)); + +} + |