diff options
Diffstat (limited to 'instrumentation')
-rw-r--r-- | instrumentation/README.gcc_plugin.md | 9 | ||||
-rw-r--r-- | instrumentation/SanitizerCoverageLTO.so.cc | 72 | ||||
-rw-r--r-- | instrumentation/SanitizerCoveragePCGUARD.so.cc | 54 | ||||
-rw-r--r-- | instrumentation/afl-compiler-rt.o.c | 26 | ||||
-rw-r--r-- | instrumentation/afl-gcc-cmplog-pass.so.cc | 404 | ||||
-rw-r--r-- | instrumentation/afl-gcc-cmptrs-pass.so.cc | 366 | ||||
-rw-r--r-- | instrumentation/afl-gcc-common.h | 500 | ||||
-rw-r--r-- | instrumentation/afl-gcc-pass.so.cc | 522 | ||||
-rw-r--r-- | instrumentation/afl-llvm-dict2file.so.cc | 10 | ||||
-rw-r--r-- | instrumentation/afl-llvm-lto-instrumentlist.so.cc | 4 | ||||
-rw-r--r-- | instrumentation/afl-llvm-pass.so.cc | 6 | ||||
-rw-r--r-- | instrumentation/cmplog-instructions-pass.cc | 8 | ||||
-rw-r--r-- | instrumentation/cmplog-routines-pass.cc | 40 | ||||
-rw-r--r-- | instrumentation/cmplog-switches-pass.cc | 6 | ||||
-rw-r--r-- | instrumentation/compare-transform-pass.so.cc | 20 | ||||
-rw-r--r-- | instrumentation/split-compares-pass.so.cc | 60 | ||||
-rw-r--r-- | instrumentation/split-switches-pass.so.cc | 16 |
17 files changed, 1486 insertions, 637 deletions
diff --git a/instrumentation/README.gcc_plugin.md b/instrumentation/README.gcc_plugin.md index ed39af9d..011a574a 100644 --- a/instrumentation/README.gcc_plugin.md +++ b/instrumentation/README.gcc_plugin.md @@ -99,4 +99,11 @@ See ## 6) Bonus feature #3: selective instrumentation It can be more effective to fuzzing to only instrument parts of the code. For -details, see [README.instrument_list.md](README.instrument_list.md). \ No newline at end of file +details, see [README.instrument_list.md](README.instrument_list.md). + +## 7) Bonus feature #4: CMPLOG + +The gcc_plugin also support CMPLOG/Redqueen, just set `AFL_GCC_CMPLOG` before +instrumenting the target. +Read more about this in the llvm document. + diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 9a48ae6d..721bc487 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -182,7 +182,7 @@ class ModuleSanitizerCoverageLTO private: void instrumentFunction(Function &F, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback); - void InjectCoverageForIndirectCalls(Function & F, + void InjectCoverageForIndirectCalls(Function &F, ArrayRef<Instruction *> IndirCalls); bool InjectCoverage(Function &F, ArrayRef<BasicBlock *> AllBlocks, bool IsLeafFunc = true); @@ -211,10 +211,10 @@ class ModuleSanitizerCoverageLTO FunctionCallee SanCovTracePC /*, SanCovTracePCGuard*/; Type *IntptrTy, *IntptrPtrTy, *Int64Ty, *Int64PtrTy, *Int32Ty, *Int32PtrTy, *Int16Ty, *Int8Ty, *Int8PtrTy, *Int1Ty, *Int1PtrTy; - Module * CurModule; + Module *CurModule; std::string CurModuleUniqueId; Triple TargetTriple; - LLVMContext * C; + LLVMContext *C; const DataLayout *DL; GlobalVariable *FunctionGuardArray; // for trace-pc-guard. @@ -235,20 +235,20 @@ class ModuleSanitizerCoverageLTO uint32_t unhandled = 0; uint32_t select_cnt = 0; uint64_t map_addr = 0; - const char * skip_nozero = NULL; - const char * use_threadsafe_counters = nullptr; + const char *skip_nozero = NULL; + const char *use_threadsafe_counters = nullptr; std::vector<BasicBlock *> BlockList; DenseMap<Value *, std::string *> valueMap; std::vector<std::string> dictionary; - IntegerType * Int8Tyi = NULL; - IntegerType * Int32Tyi = NULL; - IntegerType * Int64Tyi = NULL; - ConstantInt * Zero = NULL; - ConstantInt * One = NULL; - LLVMContext * Ct = NULL; - Module * Mo = NULL; - GlobalVariable * AFLMapPtr = NULL; - Value * MapPtrFixed = NULL; + IntegerType *Int8Tyi = NULL; + IntegerType *Int32Tyi = NULL; + IntegerType *Int64Tyi = NULL; + ConstantInt *Zero = NULL; + ConstantInt *One = NULL; + LLVMContext *Ct = NULL; + Module *Mo = NULL; + GlobalVariable *AFLMapPtr = NULL; + Value *MapPtrFixed = NULL; std::ofstream dFile; size_t found = 0; // afl++ END @@ -330,12 +330,12 @@ llvmGetPassPluginInfo() { } -PreservedAnalyses ModuleSanitizerCoverageLTO::run(Module & M, +PreservedAnalyses ModuleSanitizerCoverageLTO::run(Module &M, ModuleAnalysisManager &MAM) { ModuleSanitizerCoverageLTO ModuleSancov(Options); auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); - auto DTCallback = [&FAM](Function &F) -> const DominatorTree * { + auto DTCallback = [&FAM](Function &F) -> const DominatorTree *{ return &FAM.getResult<DominatorTreeAnalysis>(F); @@ -380,7 +380,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( FunctionPCsArray = nullptr; IntptrTy = Type::getIntNTy(*C, DL->getPointerSizeInBits()); IntptrPtrTy = PointerType::getUnqual(IntptrTy); - Type * VoidTy = Type::getVoidTy(*C); + Type *VoidTy = Type::getVoidTy(*C); IRBuilder<> IRB(*C); Int64PtrTy = PointerType::getUnqual(IRB.getInt64Ty()); Int32PtrTy = PointerType::getUnqual(IRB.getInt32Ty()); @@ -393,7 +393,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( Int1Ty = IRB.getInt1Ty(); /* afl++ START */ - char * ptr; + char *ptr; LLVMContext &Ctx = M.getContext(); Ct = &Ctx; Int8Tyi = IntegerType::getInt8Ty(Ctx); @@ -499,11 +499,11 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( for (auto &IN : BB) { CallInst *callInst = nullptr; - CmpInst * cmpInst = nullptr; + CmpInst *cmpInst = nullptr; if ((cmpInst = dyn_cast<CmpInst>(&IN))) { - Value * op = cmpInst->getOperand(1); + Value *op = cmpInst->getOperand(1); ConstantInt *ilen = dyn_cast<ConstantInt>(op); if (ilen && ilen->uge(0xffffffffffffffff) == false) { @@ -759,7 +759,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( if (HasStr2 == true) { - Value * op2 = callInst->getArgOperand(2); + Value *op2 = callInst->getArgOperand(2); ConstantInt *ilen = dyn_cast<ConstantInt>(op2); if (ilen) { @@ -866,7 +866,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( if (isMemcmp || isStrncmp || isStrncasecmp) { - Value * op2 = callInst->getArgOperand(2); + Value *op2 = callInst->getArgOperand(2); ConstantInt *ilen = dyn_cast<ConstantInt>(op2); if (ilen) { @@ -921,7 +921,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( std::string outstring; fprintf(stderr, "%s: length %zu/%zu \"", FuncName.c_str(), optLen, thestring.length()); - for (uint8_t i = 0; i < thestring.length(); i++) { + for (uint16_t i = 0; i < (uint16_t)thestring.length(); i++) { uint8_t c = thestring[i]; if (c <= 32 || c >= 127) @@ -1017,7 +1017,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( GlobalVariable *AFLMapAddrFixed = new GlobalVariable( M, Int64Tyi, true, GlobalValue::ExternalLinkage, 0, "__afl_map_addr"); ConstantInt *MapAddr = ConstantInt::get(Int64Tyi, map_addr); - StoreInst * StoreMapAddr = IRB.CreateStore(MapAddr, AFLMapAddrFixed); + StoreInst *StoreMapAddr = IRB.CreateStore(MapAddr, AFLMapAddrFixed); ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(StoreMapAddr); } @@ -1032,7 +1032,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( new GlobalVariable(M, Int32Tyi, true, GlobalValue::ExternalLinkage, 0, "__afl_final_loc"); ConstantInt *const_loc = ConstantInt::get(Int32Tyi, write_loc); - StoreInst * StoreFinalLoc = IRB.CreateStore(const_loc, AFLFinalLoc); + StoreInst *StoreFinalLoc = IRB.CreateStore(const_loc, AFLFinalLoc); ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(StoreFinalLoc); } @@ -1159,7 +1159,7 @@ static bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) { } // True if block has predecessors and it postdominates all of them. -static bool isFullPostDominator(const BasicBlock * BB, +static bool isFullPostDominator(const BasicBlock *BB, const PostDominatorTree *PDT) { if (pred_begin(BB) == pred_end(BB)) return false; @@ -1175,8 +1175,8 @@ static bool isFullPostDominator(const BasicBlock * BB, } static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB, - const DominatorTree * DT, - const PostDominatorTree * PDT, + const DominatorTree *DT, + const PostDominatorTree *PDT, const SanitizerCoverageOptions &Options) { // Don't insert coverage for blocks containing nothing but unreachable: we @@ -1246,7 +1246,7 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( SmallVector<Instruction *, 8> IndirCalls; SmallVector<BasicBlock *, 16> BlocksToInstrument; - const DominatorTree * DT = DTCallback(F); + const DominatorTree *DT = DTCallback(F); const PostDominatorTree *PDT = PDTCallback(F); bool IsLeafFunc = true; uint32_t skip_next = 0; @@ -1294,8 +1294,8 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( if (!skip_next && (selectInst = dyn_cast<SelectInst>(&IN))) { uint32_t vector_cnt = 0; - Value * condition = selectInst->getCondition(); - Value * result; + Value *condition = selectInst->getCondition(); + Value *result; auto t = condition->getType(); IRBuilder<> IRB(selectInst->getNextNode()); @@ -1451,8 +1451,8 @@ GlobalVariable *ModuleSanitizerCoverageLTO::CreateFunctionLocalArrayInSection( ArrayType *ArrayTy = ArrayType::get(Ty, NumElements); auto Array = new GlobalVariable( - *CurModule, ArrayTy, false, GlobalVariable::PrivateLinkage, - Constant::getNullValue(ArrayTy), "__sancov_gen_"); + *CurModule, ArrayTy, false, GlobalVariable::PrivateLinkage, + Constant::getNullValue(ArrayTy), "__sancov_gen_"); #if LLVM_VERSION_MAJOR >= 13 if (TargetTriple.supportsCOMDAT() && @@ -1584,8 +1584,8 @@ void ModuleSanitizerCoverageLTO::InjectCoverageForIndirectCalls( for (auto I : IndirCalls) { IRBuilder<> IRB(I); - CallBase & CB = cast<CallBase>(*I); - Value * Callee = CB.getCalledOperand(); + CallBase &CB = cast<CallBase>(*I); + Value *Callee = CB.getCalledOperand(); if (isa<InlineAsm>(Callee)) continue; IRB.CreateCall(SanCovTracePCIndir, IRB.CreatePointerCast(Callee, IntptrTy)); @@ -1593,7 +1593,7 @@ void ModuleSanitizerCoverageLTO::InjectCoverageForIndirectCalls( } -void ModuleSanitizerCoverageLTO::InjectCoverageAtBlock(Function & F, +void ModuleSanitizerCoverageLTO::InjectCoverageAtBlock(Function &F, BasicBlock &BB, size_t Idx, bool IsLeafFunc) { diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index 408353b3..d5f56aa8 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -142,14 +142,14 @@ class ModuleSanitizerCoverageAFL private: void instrumentFunction(Function &F, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback); - void InjectCoverageForIndirectCalls(Function & F, + void InjectCoverageForIndirectCalls(Function &F, ArrayRef<Instruction *> IndirCalls); void InjectTraceForCmp(Function &F, ArrayRef<Instruction *> CmpTraceTargets); - void InjectTraceForDiv(Function & F, + void InjectTraceForDiv(Function &F, ArrayRef<BinaryOperator *> DivTraceTargets); - void InjectTraceForGep(Function & F, + void InjectTraceForGep(Function &F, ArrayRef<GetElementPtrInst *> GepTraceTargets); - void InjectTraceForSwitch(Function & F, + void InjectTraceForSwitch(Function &F, ArrayRef<Instruction *> SwitchTraceTargets); bool InjectCoverage(Function &F, ArrayRef<BasicBlock *> AllBlocks, bool IsLeafFunc = true); @@ -187,10 +187,10 @@ class ModuleSanitizerCoverageAFL GlobalVariable *SanCovLowestStack; Type *IntptrTy, *IntptrPtrTy, *Int64Ty, *Int64PtrTy, *Int32Ty, *Int32PtrTy, *Int16Ty, *Int8Ty, *Int8PtrTy, *Int1Ty, *Int1PtrTy; - Module * CurModule; + Module *CurModule; std::string CurModuleUniqueId; Triple TargetTriple; - LLVMContext * C; + LLVMContext *C; const DataLayout *DL; GlobalVariable *FunctionGuardArray; // for trace-pc-guard. @@ -204,8 +204,8 @@ class ModuleSanitizerCoverageAFL uint32_t instr = 0, selects = 0, unhandled = 0; GlobalVariable *AFLMapPtr = NULL; - ConstantInt * One = NULL; - ConstantInt * Zero = NULL; + ConstantInt *One = NULL; + ConstantInt *Zero = NULL; }; @@ -287,12 +287,12 @@ llvmGetPassPluginInfo() { #endif -PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module & M, +PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module &M, ModuleAnalysisManager &MAM) { ModuleSanitizerCoverageAFL ModuleSancov(Options); auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); - auto DTCallback = [&FAM](Function &F) -> const DominatorTree * { + auto DTCallback = [&FAM](Function &F) -> const DominatorTree *{ return &FAM.getResult<DominatorTreeAnalysis>(F); @@ -433,7 +433,7 @@ bool ModuleSanitizerCoverageAFL::instrumentModule( FunctionPCsArray = nullptr; IntptrTy = Type::getIntNTy(*C, DL->getPointerSizeInBits()); IntptrPtrTy = PointerType::getUnqual(IntptrTy); - Type * VoidTy = Type::getVoidTy(*C); + Type *VoidTy = Type::getVoidTy(*C); IRBuilder<> IRB(*C); Int64PtrTy = PointerType::getUnqual(IRB.getInt64Ty()); Int32PtrTy = PointerType::getUnqual(IRB.getInt32Ty()); @@ -612,8 +612,8 @@ bool isFullPostDominator(const BasicBlock *BB, const PostDominatorTree *PDT) { } bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB, - const DominatorTree * DT, - const PostDominatorTree * PDT, + const DominatorTree *DT, + const PostDominatorTree *PDT, const SanitizerCoverageOptions &Options) { // Don't insert coverage for blocks containing nothing but unreachable: we @@ -704,7 +704,7 @@ void ModuleSanitizerCoverageAFL::instrumentFunction( SmallVector<BinaryOperator *, 8> DivTraceTargets; SmallVector<GetElementPtrInst *, 8> GepTraceTargets; - const DominatorTree * DT = DTCallback(F); + const DominatorTree *DT = DTCallback(F); const PostDominatorTree *PDT = PDTCallback(F); bool IsLeafFunc = true; @@ -761,8 +761,8 @@ GlobalVariable *ModuleSanitizerCoverageAFL::CreateFunctionLocalArrayInSection( ArrayType *ArrayTy = ArrayType::get(Ty, NumElements); auto Array = new GlobalVariable( - *CurModule, ArrayTy, false, GlobalVariable::PrivateLinkage, - Constant::getNullValue(ArrayTy), "__sancov_gen_"); + *CurModule, ArrayTy, false, GlobalVariable::PrivateLinkage, + Constant::getNullValue(ArrayTy), "__sancov_gen_"); #if LLVM_VERSION_MAJOR >= 13 if (TargetTriple.supportsCOMDAT() && @@ -971,8 +971,8 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( if (!skip_next && (selectInst = dyn_cast<SelectInst>(&IN))) { uint32_t vector_cnt = 0; - Value * condition = selectInst->getCondition(); - Value * result; + Value *condition = selectInst->getCondition(); + Value *result; auto t = condition->getType(); IRBuilder<> IRB(selectInst->getNextNode()); @@ -1113,7 +1113,7 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( /* Get CurLoc */ LoadInst *CurLoc = nullptr; - Value * MapPtrIdx = nullptr; + Value *MapPtrIdx = nullptr; /* Load counter for CurLoc */ if (!vector_cnt) { @@ -1212,8 +1212,8 @@ void ModuleSanitizerCoverageAFL::InjectCoverageForIndirectCalls( for (auto I : IndirCalls) { IRBuilder<> IRB(I); - CallBase & CB = cast<CallBase>(*I); - Value * Callee = CB.getCalledOperand(); + CallBase &CB = cast<CallBase>(*I); + Value *Callee = CB.getCalledOperand(); if (isa<InlineAsm>(Callee)) continue; IRB.CreateCall(SanCovTracePCIndir, IRB.CreatePointerCast(Callee, IntptrTy)); @@ -1234,7 +1234,7 @@ void ModuleSanitizerCoverageAFL::InjectTraceForSwitch( IRBuilder<> IRB(I); SmallVector<Constant *, 16> Initializers; - Value * Cond = SI->getCondition(); + Value *Cond = SI->getCondition(); if (Cond->getType()->getScalarSizeInBits() > Int64Ty->getScalarSizeInBits()) continue; @@ -1282,7 +1282,7 @@ void ModuleSanitizerCoverageAFL::InjectTraceForDiv( for (auto BO : DivTraceTargets) { IRBuilder<> IRB(BO); - Value * A1 = BO->getOperand(1); + Value *A1 = BO->getOperand(1); if (isa<ConstantInt>(A1)) continue; if (!A1->getType()->isIntegerTy()) continue; uint64_t TypeSize = DL->getTypeStoreSizeInBits(A1->getType()); @@ -1319,8 +1319,8 @@ void ModuleSanitizerCoverageAFL::InjectTraceForCmp( if (ICmpInst *ICMP = dyn_cast<ICmpInst>(I)) { IRBuilder<> IRB(ICMP); - Value * A0 = ICMP->getOperand(0); - Value * A1 = ICMP->getOperand(1); + Value *A0 = ICMP->getOperand(0); + Value *A1 = ICMP->getOperand(1); if (!A0->getType()->isIntegerTy()) continue; uint64_t TypeSize = DL->getTypeStoreSizeInBits(A0->getType()); int CallbackIdx = TypeSize == 8 ? 0 @@ -1353,7 +1353,7 @@ void ModuleSanitizerCoverageAFL::InjectTraceForCmp( } -void ModuleSanitizerCoverageAFL::InjectCoverageAtBlock(Function & F, +void ModuleSanitizerCoverageAFL::InjectCoverageAtBlock(Function &F, BasicBlock &BB, size_t Idx, bool IsLeafFunc) { @@ -1472,7 +1472,7 @@ void ModuleSanitizerCoverageAFL::InjectCoverageAtBlock(Function & F, if (Options.StackDepth && IsEntryBB && !IsLeafFunc) { // Check stack depth. If it's the deepest so far, record it. - Module * M = F.getParent(); + Module *M = F.getParent(); Function *GetFrameAddr = Intrinsic::getDeclaration( M, Intrinsic::frameaddress, IRB.getInt8PtrTy(M->getDataLayout().getAllocaAddrSpace())); diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index f3a16e95..97974c4a 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -92,11 +92,11 @@ static u8 __afl_area_initial[MAP_INITIAL_SIZE]; static u8 *__afl_area_ptr_dummy = __afl_area_initial; static u8 *__afl_area_ptr_backup = __afl_area_initial; -u8 * __afl_area_ptr = __afl_area_initial; -u8 * __afl_dictionary; -u8 * __afl_fuzz_ptr; +u8 *__afl_area_ptr = __afl_area_initial; +u8 *__afl_dictionary; +u8 *__afl_fuzz_ptr; static u32 __afl_fuzz_len_dummy; -u32 * __afl_fuzz_len = &__afl_fuzz_len_dummy; +u32 *__afl_fuzz_len = &__afl_fuzz_len_dummy; u32 __afl_final_loc; u32 __afl_map_size = MAP_SIZE; @@ -399,7 +399,7 @@ static void __afl_map_shm(void) { } #ifdef USEMMAP - const char * shm_file_path = id_str; + const char *shm_file_path = id_str; int shm_fd = -1; unsigned char *shm_base = NULL; @@ -450,11 +450,11 @@ static void __afl_map_shm(void) { if (__afl_map_size && __afl_map_size > MAP_SIZE) { - u8 *map_env = (u8 *)getenv("AFL_MAP_SIZE"); - if (!map_env || atoi((char *)map_env) < MAP_SIZE) { + u8 *map_env = (u8 *)getenv("AFL_MAP_SIZE"); + if (!map_env || atoi((char *)map_env) < MAP_SIZE) { - send_forkserver_error(FS_ERROR_MAP_SIZE); - _exit(1); + send_forkserver_error(FS_ERROR_MAP_SIZE); + _exit(1); } @@ -466,13 +466,13 @@ static void __afl_map_shm(void) { if (!__afl_area_ptr || __afl_area_ptr == (void *)-1) { - if (__afl_map_addr) + if (__afl_map_addr) send_forkserver_error(FS_ERROR_MAP_ADDR); else send_forkserver_error(FS_ERROR_SHMAT); perror("shmat for map"); - _exit(1); + _exit(1); } @@ -583,7 +583,7 @@ static void __afl_map_shm(void) { } #ifdef USEMMAP - const char * shm_file_path = id_str; + const char *shm_file_path = id_str; int shm_fd = -1; struct cmp_map *shm_base = NULL; @@ -689,7 +689,7 @@ static void __afl_unmap_shm(void) { void write_error_with_location(char *text, char *filename, int linenumber) { - u8 * o = getenv("__AFL_OUT_DIR"); + u8 *o = getenv("__AFL_OUT_DIR"); char *e = strerror(errno); if (o) { diff --git a/instrumentation/afl-gcc-cmplog-pass.so.cc b/instrumentation/afl-gcc-cmplog-pass.so.cc new file mode 100644 index 00000000..5e5792c3 --- /dev/null +++ b/instrumentation/afl-gcc-cmplog-pass.so.cc @@ -0,0 +1,404 @@ +/* GCC plugin for cmplog instrumentation of code for AFL++. + + Copyright 2014-2019 Free Software Foundation, Inc + Copyright 2015, 2016 Google Inc. All rights reserved. + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + Copyright 2019-2022 AdaCore + + Written by Alexandre Oliva <oliva@adacore.com>, based on the AFL++ + LLVM CmpLog pass by Andrea Fioraldi <andreafioraldi@gmail.com>, and + on the AFL GCC pass. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + */ + +#include "afl-gcc-common.h" + +/* This plugin, being under the same license as GCC, satisfies the + "GPL-compatible Software" definition in the GCC RUNTIME LIBRARY + EXCEPTION, so it can be part of an "Eligible" "Compilation + Process". */ +int plugin_is_GPL_compatible = 1; + +namespace { + +static const struct pass_data afl_cmplog_pass_data = { + + .type = GIMPLE_PASS, + .name = "aflcmplog", + .optinfo_flags = OPTGROUP_NONE, + .tv_id = TV_NONE, + .properties_required = 0, + .properties_provided = 0, + .properties_destroyed = 0, + .todo_flags_start = 0, + .todo_flags_finish = (TODO_update_ssa | TODO_cleanup_cfg | TODO_verify_il | + TODO_rebuild_cgraph_edges), + +}; + +struct afl_cmplog_pass : afl_base_pass { + + afl_cmplog_pass(bool quiet) + : afl_base_pass(quiet, /*debug=*/false, afl_cmplog_pass_data), + t8u(), + cmplog_hooks() { + + } + + /* An unsigned 8-bit integral type. */ + tree t8u; + + /* Declarations for the various cmplog hook functions, allocated on demand.. + [0] is for __cmplog_ins_hookN, that accepts non-power-of-2 sizes. + [n in 1..5] are for unsigned ints of 2^{n-1} bytes. */ + tree cmplog_hooks[6]; + + tree cmplog_hook(unsigned i) { + + tree t, fnt; + + if (!t8u) { + + if (BITS_PER_UNIT == 8) + t8u = unsigned_char_type_node; + else + t8u = build_nonstandard_integer_type(8, 1); + + } + + if (i <= ARRAY_SIZE(cmplog_hooks) && cmplog_hooks[i]) + return cmplog_hooks[i]; + + switch (i) { + + case 0: +#ifdef uint128_type_node + t = uint128_type_node; +#else + t = build_nonstandard_integer_type(128, 1); +#endif + fnt = + build_function_type_list(void_type_node, t, t, t8u, t8u, NULL_TREE); + t = cmplog_hooks[0] = build_fn_decl("__cmplog_ins_hookN", fnt); + break; + + case 1: + t = t8u; + fnt = build_function_type_list(void_type_node, t, t, t8u, NULL_TREE); + t = cmplog_hooks[1] = build_fn_decl("__cmplog_ins_hook1", fnt); + break; + + case 2: + t = uint16_type_node; + fnt = build_function_type_list(void_type_node, t, t, t8u, NULL_TREE); + t = cmplog_hooks[2] = build_fn_decl("__cmplog_ins_hook2", fnt); + break; + + case 3: + t = uint32_type_node; + fnt = build_function_type_list(void_type_node, t, t, t8u, NULL_TREE); + t = cmplog_hooks[3] = build_fn_decl("__cmplog_ins_hook4", fnt); + break; + + case 4: + t = uint64_type_node; + fnt = build_function_type_list(void_type_node, t, t, t8u, NULL_TREE); + t = cmplog_hooks[4] = build_fn_decl("__cmplog_ins_hook8", fnt); + break; + + case 5: +#ifdef uint128_type_node + t = uint128_type_node; +#else + t = build_nonstandard_integer_type(128, 1); +#endif + fnt = build_function_type_list(void_type_node, t, t, t8u, NULL_TREE); + t = cmplog_hooks[5] = build_fn_decl("__cmplog_ins_hook16", fnt); + break; + + default: + gcc_unreachable(); + + } + + /* Mark the newly-created decl as non-throwing, so that we can + insert call within basic blocks. */ + TREE_NOTHROW(t) = 1; + + return t; + + } + + /* Insert a cmplog hook call before GSI for a CODE compare between + LHS and RHS. */ + void insert_cmplog_call(gimple_stmt_iterator gsi, tree_code code, tree lhs, + tree rhs) { + + gcc_checking_assert(TYPE_MAIN_VARIANT(TREE_TYPE(lhs)) == + TYPE_MAIN_VARIANT(TREE_TYPE(rhs))); + + tree fn; + bool pass_n = false; + + /* Obtain the compare operand size as a constant. */ + tree st = TREE_TYPE(lhs); + tree szt = TYPE_SIZE(st); + + if (!tree_fits_uhwi_p(szt)) return; + + unsigned HOST_WIDE_INT sz = tree_to_uhwi(szt); + + /* Round it up. */ + if (sz % 8) sz = (((sz - 1) / 8) + 1) * 8; + + /* Select the hook function to call, based on the size. */ + switch (sz) { + + default: + fn = cmplog_hook(0); + pass_n = true; + break; + + case 8: + fn = cmplog_hook(1); + break; + + case 16: + fn = cmplog_hook(2); + break; + + case 32: + fn = cmplog_hook(3); + break; + + case 64: + fn = cmplog_hook(4); + break; + + case 128: + fn = cmplog_hook(5); + break; + + } + + /* Set attr according to the compare operation. */ + unsigned char attr = 0; + + switch (code) { + + case UNORDERED_EXPR: + case ORDERED_EXPR: + /* ??? */ + /* Fallthrough. */ + case NE_EXPR: + case LTGT_EXPR: + break; + + case EQ_EXPR: + case UNEQ_EXPR: + attr += 1; + break; + + case GT_EXPR: + case UNGT_EXPR: + attr += 2; + break; + + case GE_EXPR: + case UNGE_EXPR: + attr += 3; + break; + + case LT_EXPR: + case UNLT_EXPR: + attr += 4; + break; + + case LE_EXPR: + case UNLE_EXPR: + attr += 5; + break; + + default: + gcc_unreachable(); + + } + + if (FLOAT_TYPE_P(TREE_TYPE(lhs))) { + + attr += 8; + + tree t = build_nonstandard_integer_type(sz, 1); + + tree s = make_ssa_name(t); + gimple *g = gimple_build_assign(s, VIEW_CONVERT_EXPR, + build1(VIEW_CONVERT_EXPR, t, lhs)); + lhs = s; + gsi_insert_before(&gsi, g, GSI_SAME_STMT); + + s = make_ssa_name(t); + g = gimple_build_assign(s, VIEW_CONVERT_EXPR, + build1(VIEW_CONVERT_EXPR, t, rhs)); + rhs = s; + gsi_insert_before(&gsi, g, GSI_SAME_STMT); + + } + + /* Convert the operands to the hook arg type, if needed. */ + tree t = TREE_VALUE(TYPE_ARG_TYPES(TREE_TYPE(fn))); + + lhs = fold_convert_loc(UNKNOWN_LOCATION, t, lhs); + if (!is_gimple_val(lhs)) { + + tree s = make_ssa_name(t); + gimple *g = gimple_build_assign(s, lhs); + lhs = s; + gsi_insert_before(&gsi, g, GSI_SAME_STMT); + + } + + rhs = fold_convert_loc(UNKNOWN_LOCATION, t, rhs); + if (!is_gimple_val(rhs)) { + + tree s = make_ssa_name(t); + gimple *g = gimple_build_assign(s, rhs); + rhs = s; + gsi_insert_before(&gsi, g, GSI_SAME_STMT); + + } + + /* Insert the call. */ + tree att = build_int_cst(t8u, attr); + gimple *call; + if (pass_n) + call = gimple_build_call(fn, 4, lhs, rhs, att, + build_int_cst(t8u, sz / 8 - 1)); + else + call = gimple_build_call(fn, 3, lhs, rhs, att); + + gsi_insert_before(&gsi, call, GSI_SAME_STMT); + + } + + virtual unsigned int execute(function *fn) { + + if (!isInInstrumentList(fn)) return 0; + + basic_block bb; + FOR_EACH_BB_FN(bb, fn) { + + /* A GIMPLE_COND or GIMPLE_SWITCH will always be the last stmt + in a BB. */ + gimple_stmt_iterator gsi = gsi_last_bb(bb); + if (gsi_end_p(gsi)) continue; + + gimple *stmt = gsi_stmt(gsi); + + if (gimple_code(stmt) == GIMPLE_COND) { + + tree_code code = gimple_cond_code(stmt); + tree lhs = gimple_cond_lhs(stmt); + tree rhs = gimple_cond_rhs(stmt); + + insert_cmplog_call(gsi, code, lhs, rhs); + + } else if (gimple_code(stmt) == GIMPLE_SWITCH) { + + gswitch *sw = as_a<gswitch *>(stmt); + tree lhs = gimple_switch_index(sw); + + for (int i = 0, e = gimple_switch_num_labels(sw); i < e; i++) { + + tree clx = gimple_switch_label(sw, i); + tree rhsl = CASE_LOW(clx); + /* Default case labels exprs don't have a CASE_LOW. */ + if (!rhsl) continue; + tree rhsh = CASE_HIGH(clx); + /* If there is a CASE_HIGH, issue range compares. */ + if (rhsh) { + + insert_cmplog_call(gsi, GE_EXPR, lhs, rhsl); + insert_cmplog_call(gsi, LE_EXPR, lhs, rhsh); + + } + + /* Otherwise, use a single equality compare. */ + else + insert_cmplog_call(gsi, EQ_EXPR, lhs, rhsl); + + } + + } else + + continue; + + } + + return 0; + + } + +}; + +static struct plugin_info afl_cmplog_plugin = { + + .version = "20220420", + .help = G_("AFL gcc cmplog plugin\n\ +\n\ +Set AFL_QUIET in the environment to silence it.\n\ +"), + +}; + +} // namespace + +/* This is the function GCC calls when loading a plugin. Initialize + and register further callbacks. */ +int plugin_init(struct plugin_name_args *info, + struct plugin_gcc_version *version) { + + if (!plugin_default_version_check(version, &gcc_version)) + FATAL(G_("GCC and plugin have incompatible versions, expected GCC %s, " + "is %s"), + gcc_version.basever, version->basever); + + /* Show a banner. */ + bool quiet = false; + if (isatty(2) && !getenv("AFL_QUIET")) + SAYF(cCYA "afl-gcc-cmplog-pass " cBRI VERSION cRST + " by <oliva@adacore.com>\n"); + else + quiet = true; + + const char *name = info->base_name; + register_callback(name, PLUGIN_INFO, NULL, &afl_cmplog_plugin); + + afl_cmplog_pass *aflp = new afl_cmplog_pass(quiet); + struct register_pass_info pass_info = { + + .pass = aflp, + .reference_pass_name = "ssa", + .ref_pass_instance_number = 1, + .pos_op = PASS_POS_INSERT_AFTER, + + }; + + register_callback(name, PLUGIN_PASS_MANAGER_SETUP, NULL, &pass_info); + + return 0; + +} + diff --git a/instrumentation/afl-gcc-cmptrs-pass.so.cc b/instrumentation/afl-gcc-cmptrs-pass.so.cc new file mode 100644 index 00000000..e9e2fe0d --- /dev/null +++ b/instrumentation/afl-gcc-cmptrs-pass.so.cc @@ -0,0 +1,366 @@ +/* GCC plugin for cmplog routines instrumentation of code for AFL++. + + Copyright 2014-2019 Free Software Foundation, Inc + Copyright 2015, 2016 Google Inc. All rights reserved. + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + Copyright 2019-2022 AdaCore + + Written by Alexandre Oliva <oliva@adacore.com>, based on the AFL++ + LLVM CmpLog Routines pass by Andrea Fioraldi + <andreafioraldi@gmail.com>, and on the AFL GCC CmpLog pass. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + */ + +#include "afl-gcc-common.h" + +/* This plugin, being under the same license as GCC, satisfies the + "GPL-compatible Software" definition in the GCC RUNTIME LIBRARY + EXCEPTION, so it can be part of an "Eligible" "Compilation + Process". */ +int plugin_is_GPL_compatible = 1; + +namespace { + +static const struct pass_data afl_cmptrs_pass_data = { + + .type = GIMPLE_PASS, + .name = "aflcmptrs", + .optinfo_flags = OPTGROUP_NONE, + .tv_id = TV_NONE, + .properties_required = 0, + .properties_provided = 0, + .properties_destroyed = 0, + .todo_flags_start = 0, + .todo_flags_finish = (TODO_update_ssa | TODO_cleanup_cfg | TODO_verify_il | + TODO_rebuild_cgraph_edges), + +}; + +struct afl_cmptrs_pass : afl_base_pass { + + afl_cmptrs_pass(bool quiet) + : afl_base_pass(quiet, /*debug=*/false, afl_cmptrs_pass_data), + tp8u(), + cmptrs_hooks() { + + } + + /* A pointer type to a unsigned 8-bit integral type. */ + tree tp8u; + + /* Declarations for the various cmptrs hook functions, allocated on + demand.. [0] is for compares between any pointers, [1] is for + compares between G++ std::string, [2] is for compares between G++ + std::string and GCC C strings, [3] and [4] are analogous to [1] + and [2] but for LLVM C++ strings. */ + tree cmptrs_hooks[5]; + + tree cmptrs_hook(unsigned i) { + + if (!tp8u) { + + tree t8u; + if (BITS_PER_UNIT == 8) + t8u = unsigned_char_type_node; + else + t8u = build_nonstandard_integer_type(8, 1); + tp8u = build_pointer_type(t8u); + + } + + if (i <= ARRAY_SIZE(cmptrs_hooks) && cmptrs_hooks[i]) + return cmptrs_hooks[i]; + + const char *n = NULL; + + switch (i) { + + case 0: + n = "__cmplog_rtn_hook"; + break; + + case 1: + n = "__cmplog_rtn_gcc_stdstring_stdstring"; + break; + + case 2: + n = "__cmplog_rtn_gcc_stdstring_cstring"; + break; + + case 3: + n = "__cmplog_rtn_llvm_stdstring_stdstring"; + break; + + case 4: + n = "__cmplog_rtn_llvm_stdstring_cstring"; + break; + + default: + gcc_unreachable(); + + } + + tree fnt = build_function_type_list(void_type_node, tp8u, tp8u, NULL_TREE); + tree t = cmptrs_hooks[i] = build_fn_decl(n, fnt); + + /* Mark the newly-created decl as non-throwing, so that we can + insert call within basic blocks. */ + TREE_NOTHROW(t) = 1; + + return t; + + } + + /* Return true if T is the char* type. */ + bool is_c_string(tree t) { + + return (POINTER_TYPE_P(t) && + TYPE_MAIN_VARIANT(TREE_TYPE(t)) == char_type_node); + + } + + /* Return true if T is an indirect std::string type. The LLVM pass + tests portions of the mangled name of the callee. We could do + that in GCC too, but computing the mangled name may cause + template instantiations and get symbols defined that could + otherwise be considered unused. We check for compatible layout, + and class, namespace, and field names. These have been unchanged + since at least GCC 7, probably longer, up to GCC 11. Odds are + that, if it were to change in significant ways, mangling would + also change to flag the incompatibility, and we'd have to use a + different hook anyway. */ + bool is_gxx_std_string(tree t) { + + /* We need a pointer or reference type. */ + if (!POINTER_TYPE_P(t)) return false; + + /* Get to the pointed-to type. */ + t = TREE_TYPE(t); + if (!t) return false; + + /* Select the main variant, so that can compare types with pointers. */ + t = TYPE_MAIN_VARIANT(t); + + /* We expect it to be a record type. */ + if (TREE_CODE(t) != RECORD_TYPE) return false; + + /* The type of the template is basic_string. */ + if (strcmp(IDENTIFIER_POINTER(TYPE_IDENTIFIER(t)), "basic_string") != 0) + return false; + + /* It's declared in an internal namespace named __cxx11. */ + tree c = DECL_CONTEXT(TYPE_NAME(t)); + if (!c || TREE_CODE(c) != NAMESPACE_DECL || + strcmp(IDENTIFIER_POINTER(DECL_NAME(c)), "__cxx11") != 0) + return false; + + /* The __cxx11 namespace is a member of namespace std. */ + c = DECL_CONTEXT(c); + if (!c || TREE_CODE(c) != NAMESPACE_DECL || + strcmp(IDENTIFIER_POINTER(DECL_NAME(c)), "std") != 0) + return false; + + /* And the std namespace is in the global namespace. */ + c = DECL_CONTEXT(c); + if (c && TREE_CODE(c) != TRANSLATION_UNIT_DECL) return false; + + /* Check that the first nonstatic data member of the record type + is named _M_dataplus. */ + for (c = TYPE_FIELDS(t); c; c = DECL_CHAIN(c)) + if (TREE_CODE(c) == FIELD_DECL) break; + if (!c || !integer_zerop(DECL_FIELD_BIT_OFFSET(c)) || + strcmp(IDENTIFIER_POINTER(DECL_NAME(c)), "_M_dataplus") != 0) + return false; + + /* Check that the second nonstatic data member of the record type + is named _M_string_length. */ + tree f2; + for (f2 = DECL_CHAIN(c); f2; f2 = DECL_CHAIN(f2)) + if (TREE_CODE(f2) == FIELD_DECL) break; + if (!f2 /* No need to check this field's offset. */ + || strcmp(IDENTIFIER_POINTER(DECL_NAME(f2)), "_M_string_length") != 0) + return false; + + /* The type of the second data member is size_t. */ + if (!TREE_TYPE(f2) || TYPE_MAIN_VARIANT(TREE_TYPE(f2)) != size_type_node) + return false; + + /* Now go back to the first data member. Its type should be a + record type named _Alloc_hider. */ + c = TREE_TYPE(c); + if (!c || TREE_CODE(c) != RECORD_TYPE || + strcmp(IDENTIFIER_POINTER(TYPE_IDENTIFIER(c)), "_Alloc_hider") != 0) + return false; + + /* And its first data member is named _M_p. */ + for (c = TYPE_FIELDS(c); c; c = DECL_CHAIN(c)) + if (TREE_CODE(c) == FIELD_DECL) break; + if (!c || !integer_zerop(DECL_FIELD_BIT_OFFSET(c)) || + strcmp(IDENTIFIER_POINTER(DECL_NAME(c)), "_M_p") != 0) + return false; + + /* For the basic_string<char> type we're interested in, the type + of the data member is the C string type. */ + if (!is_c_string(TREE_TYPE(c))) return false; + + /* This might not be the real thing, but the bits that matter for + the hook are there. */ + + return true; + + } + + /* ??? This is not implemented. What would the point be of + recognizing LLVM's string type in GCC? */ + bool is_llvm_std_string(tree t) { + + return false; + + } + + virtual unsigned int execute(function *fn) { + + if (!isInInstrumentList(fn)) return 0; + + basic_block bb; + FOR_EACH_BB_FN(bb, fn) { + + for (gimple_stmt_iterator gsi = gsi_after_labels(bb); !gsi_end_p(gsi); + gsi_next(&gsi)) { + + gimple *stmt = gsi_stmt(gsi); + + /* We're only interested in GIMPLE_CALLs. */ + if (gimple_code(stmt) != GIMPLE_CALL) continue; + + if (gimple_call_num_args(stmt) < 2) continue; + + gcall *c = as_a<gcall *>(stmt); + + tree callee_type = gimple_call_fntype(c); + + if (!callee_type || !TYPE_ARG_TYPES(callee_type) || + !TREE_CHAIN(TYPE_ARG_TYPES(callee_type))) + continue; + + tree arg_type[2] = { + + TYPE_MAIN_VARIANT(TREE_VALUE(TYPE_ARG_TYPES(callee_type))), + TYPE_MAIN_VARIANT( + TREE_VALUE(TREE_CHAIN(TYPE_ARG_TYPES(callee_type))))}; + + tree fn = NULL; + /* Callee arglist starts with two GCC std::string arguments. */ + if (arg_type[0] == arg_type[1] && is_gxx_std_string(arg_type[0])) + fn = cmptrs_hook(1); + /* Callee arglist starts with GCC std::string and C string. */ + else if (is_gxx_std_string(arg_type[0]) && is_c_string(arg_type[1])) + fn = cmptrs_hook(2); + /* Callee arglist starts with two LLVM std::string arguments. */ + else if (arg_type[0] == arg_type[1] && is_llvm_std_string(arg_type[0])) + fn = cmptrs_hook(3); + /* Callee arglist starts with LLVM std::string and C string. */ + else if (is_llvm_std_string(arg_type[0]) && is_c_string(arg_type[1])) + fn = cmptrs_hook(4); + /* Callee arglist starts with two pointers to the same type, + and callee returns a value. */ + else if (arg_type[0] == arg_type[1] && POINTER_TYPE_P(arg_type[0]) && + (TYPE_MAIN_VARIANT(gimple_call_return_type(c)) != + void_type_node)) + fn = cmptrs_hook(0); + else + continue; + + tree arg[2] = {gimple_call_arg(c, 0), gimple_call_arg(c, 1)}; + + for (unsigned i = 0; i < ARRAY_SIZE(arg); i++) { + + tree c = fold_convert_loc(UNKNOWN_LOCATION, tp8u, arg[i]); + if (!is_gimple_val(c)) { + + tree s = make_ssa_name(tp8u); + gimple *g = gimple_build_assign(s, c); + c = s; + gsi_insert_before(&gsi, g, GSI_SAME_STMT); + + } + + arg[i] = c; + + } + + gimple *call = gimple_build_call(fn, 2, arg[0], arg[1]); + gsi_insert_before(&gsi, call, GSI_SAME_STMT); + + } + + } + + return 0; + + } + +}; + +static struct plugin_info afl_cmptrs_plugin = { + + .version = "20220420", + .help = G_("AFL gcc cmptrs plugin\n\ +\n\ +Set AFL_QUIET in the environment to silence it.\n\ +"), + +}; + +} // namespace + +/* This is the function GCC calls when loading a plugin. Initialize + and register further callbacks. */ +int plugin_init(struct plugin_name_args *info, + struct plugin_gcc_version *version) { + + if (!plugin_default_version_check(version, &gcc_version)) + FATAL(G_("GCC and plugin have incompatible versions, expected GCC %s, " + "is %s"), + gcc_version.basever, version->basever); + + /* Show a banner. */ + bool quiet = false; + if (isatty(2) && !getenv("AFL_QUIET")) + SAYF(cCYA "afl-gcc-cmptrs-pass " cBRI VERSION cRST + " by <oliva@adacore.com>\n"); + else + quiet = true; + + const char *name = info->base_name; + register_callback(name, PLUGIN_INFO, NULL, &afl_cmptrs_plugin); + + afl_cmptrs_pass *aflp = new afl_cmptrs_pass(quiet); + struct register_pass_info pass_info = { + + .pass = aflp, + .reference_pass_name = "ssa", + .ref_pass_instance_number = 1, + .pos_op = PASS_POS_INSERT_AFTER, + + }; + + register_callback(name, PLUGIN_PASS_MANAGER_SETUP, NULL, &pass_info); + + return 0; + +} + diff --git a/instrumentation/afl-gcc-common.h b/instrumentation/afl-gcc-common.h new file mode 100644 index 00000000..2b71bd22 --- /dev/null +++ b/instrumentation/afl-gcc-common.h @@ -0,0 +1,500 @@ +/* GCC plugin common infrastructure for AFL++ instrumentation passes. + + Copyright 2014-2019 Free Software Foundation, Inc + Copyright 2015, 2016 Google Inc. All rights reserved. + Copyright 2019-2022 AdaCore + + Written by Alexandre Oliva <oliva@adacore.com>, based on the AFL++ + GCC plugin. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + */ + +#include "../include/config.h" +#include "../include/debug.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#ifdef likely + #undef likely +#endif +#ifdef unlikely + #undef unlikely +#endif + +#include <list> +#include <string> +#include <fstream> + +#include <algorithm> +#include <fnmatch.h> + +#include <gcc-plugin.h> +#include <plugin-version.h> +#include <toplev.h> +#include <tree-pass.h> +#include <context.h> +#include <tree.h> +#include <gimplify.h> +#include <basic-block.h> +#include <tree-ssa-alias.h> +#include <gimple-expr.h> +#include <gimple.h> +#include <gimple-iterator.h> +#include <stringpool.h> +#include <gimple-ssa.h> +#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= \ + 60200 /* >= version 6.2.0 */ + #include <tree-vrp.h> +#endif +#include <tree-ssanames.h> +#include <tree-phinodes.h> +#include <ssa-iterators.h> + +#include <intl.h> + +namespace { + +struct afl_base_pass : gimple_opt_pass { + + afl_base_pass(bool quiet, bool debug, struct pass_data const &pd) + : gimple_opt_pass(pd, g), be_quiet(quiet), debug(debug) { + + initInstrumentList(); + + } + + /* Are we outputting to a non-terminal, or running with AFL_QUIET + set? */ + const bool be_quiet; + + /* Are we running with AFL_DEBUG set? */ + const bool debug; + +#define report_fatal_error(msg) BADF(msg) + + std::list<std::string> allowListFiles; + std::list<std::string> allowListFunctions; + std::list<std::string> denyListFiles; + std::list<std::string> denyListFunctions; + + /* Note: this ignore check is also called in isInInstrumentList() */ + bool isIgnoreFunction(function *F) { + + // Starting from "LLVMFuzzer" these are functions used in libfuzzer based + // fuzzing campaign installations, e.g. oss-fuzz + + static constexpr const char *ignoreList[] = { + + "asan.", + "llvm.", + "sancov.", + "__ubsan_", + "ign.", + "__afl_", + "_fini", + "__libc_csu", + "__asan", + "__msan", + "__cmplog", + "__sancov", + "msan.", + "LLVMFuzzerM", + "LLVMFuzzerC", + "LLVMFuzzerI", + "__decide_deferred", + "maybe_duplicate_stderr", + "discard_output", + "close_stdout", + "dup_and_close_stderr", + "maybe_close_fd_mask", + "ExecuteFilesOnyByOne" + + }; + + const char *name = IDENTIFIER_POINTER(DECL_NAME(F->decl)); + int len = IDENTIFIER_LENGTH(DECL_NAME(F->decl)); + + for (auto const &ignoreListFunc : ignoreList) { + + if (strncmp(name, ignoreListFunc, len) == 0) { return true; } + + } + + return false; + + } + + void initInstrumentList() { + + char *allowlist = getenv("AFL_GCC_ALLOWLIST"); + if (!allowlist) allowlist = getenv("AFL_GCC_INSTRUMENT_FILE"); + if (!allowlist) allowlist = getenv("AFL_GCC_WHITELIST"); + if (!allowlist) allowlist = getenv("AFL_LLVM_ALLOWLIST"); + if (!allowlist) allowlist = getenv("AFL_LLVM_INSTRUMENT_FILE"); + if (!allowlist) allowlist = getenv("AFL_LLVM_WHITELIST"); + char *denylist = getenv("AFL_GCC_DENYLIST"); + if (!denylist) denylist = getenv("AFL_GCC_BLOCKLIST"); + if (!denylist) denylist = getenv("AFL_LLVM_DENYLIST"); + if (!denylist) denylist = getenv("AFL_LLVM_BLOCKLIST"); + + if (allowlist && denylist) + FATAL( + "You can only specify either AFL_GCC_ALLOWLIST or AFL_GCC_DENYLIST " + "but not both!"); + + if (allowlist) { + + std::string line; + std::ifstream fileStream; + fileStream.open(allowlist); + if (!fileStream) report_fatal_error("Unable to open AFL_GCC_ALLOWLIST"); + getline(fileStream, line); + + while (fileStream) { + + int is_file = -1; + std::size_t npos; + std::string original_line = line; + + line.erase(std::remove_if(line.begin(), line.end(), ::isspace), + line.end()); + + // remove # and following + if ((npos = line.find("#")) != std::string::npos) + line = line.substr(0, npos); + + if (line.compare(0, 4, "fun:") == 0) { + + is_file = 0; + line = line.substr(4); + + } else if (line.compare(0, 9, "function:") == 0) { + + is_file = 0; + line = line.substr(9); + + } else if (line.compare(0, 4, "src:") == 0) { + + is_file = 1; + line = line.substr(4); + + } else if (line.compare(0, 7, "source:") == 0) { + + is_file = 1; + line = line.substr(7); + + } + + if (line.find(":") != std::string::npos) { + + FATAL("invalid line in AFL_GCC_ALLOWLIST: %s", original_line.c_str()); + + } + + if (line.length() > 0) { + + // if the entry contains / or . it must be a file + if (is_file == -1) + if (line.find("/") != std::string::npos || + line.find(".") != std::string::npos) + is_file = 1; + // otherwise it is a function + + if (is_file == 1) + allowListFiles.push_back(line); + else + allowListFunctions.push_back(line); + + } + + getline(fileStream, line); + + } + + if (debug) + DEBUGF("loaded allowlist with %zu file and %zu function entries\n", + allowListFiles.size(), allowListFunctions.size()); + + } + + if (denylist) { + + std::string line; + std::ifstream fileStream; + fileStream.open(denylist); + if (!fileStream) report_fatal_error("Unable to open AFL_GCC_DENYLIST"); + getline(fileStream, line); + + while (fileStream) { + + int is_file = -1; + std::size_t npos; + std::string original_line = line; + + line.erase(std::remove_if(line.begin(), line.end(), ::isspace), + line.end()); + + // remove # and following + if ((npos = line.find("#")) != std::string::npos) + line = line.substr(0, npos); + + if (line.compare(0, 4, "fun:") == 0) { + + is_file = 0; + line = line.substr(4); + + } else if (line.compare(0, 9, "function:") == 0) { + + is_file = 0; + line = line.substr(9); + + } else if (line.compare(0, 4, "src:") == 0) { + + is_file = 1; + line = line.substr(4); + + } else if (line.compare(0, 7, "source:") == 0) { + + is_file = 1; + line = line.substr(7); + + } + + if (line.find(":") != std::string::npos) { + + FATAL("invalid line in AFL_GCC_DENYLIST: %s", original_line.c_str()); + + } + + if (line.length() > 0) { + + // if the entry contains / or . it must be a file + if (is_file == -1) + if (line.find("/") != std::string::npos || + line.find(".") != std::string::npos) + is_file = 1; + // otherwise it is a function + + if (is_file == 1) + denyListFiles.push_back(line); + else + denyListFunctions.push_back(line); + + } + + getline(fileStream, line); + + } + + if (debug) + DEBUGF("loaded denylist with %zu file and %zu function entries\n", + denyListFiles.size(), denyListFunctions.size()); + + } + + } + + /* Returns the source file name attached to the function declaration F. If + there is no source location information, returns an empty string. */ + std::string getSourceName(function *F) { + + return DECL_SOURCE_FILE(F->decl) ? DECL_SOURCE_FILE(F->decl) : ""; + + } + + bool isInInstrumentList(function *F) { + + bool return_default = true; + + // is this a function with code? If it is external we don't instrument it + // anyway and it can't be in the instrument file list. Or if it is it is + // ignored. + if (isIgnoreFunction(F)) return false; + + if (!denyListFiles.empty() || !denyListFunctions.empty()) { + + if (!denyListFunctions.empty()) { + + std::string instFunction = IDENTIFIER_POINTER(DECL_NAME(F->decl)); + + for (std::list<std::string>::iterator it = denyListFunctions.begin(); + it != denyListFunctions.end(); ++it) { + + /* We don't check for filename equality here because + * filenames might actually be full paths. Instead we + * check that the actual filename ends in the filename + * specified in the list. We also allow UNIX-style pattern + * matching */ + + if (instFunction.length() >= it->length()) { + + if (fnmatch(("*" + *it).c_str(), instFunction.c_str(), 0) == 0) { + + if (debug) + DEBUGF( + "Function %s is in the deny function list, not " + "instrumenting ... \n", + instFunction.c_str()); + return false; + + } + + } + + } + + } + + if (!denyListFiles.empty()) { + + std::string source_file = getSourceName(F); + + if (!source_file.empty()) { + + for (std::list<std::string>::iterator it = denyListFiles.begin(); + it != denyListFiles.end(); ++it) { + + /* We don't check for filename equality here because + * filenames might actually be full paths. Instead we + * check that the actual filename ends in the filename + * specified in the list. We also allow UNIX-style pattern + * matching */ + + if (source_file.length() >= it->length()) { + + if (fnmatch(("*" + *it).c_str(), source_file.c_str(), 0) == 0) { + + return false; + + } + + } + + } + + } else { + + // we could not find out the location. in this case we say it is not + // in the instrument file list + if (!be_quiet) + WARNF( + "No debug information found for function %s, will be " + "instrumented (recompile with -g -O[1-3]).", + IDENTIFIER_POINTER(DECL_NAME(F->decl))); + + } + + } + + } + + // if we do not have a instrument file list return true + if (!allowListFiles.empty() || !allowListFunctions.empty()) { + + return_default = false; + + if (!allowListFunctions.empty()) { + + std::string instFunction = IDENTIFIER_POINTER(DECL_NAME(F->decl)); + + for (std::list<std::string>::iterator it = allowListFunctions.begin(); + it != allowListFunctions.end(); ++it) { + + /* We don't check for filename equality here because + * filenames might actually be full paths. Instead we + * check that the actual filename ends in the filename + * specified in the list. We also allow UNIX-style pattern + * matching */ + + if (instFunction.length() >= it->length()) { + + if (fnmatch(("*" + *it).c_str(), instFunction.c_str(), 0) == 0) { + + if (debug) + DEBUGF( + "Function %s is in the allow function list, instrumenting " + "... \n", + instFunction.c_str()); + return true; + + } + + } + + } + + } + + if (!allowListFiles.empty()) { + + std::string source_file = getSourceName(F); + + if (!source_file.empty()) { + + for (std::list<std::string>::iterator it = allowListFiles.begin(); + it != allowListFiles.end(); ++it) { + + /* We don't check for filename equality here because + * filenames might actually be full paths. Instead we + * check that the actual filename ends in the filename + * specified in the list. We also allow UNIX-style pattern + * matching */ + + if (source_file.length() >= it->length()) { + + if (fnmatch(("*" + *it).c_str(), source_file.c_str(), 0) == 0) { + + if (debug) + DEBUGF( + "Function %s is in the allowlist (%s), instrumenting ... " + "\n", + IDENTIFIER_POINTER(DECL_NAME(F->decl)), + source_file.c_str()); + return true; + + } + + } + + } + + } else { + + // we could not find out the location. In this case we say it is not + // in the instrument file list + if (!be_quiet) + WARNF( + "No debug information found for function %s, will not be " + "instrumented (recompile with -g -O[1-3]).", + IDENTIFIER_POINTER(DECL_NAME(F->decl))); + return false; + + } + + } + + } + + return return_default; + + } + +}; + +} // namespace + diff --git a/instrumentation/afl-gcc-pass.so.cc b/instrumentation/afl-gcc-pass.so.cc index bb5483fc..052b3159 100644 --- a/instrumentation/afl-gcc-pass.so.cc +++ b/instrumentation/afl-gcc-pass.so.cc @@ -124,50 +124,8 @@ entry edge for the entry block. */ -#include "../include/config.h" -#include "../include/debug.h" - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -#ifdef likely - #undef likely -#endif -#ifdef unlikely - #undef unlikely -#endif - -#include <list> -#include <string> -#include <fstream> - -#include <algorithm> -#include <fnmatch.h> - -#include <gcc-plugin.h> -#include <plugin-version.h> -#include <toplev.h> -#include <tree-pass.h> -#include <context.h> -#include <tree.h> -#include <gimplify.h> -#include <basic-block.h> -#include <tree-ssa-alias.h> -#include <gimple-expr.h> -#include <gimple.h> -#include <gimple-iterator.h> -#include <stringpool.h> -#include <gimple-ssa.h> -#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= \ - 60200 /* >= version 6.2.0 */ - #include <tree-vrp.h> -#endif -#include <tree-ssanames.h> -#include <tree-phinodes.h> -#include <ssa-iterators.h> - -#include <intl.h> +#include "afl-gcc-common.h" +#include "memmodel.h" /* This plugin, being under the same license as GCC, satisfies the "GPL-compatible Software" definition in the GCC RUNTIME LIBRARY @@ -191,12 +149,10 @@ static constexpr struct pass_data afl_pass_data = { }; -struct afl_pass : gimple_opt_pass { +struct afl_pass : afl_base_pass { afl_pass(bool quiet, unsigned int ratio) - : gimple_opt_pass(afl_pass_data, g), - be_quiet(quiet), - debug(!!getenv("AFL_DEBUG")), + : afl_base_pass(quiet, !!getenv("AFL_DEBUG"), afl_pass_data), inst_ratio(ratio), #ifdef AFL_GCC_OUT_OF_LINE out_of_line(!!(AFL_GCC_OUT_OF_LINE)), @@ -210,13 +166,6 @@ struct afl_pass : gimple_opt_pass { } - /* Are we outputting to a non-terminal, or running with AFL_QUIET - set? */ - const bool be_quiet; - - /* Are we running with AFL_DEBUG set? */ - const bool debug; - /* How likely (%) is a block to be instrumented? */ const unsigned int inst_ratio; @@ -297,21 +246,22 @@ struct afl_pass : gimple_opt_pass { gimple_build_assign(ntry, POINTER_PLUS_EXPR, map_ptr, indx); gimple_seq_add_stmt(&seq, idx_map); - /* Increment the counter in idx_map. */ - tree memref = build2(MEM_REF, TREE_TYPE(TREE_TYPE(ntry)), ntry, - build_zero_cst(TREE_TYPE(ntry))); - if (blocks == 0) - cntr = create_tmp_var(TREE_TYPE(memref), ".afl_edge_count"); - - /* Load the count from the entry. */ - auto load_cntr = gimple_build_assign(cntr, memref); - gimple_seq_add_stmt(&seq, load_cntr); - /* Prepare to add constant 1 to it. */ - tree incrv = build_one_cst(TREE_TYPE(cntr)); + tree incrv = build_one_cst(TREE_TYPE(TREE_TYPE(ntry))); if (neverZero) { + /* Increment the counter in idx_map. */ + tree memref = build2(MEM_REF, TREE_TYPE(TREE_TYPE(ntry)), ntry, + build_zero_cst(TREE_TYPE(ntry))); + + if (blocks == 0) + cntr = create_tmp_var(TREE_TYPE(memref), ".afl_edge_count"); + + /* Load the count from the entry. */ + auto load_cntr = gimple_build_assign(cntr, memref); + gimple_seq_add_stmt(&seq, load_cntr); + /* NeverZero: if count wrapped around to zero, advance to one. */ if (blocks == 0) { @@ -348,15 +298,24 @@ struct afl_pass : gimple_opt_pass { in xincr. */ incrv = xincr; - } + /* Add the increment (1 or the overflow bit) to count. */ + auto incr_cntr = gimple_build_assign(cntr, PLUS_EXPR, cntr, incrv); + gimple_seq_add_stmt(&seq, incr_cntr); + + /* Store count in the map entry. */ + auto store_cntr = gimple_build_assign(unshare_expr(memref), cntr); + gimple_seq_add_stmt(&seq, store_cntr); - /* Add the increment (1 or the overflow bit) to count. */ - auto incr_cntr = gimple_build_assign(cntr, PLUS_EXPR, cntr, incrv); - gimple_seq_add_stmt(&seq, incr_cntr); + } else { - /* Store count in the map entry. */ - auto store_cntr = gimple_build_assign(unshare_expr(memref), cntr); - gimple_seq_add_stmt(&seq, store_cntr); + /* Use a serialized memory model. */ + tree memmod = build_int_cst(integer_type_node, MEMMODEL_SEQ_CST); + + tree fadd = builtin_decl_explicit(BUILT_IN_ATOMIC_FETCH_ADD_1); + auto incr_cntr = gimple_build_call(fadd, 3, ntry, incrv, memmod); + gimple_seq_add_stmt(&seq, incr_cntr); + + } /* Store bid >> 1 in __afl_prev_loc. */ auto shift_loc = @@ -456,6 +415,8 @@ struct afl_pass : gimple_opt_pass { thread-local variable. */ static inline tree get_afl_area_ptr_decl() { + /* If type changes, the size N in FETCH_ADD_<N> must be adjusted + in builtin calls above. */ tree type = build_pointer_type(unsigned_char_type_node); tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, get_identifier("__afl_area_ptr"), type); @@ -490,420 +451,11 @@ struct afl_pass : gimple_opt_pass { } -#define report_fatal_error(msg) BADF(msg) - - std::list<std::string> allowListFiles; - std::list<std::string> allowListFunctions; - std::list<std::string> denyListFiles; - std::list<std::string> denyListFunctions; - - /* Note: this ignore check is also called in isInInstrumentList() */ - bool isIgnoreFunction(function *F) { - - // Starting from "LLVMFuzzer" these are functions used in libfuzzer based - // fuzzing campaign installations, e.g. oss-fuzz - - static constexpr const char *ignoreList[] = { - - "asan.", - "llvm.", - "sancov.", - "__ubsan_", - "ign.", - "__afl_", - "_fini", - "__libc_csu", - "__asan", - "__msan", - "__cmplog", - "__sancov", - "msan.", - "LLVMFuzzerM", - "LLVMFuzzerC", - "LLVMFuzzerI", - "__decide_deferred", - "maybe_duplicate_stderr", - "discard_output", - "close_stdout", - "dup_and_close_stderr", - "maybe_close_fd_mask", - "ExecuteFilesOnyByOne" - - }; - - const char *name = IDENTIFIER_POINTER(DECL_NAME(F->decl)); - int len = IDENTIFIER_LENGTH(DECL_NAME(F->decl)); - - for (auto const &ignoreListFunc : ignoreList) { - - if (strncmp(name, ignoreListFunc, len) == 0) { return true; } - - } - - return false; - - } - - void initInstrumentList() { - - char *allowlist = getenv("AFL_GCC_ALLOWLIST"); - if (!allowlist) allowlist = getenv("AFL_GCC_INSTRUMENT_FILE"); - if (!allowlist) allowlist = getenv("AFL_GCC_WHITELIST"); - if (!allowlist) allowlist = getenv("AFL_LLVM_ALLOWLIST"); - if (!allowlist) allowlist = getenv("AFL_LLVM_INSTRUMENT_FILE"); - if (!allowlist) allowlist = getenv("AFL_LLVM_WHITELIST"); - char *denylist = getenv("AFL_GCC_DENYLIST"); - if (!denylist) denylist = getenv("AFL_GCC_BLOCKLIST"); - if (!denylist) denylist = getenv("AFL_LLVM_DENYLIST"); - if (!denylist) denylist = getenv("AFL_LLVM_BLOCKLIST"); - - if (allowlist && denylist) - FATAL( - "You can only specify either AFL_GCC_ALLOWLIST or AFL_GCC_DENYLIST " - "but not both!"); - - if (allowlist) { - - std::string line; - std::ifstream fileStream; - fileStream.open(allowlist); - if (!fileStream) report_fatal_error("Unable to open AFL_GCC_ALLOWLIST"); - getline(fileStream, line); - - while (fileStream) { - - int is_file = -1; - std::size_t npos; - std::string original_line = line; - - line.erase(std::remove_if(line.begin(), line.end(), ::isspace), - line.end()); - - // remove # and following - if ((npos = line.find("#")) != std::string::npos) - line = line.substr(0, npos); - - if (line.compare(0, 4, "fun:") == 0) { - - is_file = 0; - line = line.substr(4); - - } else if (line.compare(0, 9, "function:") == 0) { - - is_file = 0; - line = line.substr(9); - - } else if (line.compare(0, 4, "src:") == 0) { - - is_file = 1; - line = line.substr(4); - - } else if (line.compare(0, 7, "source:") == 0) { - - is_file = 1; - line = line.substr(7); - - } - - if (line.find(":") != std::string::npos) { - - FATAL("invalid line in AFL_GCC_ALLOWLIST: %s", original_line.c_str()); - - } - - if (line.length() > 0) { - - // if the entry contains / or . it must be a file - if (is_file == -1) - if (line.find("/") != std::string::npos || - line.find(".") != std::string::npos) - is_file = 1; - // otherwise it is a function - - if (is_file == 1) - allowListFiles.push_back(line); - else - allowListFunctions.push_back(line); - - } - - getline(fileStream, line); - - } - - if (debug) - DEBUGF("loaded allowlist with %zu file and %zu function entries\n", - allowListFiles.size(), allowListFunctions.size()); - - } - - if (denylist) { - - std::string line; - std::ifstream fileStream; - fileStream.open(denylist); - if (!fileStream) report_fatal_error("Unable to open AFL_GCC_DENYLIST"); - getline(fileStream, line); - - while (fileStream) { - - int is_file = -1; - std::size_t npos; - std::string original_line = line; - - line.erase(std::remove_if(line.begin(), line.end(), ::isspace), - line.end()); - - // remove # and following - if ((npos = line.find("#")) != std::string::npos) - line = line.substr(0, npos); - - if (line.compare(0, 4, "fun:") == 0) { - - is_file = 0; - line = line.substr(4); - - } else if (line.compare(0, 9, "function:") == 0) { - - is_file = 0; - line = line.substr(9); - - } else if (line.compare(0, 4, "src:") == 0) { - - is_file = 1; - line = line.substr(4); - - } else if (line.compare(0, 7, "source:") == 0) { - - is_file = 1; - line = line.substr(7); - - } - - if (line.find(":") != std::string::npos) { - - FATAL("invalid line in AFL_GCC_DENYLIST: %s", original_line.c_str()); - - } - - if (line.length() > 0) { - - // if the entry contains / or . it must be a file - if (is_file == -1) - if (line.find("/") != std::string::npos || - line.find(".") != std::string::npos) - is_file = 1; - // otherwise it is a function - - if (is_file == 1) - denyListFiles.push_back(line); - else - denyListFunctions.push_back(line); - - } - - getline(fileStream, line); - - } - - if (debug) - DEBUGF("loaded denylist with %zu file and %zu function entries\n", - denyListFiles.size(), denyListFunctions.size()); - - } - - } - - /* Returns the source file name attached to the function declaration F. If - there is no source location information, returns an empty string. */ - std::string getSourceName(function *F) { - - return DECL_SOURCE_FILE(F->decl) ? DECL_SOURCE_FILE(F->decl) : ""; - - } - - bool isInInstrumentList(function *F) { - - bool return_default = true; - - // is this a function with code? If it is external we don't instrument it - // anyway and it can't be in the instrument file list. Or if it is it is - // ignored. - if (isIgnoreFunction(F)) return false; - - if (!denyListFiles.empty() || !denyListFunctions.empty()) { - - if (!denyListFunctions.empty()) { - - std::string instFunction = IDENTIFIER_POINTER(DECL_NAME(F->decl)); - - for (std::list<std::string>::iterator it = denyListFunctions.begin(); - it != denyListFunctions.end(); ++it) { - - /* We don't check for filename equality here because - * filenames might actually be full paths. Instead we - * check that the actual filename ends in the filename - * specified in the list. We also allow UNIX-style pattern - * matching */ - - if (instFunction.length() >= it->length()) { - - if (fnmatch(("*" + *it).c_str(), instFunction.c_str(), 0) == 0) { - - if (debug) - DEBUGF( - "Function %s is in the deny function list, not " - "instrumenting ... \n", - instFunction.c_str()); - return false; - - } - - } - - } - - } - - if (!denyListFiles.empty()) { - - std::string source_file = getSourceName(F); - - if (!source_file.empty()) { - - for (std::list<std::string>::iterator it = denyListFiles.begin(); - it != denyListFiles.end(); ++it) { - - /* We don't check for filename equality here because - * filenames might actually be full paths. Instead we - * check that the actual filename ends in the filename - * specified in the list. We also allow UNIX-style pattern - * matching */ - - if (source_file.length() >= it->length()) { - - if (fnmatch(("*" + *it).c_str(), source_file.c_str(), 0) == 0) { - - return false; - - } - - } - - } - - } else { - - // we could not find out the location. in this case we say it is not - // in the instrument file list - if (!be_quiet) - WARNF( - "No debug information found for function %s, will be " - "instrumented (recompile with -g -O[1-3]).", - IDENTIFIER_POINTER(DECL_NAME(F->decl))); - - } - - } - - } - - // if we do not have a instrument file list return true - if (!allowListFiles.empty() || !allowListFunctions.empty()) { - - return_default = false; - - if (!allowListFunctions.empty()) { - - std::string instFunction = IDENTIFIER_POINTER(DECL_NAME(F->decl)); - - for (std::list<std::string>::iterator it = allowListFunctions.begin(); - it != allowListFunctions.end(); ++it) { - - /* We don't check for filename equality here because - * filenames might actually be full paths. Instead we - * check that the actual filename ends in the filename - * specified in the list. We also allow UNIX-style pattern - * matching */ - - if (instFunction.length() >= it->length()) { - - if (fnmatch(("*" + *it).c_str(), instFunction.c_str(), 0) == 0) { - - if (debug) - DEBUGF( - "Function %s is in the allow function list, instrumenting " - "... \n", - instFunction.c_str()); - return true; - - } - - } - - } - - } - - if (!allowListFiles.empty()) { - - std::string source_file = getSourceName(F); - - if (!source_file.empty()) { - - for (std::list<std::string>::iterator it = allowListFiles.begin(); - it != allowListFiles.end(); ++it) { - - /* We don't check for filename equality here because - * filenames might actually be full paths. Instead we - * check that the actual filename ends in the filename - * specified in the list. We also allow UNIX-style pattern - * matching */ - - if (source_file.length() >= it->length()) { - - if (fnmatch(("*" + *it).c_str(), source_file.c_str(), 0) == 0) { - - if (debug) - DEBUGF( - "Function %s is in the allowlist (%s), instrumenting ... " - "\n", - IDENTIFIER_POINTER(DECL_NAME(F->decl)), - source_file.c_str()); - return true; - - } - - } - - } - - } else { - - // we could not find out the location. In this case we say it is not - // in the instrument file list - if (!be_quiet) - WARNF( - "No debug information found for function %s, will not be " - "instrumented (recompile with -g -O[1-3]).", - IDENTIFIER_POINTER(DECL_NAME(F->decl))); - return false; - - } - - } - - } - - return return_default; - - } - }; static struct plugin_info afl_plugin = { - .version = "20220907", + .version = "20220420", .help = G_("AFL gcc plugin\n\ \n\ Set AFL_QUIET in the environment to silence it.\n\ @@ -920,7 +472,7 @@ Specify -frandom-seed for reproducible instrumentation.\n\ /* This is the function GCC calls when loading a plugin. Initialize and register further callbacks. */ -int plugin_init(struct plugin_name_args * info, +int plugin_init(struct plugin_name_args *info, struct plugin_gcc_version *version) { if (!plugin_default_version_check(version, &gcc_version)) @@ -950,7 +502,7 @@ int plugin_init(struct plugin_name_args * info, const char *name = info->base_name; register_callback(name, PLUGIN_INFO, NULL, &afl_plugin); - afl_pass * aflp = new afl_pass(quiet, inst_ratio); + afl_pass *aflp = new afl_pass(quiet, inst_ratio); struct register_pass_info pass_info = { .pass = aflp, diff --git a/instrumentation/afl-llvm-dict2file.so.cc b/instrumentation/afl-llvm-dict2file.so.cc index 31aaab07..fd8baea2 100644 --- a/instrumentation/afl-llvm-dict2file.so.cc +++ b/instrumentation/afl-llvm-dict2file.so.cc @@ -181,7 +181,7 @@ bool AFLdict2filePass::runOnModule(Module &M) { #endif DenseMap<Value *, std::string *> valueMap; - char * ptr; + char *ptr; int found = 0; /* Show a banner */ @@ -246,11 +246,11 @@ bool AFLdict2filePass::runOnModule(Module &M) { for (auto &IN : BB) { CallInst *callInst = nullptr; - CmpInst * cmpInst = nullptr; + CmpInst *cmpInst = nullptr; if ((cmpInst = dyn_cast<CmpInst>(&IN))) { - Value * op = cmpInst->getOperand(1); + Value *op = cmpInst->getOperand(1); ConstantInt *ilen = dyn_cast<ConstantInt>(op); /* We skip > 64 bit integers. why? first because their value is @@ -518,7 +518,7 @@ bool AFLdict2filePass::runOnModule(Module &M) { if (HasStr2 == true) { - Value * op2 = callInst->getArgOperand(2); + Value *op2 = callInst->getArgOperand(2); ConstantInt *ilen = dyn_cast<ConstantInt>(op2); if (ilen) { @@ -631,7 +631,7 @@ bool AFLdict2filePass::runOnModule(Module &M) { if (isMemcmp || isStrncmp || isStrncasecmp) { - Value * op2 = callInst->getArgOperand(2); + Value *op2 = callInst->getArgOperand(2); ConstantInt *ilen = dyn_cast<ConstantInt>(op2); if (ilen) { diff --git a/instrumentation/afl-llvm-lto-instrumentlist.so.cc b/instrumentation/afl-llvm-lto-instrumentlist.so.cc index 70c6b10d..32b1798a 100644 --- a/instrumentation/afl-llvm-lto-instrumentlist.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentlist.so.cc @@ -101,7 +101,7 @@ llvmGetPassPluginInfo() { } -PreservedAnalyses AFLcheckIfInstrument::run(Module & M, +PreservedAnalyses AFLcheckIfInstrument::run(Module &M, ModuleAnalysisManager &MAM) { /* Show a banner */ @@ -135,7 +135,7 @@ PreservedAnalyses AFLcheckIfInstrument::run(Module & M, DEBUGF("function %s is NOT in the instrument file list\n", F.getName().str().c_str()); - auto & Ctx = F.getContext(); + auto &Ctx = F.getContext(); AttributeList Attrs = F.getAttributes(); #if LLVM_VERSION_MAJOR >= 14 AttributeList NewAttrs = Attrs.addFnAttribute(Ctx, "skipinstrument"); diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc index fde785bd..df1ccc4f 100644 --- a/instrumentation/afl-llvm-pass.so.cc +++ b/instrumentation/afl-llvm-pass.so.cc @@ -251,7 +251,7 @@ bool AFLCoverage::runOnModule(Module &M) { /* Decide instrumentation ratio */ - char * inst_ratio_str = getenv("AFL_INST_RATIO"); + char *inst_ratio_str = getenv("AFL_INST_RATIO"); unsigned int inst_ratio = 100; if (inst_ratio_str) { @@ -486,7 +486,7 @@ bool AFLCoverage::runOnModule(Module &M) { Constant *PrevLocShuffleMask = ConstantVector::get(PrevLocShuffle); - Constant * PrevCallerShuffleMask = NULL; + Constant *PrevCallerShuffleMask = NULL; SmallVector<Constant *, 32> PrevCallerShuffle = {UndefValue::get(Int32Ty)}; if (ctx_k) { @@ -506,7 +506,7 @@ bool AFLCoverage::runOnModule(Module &M) { // other constants we need ConstantInt *One = ConstantInt::get(Int8Ty, 1); - Value * PrevCtx = NULL; // CTX sensitive coverage + Value *PrevCtx = NULL; // CTX sensitive coverage LoadInst *PrevCaller = NULL; // K-CTX coverage /* Instrument all the things! */ diff --git a/instrumentation/cmplog-instructions-pass.cc b/instrumentation/cmplog-instructions-pass.cc index 4d37bcb2..084ad8c9 100644 --- a/instrumentation/cmplog-instructions-pass.cc +++ b/instrumentation/cmplog-instructions-pass.cc @@ -156,9 +156,9 @@ Iterator Unique(Iterator first, Iterator last) { bool CmpLogInstructions::hookInstrs(Module &M) { std::vector<Instruction *> icomps; - LLVMContext & C = M.getContext(); + LLVMContext &C = M.getContext(); - Type * VoidTy = Type::getVoidTy(C); + Type *VoidTy = Type::getVoidTy(C); IntegerType *Int8Ty = IntegerType::getInt8Ty(C); IntegerType *Int16Ty = IntegerType::getInt16Ty(C); IntegerType *Int32Ty = IntegerType::getInt32Ty(C); @@ -338,7 +338,7 @@ bool CmpLogInstructions::hookInstrs(Module &M) { IntegerType *intTyOp1 = NULL; unsigned max_size = 0, cast_size = 0; unsigned attr = 0, vector_cnt = 0, is_fp = 0; - CmpInst * cmpInst = dyn_cast<CmpInst>(selectcmpInst); + CmpInst *cmpInst = dyn_cast<CmpInst>(selectcmpInst); if (!cmpInst) { continue; } @@ -666,7 +666,7 @@ bool CmpLogInstructions::hookInstrs(Module &M) { } #if LLVM_MAJOR >= 11 /* use new pass manager */ -PreservedAnalyses CmpLogInstructions::run(Module & M, +PreservedAnalyses CmpLogInstructions::run(Module &M, ModuleAnalysisManager &MAM) { #else diff --git a/instrumentation/cmplog-routines-pass.cc b/instrumentation/cmplog-routines-pass.cc index 8205cfb0..9733f86e 100644 --- a/instrumentation/cmplog-routines-pass.cc +++ b/instrumentation/cmplog-routines-pass.cc @@ -506,8 +506,8 @@ bool CmpLogRoutines::hookRtns(Module &M) { IRBuilder<> IRB(ThenTerm); std::vector<Value *> args; - Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy); - Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy); + Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy); + Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy); args.push_back(v1Pcasted); args.push_back(v2Pcasted); @@ -537,10 +537,10 @@ bool CmpLogRoutines::hookRtns(Module &M) { IRBuilder<> IRB(ThenTerm); std::vector<Value *> args; - Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy); - Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy); - Value * v3Pbitcast = IRB.CreateBitCast( - v3P, IntegerType::get(C, v3P->getType()->getPrimitiveSizeInBits())); + Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy); + Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy); + Value *v3Pbitcast = IRB.CreateBitCast( + v3P, IntegerType::get(C, v3P->getType()->getPrimitiveSizeInBits())); Value *v3Pcasted = IRB.CreateIntCast(v3Pbitcast, IntegerType::get(C, 64), false); args.push_back(v1Pcasted); @@ -572,8 +572,8 @@ bool CmpLogRoutines::hookRtns(Module &M) { IRBuilder<> IRB(ThenTerm); std::vector<Value *> args; - Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy); - Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy); + Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy); + Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy); args.push_back(v1Pcasted); args.push_back(v2Pcasted); @@ -603,10 +603,10 @@ bool CmpLogRoutines::hookRtns(Module &M) { IRBuilder<> IRB(ThenTerm); std::vector<Value *> args; - Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy); - Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy); - Value * v3Pbitcast = IRB.CreateBitCast( - v3P, IntegerType::get(C, v3P->getType()->getPrimitiveSizeInBits())); + Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy); + Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy); + Value *v3Pbitcast = IRB.CreateBitCast( + v3P, IntegerType::get(C, v3P->getType()->getPrimitiveSizeInBits())); Value *v3Pcasted = IRB.CreateIntCast(v3Pbitcast, IntegerType::get(C, 64), false); args.push_back(v1Pcasted); @@ -638,8 +638,8 @@ bool CmpLogRoutines::hookRtns(Module &M) { IRBuilder<> IRB(ThenTerm); std::vector<Value *> args; - Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy); - Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy); + Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy); + Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy); args.push_back(v1Pcasted); args.push_back(v2Pcasted); @@ -668,8 +668,8 @@ bool CmpLogRoutines::hookRtns(Module &M) { IRBuilder<> IRB(ThenTerm); std::vector<Value *> args; - Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy); - Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy); + Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy); + Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy); args.push_back(v1Pcasted); args.push_back(v2Pcasted); @@ -698,8 +698,8 @@ bool CmpLogRoutines::hookRtns(Module &M) { IRBuilder<> IRB(ThenTerm); std::vector<Value *> args; - Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy); - Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy); + Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy); + Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy); args.push_back(v1Pcasted); args.push_back(v2Pcasted); @@ -728,8 +728,8 @@ bool CmpLogRoutines::hookRtns(Module &M) { IRBuilder<> IRB(ThenTerm); std::vector<Value *> args; - Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy); - Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy); + Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy); + Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy); args.push_back(v1Pcasted); args.push_back(v2Pcasted); diff --git a/instrumentation/cmplog-switches-pass.cc b/instrumentation/cmplog-switches-pass.cc index 37bf3889..563a4481 100644 --- a/instrumentation/cmplog-switches-pass.cc +++ b/instrumentation/cmplog-switches-pass.cc @@ -149,9 +149,9 @@ Iterator Unique(Iterator first, Iterator last) { bool CmplogSwitches::hookInstrs(Module &M) { std::vector<SwitchInst *> switches; - LLVMContext & C = M.getContext(); + LLVMContext &C = M.getContext(); - Type * VoidTy = Type::getVoidTy(C); + Type *VoidTy = Type::getVoidTy(C); IntegerType *Int8Ty = IntegerType::getInt8Ty(C); IntegerType *Int16Ty = IntegerType::getInt16Ty(C); IntegerType *Int32Ty = IntegerType::getInt32Ty(C); @@ -270,7 +270,7 @@ bool CmplogSwitches::hookInstrs(Module &M) { for (auto &SI : switches) { - Value * Val = SI->getCondition(); + Value *Val = SI->getCondition(); unsigned int max_size = Val->getType()->getIntegerBitWidth(), cast_size; unsigned char do_cast = 0; diff --git a/instrumentation/compare-transform-pass.so.cc b/instrumentation/compare-transform-pass.so.cc index 34c88735..39bff510 100644 --- a/instrumentation/compare-transform-pass.so.cc +++ b/instrumentation/compare-transform-pass.so.cc @@ -168,10 +168,10 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, DenseMap<Value *, std::string *> valueMap; std::vector<CallInst *> calls; - LLVMContext & C = M.getContext(); - IntegerType * Int8Ty = IntegerType::getInt8Ty(C); - IntegerType * Int32Ty = IntegerType::getInt32Ty(C); - IntegerType * Int64Ty = IntegerType::getInt64Ty(C); + LLVMContext &C = M.getContext(); + IntegerType *Int8Ty = IntegerType::getInt8Ty(C); + IntegerType *Int32Ty = IntegerType::getInt32Ty(C); + IntegerType *Int64Ty = IntegerType::getInt64Ty(C); #if LLVM_VERSION_MAJOR >= 9 FunctionCallee tolowerFn; @@ -409,7 +409,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, /* check if third operand is a constant integer * strlen("constStr") and sizeof() are treated as constant */ - Value * op2 = callInst->getArgOperand(2); + Value *op2 = callInst->getArgOperand(2); ConstantInt *ilen = dyn_cast<ConstantInt>(op2); if (ilen) { @@ -449,7 +449,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, *Str2P = callInst->getArgOperand(1); StringRef Str1, Str2, ConstStr; std::string TmpConstStr; - Value * VarStr; + Value *VarStr; bool HasStr1 = getConstantStringInfo(Str1P, Str1); bool HasStr2 = getConstantStringInfo(Str2P, Str2); uint64_t constStrLen, unrollLen, constSizedLen = 0; @@ -457,7 +457,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, bool isSizedcmp = false; bool isCaseInsensitive = false; bool needs_null = false; - Function * Callee = callInst->getCalledFunction(); + Function *Callee = callInst->getCalledFunction(); if (Callee) { @@ -616,14 +616,14 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, for (uint64_t i = 0; i < unrollLen; i++) { - BasicBlock * cur_cmp_bb = next_cmp_bb, *cur_lenchk_bb = next_lenchk_bb; + BasicBlock *cur_cmp_bb = next_cmp_bb, *cur_lenchk_bb = next_lenchk_bb; unsigned char c; if (cur_lenchk_bb) { IRBuilder<> cur_lenchk_IRB(&*(cur_lenchk_bb->getFirstInsertionPt())); - Value * icmp = cur_lenchk_IRB.CreateICmpEQ( - sizedValue, ConstantInt::get(sizedValue->getType(), i)); + Value *icmp = cur_lenchk_IRB.CreateICmpEQ( + sizedValue, ConstantInt::get(sizedValue->getType(), i)); cur_lenchk_IRB.CreateCondBr(icmp, end_bb, cur_cmp_bb); cur_lenchk_bb->getTerminator()->eraseFromParent(); diff --git a/instrumentation/split-compares-pass.so.cc b/instrumentation/split-compares-pass.so.cc index d7bb7aba..95eca0cb 100644 --- a/instrumentation/split-compares-pass.so.cc +++ b/instrumentation/split-compares-pass.so.cc @@ -230,9 +230,9 @@ char SplitComparesTransform::ID = 0; /// FCMP instructions with predicate xGT or xLT and EQ bool SplitComparesTransform::simplifyFPCompares(Module &M) { - LLVMContext & C = M.getContext(); + LLVMContext &C = M.getContext(); std::vector<Instruction *> fcomps; - IntegerType * Int1Ty = IntegerType::getInt1Ty(C); + IntegerType *Int1Ty = IntegerType::getInt1Ty(C); /* iterate over all functions, bbs and instruction and add * all integer comparisons with >= and <= predicates to the icomps vector */ @@ -362,8 +362,8 @@ bool SplitComparesTransform::simplifyFPCompares(Module &M) { /// This function splits ICMP instructions with xGE or xLE predicates into two /// ICMP instructions with predicate xGT or xLT and EQ -bool SplitComparesTransform::simplifyOrEqualsCompare(CmpInst * IcmpInst, - Module & M, +bool SplitComparesTransform::simplifyOrEqualsCompare(CmpInst *IcmpInst, + Module &M, CmpWorklist &worklist) { LLVMContext &C = M.getContext(); @@ -498,7 +498,7 @@ bool SplitComparesTransform::simplifySignedCompare(CmpInst *IcmpInst, Module &M, /* create a new basic block which is executed if the signedness bit is * different */ - CmpInst * icmp_inv_sig_cmp; + CmpInst *icmp_inv_sig_cmp; BasicBlock *sign_bb = BasicBlock::Create(C, "sign", end_bb->getParent(), end_bb); if (pred == CmpInst::ICMP_SGT) { @@ -522,7 +522,7 @@ bool SplitComparesTransform::simplifySignedCompare(CmpInst *IcmpInst, Module &M, BranchInst::Create(end_bb, sign_bb); /* create a new bb which is executed if signedness is equal */ - CmpInst * icmp_usign_cmp; + CmpInst *icmp_usign_cmp; BasicBlock *middle_bb = BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb); /* we can do a normal unsigned compare now */ @@ -566,8 +566,17 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, case CmpInst::ICMP_NE: case CmpInst::ICMP_UGT: case CmpInst::ICMP_ULT: + case CmpInst::ICMP_UGE: + case CmpInst::ICMP_ULE: + case CmpInst::ICMP_SGT: + case CmpInst::ICMP_SLT: + case CmpInst::ICMP_SGE: + case CmpInst::ICMP_SLE: break; default: + if (!be_quiet) + fprintf(stderr, "Error: split-compare: Unsupported predicate (%u)\n", + pred); // unsupported predicate! return false; @@ -581,6 +590,8 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, if (!intTyOp0) { // not an integer type + if (!be_quiet) + fprintf(stderr, "Error: split-compare: not an integer type\n"); return false; } @@ -595,11 +606,11 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, LLVMContext &C = M.getContext(); IntegerType *Int1Ty = IntegerType::getInt1Ty(C); - BasicBlock * bb = cmp_inst->getParent(); + BasicBlock *bb = cmp_inst->getParent(); IntegerType *OldIntType = IntegerType::get(C, bitw); IntegerType *NewIntType = IntegerType::get(C, bitw / 2); - BasicBlock * end_bb = bb->splitBasicBlock(BasicBlock::iterator(cmp_inst)); - CmpInst * icmp_high, *icmp_low; + BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(cmp_inst)); + CmpInst *icmp_high, *icmp_low; /* create the comparison of the top halves of the original operands */ Value *s_op0, *op0_high, *s_op1, *op1_high; @@ -629,7 +640,7 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, BasicBlock *cmp_low_bb = BasicBlock::Create(C, "" /*"injected"*/, end_bb->getParent(), end_bb); - Value * op0_low, *op1_low; + Value *op0_low, *op1_low; IRBuilder<> Builder(cmp_low_bb); op0_low = Builder.CreateTrunc(op0, NewIntType); @@ -675,6 +686,12 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, } + case CmpInst::ICMP_SGE: + case CmpInst::ICMP_SLE: + case CmpInst::ICMP_SGT: + case CmpInst::ICMP_SLT: + case CmpInst::ICMP_UGE: + case CmpInst::ICMP_ULE: case CmpInst::ICMP_UGT: case CmpInst::ICMP_ULT: { @@ -684,10 +701,11 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, * if this is true we can go to the end if not we have to go to the * bb which checks the lower half of the operands */ Instruction *op0_low, *op1_low; - CmpInst * icmp_inv_cmp = nullptr; - BasicBlock * inv_cmp_bb = + CmpInst *icmp_inv_cmp = nullptr; + BasicBlock *inv_cmp_bb = BasicBlock::Create(C, "inv_cmp", end_bb->getParent(), end_bb); - if (pred == CmpInst::ICMP_UGT) { + if (pred == CmpInst::ICMP_UGT || pred == CmpInst::ICMP_SGT || + pred == CmpInst::ICMP_UGE || pred == CmpInst::ICMP_SGE) { icmp_inv_cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, op0_high, op1_high); @@ -729,6 +747,8 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, } default: + if (!be_quiet) + fprintf(stderr, "Error: split-compare: should not happen\n"); return false; } @@ -944,7 +964,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); + IntegerType *intType = IntegerType::get(C, op_size); const unsigned int precision = sizeInBits == 32 ? 24 : sizeInBits == 64 ? 53 : sizeInBits == 128 ? 113 @@ -1052,8 +1072,8 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { /*** 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; + Instruction *b_op0, *b_op1; + Instruction *isMzero_op0, *isMzero_op1; const unsigned long long MinusZero = 1UL << (sizeInBits - 1U); const unsigned long long PlusZero = 0; @@ -1172,7 +1192,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { /* compare the exponents of the operands */ Instruction *icmp_exponents_equal; Instruction *icmp_exponent_result; - BasicBlock * signequal2_bb = signequal_bb; + BasicBlock *signequal2_bb = signequal_bb; switch (FcmpInst->getPredicate()) { case CmpInst::FCMP_UEQ: @@ -1342,8 +1362,8 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { /* compare the fractions of the operands */ Instruction *icmp_fraction_result; - BasicBlock * middle2_bb = middle_bb; - PHINode * PN2 = nullptr; + BasicBlock *middle2_bb = middle_bb; + PHINode *PN2 = nullptr; switch (FcmpInst->getPredicate()) { case CmpInst::FCMP_UEQ: @@ -1484,7 +1504,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { } #if LLVM_MAJOR >= 11 -PreservedAnalyses SplitComparesTransform::run(Module & M, +PreservedAnalyses SplitComparesTransform::run(Module &M, ModuleAnalysisManager &MAM) { #else diff --git a/instrumentation/split-switches-pass.so.cc b/instrumentation/split-switches-pass.so.cc index 96e01a8b..79ba12d2 100644 --- a/instrumentation/split-switches-pass.so.cc +++ b/instrumentation/split-switches-pass.so.cc @@ -102,7 +102,7 @@ class SplitSwitchesTransform : public ModulePass { struct CaseExpr { ConstantInt *Val; - BasicBlock * BB; + BasicBlock *BB; CaseExpr(ConstantInt *val = nullptr, BasicBlock *bb = nullptr) : Val(val), BB(bb) { @@ -182,7 +182,7 @@ BasicBlock *SplitSwitchesTransform::switchConvert( unsigned ValTypeBitWidth = Cases[0].Val->getBitWidth(); IntegerType *ValType = IntegerType::get(OrigBlock->getContext(), ValTypeBitWidth); - IntegerType * ByteType = IntegerType::get(OrigBlock->getContext(), 8); + IntegerType *ByteType = IntegerType::get(OrigBlock->getContext(), 8); unsigned BytesInValue = bytesChecked.size(); std::vector<uint8_t> setSizes; std::vector<std::set<uint8_t> > byteSets(BytesInValue, std::set<uint8_t>()); @@ -221,8 +221,8 @@ BasicBlock *SplitSwitchesTransform::switchConvert( /* there are only smallestSize different bytes at index smallestIndex */ Instruction *Shift, *Trunc; - Function * F = OrigBlock->getParent(); - BasicBlock * NewNode = BasicBlock::Create(Val->getContext(), "NodeBlock", F); + Function *F = OrigBlock->getParent(); + BasicBlock *NewNode = BasicBlock::Create(Val->getContext(), "NodeBlock", F); Shift = BinaryOperator::Create(Instruction::LShr, Val, ConstantInt::get(ValType, smallestIndex * 8)); NewNode->getInstList().push_back(Shift); @@ -403,9 +403,9 @@ bool SplitSwitchesTransform::splitSwitches(Module &M) { BasicBlock *CurBlock = SI->getParent(); BasicBlock *OrigBlock = CurBlock; - Function * F = CurBlock->getParent(); + Function *F = CurBlock->getParent(); /* this is the value we are switching on */ - Value * Val = SI->getCondition(); + Value *Val = SI->getCondition(); BasicBlock *Default = SI->getDefaultDest(); unsigned bitw = Val->getType()->getIntegerBitWidth(); @@ -445,7 +445,7 @@ bool SplitSwitchesTransform::splitSwitches(Module &M) { * round up bytesChecked (in case getBitWidth() % 8 != 0) */ std::vector<bool> bytesChecked((7 + Cases[0].Val->getBitWidth()) / 8, false); - BasicBlock * SwitchBlock = + BasicBlock *SwitchBlock = switchConvert(Cases, bytesChecked, OrigBlock, NewDefault, Val, 0); /* Branch to our shiny new if-then stuff... */ @@ -483,7 +483,7 @@ bool SplitSwitchesTransform::splitSwitches(Module &M) { } #if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */ -PreservedAnalyses SplitSwitchesTransform::run(Module & M, +PreservedAnalyses SplitSwitchesTransform::run(Module &M, ModuleAnalysisManager &MAM) { #else |