mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-24 14:43:22 +00:00
Compare commits
16 Commits
Author | SHA1 | Date | |
---|---|---|---|
9287f45e3e | |||
b0839ffcaf | |||
3f065ea70a | |||
d869913efa | |||
6a246516df | |||
daab85f3f1 | |||
97ed8c2877 | |||
dca144fbff | |||
ab9bd37b86 | |||
d4071b0fe4 | |||
5a0a33e52a | |||
c510ba6863 | |||
bd4c9a5eab | |||
f9e85817ad | |||
8758be3630 | |||
31a7ff2ba2 |
@ -200,6 +200,7 @@ struct queue_entry {
|
|||||||
u8 *fname; /* File name for the test case */
|
u8 *fname; /* File name for the test case */
|
||||||
u32 len; /* Input length */
|
u32 len; /* Input length */
|
||||||
u32 id; /* entry number in queue_buf */
|
u32 id; /* entry number in queue_buf */
|
||||||
|
u32 found;
|
||||||
|
|
||||||
u8 colorized, /* Do not run redqueen stage again */
|
u8 colorized, /* Do not run redqueen stage again */
|
||||||
cal_failed; /* Calibration failed? */
|
cal_failed; /* Calibration failed? */
|
||||||
@ -251,6 +252,9 @@ struct queue_entry {
|
|||||||
|
|
||||||
struct skipdet_entry *skipdet_e;
|
struct skipdet_entry *skipdet_e;
|
||||||
|
|
||||||
|
u32 score; /* complexity/vulnerability score */
|
||||||
|
u64 total_execs; /* total executes of this item */
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct extra_data {
|
struct extra_data {
|
||||||
@ -832,6 +836,9 @@ typedef struct afl_state {
|
|||||||
/* How often did we evict from the cache (for statistics only) */
|
/* How often did we evict from the cache (for statistics only) */
|
||||||
u32 q_testcase_evictions;
|
u32 q_testcase_evictions;
|
||||||
|
|
||||||
|
/* current complexity/vulnerability score received */
|
||||||
|
u32 current_score;
|
||||||
|
|
||||||
/* Refs to each queue entry with cached testcase (for eviction, if cache_count
|
/* Refs to each queue entry with cached testcase (for eviction, if cache_count
|
||||||
* is too large) */
|
* is too large) */
|
||||||
struct queue_entry **q_testcase_cache;
|
struct queue_entry **q_testcase_cache;
|
||||||
|
@ -21,18 +21,20 @@ static char *afl_environment_variables[] = {
|
|||||||
"AFL_BENCH_UNTIL_CRASH", "AFL_CAL_FAST", "AFL_CC", "AFL_CC_COMPILER",
|
"AFL_BENCH_UNTIL_CRASH", "AFL_CAL_FAST", "AFL_CC", "AFL_CC_COMPILER",
|
||||||
"AFL_CMIN_ALLOW_ANY", "AFL_CMIN_CRASHES_ONLY", "AFL_CMPLOG_ONLY_NEW",
|
"AFL_CMIN_ALLOW_ANY", "AFL_CMIN_CRASHES_ONLY", "AFL_CMPLOG_ONLY_NEW",
|
||||||
"AFL_CODE_END", "AFL_CODE_START", "AFL_COMPCOV_BINNAME",
|
"AFL_CODE_END", "AFL_CODE_START", "AFL_COMPCOV_BINNAME",
|
||||||
"AFL_DUMP_CYCLOMATIC_COMPLEXITY", "AFL_CMPLOG_MAX_LEN", "AFL_COMPCOV_LEVEL",
|
"AFL_DUMP_QUEUE_ON_EXIT", "AFL_DUMP_CYCLOMATIC_COMPLEXITY",
|
||||||
"AFL_CRASH_EXITCODE", "AFL_CRASHING_SEEDS_AS_NEW_CRASH",
|
"AFL_DUMP_VULNERABILITY_COMPLEXITY", "AFL_CMPLOG_MAX_LEN",
|
||||||
"AFL_CUSTOM_MUTATOR_LIBRARY", "AFL_CUSTOM_MUTATOR_ONLY",
|
"AFL_COMPCOV_LEVEL", "AFL_CRASH_EXITCODE",
|
||||||
"AFL_CUSTOM_INFO_PROGRAM", "AFL_CUSTOM_INFO_PROGRAM_ARGV",
|
"AFL_CRASHING_SEEDS_AS_NEW_CRASH", "AFL_CUSTOM_MUTATOR_LIBRARY",
|
||||||
"AFL_CUSTOM_INFO_PROGRAM_INPUT", "AFL_CUSTOM_INFO_OUT", "AFL_CXX",
|
"AFL_CUSTOM_MUTATOR_ONLY", "AFL_CUSTOM_INFO_PROGRAM",
|
||||||
"AFL_CYCLE_SCHEDULES", "AFL_DEBUG", "AFL_DEBUG_CHILD", "AFL_DEBUG_GDB",
|
"AFL_CUSTOM_INFO_PROGRAM_ARGV", "AFL_CUSTOM_INFO_PROGRAM_INPUT",
|
||||||
"AFL_DEBUG_UNICORN", "AFL_DISABLE_REDUNDANT", "AFL_NO_REDUNDANT",
|
"AFL_CUSTOM_INFO_OUT", "AFL_CXX", "AFL_CYCLE_SCHEDULES", "AFL_DEBUG",
|
||||||
"AFL_DISABLE_TRIM", "AFL_NO_TRIM", "AFL_DISABLE_LLVM_INSTRUMENTATION",
|
"AFL_DEBUG_CHILD", "AFL_DEBUG_GDB", "AFL_DEBUG_UNICORN",
|
||||||
"AFL_DONT_OPTIMIZE", "AFL_DRIVER_STDERR_DUPLICATE_FILENAME",
|
"AFL_DISABLE_REDUNDANT", "AFL_NO_REDUNDANT", "AFL_DISABLE_TRIM",
|
||||||
"AFL_DUMB_FORKSRV", "AFL_EARLY_FORKSERVER", "AFL_ENTRYPOINT",
|
"AFL_NO_TRIM", "AFL_DISABLE_LLVM_INSTRUMENTATION", "AFL_DONT_OPTIMIZE",
|
||||||
"AFL_EXIT_WHEN_DONE", "AFL_EXIT_ON_TIME", "AFL_EXIT_ON_SEED_ISSUES",
|
"AFL_DRIVER_STDERR_DUPLICATE_FILENAME", "AFL_DUMB_FORKSRV",
|
||||||
"AFL_FAST_CAL", "AFL_FINAL_SYNC", "AFL_FORCE_UI", "AFL_FRIDA_DEBUG_MAPS",
|
"AFL_EARLY_FORKSERVER", "AFL_ENTRYPOINT", "AFL_EXIT_WHEN_DONE",
|
||||||
|
"AFL_EXIT_ON_TIME", "AFL_EXIT_ON_SEED_ISSUES", "AFL_FAST_CAL",
|
||||||
|
"AFL_FINAL_SYNC", "AFL_FORCE_UI", "AFL_FRIDA_DEBUG_MAPS",
|
||||||
"AFL_FRIDA_DRIVER_NO_HOOK", "AFL_FRIDA_EXCLUDE_RANGES",
|
"AFL_FRIDA_DRIVER_NO_HOOK", "AFL_FRIDA_EXCLUDE_RANGES",
|
||||||
"AFL_FRIDA_INST_CACHE_SIZE", "AFL_FRIDA_INST_COVERAGE_ABSOLUTE",
|
"AFL_FRIDA_INST_CACHE_SIZE", "AFL_FRIDA_INST_COVERAGE_ABSOLUTE",
|
||||||
"AFL_FRIDA_INST_COVERAGE_FILE", "AFL_FRIDA_INST_DEBUG_FILE",
|
"AFL_FRIDA_INST_COVERAGE_FILE", "AFL_FRIDA_INST_DEBUG_FILE",
|
||||||
|
@ -60,6 +60,8 @@
|
|||||||
#include "llvm/Passes/PassPlugin.h"
|
#include "llvm/Passes/PassPlugin.h"
|
||||||
#include "llvm/Passes/PassBuilder.h"
|
#include "llvm/Passes/PassBuilder.h"
|
||||||
#include "llvm/IR/PassManager.h"
|
#include "llvm/IR/PassManager.h"
|
||||||
|
#include "llvm/Analysis/LoopInfo.h"
|
||||||
|
#include "llvm/Analysis/LoopPass.h"
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
@ -172,6 +174,7 @@ SanitizerCoverageOptions OverrideFromCL(SanitizerCoverageOptions Options) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using LoopInfoCallback = function_ref<const LoopInfo *(Function &F)>;
|
||||||
using DomTreeCallback = function_ref<const DominatorTree *(Function &F)>;
|
using DomTreeCallback = function_ref<const DominatorTree *(Function &F)>;
|
||||||
using PostDomTreeCallback =
|
using PostDomTreeCallback =
|
||||||
function_ref<const PostDominatorTree *(Function &F)>;
|
function_ref<const PostDominatorTree *(Function &F)>;
|
||||||
@ -187,13 +190,15 @@ class ModuleSanitizerCoverageLTO
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool instrumentModule(Module &M, DomTreeCallback DTCallback,
|
bool instrumentModule(Module &M, DomTreeCallback DTCallback,
|
||||||
PostDomTreeCallback PDTCallback);
|
PostDomTreeCallback PDTCallback,
|
||||||
|
LoopInfoCallback LCallback);
|
||||||
|
|
||||||
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
|
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void instrumentFunction(Function &F, DomTreeCallback DTCallback,
|
void instrumentFunction(Function &F, DomTreeCallback DTCallback,
|
||||||
PostDomTreeCallback PDTCallback);
|
PostDomTreeCallback PDTCallback,
|
||||||
|
LoopInfoCallback LCallback);
|
||||||
/* void InjectCoverageForIndirectCalls(Function &F,
|
/* void InjectCoverageForIndirectCalls(Function &F,
|
||||||
ArrayRef<Instruction *>
|
ArrayRef<Instruction *>
|
||||||
IndirCalls);*/
|
IndirCalls);*/
|
||||||
@ -250,6 +255,7 @@ class ModuleSanitizerCoverageLTO
|
|||||||
uint32_t afl_global_id = 0;
|
uint32_t afl_global_id = 0;
|
||||||
uint32_t unhandled = 0;
|
uint32_t unhandled = 0;
|
||||||
uint32_t select_cnt = 0;
|
uint32_t select_cnt = 0;
|
||||||
|
uint32_t dump_cc = 0, dump_vc = 0;
|
||||||
uint32_t instrument_ctx = 0;
|
uint32_t instrument_ctx = 0;
|
||||||
uint32_t instrument_ctx_max_depth = 0;
|
uint32_t instrument_ctx_max_depth = 0;
|
||||||
uint32_t extra_ctx_inst = 0;
|
uint32_t extra_ctx_inst = 0;
|
||||||
@ -291,6 +297,7 @@ class ModuleSanitizerCoverageLTOLegacyPass : public ModulePass {
|
|||||||
|
|
||||||
AU.addRequired<DominatorTreeWrapperPass>();
|
AU.addRequired<DominatorTreeWrapperPass>();
|
||||||
AU.addRequired<PostDominatorTreeWrapperPass>();
|
AU.addRequired<PostDominatorTreeWrapperPass>();
|
||||||
|
AU.addRequired<LoopInfoWrapperPass>();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,7 +326,15 @@ class ModuleSanitizerCoverageLTOLegacyPass : public ModulePass {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return ModuleSancov.instrumentModule(M, DTCallback, PDTCallback);
|
auto LoopCallback = [this](Function &F) -> const LoopInfo * {
|
||||||
|
|
||||||
|
return &this->getAnalysis<LoopInfoWrapperPass>(F).getLoopInfo();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
ModuleSancov.instrumentModule(M, DTCallback, PDTCallback, LoopCallback);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -372,15 +387,21 @@ PreservedAnalyses ModuleSanitizerCoverageLTO::run(Module &M,
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
|
auto LoopCallback = [&FAM](Function &F) -> const LoopInfo * {
|
||||||
return PreservedAnalyses::none();
|
|
||||||
|
|
||||||
return PreservedAnalyses::all();
|
return &FAM.getResult<LoopAnalysis>(F);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
ModuleSancov.instrumentModule(M, DTCallback, PDTCallback, LoopCallback);
|
||||||
|
|
||||||
|
return PreservedAnalyses::none();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModuleSanitizerCoverageLTO::instrumentModule(
|
bool ModuleSanitizerCoverageLTO::instrumentModule(
|
||||||
Module &M, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) {
|
Module &M, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback,
|
||||||
|
LoopInfoCallback LCallback) {
|
||||||
|
|
||||||
if (Options.CoverageType == SanitizerCoverageOptions::SCK_None) return false;
|
if (Options.CoverageType == SanitizerCoverageOptions::SCK_None) return false;
|
||||||
/*
|
/*
|
||||||
@ -474,6 +495,10 @@ bool ModuleSanitizerCoverageLTO::instrumentModule(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (getenv("AFL_DUMP_CYCLOMATIC_COMPLEXITY")) { dump_cc = 1; }
|
||||||
|
|
||||||
|
if (getenv("AFL_DUMP_VULNERABILITY_COMPLEXITY")) { dump_vc = 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");
|
||||||
|
|
||||||
@ -1057,7 +1082,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule(
|
|||||||
// M.getOrInsertFunction(SanCovTracePCGuardName, VoidTy, Int32PtrTy);
|
// M.getOrInsertFunction(SanCovTracePCGuardName, VoidTy, Int32PtrTy);
|
||||||
|
|
||||||
for (auto &F : M)
|
for (auto &F : M)
|
||||||
instrumentFunction(F, DTCallback, PDTCallback);
|
instrumentFunction(F, DTCallback, PDTCallback, LCallback);
|
||||||
|
|
||||||
// AFL++ START
|
// AFL++ START
|
||||||
if (dFile.is_open()) dFile.close();
|
if (dFile.is_open()) dFile.close();
|
||||||
@ -1347,7 +1372,8 @@ Function *returnOnlyCaller(Function *F) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ModuleSanitizerCoverageLTO::instrumentFunction(
|
void ModuleSanitizerCoverageLTO::instrumentFunction(
|
||||||
Function &F, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) {
|
Function &F, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback,
|
||||||
|
LoopInfoCallback LCallback) {
|
||||||
|
|
||||||
if (F.empty()) return;
|
if (F.empty()) return;
|
||||||
if (F.getName().find(".module_ctor") != std::string::npos)
|
if (F.getName().find(".module_ctor") != std::string::npos)
|
||||||
@ -1421,6 +1447,7 @@ void ModuleSanitizerCoverageLTO::instrumentFunction(
|
|||||||
|
|
||||||
const DominatorTree *DT = DTCallback(F);
|
const DominatorTree *DT = DTCallback(F);
|
||||||
const PostDominatorTree *PDT = PDTCallback(F);
|
const PostDominatorTree *PDT = PDTCallback(F);
|
||||||
|
const LoopInfo *LI = LCallback(F);
|
||||||
bool IsLeafFunc = true;
|
bool IsLeafFunc = true;
|
||||||
uint32_t skip_next = 0;
|
uint32_t skip_next = 0;
|
||||||
uint32_t call_counter = 0, call_depth = 0;
|
uint32_t call_counter = 0, call_depth = 0;
|
||||||
@ -1955,6 +1982,51 @@ void ModuleSanitizerCoverageLTO::instrumentFunction(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int score = 0;
|
||||||
|
|
||||||
|
if (dump_cc) { score += calcCyclomaticComplexity(&F, LI); }
|
||||||
|
if (dump_vc) { score += calcVulnerabilityScore(&F, LI, DT, PDT); }
|
||||||
|
|
||||||
|
if (score) {
|
||||||
|
|
||||||
|
BasicBlock::iterator IP = F.getEntryBlock().getFirstInsertionPt();
|
||||||
|
IRBuilder<> builder(&*IP);
|
||||||
|
|
||||||
|
// Access the int32 value at u8 offset 1 (unaligned access)
|
||||||
|
LoadInst *MapPtr =
|
||||||
|
builder.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr);
|
||||||
|
llvm::Value *CastToInt8Ptr =
|
||||||
|
builder.CreateBitCast(MapPtr, llvm::PointerType::get(Int8Ty, 0));
|
||||||
|
llvm::Value *Int32Ptr = builder.CreateGEP(
|
||||||
|
Int8Ty, CastToInt8Ptr, llvm::ConstantInt::get(Int32Ty, 1));
|
||||||
|
llvm::Value *CastToInt32Ptr =
|
||||||
|
builder.CreateBitCast(Int32Ptr, llvm::PointerType::get(Int32Ty, 0));
|
||||||
|
|
||||||
|
// Load the unaligned int32 value
|
||||||
|
llvm::LoadInst *Load = builder.CreateLoad(Int32Ty, CastToInt32Ptr);
|
||||||
|
Load->setAlignment(llvm::Align(1));
|
||||||
|
|
||||||
|
// Value to add
|
||||||
|
llvm::Value *ValueToAdd = llvm::ConstantInt::get(Int32Ty, score);
|
||||||
|
|
||||||
|
// Perform addition and check for wrap around
|
||||||
|
llvm::Value *Add =
|
||||||
|
builder.CreateAdd(Load, ValueToAdd, "addValue", true, true);
|
||||||
|
|
||||||
|
// Check if addition wrapped (unsigned)
|
||||||
|
llvm::Value *DidWrap = builder.CreateICmpULT(Add, Load, "didWrap");
|
||||||
|
|
||||||
|
// Select the maximum value if there was a wrap, otherwise use the result
|
||||||
|
llvm::Value *MaxInt32 = llvm::ConstantInt::get(Int32Ty, UINT32_MAX);
|
||||||
|
llvm::Value *Result =
|
||||||
|
builder.CreateSelect(DidWrap, MaxInt32, Add, "selectMaxOrResult");
|
||||||
|
|
||||||
|
// Store the result back at the same unaligned offset
|
||||||
|
llvm::StoreInst *Store = builder.CreateStore(Result, CastToInt32Ptr);
|
||||||
|
Store->setAlignment(llvm::Align(1));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
InjectCoverage(F, BlocksToInstrument, IsLeafFunc);
|
InjectCoverage(F, BlocksToInstrument, IsLeafFunc);
|
||||||
// InjectCoverageForIndirectCalls(F, IndirCalls);
|
// InjectCoverageForIndirectCalls(F, IndirCalls);
|
||||||
|
|
||||||
|
@ -70,6 +70,8 @@
|
|||||||
#endif
|
#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/Analysis/LoopInfo.h"
|
||||||
|
#include "llvm/Analysis/LoopPass.h"
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
@ -119,6 +121,7 @@ SanitizerCoverageOptions OverrideFromCL(SanitizerCoverageOptions Options) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using LoopInfoCallback = function_ref<const LoopInfo *(Function &F)>;
|
||||||
using DomTreeCallback = function_ref<const DominatorTree *(Function &F)>;
|
using DomTreeCallback = function_ref<const DominatorTree *(Function &F)>;
|
||||||
using PostDomTreeCallback =
|
using PostDomTreeCallback =
|
||||||
function_ref<const PostDominatorTree *(Function &F)>;
|
function_ref<const PostDominatorTree *(Function &F)>;
|
||||||
@ -135,11 +138,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,
|
||||||
|
LoopInfoCallback LCallback);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void instrumentFunction(Function &F, DomTreeCallback DTCallback,
|
void instrumentFunction(Function &F, DomTreeCallback DTCallback,
|
||||||
PostDomTreeCallback PDTCallback);
|
PostDomTreeCallback PDTCallback,
|
||||||
|
LoopInfoCallback LCallback);
|
||||||
void InjectTraceForCmp(Function &F, ArrayRef<Instruction *> CmpTraceTargets);
|
void InjectTraceForCmp(Function &F, ArrayRef<Instruction *> CmpTraceTargets);
|
||||||
void InjectTraceForSwitch(Function &F,
|
void InjectTraceForSwitch(Function &F,
|
||||||
ArrayRef<Instruction *> SwitchTraceTargets);
|
ArrayRef<Instruction *> SwitchTraceTargets);
|
||||||
@ -195,7 +200,7 @@ class ModuleSanitizerCoverageAFL
|
|||||||
|
|
||||||
SanitizerCoverageOptions Options;
|
SanitizerCoverageOptions Options;
|
||||||
|
|
||||||
uint32_t instr = 0, selects = 0, unhandled = 0, dump_cc = 0;
|
uint32_t instr = 0, selects = 0, unhandled = 0, dump_cc = 0, dump_vc = 0;
|
||||||
GlobalVariable *AFLMapPtr = NULL;
|
GlobalVariable *AFLMapPtr = NULL;
|
||||||
ConstantInt *One = NULL;
|
ConstantInt *One = NULL;
|
||||||
ConstantInt *Zero = NULL;
|
ConstantInt *Zero = NULL;
|
||||||
@ -233,8 +238,10 @@ PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module &M,
|
|||||||
ModuleAnalysisManager &MAM) {
|
ModuleAnalysisManager &MAM) {
|
||||||
|
|
||||||
ModuleSanitizerCoverageAFL ModuleSancov(Options);
|
ModuleSanitizerCoverageAFL ModuleSancov(Options);
|
||||||
|
|
||||||
auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
|
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);
|
return &FAM.getResult<DominatorTreeAnalysis>(F);
|
||||||
|
|
||||||
@ -246,9 +253,21 @@ PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module &M,
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
|
auto LoopCallback = [&FAM](Function &F) -> const LoopInfo * {
|
||||||
|
|
||||||
|
return &FAM.getResult<LoopAnalysis>(F);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback, LoopCallback)) {
|
||||||
|
|
||||||
return PreservedAnalyses::none();
|
return PreservedAnalyses::none();
|
||||||
return PreservedAnalyses::all();
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
return PreservedAnalyses::all();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,7 +343,8 @@ Function *ModuleSanitizerCoverageAFL::CreateInitCallsForSections(
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ModuleSanitizerCoverageAFL::instrumentModule(
|
bool ModuleSanitizerCoverageAFL::instrumentModule(
|
||||||
Module &M, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) {
|
Module &M, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback,
|
||||||
|
LoopInfoCallback LCallback) {
|
||||||
|
|
||||||
setvbuf(stdout, NULL, _IONBF, 0);
|
setvbuf(stdout, NULL, _IONBF, 0);
|
||||||
|
|
||||||
@ -332,6 +352,8 @@ bool ModuleSanitizerCoverageAFL::instrumentModule(
|
|||||||
|
|
||||||
if (getenv("AFL_DUMP_CYCLOMATIC_COMPLEXITY")) { dump_cc = 1; }
|
if (getenv("AFL_DUMP_CYCLOMATIC_COMPLEXITY")) { dump_cc = 1; }
|
||||||
|
|
||||||
|
if (getenv("AFL_DUMP_VULNERABILITY_COMPLEXITY")) { dump_vc = 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");
|
||||||
@ -429,7 +451,7 @@ bool ModuleSanitizerCoverageAFL::instrumentModule(
|
|||||||
M.getOrInsertFunction(SanCovTracePCGuardName, VoidTy, Int32PtrTy);
|
M.getOrInsertFunction(SanCovTracePCGuardName, VoidTy, Int32PtrTy);
|
||||||
|
|
||||||
for (auto &F : M)
|
for (auto &F : M)
|
||||||
instrumentFunction(F, DTCallback, PDTCallback);
|
instrumentFunction(F, DTCallback, PDTCallback, LCallback);
|
||||||
|
|
||||||
Function *Ctor = nullptr;
|
Function *Ctor = nullptr;
|
||||||
|
|
||||||
@ -568,7 +590,8 @@ static bool IsInterestingCmp(ICmpInst *CMP, const DominatorTree *DT,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void ModuleSanitizerCoverageAFL::instrumentFunction(
|
void ModuleSanitizerCoverageAFL::instrumentFunction(
|
||||||
Function &F, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) {
|
Function &F, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback,
|
||||||
|
LoopInfoCallback LCallback) {
|
||||||
|
|
||||||
if (F.empty()) return;
|
if (F.empty()) return;
|
||||||
if (!isInInstrumentList(&F, FMNAME)) return;
|
if (!isInInstrumentList(&F, FMNAME)) return;
|
||||||
@ -604,6 +627,7 @@ void ModuleSanitizerCoverageAFL::instrumentFunction(
|
|||||||
|
|
||||||
const DominatorTree *DT = DTCallback(F);
|
const DominatorTree *DT = DTCallback(F);
|
||||||
const PostDominatorTree *PDT = PDTCallback(F);
|
const PostDominatorTree *PDT = PDTCallback(F);
|
||||||
|
const LoopInfo *LI = LCallback(F);
|
||||||
bool IsLeafFunc = true;
|
bool IsLeafFunc = true;
|
||||||
|
|
||||||
for (auto &BB : F) {
|
for (auto &BB : F) {
|
||||||
@ -636,12 +660,55 @@ void ModuleSanitizerCoverageAFL::instrumentFunction(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int score = 0;
|
||||||
|
|
||||||
|
if (dump_cc) { score += calcCyclomaticComplexity(&F, LI); }
|
||||||
|
if (dump_vc) { score += calcVulnerabilityScore(&F, LI, DT, PDT); }
|
||||||
|
|
||||||
|
if (score) {
|
||||||
|
|
||||||
|
BasicBlock::iterator IP = F.getEntryBlock().getFirstInsertionPt();
|
||||||
|
IRBuilder<> builder(&*IP);
|
||||||
|
|
||||||
|
// Access the int32 value at u8 offset 1 (unaligned access)
|
||||||
|
LoadInst *MapPtr =
|
||||||
|
builder.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr);
|
||||||
|
llvm::Value *CastToInt8Ptr =
|
||||||
|
builder.CreateBitCast(MapPtr, llvm::PointerType::get(Int8Ty, 0));
|
||||||
|
llvm::Value *Int32Ptr = builder.CreateGEP(
|
||||||
|
Int8Ty, CastToInt8Ptr, llvm::ConstantInt::get(Int32Ty, 1));
|
||||||
|
llvm::Value *CastToInt32Ptr =
|
||||||
|
builder.CreateBitCast(Int32Ptr, llvm::PointerType::get(Int32Ty, 0));
|
||||||
|
|
||||||
|
// Load the unaligned int32 value
|
||||||
|
llvm::LoadInst *Load = builder.CreateLoad(Int32Ty, CastToInt32Ptr);
|
||||||
|
Load->setAlignment(llvm::Align(1));
|
||||||
|
|
||||||
|
// Value to add
|
||||||
|
llvm::Value *ValueToAdd = llvm::ConstantInt::get(Int32Ty, score);
|
||||||
|
|
||||||
|
// Perform addition and check for wrap around
|
||||||
|
llvm::Value *Add =
|
||||||
|
builder.CreateAdd(Load, ValueToAdd, "addValue", true, true);
|
||||||
|
|
||||||
|
// Check if addition wrapped (unsigned)
|
||||||
|
llvm::Value *DidWrap = builder.CreateICmpULT(Add, Load, "didWrap");
|
||||||
|
|
||||||
|
// Select the maximum value if there was a wrap, otherwise use the result
|
||||||
|
llvm::Value *MaxInt32 = llvm::ConstantInt::get(Int32Ty, UINT32_MAX);
|
||||||
|
llvm::Value *Result =
|
||||||
|
builder.CreateSelect(DidWrap, MaxInt32, Add, "selectMaxOrResult");
|
||||||
|
|
||||||
|
// Store the result back at the same unaligned offset
|
||||||
|
llvm::StoreInst *Store = builder.CreateStore(Result, CastToInt32Ptr);
|
||||||
|
Store->setAlignment(llvm::Align(1));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
InjectCoverage(F, BlocksToInstrument, IsLeafFunc);
|
InjectCoverage(F, BlocksToInstrument, IsLeafFunc);
|
||||||
// InjectTraceForCmp(F, CmpTraceTargets);
|
// InjectTraceForCmp(F, CmpTraceTargets);
|
||||||
// InjectTraceForSwitch(F, SwitchTraceTargets);
|
// InjectTraceForSwitch(F, SwitchTraceTargets);
|
||||||
|
|
||||||
if (dump_cc) { calcCyclomaticComplexity(&F); }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GlobalVariable *ModuleSanitizerCoverageAFL::CreateFunctionLocalArrayInSection(
|
GlobalVariable *ModuleSanitizerCoverageAFL::CreateFunctionLocalArrayInSection(
|
||||||
|
@ -1849,7 +1849,7 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
|
|||||||
to avoid duplicate calls (which can happen as an artifact of the underlying
|
to avoid duplicate calls (which can happen as an artifact of the underlying
|
||||||
implementation in LLVM). */
|
implementation in LLVM). */
|
||||||
|
|
||||||
if (__afl_final_loc < 5) __afl_final_loc = 5; // we skip the first 5 entries
|
if (__afl_final_loc < 4) __afl_final_loc = 4; // we skip the first 5 entries
|
||||||
|
|
||||||
*(start++) = ++__afl_final_loc;
|
*(start++) = ++__afl_final_loc;
|
||||||
|
|
||||||
|
@ -14,7 +14,21 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
#include <llvm/Support/raw_ostream.h>
|
#if LLVM_VERSION_MAJOR >= 13
|
||||||
|
#include "llvm/Support/raw_ostream.h"
|
||||||
|
#include "llvm/Analysis/LoopInfo.h"
|
||||||
|
#include "llvm/Analysis/LoopPass.h"
|
||||||
|
#include "llvm/IR/Function.h"
|
||||||
|
#include "llvm/IR/Module.h"
|
||||||
|
#include "llvm/Pass.h"
|
||||||
|
#include "llvm/IR/InstIterator.h"
|
||||||
|
#include "llvm/IR/Instructions.h"
|
||||||
|
#include "llvm/IR/Operator.h"
|
||||||
|
#include "llvm/IR/Dominators.h"
|
||||||
|
#include "llvm/Analysis/PostDominators.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// #define LEOPARD_USE_WEIGHTS 1
|
||||||
|
|
||||||
#define IS_EXTERN extern
|
#define IS_EXTERN extern
|
||||||
#include "afl-llvm-common.h"
|
#include "afl-llvm-common.h"
|
||||||
@ -26,11 +40,79 @@ static std::list<std::string> allowListFunctions;
|
|||||||
static std::list<std::string> denyListFiles;
|
static std::list<std::string> denyListFiles;
|
||||||
static std::list<std::string> denyListFunctions;
|
static std::list<std::string> denyListFunctions;
|
||||||
|
|
||||||
unsigned int calcCyclomaticComplexity(llvm::Function *F) {
|
#if LLVM_VERSION_MAJOR >= 13
|
||||||
|
// Leopard complexity calculations
|
||||||
|
|
||||||
|
#ifndef LEOPARD_USE_WEIGHTS
|
||||||
|
#define C1_WEIGHT 1.0
|
||||||
|
#define C2_WEIGHT 1.0
|
||||||
|
#define C3_WEIGHT 1.0
|
||||||
|
#define C4_WEIGHT 1.0
|
||||||
|
#define V1_WEIGHT 1.0
|
||||||
|
#define V2_WEIGHT 1.0
|
||||||
|
#define V3_WEIGHT 1.0
|
||||||
|
#define V4_WEIGHT 1.0
|
||||||
|
#define V5_WEIGHT 1.0
|
||||||
|
#define V6_WEIGHT 1.0
|
||||||
|
#define V7_WEIGHT 1.0
|
||||||
|
#define V8_WEIGHT 1.0
|
||||||
|
#define V9_WEIGHT 1.0
|
||||||
|
#define V10_WEIGHT 1.0
|
||||||
|
#define V11_WEIGHT 1.0
|
||||||
|
#else
|
||||||
|
// Cyclomatic weights
|
||||||
|
#define C1_WEIGHT 1.0
|
||||||
|
#define C2_WEIGHT 1.0
|
||||||
|
#define C3_WEIGHT 1.0
|
||||||
|
#define C4_WEIGHT 1.0
|
||||||
|
|
||||||
|
// Vulnerability weights
|
||||||
|
#define V1_WEIGHT 1.5
|
||||||
|
#define V2_WEIGHT 3.25
|
||||||
|
#define V3_WEIGHT 4.25
|
||||||
|
#define V4_WEIGHT 3.0
|
||||||
|
#define V5_WEIGHT 4.25
|
||||||
|
#define V6_WEIGHT 7.75
|
||||||
|
#define V7_WEIGHT 2.5
|
||||||
|
#define V8_WEIGHT 2.5
|
||||||
|
#define V9_WEIGHT 4.0
|
||||||
|
#define V10_WEIGHT 5.25
|
||||||
|
#define V11_WEIGHT 3.5
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void countNestedLoops(Loop *L, int depth, unsigned int &loopCount,
|
||||||
|
unsigned int &nestedLoopCount,
|
||||||
|
unsigned int &maxNestingLevel) {
|
||||||
|
|
||||||
|
loopCount++;
|
||||||
|
if (!L->getSubLoops().empty()) {
|
||||||
|
|
||||||
|
// Increment nested loop count by the number of sub-loops
|
||||||
|
nestedLoopCount += L->getSubLoops().size();
|
||||||
|
// Update maximum nesting level
|
||||||
|
if (depth > maxNestingLevel) { maxNestingLevel = depth; }
|
||||||
|
|
||||||
|
// Recursively count sub-loops
|
||||||
|
for (Loop *SubLoop : L->getSubLoops()) {
|
||||||
|
|
||||||
|
countNestedLoops(SubLoop, depth + 1, loopCount, nestedLoopCount,
|
||||||
|
maxNestingLevel);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int calcCyclomaticComplexity(llvm::Function *F,
|
||||||
|
const llvm::LoopInfo *LI) {
|
||||||
|
|
||||||
unsigned int numBlocks = 0;
|
unsigned int numBlocks = 0;
|
||||||
unsigned int numEdges = 0;
|
unsigned int numEdges = 0;
|
||||||
unsigned int numCalls = 0;
|
unsigned int numCalls = 0;
|
||||||
|
unsigned int numLoops = 0;
|
||||||
|
unsigned int numNestedLoops = 0;
|
||||||
|
unsigned int maxLoopNesting = 0;
|
||||||
|
|
||||||
// Iterate through each basic block in the function
|
// Iterate through each basic block in the function
|
||||||
for (BasicBlock &BB : *F) {
|
for (BasicBlock &BB : *F) {
|
||||||
@ -55,22 +137,197 @@ unsigned int calcCyclomaticComplexity(llvm::Function *F) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (Loop *L : *LI) {
|
||||||
|
|
||||||
|
countNestedLoops(L, 1, numLoops, numNestedLoops, maxLoopNesting);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Cyclomatic Complexity V(G) = E - N + 2P
|
// Cyclomatic Complexity V(G) = E - N + 2P
|
||||||
// For a single function, P (number of connected components) is 1
|
// For a single function, P (number of connected components) is 1
|
||||||
// Calls are considered to be an edge
|
// Calls are considered to be an edge
|
||||||
unsigned int CC = 2 + numCalls + numEdges - numBlocks;
|
unsigned int cc =
|
||||||
|
(unsigned int)(C1_WEIGHT * (double)(2 + numCalls + numEdges - numBlocks) +
|
||||||
|
C2_WEIGHT * (double)numLoops +
|
||||||
|
C3_WEIGHT * (double)numNestedLoops +
|
||||||
|
C4_WEIGHT * (double)maxLoopNesting);
|
||||||
|
|
||||||
// if (debug) {
|
// if (debug) {
|
||||||
|
|
||||||
fprintf(stderr, "CyclomaticComplexity for %s: %u\n",
|
fprintf(stderr,
|
||||||
F->getName().str().c_str(), CC);
|
"CyclomaticComplexity for %s: %u (calls=%u edges=%u blocks=%u "
|
||||||
|
"loops=%u nested_loops=%u max_loop_nesting_level=%u)\n",
|
||||||
|
F->getName().str().c_str(), cc, numCalls, numEdges, numBlocks,
|
||||||
|
numLoops, numNestedLoops, maxLoopNesting);
|
||||||
|
|
||||||
//}
|
//}
|
||||||
|
|
||||||
return CC;
|
return cc;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int calcVulnerabilityScore(llvm::Function *F, const llvm::LoopInfo *LI,
|
||||||
|
const llvm::DominatorTree *DT,
|
||||||
|
const llvm::PostDominatorTree *PDT) {
|
||||||
|
|
||||||
|
unsigned int score = 0;
|
||||||
|
// V1 and V2
|
||||||
|
unsigned paramCount = F->arg_size();
|
||||||
|
unsigned calledParamCount = 0;
|
||||||
|
// V3, V4 and V5
|
||||||
|
unsigned pointerArithCount = 0;
|
||||||
|
unsigned totalPointerArithParams = 0;
|
||||||
|
unsigned maxPointerArithVars = 0;
|
||||||
|
// V6 to V11
|
||||||
|
unsigned nestedControlStructCount = 0;
|
||||||
|
unsigned maxNestingLevel = 0;
|
||||||
|
unsigned maxControlDependentControls = 0;
|
||||||
|
unsigned maxDataDependentControls = 0;
|
||||||
|
unsigned ifWithoutElseCount = 0;
|
||||||
|
unsigned controlPredicateVarCount = 0;
|
||||||
|
|
||||||
|
std::function<void(Loop *, unsigned)> countNestedLoops = [&](Loop *L,
|
||||||
|
unsigned depth) {
|
||||||
|
|
||||||
|
nestedControlStructCount++;
|
||||||
|
if (depth > maxNestingLevel) { maxNestingLevel = depth; }
|
||||||
|
for (Loop *SubLoop : L->getSubLoops()) {
|
||||||
|
|
||||||
|
countNestedLoops(SubLoop, depth + 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
for (Loop *TopLoop : *LI) {
|
||||||
|
|
||||||
|
countNestedLoops(TopLoop, 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
for (inst_iterator I = inst_begin(*F), E = inst_end(*F); I != E; ++I) {
|
||||||
|
|
||||||
|
if (CallInst *CI = dyn_cast<CallInst>(&*I)) {
|
||||||
|
|
||||||
|
if (Function *CalledF = CI->getCalledFunction()) {
|
||||||
|
|
||||||
|
calledParamCount += CalledF->arg_size();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto *GEP = dyn_cast<GetElementPtrInst>(&*I)) {
|
||||||
|
|
||||||
|
pointerArithCount++;
|
||||||
|
unsigned numPointerArithVars = GEP->getNumOperands();
|
||||||
|
totalPointerArithParams += numPointerArithVars;
|
||||||
|
if (numPointerArithVars > maxPointerArithVars) {
|
||||||
|
|
||||||
|
maxPointerArithVars = numPointerArithVars;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BranchInst *BI = dyn_cast<BranchInst>(&*I)) {
|
||||||
|
|
||||||
|
if (BI->isConditional()) {
|
||||||
|
|
||||||
|
unsigned controlDependentCount = 0;
|
||||||
|
unsigned dataDependentCount = 0;
|
||||||
|
for (Use &U : BI->operands()) {
|
||||||
|
|
||||||
|
if (Instruction *Op = dyn_cast<Instruction>(U.get())) {
|
||||||
|
|
||||||
|
if (DT->dominates(Op, &*I)) { controlDependentCount++; }
|
||||||
|
if (PDT->dominates(Op, &*I)) { dataDependentCount++; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (controlDependentCount > maxControlDependentControls) {
|
||||||
|
|
||||||
|
maxControlDependentControls = controlDependentCount;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataDependentCount > maxDataDependentControls) {
|
||||||
|
|
||||||
|
maxDataDependentControls = dataDependentCount;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for if() without else
|
||||||
|
BasicBlock *TrueBB = BI->getSuccessor(0);
|
||||||
|
BasicBlock *FalseBB = BI->getSuccessor(1);
|
||||||
|
if (TrueBB && FalseBB) {
|
||||||
|
|
||||||
|
if (TrueBB->getSinglePredecessor() == &*I->getParent() &&
|
||||||
|
FalseBB->empty()) {
|
||||||
|
|
||||||
|
ifWithoutElseCount++;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count variables involved in control predicates
|
||||||
|
if (ICmpInst *ICmp = dyn_cast<ICmpInst>(BI->getCondition())) {
|
||||||
|
|
||||||
|
controlPredicateVarCount += ICmp->getNumOperands();
|
||||||
|
|
||||||
|
} else if (BinaryOperator *BinOp =
|
||||||
|
|
||||||
|
dyn_cast<BinaryOperator>(BI->getCondition())) {
|
||||||
|
|
||||||
|
controlPredicateVarCount += BinOp->getNumOperands();
|
||||||
|
|
||||||
|
} else if (SelectInst *Select =
|
||||||
|
|
||||||
|
dyn_cast<SelectInst>(BI->getCondition())) {
|
||||||
|
|
||||||
|
controlPredicateVarCount += Select->getNumOperands();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
score = (unsigned int)(V1_WEIGHT * (double)paramCount +
|
||||||
|
V2_WEIGHT * (double)calledParamCount +
|
||||||
|
V3_WEIGHT * (double)pointerArithCount +
|
||||||
|
V4_WEIGHT * (double)totalPointerArithParams +
|
||||||
|
V5_WEIGHT * (double)maxPointerArithVars +
|
||||||
|
V6_WEIGHT * (double)nestedControlStructCount +
|
||||||
|
V7_WEIGHT * (double)maxNestingLevel +
|
||||||
|
V8_WEIGHT * (double)maxControlDependentControls +
|
||||||
|
V9_WEIGHT * (double)maxDataDependentControls +
|
||||||
|
V10_WEIGHT * (double)ifWithoutElseCount +
|
||||||
|
V11_WEIGHT * (double)controlPredicateVarCount);
|
||||||
|
|
||||||
|
fprintf(stderr,
|
||||||
|
"VulnerabilityScore for %s: %u (paramCount=%u "
|
||||||
|
"calledParamCount=%u|pointerArithCount=%u totalPointerArithParams=%u "
|
||||||
|
"maxPointerArithVars=%u|maxNestingLevel=%u "
|
||||||
|
"maxControlDependentControls=%u maxDataDependentControls=%u "
|
||||||
|
"ifWithoutElseCount=%u controlPredicateVarCount=%u)\n",
|
||||||
|
F->getName().str().c_str(), score, paramCount, calledParamCount,
|
||||||
|
pointerArithCount, totalPointerArithParams, maxPointerArithVars,
|
||||||
|
maxNestingLevel, maxControlDependentControls,
|
||||||
|
maxDataDependentControls, ifWithoutElseCount,
|
||||||
|
controlPredicateVarCount);
|
||||||
|
|
||||||
|
return score;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
char *getBBName(const llvm::BasicBlock *BB) {
|
char *getBBName(const llvm::BasicBlock *BB) {
|
||||||
|
|
||||||
static char *name;
|
static char *name;
|
||||||
@ -136,7 +393,11 @@ bool isIgnoreFunction(const llvm::Function *F) {
|
|||||||
|
|
||||||
for (auto const &ignoreListFunc : ignoreList) {
|
for (auto const &ignoreListFunc : ignoreList) {
|
||||||
|
|
||||||
|
#if LLVM_VERSION_MAJOR >= 19
|
||||||
|
if (F->getName().starts_with(ignoreListFunc)) { return true; }
|
||||||
|
#else
|
||||||
if (F->getName().startswith(ignoreListFunc)) { return true; }
|
if (F->getName().startswith(ignoreListFunc)) { return true; }
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
#include "llvm/Config/llvm-config.h"
|
#include "llvm/Config/llvm-config.h"
|
||||||
|
|
||||||
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 5
|
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 5
|
||||||
typedef long double max_align_t;
|
typedef long double max_align_t;
|
||||||
#endif
|
#endif
|
||||||
@ -26,6 +27,19 @@ typedef long double max_align_t;
|
|||||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if LLVM_VERSION_MAJOR > 12
|
||||||
|
#include "llvm/Support/raw_ostream.h"
|
||||||
|
#include "llvm/Analysis/LoopInfo.h"
|
||||||
|
#include "llvm/Analysis/LoopPass.h"
|
||||||
|
#include "llvm/IR/Function.h"
|
||||||
|
#include "llvm/Pass.h"
|
||||||
|
#include "llvm/IR/InstIterator.h"
|
||||||
|
#include "llvm/IR/Instructions.h"
|
||||||
|
#include "llvm/IR/Operator.h"
|
||||||
|
#include "llvm/IR/Dominators.h"
|
||||||
|
#include "llvm/Analysis/PostDominators.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if LLVM_VERSION_MAJOR > 3 || \
|
#if LLVM_VERSION_MAJOR > 3 || \
|
||||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
|
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
|
||||||
#include "llvm/IR/DebugInfo.h"
|
#include "llvm/IR/DebugInfo.h"
|
||||||
@ -55,7 +69,11 @@ void initInstrumentList();
|
|||||||
bool isInInstrumentList(llvm::Function *F, std::string Filename);
|
bool isInInstrumentList(llvm::Function *F, std::string Filename);
|
||||||
unsigned long long int calculateCollisions(uint32_t edges);
|
unsigned long long int calculateCollisions(uint32_t edges);
|
||||||
void scanForDangerousFunctions(llvm::Module *M);
|
void scanForDangerousFunctions(llvm::Module *M);
|
||||||
unsigned int calcCyclomaticComplexity(llvm::Function *F);
|
unsigned int calcCyclomaticComplexity(llvm::Function *F,
|
||||||
|
const llvm::LoopInfo *LI);
|
||||||
|
unsigned int calcVulnerabilityScore(llvm::Function *F, const llvm::LoopInfo *LI,
|
||||||
|
const llvm::DominatorTree *DT,
|
||||||
|
const llvm::PostDominatorTree *PDT);
|
||||||
|
|
||||||
#ifndef IS_EXTERN
|
#ifndef IS_EXTERN
|
||||||
#define IS_EXTERN
|
#define IS_EXTERN
|
||||||
|
@ -57,6 +57,12 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include "afl-llvm-common.h"
|
#include "afl-llvm-common.h"
|
||||||
|
|
||||||
|
#if LLVM_MAJOR >= 19
|
||||||
|
#define STARTSWITH starts_with
|
||||||
|
#else
|
||||||
|
#define STARTSWITH startswith
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -532,10 +538,10 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!isSizedcmp) needs_null = true;
|
if (!isSizedcmp) needs_null = true;
|
||||||
if (Callee->getName().startswith("g_") ||
|
if (Callee->getName().STARTSWITH("g_") ||
|
||||||
Callee->getName().startswith("curl_") ||
|
Callee->getName().STARTSWITH("curl_") ||
|
||||||
Callee->getName().startswith("Curl_") ||
|
Callee->getName().STARTSWITH("Curl_") ||
|
||||||
Callee->getName().startswith("xml"))
|
Callee->getName().STARTSWITH("xml"))
|
||||||
nullCheck = true;
|
nullCheck = true;
|
||||||
|
|
||||||
Value *sizedValue = isSizedcmp ? callInst->getArgOperand(2) : NULL;
|
Value *sizedValue = isSizedcmp ? callInst->getArgOperand(2) : NULL;
|
||||||
|
@ -578,7 +578,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
|||||||
void *nyx_config = fsrv->nyx_handlers->nyx_config_load(fsrv->target_path);
|
void *nyx_config = fsrv->nyx_handlers->nyx_config_load(fsrv->target_path);
|
||||||
|
|
||||||
fsrv->nyx_handlers->nyx_config_set_workdir_path(nyx_config, workdir_path);
|
fsrv->nyx_handlers->nyx_config_set_workdir_path(nyx_config, workdir_path);
|
||||||
fsrv->nyx_handlers->nyx_config_set_input_buffer_size(nyx_config, fsrv->max_length);
|
fsrv->nyx_handlers->nyx_config_set_input_buffer_size(nyx_config,
|
||||||
|
fsrv->max_length);
|
||||||
fsrv->nyx_handlers->nyx_config_set_input_buffer_write_protection(nyx_config,
|
fsrv->nyx_handlers->nyx_config_set_input_buffer_write_protection(nyx_config,
|
||||||
true);
|
true);
|
||||||
|
|
||||||
|
@ -481,6 +481,14 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
|
|||||||
s32 fd;
|
s32 fd;
|
||||||
u64 cksum = 0;
|
u64 cksum = 0;
|
||||||
|
|
||||||
|
// will be classified away otherwise
|
||||||
|
if (unlikely((afl->current_score = *(u32 *)((u8 *)afl->fsrv.trace_bits + 1)) >
|
||||||
|
0)) {
|
||||||
|
|
||||||
|
memset(afl->fsrv.trace_bits + 1, 0, 4);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* Update path frequency. */
|
/* Update path frequency. */
|
||||||
|
|
||||||
/* Generating a hash on every input is super expensive. Bad idea and should
|
/* Generating a hash on every input is super expensive. Bad idea and should
|
||||||
|
@ -60,37 +60,80 @@ inline u32 select_next_queue_entry(afl_state_t *afl) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#define DEBUG_QUEUE 1
|
||||||
double compute_weight(afl_state_t *afl, struct queue_entry *q,
|
double compute_weight(afl_state_t *afl, struct queue_entry *q,
|
||||||
double avg_exec_us, double avg_bitmap_size,
|
double avg_exec_us, double avg_bitmap_size,
|
||||||
double avg_top_size) {
|
double avg_top_size, double avg_score) {
|
||||||
|
|
||||||
double weight = 1.0;
|
if (unlikely(0)) {
|
||||||
|
|
||||||
if (likely(afl->schedule >= FAST && afl->schedule <= RARE)) {
|
return q->score / avg_score;
|
||||||
|
|
||||||
u32 hits = afl->n_fuzz[q->n_fuzz_entry];
|
} else {
|
||||||
if (likely(hits)) { weight /= (log10(hits) + 1); }
|
|
||||||
|
double weight = 1.0;
|
||||||
|
|
||||||
|
if (likely(afl->schedule >= FAST && afl->schedule <= RARE)) {
|
||||||
|
|
||||||
|
u32 hits = afl->n_fuzz[q->n_fuzz_entry];
|
||||||
|
if (likely(hits)) { weight /= (log10(hits) + 1); }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_QUEUE
|
||||||
|
fprintf(stderr, "WEIGHT id=%u fname=%s start_weight=1.0\n", q->id,
|
||||||
|
q->fname);
|
||||||
|
fprintf(stderr, " after step 1: %.2f (log10(hits))\n", weight);
|
||||||
|
#endif
|
||||||
|
if (likely(afl->schedule < RARE)) { weight *= (avg_exec_us / q->exec_us); }
|
||||||
|
#ifdef DEBUG_QUEUE
|
||||||
|
fprintf(stderr, " after step 2: %.2f (exec_us)\n", weight);
|
||||||
|
#endif
|
||||||
|
weight *= (log(q->bitmap_size) / avg_bitmap_size);
|
||||||
|
#ifdef DEBUG_QUEUE
|
||||||
|
fprintf(stderr, " after step 3: %.2f (log(bitmap_size))\n", weight);
|
||||||
|
#endif
|
||||||
|
weight *= (1 + (q->tc_ref / avg_top_size));
|
||||||
|
#ifdef DEBUG_QUEUE
|
||||||
|
fprintf(stderr, " after step 4: %.2f (top_size)\n", weight);
|
||||||
|
#endif
|
||||||
|
if (unlikely(avg_score != 0.0)) { weight *= (q->score / avg_score); }
|
||||||
|
#ifdef DEBUG_QUEUE
|
||||||
|
fprintf(stderr, " after step 5: %.2f (score)\n", weight);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (unlikely(weight < 0.1)) { weight = 0.1; }
|
||||||
|
if (unlikely(q->favored)) {
|
||||||
|
|
||||||
|
weight += 1;
|
||||||
|
weight *= 5;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_QUEUE
|
||||||
|
fprintf(stderr, " after step 6: %.2f (favored)\n", weight);
|
||||||
|
#endif
|
||||||
|
if (unlikely(!q->was_fuzzed)) { weight *= 2.5; }
|
||||||
|
#ifdef DEBUG_QUEUE
|
||||||
|
fprintf(stderr, " after step 7: %.2f (was_fuzzed)\n", weight);
|
||||||
|
#endif
|
||||||
|
if (unlikely(q->fs_redundant)) { weight *= 0.75; }
|
||||||
|
#ifdef DEBUG_QUEUE
|
||||||
|
fprintf(stderr, " after final step: %.2f (fs_redundant)\n", weight);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return weight;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (likely(afl->schedule < RARE)) { weight *= (avg_exec_us / q->exec_us); }
|
|
||||||
weight *= (log(q->bitmap_size) / avg_bitmap_size);
|
|
||||||
weight *= (1 + (q->tc_ref / avg_top_size));
|
|
||||||
|
|
||||||
if (unlikely(weight < 0.1)) { weight = 0.1; }
|
|
||||||
if (unlikely(q->favored)) { weight *= 5; }
|
|
||||||
if (unlikely(!q->was_fuzzed)) { weight *= 2; }
|
|
||||||
if (unlikely(q->fs_redundant)) { weight *= 0.8; }
|
|
||||||
|
|
||||||
return weight;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create the alias table that allows weighted random selection - expensive */
|
/* create the alias table that allows weighted random selection - expensive */
|
||||||
|
|
||||||
void create_alias_table(afl_state_t *afl) {
|
void create_alias_table(afl_state_t *afl) {
|
||||||
|
|
||||||
u32 n = afl->queued_items, i = 0, nSmall = 0, nLarge = n - 1;
|
u32 n = afl->queued_items, i = 0, nSmall = 0, nLarge = n - 1,
|
||||||
|
exploit = afl->fuzz_mode;
|
||||||
double sum = 0;
|
double sum = 0;
|
||||||
|
|
||||||
double *P = (double *)afl_realloc(AFL_BUF_PARAM(out), n * sizeof(double));
|
double *P = (double *)afl_realloc(AFL_BUF_PARAM(out), n * sizeof(double));
|
||||||
@ -118,6 +161,7 @@ void create_alias_table(afl_state_t *afl) {
|
|||||||
double avg_exec_us = 0.0;
|
double avg_exec_us = 0.0;
|
||||||
double avg_bitmap_size = 0.0;
|
double avg_bitmap_size = 0.0;
|
||||||
double avg_top_size = 0.0;
|
double avg_top_size = 0.0;
|
||||||
|
double avg_score = 0.0;
|
||||||
u32 active = 0;
|
u32 active = 0;
|
||||||
|
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
@ -130,6 +174,7 @@ void create_alias_table(afl_state_t *afl) {
|
|||||||
avg_exec_us += q->exec_us;
|
avg_exec_us += q->exec_us;
|
||||||
avg_bitmap_size += log(q->bitmap_size);
|
avg_bitmap_size += log(q->bitmap_size);
|
||||||
avg_top_size += q->tc_ref;
|
avg_top_size += q->tc_ref;
|
||||||
|
if (exploit) { avg_score += /*log(*/ q->score /*)*/; }
|
||||||
++active;
|
++active;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -140,14 +185,16 @@ void create_alias_table(afl_state_t *afl) {
|
|||||||
avg_bitmap_size /= active;
|
avg_bitmap_size /= active;
|
||||||
avg_top_size /= active;
|
avg_top_size /= active;
|
||||||
|
|
||||||
|
if (exploit) { avg_score /= active; }
|
||||||
|
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
|
|
||||||
struct queue_entry *q = afl->queue_buf[i];
|
struct queue_entry *q = afl->queue_buf[i];
|
||||||
|
|
||||||
if (likely(!q->disabled)) {
|
if (likely(!q->disabled)) {
|
||||||
|
|
||||||
q->weight =
|
q->weight = compute_weight(afl, q, avg_exec_us, avg_bitmap_size,
|
||||||
compute_weight(afl, q, avg_exec_us, avg_bitmap_size, avg_top_size);
|
avg_top_size, avg_score);
|
||||||
q->perf_score = calculate_score(afl, q);
|
q->perf_score = calculate_score(afl, q);
|
||||||
sum += q->weight;
|
sum += q->weight;
|
||||||
|
|
||||||
@ -596,6 +643,8 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
|
|||||||
q->trace_mini = NULL;
|
q->trace_mini = NULL;
|
||||||
q->testcase_buf = NULL;
|
q->testcase_buf = NULL;
|
||||||
q->mother = afl->queue_cur;
|
q->mother = afl->queue_cur;
|
||||||
|
q->score = afl->current_score;
|
||||||
|
if (unlikely(!q->score)) { q->score = 1; }
|
||||||
|
|
||||||
#ifdef INTROSPECTION
|
#ifdef INTROSPECTION
|
||||||
q->bitsmap_size = afl->bitsmap_size;
|
q->bitsmap_size = afl->bitsmap_size;
|
||||||
|
@ -606,6 +606,8 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
|
|||||||
}
|
}
|
||||||
|
|
||||||
q->exec_us = diff_us / afl->stage_max;
|
q->exec_us = diff_us / afl->stage_max;
|
||||||
|
if (unlikely(!q->exec_us)) { q->exec_us = 1; }
|
||||||
|
|
||||||
q->bitmap_size = count_bytes(afl, afl->fsrv.trace_bits);
|
q->bitmap_size = count_bytes(afl, afl->fsrv.trace_bits);
|
||||||
q->handicap = handicap;
|
q->handicap = handicap;
|
||||||
q->cal_failed = 0;
|
q->cal_failed = 0;
|
||||||
|
@ -1806,7 +1806,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
|||||||
|
|
||||||
afl->fsrv.use_fauxsrv = afl->non_instrumented_mode == 1 || afl->no_forkserver;
|
afl->fsrv.use_fauxsrv = afl->non_instrumented_mode == 1 || afl->no_forkserver;
|
||||||
afl->fsrv.max_length = afl->max_length;
|
afl->fsrv.max_length = afl->max_length;
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
if (!afl->fsrv.nyx_mode) {
|
if (!afl->fsrv.nyx_mode) {
|
||||||
|
|
||||||
@ -2868,7 +2868,9 @@ int main(int argc, char **argv_orig, char **envp) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u64 execs_before = afl->fsrv.total_execs;
|
||||||
skipped_fuzz = fuzz_one(afl);
|
skipped_fuzz = fuzz_one(afl);
|
||||||
|
afl->queue_cur->total_execs += afl->fsrv.total_execs - execs_before;
|
||||||
#ifdef INTROSPECTION
|
#ifdef INTROSPECTION
|
||||||
++afl->queue_cur->stats_selected;
|
++afl->queue_cur->stats_selected;
|
||||||
|
|
||||||
@ -3067,6 +3069,37 @@ stop_fuzzing:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (getenv("AFL_DUMP_QUEUE_ON_EXIT")) {
|
||||||
|
|
||||||
|
for (u32 mode = 0; mode < 2; mode++) { // explore + exploit mode data
|
||||||
|
|
||||||
|
afl->fuzz_mode = mode;
|
||||||
|
create_alias_table(afl);
|
||||||
|
fprintf(stderr, "\nQUEUE DUMP MODE: %u\n", mode);
|
||||||
|
|
||||||
|
for (u32 k = 0; k < afl->queued_items; ++k) {
|
||||||
|
|
||||||
|
struct queue_entry *q = afl->queue_buf[k];
|
||||||
|
fprintf(stderr,
|
||||||
|
"item=%u fname=%s len=%u exec_us=%llu total_execs=%llu "
|
||||||
|
"has_new_cov=%u "
|
||||||
|
"var_behavior=%u favored=%u fs_redundant=%u disabled=%u "
|
||||||
|
"bitmap_size=%u tc_ref=%u fuzz_level=%u was_fuzzed=%u "
|
||||||
|
"mother=%d found=%u perf_score=%.2f weight=%.2f score=%u\n",
|
||||||
|
k, q->fname, q->len, q->exec_us, q->total_execs, q->has_new_cov,
|
||||||
|
q->var_behavior, q->favored, q->fs_redundant, q->disabled,
|
||||||
|
q->bitmap_size, q->tc_ref, q->fuzz_level, q->was_fuzzed,
|
||||||
|
q->mother == NULL ? -1 : (int)q->mother->id, q->found,
|
||||||
|
q->perf_score, q->weight, q->score);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (frida_afl_preload) { ck_free(frida_afl_preload); }
|
if (frida_afl_preload) { ck_free(frida_afl_preload); }
|
||||||
|
|
||||||
fclose(afl->fsrv.plot_file);
|
fclose(afl->fsrv.plot_file);
|
||||||
|
@ -83,6 +83,8 @@ static u32 tcnt, highest; /* tuple content information */
|
|||||||
|
|
||||||
static u32 in_len; /* Input data length */
|
static u32 in_len; /* Input data length */
|
||||||
|
|
||||||
|
static u32 score;
|
||||||
|
|
||||||
static u32 map_size = MAP_SIZE, timed_out = 0;
|
static u32 map_size = MAP_SIZE, timed_out = 0;
|
||||||
|
|
||||||
static bool quiet_mode, /* Hide non-essential messages? */
|
static bool quiet_mode, /* Hide non-essential messages? */
|
||||||
@ -238,6 +240,13 @@ static void at_exit_handler(void) {
|
|||||||
static void analyze_results(afl_forkserver_t *fsrv) {
|
static void analyze_results(afl_forkserver_t *fsrv) {
|
||||||
|
|
||||||
u32 i;
|
u32 i;
|
||||||
|
|
||||||
|
if (unlikely((score = *(u32 *)((u8 *)fsrv->trace_bits + 1)) > 0)) {
|
||||||
|
|
||||||
|
memset(fsrv->trace_bits + 1, 0, 4);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < map_size; i++) {
|
for (i = 0; i < map_size; i++) {
|
||||||
|
|
||||||
if (fsrv->trace_bits[i]) {
|
if (fsrv->trace_bits[i]) {
|
||||||
@ -269,6 +278,12 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (unlikely((score = *(u32 *)((u8 *)fsrv->trace_bits + 1)) > 0)) {
|
||||||
|
|
||||||
|
memset(fsrv->trace_bits + 1, 0, 4);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (cmin_mode &&
|
if (cmin_mode &&
|
||||||
(fsrv->last_run_timed_out || (!caa && child_crashed != cco))) {
|
(fsrv->last_run_timed_out || (!caa && child_crashed != cco))) {
|
||||||
|
|
||||||
@ -1766,12 +1781,20 @@ int main(int argc, char **argv_orig, char **envp) {
|
|||||||
OKF("Captured %u tuples (map size %u, highest value %u, total values %llu) "
|
OKF("Captured %u tuples (map size %u, highest value %u, total values %llu) "
|
||||||
"in '%s'." cRST,
|
"in '%s'." cRST,
|
||||||
tcnt, fsrv->real_map_size, highest, total, out_file);
|
tcnt, fsrv->real_map_size, highest, total, out_file);
|
||||||
if (collect_coverage)
|
if (collect_coverage) {
|
||||||
|
|
||||||
OKF("A coverage of %u edges were achieved out of %u existing (%.02f%%) "
|
OKF("A coverage of %u edges were achieved out of %u existing (%.02f%%) "
|
||||||
"with %llu input files.",
|
"with %llu input files.",
|
||||||
tcnt, map_size, ((float)tcnt * 100) / (float)map_size,
|
tcnt, map_size, ((float)tcnt * 100) / (float)map_size,
|
||||||
fsrv->total_execs);
|
fsrv->total_execs);
|
||||||
|
|
||||||
|
} else if (score > 0) {
|
||||||
|
|
||||||
|
OKF("Path score is %u (cyclomatic and/or vulnerability scoring).\n",
|
||||||
|
score);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stdin_file) {
|
if (stdin_file) {
|
||||||
|
Reference in New Issue
Block a user