Merge pull request #1755 from AFLplusplus/dev

push to stable
This commit is contained in:
van Hauser 2023-06-05 14:12:56 +03:00 committed by GitHub
commit f9b72b6f2f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 487 additions and 476 deletions

View File

@ -49,7 +49,7 @@ LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^[
LLVM_TOO_NEW = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[5-9]' && echo 1 || echo 0 ) LLVM_TOO_NEW = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[5-9]' && echo 1 || echo 0 )
LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[0-9]' && echo 1 || echo 0 ) LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[0-9]' && echo 1 || echo 0 )
LLVM_NEWER_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[6-9]' && echo 1 || echo 0 ) LLVM_NEWER_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[6-9]' && echo 1 || echo 0 )
LLVM_10_OK = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[1-9]|^10\.[1-9]|^10\.0.[1-9]' && echo 1 || echo 0 ) LLVM_13_OK = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[3-9]' && echo 1 || echo 0 )
LLVM_HAVE_LTO = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[1-9]' && echo 1 || echo 0 ) LLVM_HAVE_LTO = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[1-9]' && echo 1 || echo 0 )
LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null) LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null)
LLVM_LIBDIR = $(shell $(LLVM_CONFIG) --libdir 2>/dev/null) LLVM_LIBDIR = $(shell $(LLVM_CONFIG) --libdir 2>/dev/null)
@ -422,7 +422,7 @@ endif
$(CXX) $(CLANG_CPPFL) -Wdeprecated -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o $(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 ./SanitizerCoveragePCGUARD.so: instrumentation/SanitizerCoveragePCGUARD.so.cc instrumentation/afl-llvm-common.o | test_deps
ifeq "$(LLVM_10_OK)" "1" ifeq "$(LLVM_13_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 -$(CXX) $(CLANG_CPPFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) -Wno-deprecated-copy-dtor -Wdeprecated instrumentation/afl-llvm-common.o
endif endif

View File

@ -2,9 +2,7 @@
## Should ## Should
- redo PCGUARD + LTO for llvm 15+
- test cmplog for less than 16bit - test cmplog for less than 16bit
- splicing selection weighted?
- support persistent and deferred fork server in afl-showmap? - support persistent and deferred fork server in afl-showmap?
- better autodetection of shifting runtime timeout values - better autodetection of shifting runtime timeout values
- Update afl->pending_not_fuzzed for MOpt - Update afl->pending_not_fuzzed for MOpt

View File

@ -206,7 +206,7 @@ fi
# Check for obvious errors. # Check for obvious errors.
if [ ! "$T_ARG" = "" -a ! "$F_ARG" = "" -a ! "$NYX_MODE" == 1 ]; then if [ ! "$T_ARG" = "" -a -n "$F_ARG" -a ! "$NYX_MODE" == 1 ]; then
echo "[-] Error: -T and -f can not be used together." 1>&2 echo "[-] Error: -T and -f can not be used together." 1>&2
exit 1 exit 1
fi fi
@ -323,7 +323,7 @@ if [ ! "$T_ARG" = "" ]; then
fi fi
fi fi
else else
if [ "$F_ARG" = ""]; then if [ -z "$F_ARG" ]; then
echo "[*] Are you aware of the '-T all' parallelize option that massively improves the speed?" echo "[*] Are you aware of the '-T all' parallelize option that massively improves the speed?"
fi fi
fi fi

View File

@ -15,13 +15,16 @@
- new env `AFL_LLVM_LTO_SKIPINIT` to support the AFL++ based WASM - new env `AFL_LLVM_LTO_SKIPINIT` to support the AFL++ based WASM
(https://github.com/fgsect/WAFL) project (https://github.com/fgsect/WAFL) project
- error and print help if afl-clan-lto is used with lto=thin - error and print help if afl-clan-lto is used with lto=thin
- rewrote our PCGUARD pass to be compatible with LLVM 15+ shenanigans,
requires LLVM 13+ now instead of 10.0.1+
- fallback to native LLVM PCGUARD if our PCGUARD is unavailable
- afl-showmap: - afl-showmap:
- added custom mutator post_process and send support - added custom mutator post_process and send support
- add `-I filelist` option, an alternative to `-i in_dir` - add `-I filelist` option, an alternative to `-i in_dir`
- afl-cmin + afl-cmin.bash: - afl-cmin + afl-cmin.bash:
- `-T threads` parallel task support, can be a huge speedup! - `-T threads` parallel task support, can be a huge speedup!
- qemu_mode: - qemu_mode:
- Persistent mode +QASAN support for ppc32 tragets by @worksbutnottested - Persistent mode + QASAN support for ppc32 targets by @worksbutnottested
- a new grammar custom mutator atnwalk was submitted by @voidptr127 ! - a new grammar custom mutator atnwalk was submitted by @voidptr127 !
- two new custom mutators are now available: - two new custom mutators are now available:
- TritonDSE in custom_mutators/aflpp_tritondse - TritonDSE in custom_mutators/aflpp_tritondse

View File

@ -14,8 +14,6 @@ void entry_init(void);
void entry_start(void); void entry_start(void);
void entry_prologue(GumStalkerIterator *iterator, GumStalkerOutput *output);
void entry_on_fork(void); void entry_on_fork(void);
#endif #endif

View File

@ -78,6 +78,7 @@ void entry_init(void) {
void entry_start(void) { void entry_start(void) {
FVERBOSE("AFL_ENTRYPOINT reached");
if (persistent_start == 0) { if (persistent_start == 0) {
ranges_exclude(); ranges_exclude();
@ -85,32 +86,7 @@ void entry_start(void) {
} }
if (entry_point == 0) { entry_launch(); }
}
static void entry_callout(GumCpuContext *cpu_context, gpointer user_data) {
UNUSED_PARAMETER(cpu_context);
UNUSED_PARAMETER(user_data);
entry_compiled = TRUE;
entry_launch(); entry_launch();
} }
void entry_prologue(GumStalkerIterator *iterator, GumStalkerOutput *output) {
UNUSED_PARAMETER(output);
FVERBOSE("AFL_ENTRYPOINT reached");
if (persistent_start == 0) {
ranges_exclude();
stalker_trust();
}
gum_stalker_iterator_put_callout(iterator, entry_callout, NULL, NULL);
}

View File

@ -169,7 +169,6 @@ static void instrument_basic_block(GumStalkerIterator *iterator,
if (unlikely(begin)) { instrument_debug_start(instr->address, output); } if (unlikely(begin)) { instrument_debug_start(instr->address, output); }
if (instr->address == entry_point) { entry_prologue(iterator, output); }
if (instr->address == persistent_start) { persistent_prologue(output); } if (instr->address == persistent_start) { persistent_prologue(output); }
if (instr->address == persistent_ret) { persistent_epilogue(output); } if (instr->address == persistent_ret) { persistent_epilogue(output); }

View File

@ -76,6 +76,45 @@ typedef struct {
} afl_log_code_asm_t; } afl_log_code_asm_t;
typedef struct {
uint32_t b_imm8; /* br #XX (end) */
uint32_t restoration_prolog; /* ldp x16, x17, [sp], #0x90 */
uint32_t stp_x0_x1; /* stp x0, x1, [sp, #-0xa0] */
uint32_t ldr_x0_p_prev_loc_1; /* ldr x0, #0xXXXX */
uint32_t ldr_x1_ptr_x0; /* ldr x1, [x0] */
uint32_t ldr_x0_p_area_offset; /* ldr x0, #0xXXXX */
uint32_t eor_x0_x1_x0; /* eor x0, x1, x0 */
uint32_t ldr_x1_p_area_ptr; /* ldr x1, #0xXXXX */
uint32_t add_x0_x1_x0; /* add x0, x1, x0 */
uint32_t ldrb_w1_x0; /* ldrb w1, [x0] */
uint32_t add_w1_w1_1; /* add w1, w1, #1 */
uint32_t add_w1_w1_w1_lsr_8; /* add x1, x1, x1, lsr #8 */
uint32_t strb_w1_ptr_x0; /* strb w1, [x0] */
uint32_t ldr_x0_p_prev_loc_2; /* ldr x0, #0xXXXX */
uint32_t ldr_x1_p_area_offset_ror; /* ldr x1, #0xXXXX */
uint32_t str_x1_ptr_x0; /* str x1, [x0] */
uint32_t ldp_x0_x1; /* ldp x0, x1, [sp, #-0xa0] */
uint32_t b_end; /* skip the data */
uint64_t area_ptr;
uint64_t prev_loc_ptr;
uint64_t area_offset;
uint64_t area_offset_ror;
uint8_t end[0];
} afl_log_code_asm_long_t;
#pragma pack(pop) #pragma pack(pop)
typedef union { typedef union {
@ -85,6 +124,13 @@ typedef union {
} afl_log_code; } afl_log_code;
typedef union {
afl_log_code_asm_long_t code;
uint8_t bytes[0];
} afl_log_code_long;
static const afl_log_code_asm_t template = static const afl_log_code_asm_t template =
{ {
@ -119,6 +165,46 @@ static const afl_log_code_asm_t template =
; ;
static const afl_log_code_asm_long_t template_long =
{.b_imm8 = 0x1400001a,
.restoration_prolog = 0xa8c947f0, /* ldp x16, x17, [sp], #0x90 */
.stp_x0_x1 = 0xa93607e0, /* stp x0, x1, [sp, #-0xa0] */
.ldr_x0_p_prev_loc_1 = 0x58000220, /* ldr x0, #0xXXXX */
.ldr_x1_ptr_x0 = 0xf9400001, /* ldr x1, [x0] */
.ldr_x0_p_area_offset = 0x58000220, /* ldr x0, #0xXXXX */
.eor_x0_x1_x0 = 0xca000020, /* eor x0, x1, x0 */
.ldr_x1_p_area_ptr = 0x58000161, /* ldr x1, #0xXXXX */
.add_x0_x1_x0 = 0x8b000020, /* add x0, x1, x0 */
.ldrb_w1_x0 = 0x39400001, /* ldrb w1, [x0] */
.add_w1_w1_1 = 0x11000421, /* add w1, w1, #1 */
.add_w1_w1_w1_lsr_8 = 0x8b412021, /* add x1, x1, x1, lsr #8 */
.strb_w1_ptr_x0 = 0x39000001, /* strb w1, [x0] */
.ldr_x0_p_prev_loc_2 = 0x580000e0, /* ldr x0, #0xXXXX */
.ldr_x1_p_area_offset_ror = 0x58000141, /* ldr x1, #0xXXXX */
.str_x1_ptr_x0 = 0xf9000001, /* str x1, [x0] */
.ldp_x0_x1 = 0xa97607e0, /* ldp x0, x1, [sp, #-0xa0] */
.b_end = 0x14000009, /* skip the data */
.area_ptr = 0x0,
.prev_loc_ptr = 0x0,
.area_offset = 0x0,
.area_offset_ror = 0x0,
.end = {}
}
;
gboolean instrument_is_coverage_optimize_supported(void) { gboolean instrument_is_coverage_optimize_supported(void) {
return true; return true;
@ -266,16 +352,22 @@ static gboolean instrument_coverage_in_range(gssize offset) {
} }
static void instrument_patch_ardp(guint32 *patch, GumAddress insn, static bool instrument_patch_ardp(guint32 *patch, GumAddress insn,
GumAddress target) { GumAddress target) {
if (!PAGE_ALIGNED(target)) { FATAL("Target not page aligned"); } if (!PAGE_ALIGNED(target)) {
FWARNF("Target not page aligned");
return false;
}
gssize distance = target - (GUM_ADDRESS(insn) & PAGE_MASK); gssize distance = target - (GUM_ADDRESS(insn) & PAGE_MASK);
if (!instrument_coverage_in_range(distance)) { if (!instrument_coverage_in_range(distance)) {
FATAL("Patch out of range 0x%016lX->0x%016lX = 0x%016lX", insn, target, FVERBOSE("Patch out of range 0x%016lX->0x%016lX = 0x%016lX", insn, target,
distance); distance);
return false;
} }
@ -283,6 +375,95 @@ static void instrument_patch_ardp(guint32 *patch, GumAddress insn,
guint32 imm_high = ((distance >> 14) & 0x7FFFF) << 5; guint32 imm_high = ((distance >> 14) & 0x7FFFF) << 5;
*patch |= imm_low; *patch |= imm_low;
*patch |= imm_high; *patch |= imm_high;
return true;
}
bool instrument_write_inline(GumArm64Writer *cw, GumAddress code_addr,
guint64 area_offset, gsize area_offset_ror) {
afl_log_code code = {0};
code.code = template;
/*
* Given our map is allocated on a 64KB boundary and our map is a multiple of
* 64KB in size, then it should also end on a 64 KB boundary. It is followed
* by our previous_pc, so this too should be 64KB aligned.
*/
g_assert(PAGE_ALIGNED(instrument_previous_pc_addr));
g_assert(PAGE_ALIGNED(__afl_area_ptr));
if (!instrument_patch_ardp(
&code.code.adrp_x0_prev_loc1,
code_addr + offsetof(afl_log_code, code.adrp_x0_prev_loc1),
GUM_ADDRESS(instrument_previous_pc_addr))) {
return false;
}
code.code.mov_x0_curr_loc |= area_offset << 5;
if (!instrument_patch_ardp(
&code.code.adrp_x1_area_ptr,
code_addr + offsetof(afl_log_code, code.adrp_x1_area_ptr),
GUM_ADDRESS(__afl_area_ptr))) {
return false;
}
if (!instrument_patch_ardp(
&code.code.adrp_x0_prev_loc2,
code_addr + offsetof(afl_log_code, code.adrp_x0_prev_loc2),
GUM_ADDRESS(instrument_previous_pc_addr))) {
return false;
}
code.code.mov_x1_curr_loc_shr_1 |= (area_offset_ror << 5);
if (instrument_suppress) {
gum_arm64_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code));
} else {
size_t offset = offsetof(afl_log_code, code.stp_x0_x1);
gum_arm64_writer_put_bytes(cw, &code.bytes[offset],
sizeof(afl_log_code) - offset);
}
return true;
}
bool instrument_write_inline_long(GumArm64Writer *cw, GumAddress code_addr,
guint64 area_offset, gsize area_offset_ror) {
afl_log_code_long code = {0};
code.code = template_long;
code.code.area_ptr = GUM_ADDRESS(__afl_area_ptr);
code.code.prev_loc_ptr = GUM_ADDRESS(instrument_previous_pc_addr);
code.code.area_offset = area_offset;
code.code.area_offset_ror = GUM_ADDRESS(area_offset_ror);
if (instrument_suppress) {
gum_arm64_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code_long));
} else {
size_t offset = offsetof(afl_log_code_long, code.stp_x0_x1);
gum_arm64_writer_put_bytes(cw, &code.bytes[offset],
sizeof(afl_log_code_long) - offset);
}
return true;
} }
@ -312,6 +493,8 @@ void instrument_coverage_optimize(const cs_insn *instr,
} }
// gum_arm64_writer_put_brk_imm(cw, 0x0); // gum_arm64_writer_put_brk_imm(cw, 0x0);
// uint32_t jmp_dot = 0x14000000;
// gum_arm64_writer_put_bytes(cw, (guint8 *)&jmp_dot, sizeof(jmp_dot));
if (instrument_suppress) { instrument_coverage_suppress_init(); } if (instrument_suppress) { instrument_coverage_suppress_init(); }
@ -343,47 +526,19 @@ void instrument_coverage_optimize(const cs_insn *instr,
} }
code.code = template;
/*
* Given our map is allocated on a 64KB boundary and our map is a multiple of
* 64KB in size, then it should also end on a 64 KB boundary. It is followed
* by our previous_pc, so this too should be 64KB aligned.
*/
g_assert(PAGE_ALIGNED(instrument_previous_pc_addr));
g_assert(PAGE_ALIGNED(__afl_area_ptr));
instrument_patch_ardp(
&code.code.adrp_x0_prev_loc1,
code_addr + offsetof(afl_log_code, code.adrp_x0_prev_loc1),
GUM_ADDRESS(instrument_previous_pc_addr));
code.code.mov_x0_curr_loc |= area_offset << 5;
instrument_patch_ardp(
&code.code.adrp_x1_area_ptr,
code_addr + offsetof(afl_log_code, code.adrp_x1_area_ptr),
GUM_ADDRESS(__afl_area_ptr));
map_size_pow2 = util_log2(__afl_map_size); map_size_pow2 = util_log2(__afl_map_size);
area_offset_ror = util_rotate(area_offset, 1, map_size_pow2); area_offset_ror = util_rotate(area_offset, 1, map_size_pow2);
instrument_patch_ardp( code.code = template;
&code.code.adrp_x0_prev_loc2,
code_addr + offsetof(afl_log_code, code.adrp_x0_prev_loc2),
GUM_ADDRESS(instrument_previous_pc_addr));
code.code.mov_x1_curr_loc_shr_1 |= (area_offset_ror << 5); if (!instrument_write_inline(cw, code_addr, area_offset, area_offset_ror)) {
if (instrument_suppress) { if (!instrument_write_inline_long(cw, code_addr, area_offset,
area_offset_ror)) {
gum_arm64_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code)); FATAL("Failed to write inline instrumentation");
} else { }
size_t offset = offsetof(afl_log_code, code.stp_x0_x1);
gum_arm64_writer_put_bytes(cw, &code.bytes[offset],
sizeof(afl_log_code) - offset);
} }

View File

@ -197,7 +197,7 @@ static void afl_print_env(void) {
} }
__attribute__((visibility("default"))) void afl_frida_start(void) { void afl_frida_config(void) {
FOKF(cRED "**********************"); FOKF(cRED "**********************");
FOKF(cRED "* " cYEL "******************" cRED " *"); FOKF(cRED "* " cYEL "******************" cRED " *");
@ -225,9 +225,7 @@ __attribute__((visibility("default"))) void afl_frida_start(void) {
js_start(); js_start();
/* Initialize */
output_init(); output_init();
embedded_init(); embedded_init();
entry_init(); entry_init();
instrument_init(); instrument_init();
@ -240,12 +238,35 @@ __attribute__((visibility("default"))) void afl_frida_start(void) {
ranges_init(); ranges_init();
stats_init(); stats_init();
/* Start */ }
void afl_frida_run(void) {
stalker_start(); stalker_start();
entry_start(); entry_start();
} }
__attribute__((visibility("default"))) void afl_frida_start(void) {
afl_frida_config();
afl_frida_run();
}
typedef void *(*entry_func_t)(size_t a1, size_t a2, size_t a3, size_t a4,
size_t a5, size_t a6);
static void *on_entry(size_t a1, size_t a2, size_t a3, size_t a4, size_t a5,
size_t a6) {
intercept_unhook(GSIZE_TO_POINTER(entry_point));
afl_frida_run();
entry_func_t entry = (entry_func_t)entry_point;
return entry(a1, a2, a3, a4, a5, a6);
}
static int on_main(int argc, char **argv, char **envp) { static int on_main(int argc, char **argv, char **envp) {
int ret; int ret;
@ -254,7 +275,17 @@ static int on_main(int argc, char **argv, char **envp) {
intercept_unhook_self(); intercept_unhook_self();
afl_frida_start(); afl_frida_config();
if (entry_point == 0) {
afl_frida_run();
} else {
intercept_hook(GSIZE_TO_POINTER(entry_point), on_entry, NULL);
}
if (js_main_hook != NULL) { if (js_main_hook != NULL) {

View File

@ -67,3 +67,8 @@ debug:
--ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \ --ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \
--ex 'set disassembly-flavor intel' \ --ex 'set disassembly-flavor intel' \
--args $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) --args $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
lldb:
lldb \
-O 'settings set target.env-vars DYLD_INSERT_LIBRARIES=$(ROOT)afl-frida-trace.so' \
-- $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)

View File

@ -331,7 +331,7 @@ llvmGetPassPluginInfo() {
#if LLVM_VERSION_MAJOR <= 13 #if LLVM_VERSION_MAJOR <= 13
using OptimizationLevel = typename PassBuilder::OptimizationLevel; using OptimizationLevel = typename PassBuilder::OptimizationLevel;
#endif #endif
#if LLVM_VERSION_MAJOR >= 15 #if LLVM_VERSION_MAJOR >= 16
PB.registerFullLinkTimeOptimizationLastEPCallback( PB.registerFullLinkTimeOptimizationLastEPCallback(
#else #else
PB.registerOptimizerLastEPCallback( PB.registerOptimizerLastEPCallback(

View File

@ -13,42 +13,64 @@
#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h" #include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallVector.h"
#if LLVM_VERSION_MAJOR >= 15
#if LLVM_VERSION_MAJOR < 17
#include "llvm/ADT/Triple.h"
#endif
#endif
#if LLVM_VERSION_MAJOR < 17 #if LLVM_VERSION_MAJOR < 17
#include "llvm/ADT/Triple.h"
#include "llvm/Analysis/EHPersonalities.h" #include "llvm/Analysis/EHPersonalities.h"
#else
#include "llvm/IR/EHPersonalities.h"
#endif #endif
#include "llvm/Analysis/PostDominators.h" #include "llvm/Analysis/PostDominators.h"
#include "llvm/IR/CFG.h" #if LLVM_VERSION_MAJOR < 15
#include "llvm/IR/CFG.h"
#endif
#include "llvm/IR/Constant.h" #include "llvm/IR/Constant.h"
#include "llvm/IR/DataLayout.h" #include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugInfo.h" #if LLVM_VERSION_MAJOR < 15
#include "llvm/IR/DebugInfo.h"
#endif
#include "llvm/IR/Dominators.h" #include "llvm/IR/Dominators.h"
#if LLVM_VERSION_MAJOR >= 17
#include "llvm/Analysis/EHPersonalities.h"
#endif
#include "llvm/IR/Function.h" #include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h" #if LLVM_VERSION_MAJOR >= 16
#include "llvm/IR/GlobalVariable.h"
#endif
#include "llvm/IR/IRBuilder.h" #include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InlineAsm.h" #if LLVM_VERSION_MAJOR < 15
#include "llvm/IR/InlineAsm.h"
#endif
#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h" #include "llvm/IR/Intrinsics.h"
#include "llvm/IR/LLVMContext.h" #include "llvm/IR/LLVMContext.h"
#include "llvm/IR/MDBuilder.h" #if LLVM_VERSION_MAJOR < 15
#include "llvm/IR/Mangler.h" #include "llvm/IR/MDBuilder.h"
#include "llvm/IR/Mangler.h"
#endif
#include "llvm/IR/Module.h" #include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h" #include "llvm/IR/PassManager.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/IR/Type.h" #include "llvm/IR/Type.h"
#include "llvm/InitializePasses.h" #if LLVM_VERSION_MAJOR < 17
#include "llvm/InitializePasses.h"
#endif
#include "llvm/Support/CommandLine.h" #include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h" #include "llvm/Support/Debug.h"
#include "llvm/Support/SpecialCaseList.h" #include "llvm/Support/SpecialCaseList.h"
#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/VirtualFileSystem.h"
#include "llvm/Support/raw_ostream.h" #if LLVM_VERSION_MAJOR < 15
#include "llvm/Transforms/Instrumentation.h" #include "llvm/Support/raw_ostream.h"
#endif
#if LLVM_VERSION_MAJOR < 17
#include "llvm/Transforms/Instrumentation.h"
#else
#include "llvm/TargetParser/Triple.h"
#endif
#include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/ModuleUtils.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 "config.h"
#include "debug.h" #include "debug.h"
@ -58,7 +80,8 @@ using namespace llvm;
#define DEBUG_TYPE "sancov" #define DEBUG_TYPE "sancov"
const char SanCovTracePCIndirName[] = "__sanitizer_cov_trace_pc_indir"; static const uint64_t SanCtorAndDtorPriority = 2;
const char SanCovTracePCName[] = "__sanitizer_cov_trace_pc"; const char SanCovTracePCName[] = "__sanitizer_cov_trace_pc";
const char SanCovTraceCmp1[] = "__sanitizer_cov_trace_cmp1"; const char SanCovTraceCmp1[] = "__sanitizer_cov_trace_cmp1";
const char SanCovTraceCmp2[] = "__sanitizer_cov_trace_cmp2"; const char SanCovTraceCmp2[] = "__sanitizer_cov_trace_cmp2";
@ -68,22 +91,13 @@ const char SanCovTraceConstCmp1[] = "__sanitizer_cov_trace_const_cmp1";
const char SanCovTraceConstCmp2[] = "__sanitizer_cov_trace_const_cmp2"; const char SanCovTraceConstCmp2[] = "__sanitizer_cov_trace_const_cmp2";
const char SanCovTraceConstCmp4[] = "__sanitizer_cov_trace_const_cmp4"; const char SanCovTraceConstCmp4[] = "__sanitizer_cov_trace_const_cmp4";
const char SanCovTraceConstCmp8[] = "__sanitizer_cov_trace_const_cmp8"; 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 SanCovTraceSwitchName[] = "__sanitizer_cov_trace_switch";
const char SanCovModuleCtorTracePcGuardName[] = const char SanCovModuleCtorTracePcGuardName[] =
"sancov.module_ctor_trace_pc_guard"; "sancov.module_ctor_trace_pc_guard";
const char SanCovModuleCtor8bitCountersName[] = const char SanCovTracePCGuardInitName[] = "__sanitizer_cov_trace_pc_guard_init";
"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 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 SanCovGuardsSectionName[] = "sancov_guards";
const char SanCovCountersSectionName[] = "sancov_cntrs"; const char SanCovCountersSectionName[] = "sancov_cntrs";
@ -99,27 +113,9 @@ namespace {
SanitizerCoverageOptions OverrideFromCL(SanitizerCoverageOptions Options) { SanitizerCoverageOptions OverrideFromCL(SanitizerCoverageOptions Options) {
// Sets CoverageType and IndirectCalls. Options.CoverageType = SanitizerCoverageOptions::SCK_Edge;
// SanitizerCoverageOptions CLOpts = getOptions(ClCoverageLevel); // Options.NoPrune = true;
Options.CoverageType = Options.TracePCGuard = true; // TracePCGuard is default.
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; return Options;
} }
@ -139,20 +135,13 @@ class ModuleSanitizerCoverageAFL
} }
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM); PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
bool instrumentModule(Module &M, DomTreeCallback DTCallback,
bool instrumentModule(Module &M, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback);
PostDomTreeCallback PDTCallback);
private: private:
void instrumentFunction(Function &F, DomTreeCallback DTCallback, void instrumentFunction(Function &F, DomTreeCallback DTCallback,
PostDomTreeCallback PDTCallback); PostDomTreeCallback PDTCallback);
void InjectCoverageForIndirectCalls(Function &F,
ArrayRef<Instruction *> IndirCalls);
void InjectTraceForCmp(Function &F, ArrayRef<Instruction *> CmpTraceTargets); 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, void InjectTraceForSwitch(Function &F,
ArrayRef<Instruction *> SwitchTraceTargets); ArrayRef<Instruction *> SwitchTraceTargets);
bool InjectCoverage(Function &F, ArrayRef<BasicBlock *> AllBlocks, bool InjectCoverage(Function &F, ArrayRef<BasicBlock *> AllBlocks,
@ -173,20 +162,21 @@ class ModuleSanitizerCoverageAFL
void SetNoSanitizeMetadata(Instruction *I) { void SetNoSanitizeMetadata(Instruction *I) {
#if LLVM_VERSION_MAJOR >= 16
I->setMetadata(LLVMContext::MD_nosanitize, MDNode::get(*C, std::nullopt));
#else
I->setMetadata(I->getModule()->getMDKindID("nosanitize"), I->setMetadata(I->getModule()->getMDKindID("nosanitize"),
MDNode::get(*C, None)); MDNode::get(*C, None));
#endif
} }
std::string getSectionName(const std::string &Section) const; std::string getSectionName(const std::string &Section) const;
std::string getSectionStart(const std::string &Section) const; std::string getSectionStart(const std::string &Section) const;
std::string getSectionEnd(const std::string &Section) const; std::string getSectionEnd(const std::string &Section) const;
FunctionCallee SanCovTracePCIndir;
FunctionCallee SanCovTracePC, SanCovTracePCGuard; FunctionCallee SanCovTracePC, SanCovTracePCGuard;
FunctionCallee SanCovTraceCmpFunction[4]; FunctionCallee SanCovTraceCmpFunction[4];
FunctionCallee SanCovTraceConstCmpFunction[4]; FunctionCallee SanCovTraceConstCmpFunction[4];
FunctionCallee SanCovTraceDivFunction[2];
FunctionCallee SanCovTraceGepFunction;
FunctionCallee SanCovTraceSwitchFunction; FunctionCallee SanCovTraceSwitchFunction;
GlobalVariable *SanCovLowestStack; GlobalVariable *SanCovLowestStack;
Type *IntptrTy, *IntptrPtrTy, *Int64Ty, *Int64PtrTy, *Int32Ty, *Int32PtrTy, Type *IntptrTy, *IntptrPtrTy, *Int64Ty, *Int64PtrTy, *Int32Ty, *Int32PtrTy,
@ -215,18 +205,16 @@ class ModuleSanitizerCoverageAFL
} // namespace } // namespace
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
llvmGetPassPluginInfo() { llvmGetPassPluginInfo() {
return {LLVM_PLUGIN_API_VERSION, "SanitizerCoveragePCGUARD", "v0.1", return {LLVM_PLUGIN_API_VERSION, "SanitizerCoveragePCGUARD", "v0.2",
/* lambda to insert our pass into the pass pipeline. */ /* lambda to insert our pass into the pass pipeline. */
[](PassBuilder &PB) { [](PassBuilder &PB) {
#if LLVM_VERSION_MAJOR <= 13 #if LLVM_VERSION_MAJOR == 13
using OptimizationLevel = typename PassBuilder::OptimizationLevel; using OptimizationLevel = typename PassBuilder::OptimizationLevel;
#endif #endif
PB.registerOptimizerLastEPCallback( PB.registerOptimizerLastEPCallback(
[](ModulePassManager &MPM, OptimizationLevel OL) { [](ModulePassManager &MPM, OptimizationLevel OL) {
@ -238,8 +226,7 @@ llvmGetPassPluginInfo() {
} }
#endif #if LLVM_VERSION_MAJOR == 1
PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module &M, PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module &M,
ModuleAnalysisManager &MAM) { ModuleAnalysisManager &MAM) {
@ -257,34 +244,65 @@ PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module &M,
}; };
if (!ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
return PreservedAnalyses::all();
PreservedAnalyses PA = PreservedAnalyses::none();
// GlobalsAA is considered stateless and does not get invalidated unless
// explicitly invalidated; PreservedAnalyses::none() is not enough. Sanitizers
// make changes that require GlobalsAA to be invalidated.
PA.abandon<GlobalsAA>();
return PA;
}
#else
#if LLVM_VERSION_MAJOR >= 16
PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module &M,
ModuleAnalysisManager &MAM) {
#else
PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module &M,
ModuleAnalysisManager &MAM) {
#endif
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)) if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
return PreservedAnalyses::none(); return PreservedAnalyses::none();
return PreservedAnalyses::all(); return PreservedAnalyses::all();
} }
#endif
std::pair<Value *, Value *> ModuleSanitizerCoverageAFL::CreateSecStartEnd( std::pair<Value *, Value *> ModuleSanitizerCoverageAFL::CreateSecStartEnd(
Module &M, const char *Section, Type *Ty) { Module &M, const char *Section, Type *Ty) {
GlobalVariable *SecStart = // Use ExternalWeak so that if all sections are discarded due to section
new GlobalVariable(M, // garbage collection, the linker will not report undefined symbol errors.
#if LLVM_VERSION_MAJOR >= 15 // Windows defines the start/stop symbols in compiler-rt so no need for
Ty, // ExternalWeak.
#else GlobalValue::LinkageTypes Linkage = TargetTriple.isOSBinFormatCOFF()
Ty->getPointerElementType(), ? GlobalVariable::ExternalLinkage
#endif : GlobalVariable::ExternalWeakLinkage;
false, GlobalVariable::ExternalWeakLinkage, nullptr, GlobalVariable *SecStart = new GlobalVariable(M, Ty, false, Linkage, nullptr,
getSectionStart(Section)); getSectionStart(Section));
SecStart->setVisibility(GlobalValue::HiddenVisibility); SecStart->setVisibility(GlobalValue::HiddenVisibility);
GlobalVariable *SecEnd = GlobalVariable *SecEnd = new GlobalVariable(M, Ty, false, Linkage, nullptr,
new GlobalVariable(M, getSectionEnd(Section));
#if LLVM_VERSION_MAJOR >= 15
Ty,
#else
Ty->getPointerElementType(),
#endif
false, GlobalVariable::ExternalWeakLinkage, nullptr,
getSectionEnd(Section));
SecEnd->setVisibility(GlobalValue::HiddenVisibility); SecEnd->setVisibility(GlobalValue::HiddenVisibility);
IRBuilder<> IRB(M.getContext()); IRBuilder<> IRB(M.getContext());
if (!TargetTriple.isOSBinFormatCOFF()) if (!TargetTriple.isOSBinFormatCOFF())
@ -295,7 +313,8 @@ std::pair<Value *, Value *> ModuleSanitizerCoverageAFL::CreateSecStartEnd(
auto SecStartI8Ptr = IRB.CreatePointerCast(SecStart, Int8PtrTy); auto SecStartI8Ptr = IRB.CreatePointerCast(SecStart, Int8PtrTy);
auto GEP = IRB.CreateGEP(Int8Ty, SecStartI8Ptr, auto GEP = IRB.CreateGEP(Int8Ty, SecStartI8Ptr,
ConstantInt::get(IntptrTy, sizeof(uint64_t))); ConstantInt::get(IntptrTy, sizeof(uint64_t)));
return std::make_pair(IRB.CreatePointerCast(GEP, Ty), SecEnd); return std::make_pair(IRB.CreatePointerCast(GEP, PointerType::getUnqual(Ty)),
SecEnd);
} }
@ -307,8 +326,9 @@ Function *ModuleSanitizerCoverageAFL::CreateInitCallsForSections(
auto SecStart = SecStartEnd.first; auto SecStart = SecStartEnd.first;
auto SecEnd = SecStartEnd.second; auto SecEnd = SecStartEnd.second;
Function *CtorFunc; Function *CtorFunc;
Type *PtrTy = PointerType::getUnqual(Ty);
std::tie(CtorFunc, std::ignore) = createSanitizerCtorAndInitFunctions( std::tie(CtorFunc, std::ignore) = createSanitizerCtorAndInitFunctions(
M, CtorName, InitFunctionName, {Ty, Ty}, {SecStart, SecEnd}); M, CtorName, InitFunctionName, {PtrTy, PtrTy}, {SecStart, SecEnd});
assert(CtorFunc->getName() == CtorName); assert(CtorFunc->getName() == CtorName);
if (TargetTriple.supportsCOMDAT()) { if (TargetTriple.supportsCOMDAT()) {
@ -332,7 +352,6 @@ Function *ModuleSanitizerCoverageAFL::CreateInitCallsForSections(
// to include the sancov constructor. This way the linker can deduplicate // to include the sancov constructor. This way the linker can deduplicate
// the constructors but always leave one copy. // the constructors but always leave one copy.
CtorFunc->setLinkage(GlobalValue::WeakODRLinkage); CtorFunc->setLinkage(GlobalValue::WeakODRLinkage);
appendToUsed(M, CtorFunc);
} }
@ -344,37 +363,25 @@ bool ModuleSanitizerCoverageAFL::instrumentModule(
Module &M, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) { Module &M, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) {
setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0);
if (getenv("AFL_DEBUG")) debug = 1;
if (getenv("AFL_DEBUG")) { debug = 1; }
if ((isatty(2) && !getenv("AFL_QUIET")) || debug) { if ((isatty(2) && !getenv("AFL_QUIET")) || debug) {
SAYF(cCYA "SanitizerCoveragePCGUARD" VERSION cRST "\n"); SAYF(cCYA "SanitizerCoveragePCGUARD" VERSION cRST "\n");
} else } else {
be_quiet = 1; be_quiet = 1;
}
skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO"); skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
use_threadsafe_counters = getenv("AFL_LLVM_THREADSAFE_INST"); use_threadsafe_counters = getenv("AFL_LLVM_THREADSAFE_INST");
initInstrumentList(); initInstrumentList();
scanForDangerousFunctions(&M); 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()); C = &(M.getContext());
DL = &M.getDataLayout(); DL = &M.getDataLayout();
CurModule = &M; CurModule = &M;
@ -397,16 +404,14 @@ bool ModuleSanitizerCoverageAFL::instrumentModule(
Int16Ty = IRB.getInt16Ty(); Int16Ty = IRB.getInt16Ty();
Int8Ty = IRB.getInt8Ty(); Int8Ty = IRB.getInt8Ty();
Int1Ty = IRB.getInt1Ty(); Int1Ty = IRB.getInt1Ty();
LLVMContext &Ctx = M.getContext();
LLVMContext &Ctx = M.getContext();
AFLMapPtr = AFLMapPtr =
new GlobalVariable(M, PointerType::get(Int8Ty, 0), false, new GlobalVariable(M, PointerType::get(Int8Ty, 0), false,
GlobalValue::ExternalLinkage, 0, "__afl_area_ptr"); GlobalValue::ExternalLinkage, 0, "__afl_area_ptr");
One = ConstantInt::get(IntegerType::getInt8Ty(Ctx), 1); One = ConstantInt::get(IntegerType::getInt8Ty(Ctx), 1);
Zero = ConstantInt::get(IntegerType::getInt8Ty(Ctx), 0); 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 // Make sure smaller parameters are zero-extended to i64 if required by the
// target ABI. // target ABI.
AttributeList SanCovTraceCmpZeroExtAL; AttributeList SanCovTraceCmpZeroExtAL;
@ -436,26 +441,13 @@ bool ModuleSanitizerCoverageAFL::instrumentModule(
SanCovTraceConstCmpFunction[3] = SanCovTraceConstCmpFunction[3] =
M.getOrInsertFunction(SanCovTraceConstCmp8, VoidTy, Int64Ty, Int64Ty); 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 = SanCovTraceSwitchFunction =
M.getOrInsertFunction(SanCovTraceSwitchName, VoidTy, Int64Ty, Int64PtrTy); M.getOrInsertFunction(SanCovTraceSwitchName, VoidTy, Int64Ty, Int64PtrTy);
Constant *SanCovLowestStackConstant = Constant *SanCovLowestStackConstant =
M.getOrInsertGlobal(SanCovLowestStackName, IntptrTy); M.getOrInsertGlobal(SanCovLowestStackName, IntptrTy);
SanCovLowestStack = dyn_cast<GlobalVariable>(SanCovLowestStackConstant); SanCovLowestStack = dyn_cast<GlobalVariable>(SanCovLowestStackConstant);
if (!SanCovLowestStack) { if (!SanCovLowestStack || SanCovLowestStack->getValueType() != IntptrTy) {
C->emitError(StringRef("'") + SanCovLowestStackName + C->emitError(StringRef("'") + SanCovLowestStackName +
"' should not be declared by the user"); "' should not be declared by the user");
@ -465,8 +457,6 @@ bool ModuleSanitizerCoverageAFL::instrumentModule(
SanCovLowestStack->setThreadLocalMode( SanCovLowestStack->setThreadLocalMode(
GlobalValue::ThreadLocalMode::InitialExecTLSModel); GlobalValue::ThreadLocalMode::InitialExecTLSModel);
if (Options.StackDepth && !SanCovLowestStack->isDeclaration())
SanCovLowestStack->setInitializer(Constant::getAllOnesValue(IntptrTy));
SanCovTracePC = M.getOrInsertFunction(SanCovTracePCName, VoidTy); SanCovTracePC = M.getOrInsertFunction(SanCovTracePCName, VoidTy);
SanCovTracePCGuard = SanCovTracePCGuard =
@ -481,40 +471,25 @@ bool ModuleSanitizerCoverageAFL::instrumentModule(
Ctor = CreateInitCallsForSections(M, SanCovModuleCtorTracePcGuardName, Ctor = CreateInitCallsForSections(M, SanCovModuleCtorTracePcGuardName,
SanCovTracePCGuardInitName, Int32PtrTy, SanCovTracePCGuardInitName, Int32PtrTy,
SanCovGuardsSectionName); SanCovGuardsSectionName);
if (Function8bitCounterArray)
Ctor = CreateInitCallsForSections(M, SanCovModuleCtor8bitCountersName,
SanCov8bitCountersInitName, Int8PtrTy,
SanCovCountersSectionName);
if (FunctionBoolArray) {
Ctor = CreateInitCallsForSections(M, SanCovModuleCtorBoolFlagName, if (Ctor && debug) {
SanCovBoolFlagInitName, Int1PtrTy,
SanCovBoolFlagSectionName); fprintf(stderr, "SANCOV: installed pcguard_init in ctor\n");
} }
if (Ctor && Options.PCTable) { appendToUsed(M, GlobalsToAppendToUsed);
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); appendToCompilerUsed(M, GlobalsToAppendToCompilerUsed);
if (!be_quiet) { if (!be_quiet) {
if (!instr) if (!instr) {
WARNF("No instrumentation targets found.");
else {
char modeline[100]; WARNF("No instrumentation targets found.");
} else {
char modeline[128];
snprintf(modeline, sizeof(modeline), "%s%s%s%s%s%s", snprintf(modeline, sizeof(modeline), "%s%s%s%s%s%s",
getenv("AFL_HARDEN") ? "hardened" : "non-hardened", getenv("AFL_HARDEN") ? "hardened" : "non-hardened",
getenv("AFL_USE_ASAN") ? ", ASAN" : "", getenv("AFL_USE_ASAN") ? ", ASAN" : "",
@ -535,39 +510,36 @@ bool ModuleSanitizerCoverageAFL::instrumentModule(
} }
// True if block has successors and it dominates all of them. // True if block has successors and it dominates all of them.
bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) { static bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) {
if (succ_begin(BB) == succ_end(BB)) return false; if (succ_empty(BB)) return false;
for (const BasicBlock *SUCC : make_range(succ_begin(BB), succ_end(BB))) { return llvm::all_of(successors(BB), [&](const BasicBlock *SUCC) {
if (!DT->dominates(BB, SUCC)) return false; return DT->dominates(BB, SUCC);
} });
return true;
} }
// True if block has predecessors and it postdominates all of them. // True if block has predecessors and it postdominates all of them.
bool isFullPostDominator(const BasicBlock *BB, const PostDominatorTree *PDT) { static bool isFullPostDominator(const BasicBlock *BB,
const PostDominatorTree *PDT) {
if (pred_begin(BB) == pred_end(BB)) return false; if (pred_empty(BB)) return false;
for (const BasicBlock *PRED : make_range(pred_begin(BB), pred_end(BB))) { return llvm::all_of(predecessors(BB), [&](const BasicBlock *PRED) {
if (!PDT->dominates(BB, PRED)) return false; return PDT->dominates(BB, PRED);
} });
return true;
} }
bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB, static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB,
const DominatorTree *DT, const DominatorTree *DT,
const PostDominatorTree *PDT, const PostDominatorTree *PDT,
const SanitizerCoverageOptions &Options) { const SanitizerCoverageOptions &Options) {
// Don't insert coverage for blocks containing nothing but unreachable: we // Don't insert coverage for blocks containing nothing but unreachable: we
// will never call __sanitizer_cov() for them, so counting them in // will never call __sanitizer_cov() for them, so counting them in
@ -582,10 +554,6 @@ bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB,
if (Options.NoPrune || &F.getEntryBlock() == BB) return true; 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 // Do not instrument full dominators, or full post-dominators with multiple
// predecessors. // predecessors.
return !isFullDominator(BB, DT) && return !isFullDominator(BB, DT) &&
@ -597,38 +565,47 @@ bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB,
// A twist here is that we treat From->To as a backedge if // A twist here is that we treat From->To as a backedge if
// * To dominates From or // * To dominates From or
// * To->UniqueSuccessor dominates From // * To->UniqueSuccessor dominates From
bool IsBackEdge(BasicBlock *From, BasicBlock *To, const DominatorTree *DT) { #if 0
static bool IsBackEdge(BasicBlock *From, BasicBlock *To,
const DominatorTree *DT) {
if (DT->dominates(To, From)) return true; if (DT->dominates(To, From))
return true;
if (auto Next = To->getUniqueSuccessor()) if (auto Next = To->getUniqueSuccessor())
if (DT->dominates(Next, From)) return true; if (DT->dominates(Next, From))
return true;
return false; return false;
} }
#endif
// Prunes uninteresting Cmp instrumentation: // Prunes uninteresting Cmp instrumentation:
// * CMP instructions that feed into loop backedge branch. // * CMP instructions that feed into loop backedge branch.
// //
// Note that Cmp pruning is controlled by the same flag as the // Note that Cmp pruning is controlled by the same flag as the
// BB pruning. // BB pruning.
bool IsInterestingCmp(ICmpInst *CMP, const DominatorTree *DT, #if 0
const SanitizerCoverageOptions &Options) { static bool IsInterestingCmp(ICmpInst *CMP, const DominatorTree *DT,
const SanitizerCoverageOptions &Options) {
if (!Options.NoPrune) if (!Options.NoPrune)
if (CMP->hasOneUse()) if (CMP->hasOneUse())
if (auto BR = dyn_cast<BranchInst>(CMP->user_back())) if (auto BR = dyn_cast<BranchInst>(CMP->user_back()))
for (BasicBlock *B : BR->successors()) for (BasicBlock *B : BR->successors())
if (IsBackEdge(BR->getParent(), B, DT)) return false; if (IsBackEdge(BR->getParent(), B, DT))
return false;
return true; return true;
} }
#endif
void ModuleSanitizerCoverageAFL::instrumentFunction( void ModuleSanitizerCoverageAFL::instrumentFunction(
Function &F, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) { Function &F, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) {
if (F.empty()) return; if (F.empty()) return;
if (!isInInstrumentList(&F, FMNAME)) return; if (!isInInstrumentList(&F, FMNAME)) return;
if (F.getName().find(".module_ctor") != std::string::npos) if (F.getName().find(".module_ctor") != std::string::npos)
return; // Should not instrument sanitizer init functions. return; // Should not instrument sanitizer init functions.
if (F.getName().startswith("__sanitizer_")) if (F.getName().startswith("__sanitizer_"))
@ -647,15 +624,13 @@ void ModuleSanitizerCoverageAFL::instrumentFunction(
if (F.hasPersonalityFn() && if (F.hasPersonalityFn() &&
isAsynchronousEHPersonality(classifyEHPersonality(F.getPersonalityFn()))) isAsynchronousEHPersonality(classifyEHPersonality(F.getPersonalityFn())))
return; return;
if (F.hasFnAttribute(Attribute::NoSanitizeCoverage)) return;
if (Options.CoverageType >= SanitizerCoverageOptions::SCK_Edge) if (Options.CoverageType >= SanitizerCoverageOptions::SCK_Edge)
SplitAllCriticalEdges( SplitAllCriticalEdges(
F, CriticalEdgeSplittingOptions().setIgnoreUnreachableDests()); F, CriticalEdgeSplittingOptions().setIgnoreUnreachableDests());
SmallVector<Instruction *, 8> IndirCalls; SmallVector<BasicBlock *, 16> BlocksToInstrument;
SmallVector<BasicBlock *, 16> BlocksToInstrument; SmallVector<Instruction *, 8> CmpTraceTargets;
SmallVector<Instruction *, 8> CmpTraceTargets; SmallVector<Instruction *, 8> SwitchTraceTargets;
SmallVector<Instruction *, 8> SwitchTraceTargets;
SmallVector<BinaryOperator *, 8> DivTraceTargets;
SmallVector<GetElementPtrInst *, 8> GepTraceTargets;
const DominatorTree *DT = DTCallback(F); const DominatorTree *DT = DTCallback(F);
const PostDominatorTree *PDT = PDTCallback(F); const PostDominatorTree *PDT = PDTCallback(F);
@ -665,47 +640,28 @@ void ModuleSanitizerCoverageAFL::instrumentFunction(
if (shouldInstrumentBlock(F, &BB, DT, PDT, Options)) if (shouldInstrumentBlock(F, &BB, DT, PDT, Options))
BlocksToInstrument.push_back(&BB); BlocksToInstrument.push_back(&BB);
for (auto &Inst : BB) { /*
for (auto &Inst : BB) {
if (Options.IndirectCalls) { if (Options.TraceCmp) {
CallBase *CB = dyn_cast<CallBase>(&Inst); if (ICmpInst *CMP = dyn_cast<ICmpInst>(&Inst))
if (CB && !CB->getCalledFunction()) IndirCalls.push_back(&Inst); if (IsInterestingCmp(CMP, DT, Options))
CmpTraceTargets.push_back(&Inst);
if (isa<SwitchInst>(&Inst))
SwitchTraceTargets.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); InjectCoverage(F, BlocksToInstrument, IsLeafFunc);
InjectCoverageForIndirectCalls(F, IndirCalls); // InjectTraceForCmp(F, CmpTraceTargets);
InjectTraceForCmp(F, CmpTraceTargets); // InjectTraceForSwitch(F, SwitchTraceTargets);
InjectTraceForSwitch(F, SwitchTraceTargets);
InjectTraceForDiv(F, DivTraceTargets);
InjectTraceForGep(F, GepTraceTargets);
} }
@ -717,33 +673,30 @@ GlobalVariable *ModuleSanitizerCoverageAFL::CreateFunctionLocalArrayInSection(
*CurModule, ArrayTy, false, GlobalVariable::PrivateLinkage, *CurModule, ArrayTy, false, GlobalVariable::PrivateLinkage,
Constant::getNullValue(ArrayTy), "__sancov_gen_"); Constant::getNullValue(ArrayTy), "__sancov_gen_");
#if LLVM_VERSION_MAJOR >= 13
if (TargetTriple.supportsCOMDAT() && if (TargetTriple.supportsCOMDAT() &&
(TargetTriple.isOSBinFormatELF() || !F.isInterposable())) (TargetTriple.isOSBinFormatELF() || !F.isInterposable()))
if (auto Comdat = getOrCreateFunctionComdat(F, TargetTriple)) if (auto Comdat = getOrCreateFunctionComdat(F, TargetTriple))
Array->setComdat(Comdat); Array->setComdat(Comdat);
Array->setSection(getSectionName(Section));
#if LLVM_VERSION_MAJOR >= 16
Array->setAlignment(Align(DL->getTypeStoreSize(Ty).getFixedValue()));
#else #else
if (TargetTriple.supportsCOMDAT() && !F.isInterposable()) Array->setAlignment(Align(DL->getTypeStoreSize(Ty).getFixedSize()));
if (auto Comdat =
GetOrCreateFunctionComdat(F, TargetTriple, CurModuleUniqueId))
Array->setComdat(Comdat);
#endif #endif
Array->setSection(getSectionName(Section)); // sancov_pcs parallels the other metadata section(s). Optimizers (e.g.
#if (LLVM_VERSION_MAJOR >= 11) || \ // GlobalOpt/ConstantMerge) may not discard sancov_pcs and the other
(LLVM_VERSION_MAJOR == 10 && LLVM_VERSION_MINOR >= 1) // section(s) as a unit, so we conservatively retain all unconditionally in
#if LLVM_VERSION_MAJOR >= 16 // the compiler.
Array->setAlignment(Align(DL->getTypeStoreSize(Ty).getFixedValue())); //
#else // With comdat (COFF/ELF), the linker can guarantee the associated sections
Array->setAlignment(Align(DL->getTypeStoreSize(Ty).getFixedSize())); // will be retained or discarded as a unit, so llvm.compiler.used is
#endif // sufficient. Otherwise, conservatively make all of them retained by the
#else // linker.
Array->setAlignment(Align(4)); // cheating if (Array->hasComdat())
#endif GlobalsToAppendToCompilerUsed.push_back(Array);
GlobalsToAppendToUsed.push_back(Array); else
GlobalsToAppendToCompilerUsed.push_back(Array); GlobalsToAppendToUsed.push_back(Array);
MDNode *MD = MDNode::get(F.getContext(), ValueAsMetadata::get(&F));
Array->addMetadata(LLVMContext::MD_associated, *MD);
return Array; return Array;
@ -768,8 +721,12 @@ GlobalVariable *ModuleSanitizerCoverageAFL::CreatePCArray(
PCs.push_back((Constant *)IRB.CreatePointerCast( PCs.push_back((Constant *)IRB.CreatePointerCast(
BlockAddress::get(AllBlocks[i]), IntptrPtrTy)); BlockAddress::get(AllBlocks[i]), IntptrPtrTy));
#if LLVM_VERSION_MAJOR >= 16
PCs.push_back(Constant::getNullValue(IntptrPtrTy));
#else
PCs.push_back((Constant *)IRB.CreateIntToPtr( PCs.push_back((Constant *)IRB.CreateIntToPtr(
ConstantInt::get(IntptrTy, 0), IntptrPtrTy)); ConstantInt::get(IntptrTy, 0), IntptrPtrTy));
#endif
} }
@ -792,21 +749,13 @@ void ModuleSanitizerCoverageAFL::CreateFunctionLocalArrays(
FunctionGuardArray = CreateFunctionLocalArrayInSection( FunctionGuardArray = CreateFunctionLocalArrayInSection(
AllBlocks.size() + special, F, Int32Ty, SanCovGuardsSectionName); 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( bool ModuleSanitizerCoverageAFL::InjectCoverage(
Function &F, ArrayRef<BasicBlock *> AllBlocks, bool IsLeafFunc) { Function &F, ArrayRef<BasicBlock *> AllBlocks, bool IsLeafFunc) {
if (AllBlocks.empty()) return false;
uint32_t cnt_cov = 0, cnt_sel = 0, cnt_sel_inc = 0; uint32_t cnt_cov = 0, cnt_sel = 0, cnt_sel_inc = 0;
static uint32_t first = 1; static uint32_t first = 1;
@ -855,7 +804,6 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
} }
#if (LLVM_VERSION_MAJOR >= 12)
else if (t->getTypeID() == llvm::Type::FixedVectorTyID) { else if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
FixedVectorType *tt = dyn_cast<FixedVectorType>(t); FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
@ -868,16 +816,14 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
} }
#endif
} }
} }
} }
/* Create PCGUARD array */
CreateFunctionLocalArrays(F, AllBlocks, first + cnt_cov + cnt_sel_inc); CreateFunctionLocalArrays(F, AllBlocks, first + cnt_cov + cnt_sel_inc);
if (first) { first = 0; } if (first) { first = 0; }
selects += cnt_sel; selects += cnt_sel;
@ -889,12 +835,6 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
CallInst *callInst = nullptr; 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))) { if ((callInst = dyn_cast<CallInst>(&IN))) {
Function *Callee = callInst->getCalledFunction(); Function *Callee = callInst->getCalledFunction();
@ -1033,12 +973,6 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
} }
/*
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); result = IRB.CreateSelect(condition, x, y);
} }
@ -1063,13 +997,6 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
IRB.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr); IRB.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr);
ModuleSanitizerCoverageAFL::SetNoSanitizeMetadata(MapPtr); 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) { while (1) {
/* Get CurLoc */ /* Get CurLoc */
@ -1159,29 +1086,6 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
} }
// 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: // For every switch statement we insert a call:
// __sanitizer_cov_trace_switch(CondValue, // __sanitizer_cov_trace_switch(CondValue,
// {NumCases, ValueSizeInBits, Case0Value, Case1Value, Case2Value, ... }) // {NumCases, ValueSizeInBits, Case0Value, Case1Value, Case2Value, ... })
@ -1237,41 +1141,6 @@ void ModuleSanitizerCoverageAFL::InjectTraceForSwitch(
} }
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( void ModuleSanitizerCoverageAFL::InjectTraceForCmp(
Function &, ArrayRef<Instruction *> CmpTraceTargets) { Function &, ArrayRef<Instruction *> CmpTraceTargets) {
@ -1321,27 +1190,44 @@ void ModuleSanitizerCoverageAFL::InjectCoverageAtBlock(Function &F,
BasicBlock::iterator IP = BB.getFirstInsertionPt(); BasicBlock::iterator IP = BB.getFirstInsertionPt();
bool IsEntryBB = &BB == &F.getEntryBlock(); bool IsEntryBB = &BB == &F.getEntryBlock();
DebugLoc EntryLoc;
if (IsEntryBB) { if (IsEntryBB) {
// Keep allocas and llvm.localescape calls in the entry block. Even if (auto SP = F.getSubprogram())
EntryLoc = DILocation::get(SP->getContext(), SP->getScopeLine(), 0, SP);
// 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 // if we aren't splitting the block, it's nice for allocas to be before
// calls. // calls.
IP = PrepareToSplitEntryBlock(BB, IP); IP = PrepareToSplitEntryBlock(BB, IP);
#if LLVM_VERSION_MAJOR < 15
} else {
EntryLoc = IP->getDebugLoc();
if (!EntryLoc)
if (auto *SP = F.getSubprogram())
EntryLoc = DILocation::get(SP->getContext(), 0, 0, SP);
#endif
} }
#if LLVM_VERSION_MAJOR >= 16
InstrumentationIRBuilder IRB(&*IP);
#else
IRBuilder<> IRB(&*IP); IRBuilder<> IRB(&*IP);
#endif
if (Options.TracePC) { if (EntryLoc) IRB.SetCurrentDebugLocation(EntryLoc);
IRB.CreateCall(SanCovTracePC);
// ->setCannotMerge(); // gets the PC using GET_CALLER_PC.
}
if (Options.TracePCGuard) { if (Options.TracePCGuard) {
/*
auto GuardPtr = IRB.CreateIntToPtr(
IRB.CreateAdd(IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
ConstantInt::get(IntptrTy, Idx * 4)),
Int32PtrTy);
IRB.CreateCall(SanCovTracePCGuard, GuardPtr)->setCannotMerge();
*/
/* Get CurLoc */ /* Get CurLoc */
Value *GuardPtr = IRB.CreateIntToPtr( Value *GuardPtr = IRB.CreateIntToPtr(
@ -1399,57 +1285,6 @@ void ModuleSanitizerCoverageAFL::InjectCoverageAtBlock(Function &F,
} }
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( std::string ModuleSanitizerCoverageAFL::getSectionName(

View File

@ -997,7 +997,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
if (instrument_mode == INSTRUMENT_PCGUARD) { if (instrument_mode == INSTRUMENT_PCGUARD) {
#if LLVM_MAJOR >= 11 #if LLVM_MAJOR >= 13
#if defined __ANDROID__ || ANDROID #if defined __ANDROID__ || ANDROID
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard"; cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
instrument_mode = INSTRUMENT_LLVMNATIVE; instrument_mode = INSTRUMENT_LLVMNATIVE;
@ -1014,7 +1014,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
} else { } else {
#if LLVM_MAJOR >= 11 /* use new pass manager */ #if LLVM_MAJOR >= 13 /* use new pass manager */
#if LLVM_MAJOR < 16 #if LLVM_MAJOR < 16
cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager"; cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
#endif #endif
@ -1035,12 +1035,12 @@ static void edit_params(u32 argc, char **argv, char **envp) {
#if LLVM_MAJOR >= 4 #if LLVM_MAJOR >= 4
if (!be_quiet) if (!be_quiet)
SAYF( SAYF(
"Using unoptimized trace-pc-guard, upgrade to llvm 10.0.1+ for " "Using unoptimized trace-pc-guard, upgrade to LLVM 13+ for "
"enhanced version.\n"); "enhanced version.\n");
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard"; cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
instrument_mode = INSTRUMENT_LLVMNATIVE; instrument_mode = INSTRUMENT_LLVMNATIVE;
#else #else
FATAL("pcguard instrumentation requires llvm 4.0.1+"); FATAL("pcguard instrumentation requires LLVM 4.0.1+");
#endif #endif
#endif #endif
@ -1053,7 +1053,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
cc_params[cc_par_cnt++] = cc_params[cc_par_cnt++] =
"-fsanitize-coverage=trace-pc-guard,bb,no-prune,pc-table"; "-fsanitize-coverage=trace-pc-guard,bb,no-prune,pc-table";
#else #else
FATAL("pcguard instrumentation with pc-table requires llvm 6.0.1+"); FATAL("pcguard instrumentation with pc-table requires LLVM 6.0.1+");
#endif #endif
} else { } else {
@ -1063,7 +1063,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
} }
#else #else
FATAL("pcguard instrumentation requires llvm 4.0.1+"); FATAL("pcguard instrumentation requires LLVM 4.0.1+");
#endif #endif
} else { } else {
@ -2031,7 +2031,7 @@ int main(int argc, char **argv, char **envp) {
if (!compiler_mode) { if (!compiler_mode) {
// lto is not a default because outside of afl-cc RANLIB and AR have to // lto is not a default because outside of afl-cc RANLIB and AR have to
// be set to llvm versions so this would work // be set to LLVM versions so this would work
if (have_llvm) if (have_llvm)
compiler_mode = LLVM; compiler_mode = LLVM;
else if (have_gcc_plugin) else if (have_gcc_plugin)
@ -2050,6 +2050,17 @@ int main(int argc, char **argv, char **envp) {
} }
/* if our PCGUARD implementation is not available then silently switch to
native LLVM PCGUARD */
if (compiler_mode == CLANG &&
(instrument_mode == INSTRUMENT_DEFAULT ||
instrument_mode == INSTRUMENT_PCGUARD) &&
find_object("SanitizerCoveragePCGUARD.so", argv[0]) == NULL) {
instrument_mode = INSTRUMENT_LLVMNATIVE;
}
if (compiler_mode == GCC) { if (compiler_mode == GCC) {
if (clang_mode) { if (clang_mode) {
@ -2096,12 +2107,12 @@ int main(int argc, char **argv, char **envp) {
"-------------|\n" "-------------|\n"
"MODES: NCC PERSIST DICT LAF " "MODES: NCC PERSIST DICT LAF "
"CMPLOG SELECT\n" "CMPLOG SELECT\n"
" [LTO] llvm LTO: %s%s\n" " [LTO] LLVM LTO: %s%s\n"
" PCGUARD DEFAULT yes yes yes yes yes " " PCGUARD DEFAULT yes yes yes yes yes "
" yes\n" " yes\n"
" CLASSIC yes yes yes yes yes " " CLASSIC yes yes yes yes yes "
" yes\n" " yes\n"
" [LLVM] llvm: %s%s\n" " [LLVM] LLVM: %s%s\n"
" PCGUARD %s yes yes module yes yes " " PCGUARD %s yes yes module yes yes "
"yes\n" "yes\n"
" CLASSIC %s no yes module yes yes " " CLASSIC %s no yes module yes yes "
@ -2171,7 +2182,7 @@ int main(int argc, char **argv, char **envp) {
" (instrumentation/README.lto.md)\n" " (instrumentation/README.lto.md)\n"
" PERSIST: persistent mode support [code] (huge speed increase!)\n" " PERSIST: persistent mode support [code] (huge speed increase!)\n"
" (instrumentation/README.persistent_mode.md)\n" " (instrumentation/README.persistent_mode.md)\n"
" DICT: dictionary in the target [yes=automatic or llvm module " " DICT: dictionary in the target [yes=automatic or LLVM module "
"pass]\n" "pass]\n"
" (instrumentation/README.lto.md + " " (instrumentation/README.lto.md + "
"instrumentation/README.llvm.md)\n" "instrumentation/README.llvm.md)\n"