main^2
em0 8 months ago
parent 8f017a1f4c
commit 7f8464c6db

@ -47,79 +47,73 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
static u8 *as_path; /*AFL“as”包装器的路径*/ static u8 *as_path; /* AFL“as”包装器的路径 */
static u8 **cc_params; /*传递给真实CC的参数*/ static u8 **cc_params; /* 传递给真实C编译器的参数 */
static u32 cc_par_cnt = 1; /*参数计数包括argv0*/ static u32 cc_par_cnt = 1; /* 参数计数包括argv0 */
static u8 be_quiet, /*静音模式*/ static u8 be_quiet, /* 静音模式 */
clang_mode; /*被称为afl clang模式**/ clang_mode; /* 被称为afl clang模式 */
/* 尝试在 AFL_PATH 或从 argv[0] 派生的位置找到我们的“假”GNU 汇编器。 /* 尝试在 AFL_PATH 或从 argv[0] 派生的位置找到我们的“假”GNU 汇编器。
*/ */
static void find_as(u8 *argv0) static void find_as(u8 *argv0)
{ {
u8 *afl_path = getenv("AFL_PATH"); // 获取环境变量AFL_PATH的值
u8 *afl_path = getenv("AFL_PATH");
u8 *slash, *tmp; u8 *slash, *tmp;
if (afl_path) if (afl_path) // 如果AFL_PATH环境变量存在
{ {
tmp = alloc_printf("%s/as", afl_path); // 构造路径字符串
tmp = alloc_printf("%s/as", afl_path); if (!access(tmp, X_OK)) // 检查路径是否存在且可执行
if (!access(tmp, X_OK))
{ {
as_path = afl_path; as_path = afl_path; // 设置as_path为找到的路径
ck_free(tmp); ck_free(tmp); // 释放临时字符串
return; return;
} }
ck_free(tmp); ck_free(tmp); // 如果不可执行,释放临时字符串
} }
slash = strrchr(argv0, '/'); slash = strrchr(argv0, '/'); // 在argv0中查找最后一个'/',以获取目录部分
if (slash) if (slash) // 如果找到了'/'说明argv0是一个路径
{ {
u8 *dir; u8 *dir;
*slash = 0; *slash = 0; // 暂时将'/'替换为'\0',以便截取目录部分
dir = ck_strdup(argv0); dir = ck_strdup(argv0); // 复制目录部分
*slash = '/'; *slash = '/'; // 恢复'/'恢复argv0的完整路径
tmp = alloc_printf("%s/afl-as", dir); tmp = alloc_printf("%s/afl-as", dir); // 构造路径字符串
if (!access(tmp, X_OK)) if (!access(tmp, X_OK)) // 检查路径是否存在且可执行
{ {
as_path = dir; as_path = dir; // 设置as_path为找到的路径
ck_free(tmp); ck_free(tmp); // 释放临时字符串
return; return;
} }
ck_free(tmp); ck_free(tmp); // 如果不可执行,释放临时字符串
ck_free(dir); ck_free(dir); // 释放目录字符串
} }
if (!access(AFL_PATH "/as", X_OK)) if (!access(AFL_PATH "/as", X_OK)) // 检查默认路径AFL_PATH/as是否存在且可执行
{ {
as_path = AFL_PATH; as_path = AFL_PATH; // 设置as_path为默认路径
return; return;
} }
FATAL("Unable to find AFL wrapper binary for 'as'. Please set AFL_PATH"); FATAL("Unable to find AFL wrapper binary for 'as'. Please set AFL_PATH"); // 如果找不到,输出错误信息并中止
} }
/*将argv复制到cc_params进行必要的编辑*/ /* 将argv复制到cc_params进行必要的编辑 */
static void edit_params(u32 argc, char **argv) static void edit_params(u32 argc, char **argv)
{ {
u8 fortify_set = 0, asan_set = 0; // 标志变量用于检测是否设置了fortify和asan
u8 fortify_set = 0, asan_set = 0;
u8 *name; u8 *name;
#if defined(__FreeBSD__) && defined(__x86_64__) #if defined(__FreeBSD__) && defined(__x86_64__)
u8 m32_set = 0; u8 m32_set = 0; // FreeBSD x86_64环境下检测是否设置了m32
#endif #endif
/******************************************************************************** /********************************************************************************
@ -127,77 +121,74 @@ static void edit_params(u32 argc, char **argv)
* 使 afl-clang使 C C++ * 使 afl-clang使 C C++
********************************************************************************/ ********************************************************************************/
cc_params = ck_alloc((argc + 128) * sizeof(u8 *)); cc_params = ck_alloc((argc + 128) * sizeof(u8 *)); // 分配足够大的空间来存储编译器参数
name = strrchr(argv[0], '/'); name = strrchr(argv[0], '/'); // 获取可执行文件名
if (!name) if (!name)
name = argv[0]; name = argv[0]; // 如果没有找到'/'则argv0就是可执行文件名
else
name++;
if (!strncmp(name, "afl-clang", 9))
{
clang_mode = 1;
setenv(CLANG_ENV_VAR, "1", 1);
if (!strcmp(name, "afl-clang++"))
{
u8 *alt_cxx = getenv("AFL_CXX");
cc_params[0] = alt_cxx ? alt_cxx : (u8 *)"clang++";
}
else
{
u8 *alt_cc = getenv("AFL_CC");
cc_params[0] = alt_cc ? alt_cc : (u8 *)"clang";
}
}
else else
{ name++; // 否则name指向可执行文件名的第一个字符
/*安装了GCJ和Eclipse后您实际上可以编译Java这个 if (!strncmp(name, "afl-clang", 9)) // 如果可执行文件名以afl-clang开头
{
abortafl-fuzz使 clang_mode = 1; // 设置clang_mode标志为1表示使用clang模式
使Java退
*/
#ifdef __APPLE__ setenv(CLANG_ENV_VAR, "1", 1); // 设置环境变量表示正在使用afl-clang
if (!strcmp(name, "afl-g++")) if (!strcmp(name, "afl-clang++")) // 如果是afl-clang++
cc_params[0] = getenv("AFL_CXX"); {
else if (!strcmp(name, "afl-gcj")) u8 *alt_cxx = getenv("AFL_CXX"); // 获取环境变量AFL_CXX的值
cc_params[0] = getenv("AFL_GCJ"); cc_params[0] = alt_cxx ? alt_cxx : (u8 *)"clang++"; // 如果设置了AFL_CXX则使用该值作为编译器否则使用clang++
}
else // 如果是afl-clang
{
u8 *alt_cc = getenv("AFL_CC"); // 获取环境变量AFL_CC的值
cc_params[0] = alt_cc ? alt_cc : (u8 *)"clang"; // 如果设置了AFL_CC则使用该值作为编译器否则使用clang
}
}
else // 如果不是afl-clang
{
// 安装了GCJ和Eclipse后您实际上可以编译Java这个
// 仪器将工作(令人惊讶)。唉,未处理的异常确实如此
// 不调用abort因此需要修改afl-fuzz以使其相等
// 使用Java时具有崩溃条件的非零退出代码
// 二进制文件。嗯
#ifdef __APPLE__ // 如果是在MacOS X系统上
if (!strcmp(name, "afl-g++")) // 如果是afl-g++
cc_params[0] = getenv("AFL_CXX"); // 获取环境变量AFL_CXX的值作为编译器
else if (!strcmp(name, "afl-gcj")) // 如果是afl-gcj
cc_params[0] = getenv("AFL_GCJ"); // 获取环境变量AFL_GCJ的值作为编译器
else else
cc_params[0] = getenv("AFL_CC"); cc_params[0] = getenv("AFL_CC"); // 其他情况获取环境变量AFL_CC的值作为编译器
if (!cc_params[0]) if (!cc_params[0]) // 如果没有设置相应的环境变量
{ {
SAYF("\n" cLRD "[-] " cRST // 输出错误信息
SAYF("\n" cLRD "[-] " cRST
"On Apple systems, 'gcc' is usually just a wrapper for clang. Please use the\n" "On Apple systems, 'gcc' is usually just a wrapper for clang. Please use the\n"
" 'afl-clang' utility instead of 'afl-gcc'. If you really have GCC installed,\n" " 'afl-clang' utility instead of 'afl-gcc'. If you really have GCC installed,\n"
" set AFL_CC or AFL_CXX to specify the correct path to that compiler.\n"); " set AFL_CC or AFL_CXX to specify the correct path to that compiler.\n");
FATAL("AFL_CC or AFL_CXX required on MacOS X"); FATAL("AFL_CC or AFL_CXX required on MacOS X"); // 输出错误信息并中止
} }
#else #else // 如果不是在MacOS X系统上
if (!strcmp(name, "afl-g++")) if (!strcmp(name, "afl-g++")) // 如果是afl-g++
{ {
u8 *alt_cxx = getenv("AFL_CXX"); u8 *alt_cxx = getenv("AFL_CXX"); // 获取环境变量AFL_CXX的值
cc_params[0] = alt_cxx ? alt_cxx : (u8 *)"g++"; cc_params[0] = alt_cxx ? alt_cxx : (u8 *)"g++"; // 如果设置了AFL_CXX则使用该值作为编译器否则使用g++
} }
else if (!strcmp(name, "afl-gcj")) else if (!strcmp(name, "afl-gcj")) // 如果是afl-gcj
{ {
u8 *alt_cc = getenv("AFL_GCJ"); u8 *alt_cc = getenv("AFL_GCJ"); // 获取环境变量AFL_GCJ的值
cc_params[0] = alt_cc ? alt_cc : (u8 *)"gcj"; cc_params[0] = alt_cc ? alt_cc : (u8 *)"gcj"; // 如果设置了AFL_GCJ则使用该值作为编译器否则使用gcj
} }
else else // 如果是afl-gcc
{ {
u8 *alt_cc = getenv("AFL_CC"); u8 *alt_cc = getenv("AFL_CC"); // 获取环境变量AFL_CC的值
cc_params[0] = alt_cc ? alt_cc : (u8 *)"gcc"; cc_params[0] = alt_cc ? alt_cc : (u8 *)"gcc"; // 如果设置了AFL_CC则使用该值作为编译器否则使用gcc
} }
#endif /* __APPLE__ */ #endif /* __APPLE__ */
@ -233,32 +224,35 @@ static void edit_params(u32 argc, char **argv)
if (!strcmp(cur, "-pipe")) if (!strcmp(cur, "-pipe"))
continue; continue;
/ *
*
*
* FORTIFY_SOURCEASAN/MSAN
* /
#if defined(__FreeBSD__) && defined(__x86_64__) #if defined(__FreeBSD__) && defined(__x86_64__)
// 检测是否在FreeBSD的64位系统上使用了-m32选项如果是则设置m32_set为1
if (!strcmp(cur, "-m32")) if (!strcmp(cur, "-m32"))
m32_set = 1; m32_set = 1;
#endif #endif
// 检测是否使用了address sanitizer或memory sanitizer选项如果是则设置asan_set为1
if (!strcmp(cur, "-fsanitize=address") || if (!strcmp(cur, "-fsanitize=address") ||
!strcmp(cur, "-fsanitize=memory")) !strcmp(cur, "-fsanitize=memory"))
asan_set = 1; asan_set = 1;
// 检测是否设置了_FORTIFY_SOURCE宏如果是则设置fortify_set为1
if (strstr(cur, "FORTIFY_SOURCE")) if (strstr(cur, "FORTIFY_SOURCE"))
fortify_set = 1; fortify_set = 1;
// 将当前命令行参数添加到编译器参数列表中
cc_params[cc_par_cnt++] = cur; cc_params[cc_par_cnt++] = cur;
} }
// 添加编译器的-B参数指定路径给as_path
cc_params[cc_par_cnt++] = "-B"; cc_params[cc_par_cnt++] = "-B";
cc_params[cc_par_cnt++] = as_path; cc_params[cc_par_cnt++] = as_path;
// 如果clang_mode为真则添加-no-integrated-as参数
if (clang_mode) if (clang_mode)
cc_params[cc_par_cnt++] = "-no-integrated-as"; cc_params[cc_par_cnt++] = "-no-integrated-as";
// 如果设置了AFL_HARDEN环境变量则添加-fstack-protector-all参数并在未设置_FORTIFY_SOURCE时定义它
if (getenv("AFL_HARDEN")) if (getenv("AFL_HARDEN"))
{ {
@ -268,6 +262,7 @@ static void edit_params(u32 argc, char **argv)
cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2"; cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2";
} }
// 如果asan_set为真则设置AFL_USE_ASAN环境变量为1用于通知afl使用asan
if (asan_set) if (asan_set)
{ {
@ -277,25 +272,27 @@ static void edit_params(u32 argc, char **argv)
} }
else if (getenv("AFL_USE_ASAN")) else if (getenv("AFL_USE_ASAN"))
{ {
// 如果设置了AFL_USE_ASAN但未设置asan_set检查是否同时设置了MSAN和AFL_HARDEN如果是则报错
if (getenv("AFL_USE_MSAN")) if (getenv("AFL_USE_MSAN"))
FATAL("ASAN and MSAN are mutually exclusive"); FATAL("ASAN和MSAN是互斥的");
if (getenv("AFL_HARDEN")) if (getenv("AFL_HARDEN"))
FATAL("ASAN and AFL_HARDEN are mutually exclusive"); FATAL("ASAN和AFL_HARDEN是互斥的");
// 取消定义_FORTIFY_SOURCE宏添加address sanitizer参数
cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE"; cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE";
cc_params[cc_par_cnt++] = "-fsanitize=address"; cc_params[cc_par_cnt++] = "-fsanitize=address";
} }
else if (getenv("AFL_USE_MSAN")) else if (getenv("AFL_USE_MSAN"))
{ {
// 如果设置了AFL_USE_MSAN检查是否同时设置了ASAN和AFL_HARDEN如果是则报错
if (getenv("AFL_USE_ASAN")) if (getenv("AFL_USE_ASAN"))
FATAL("ASAN and MSAN are mutually exclusive"); FATAL("ASAN和MSAN是互斥的");
if (getenv("AFL_HARDEN")) if (getenv("AFL_HARDEN"))
FATAL("MSAN and AFL_HARDEN are mutually exclusive"); FATAL("MSAN和AFL_HARDEN是互斥的");
// 取消定义_FORTIFY_SOURCE宏添加memory sanitizer参数
cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE"; cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE";
cc_params[cc_par_cnt++] = "-fsanitize=memory"; cc_params[cc_par_cnt++] = "-fsanitize=memory";
} }
@ -306,6 +303,7 @@ static void edit_params(u32 argc, char **argv)
* : d:\code\google_AFL\src\afl-gcc.c * : d:\code\google_AFL\src\afl-gcc.c
********************************************************************************/ ********************************************************************************/
// 如果未设置AFL_DONT_OPTIMIZE环境变量则进行优化设置
if (!getenv("AFL_DONT_OPTIMIZE")) if (!getenv("AFL_DONT_OPTIMIZE"))
{ {
@ -315,41 +313,45 @@ static void edit_params(u32 argc, char **argv)
bug*/ bug*/
// 如果不是clang模式或者未设置m32选项则添加-g参数
if (!clang_mode || !m32_set) if (!clang_mode || !m32_set)
cc_params[cc_par_cnt++] = "-g"; cc_params[cc_par_cnt++] = "-g";
#else #else
// 添加调试信息参数-g
cc_params[cc_par_cnt++] = "-g"; cc_params[cc_par_cnt++] = "-g";
#endif #endif
// 添加-O3优化级别参数和-unroll-loops参数
cc_params[cc_par_cnt++] = "-O3"; cc_params[cc_par_cnt++] = "-O3";
cc_params[cc_par_cnt++] = "-funroll-loops"; cc_params[cc_par_cnt++] = "-funroll-loops";
/* Two indicators that you're building for fuzzing; one of them is /* Two indicators that you're building for fuzzing; one of them is
AFL-specific, the other is shared with libfuzzer. */ AFL-specific, the other is shared with libfuzzer. */
// 添加编译器标志,指示正在为模糊测试构建代码
cc_params[cc_par_cnt++] = "-D__AFL_COMPILER=1"; cc_params[cc_par_cnt++] = "-D__AFL_COMPILER=1";
cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1"; cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1";
} }
/***********************************************
* // 如果设置了AFL_NO_BUILTIN环境变量则添加参数禁用内置的字符串和内存比较函数
* "AFL_NO_BUILTIN" if (getenv("AFL_NO_BUILTIN"))
* {
***********************************************/ cc_params[cc_par_cnt++] = "-fno-builtin-strcmp";
if (getenv("AFL_NO_BUILTIN")) cc_params[cc_par_cnt++] = "-fno-builtin-strncmp";
{ cc_params[cc_par_cnt++] = "-fno-builtin-strcasecmp";
cc_params[cc_par_cnt++] = "-fno-builtin-strncasecmp";
cc_params[cc_par_cnt++] = "-fno-builtin-strcmp"; cc_params[cc_par_cnt++] = "-fno-builtin-memcmp";
cc_params[cc_par_cnt++] = "-fno-builtin-strncmp"; cc_params[cc_par_cnt++] = "-fno-builtin-strstr";
cc_params[cc_par_cnt++] = "-fno-builtin-strcasecmp"; cc_params[cc_par_cnt++] = "-fno-builtin-strcasestr";
cc_params[cc_par_cnt++] = "-fno-builtin-strncasecmp"; // 注意:这里重复了两遍-fno-builtin-strncasecmp 和 -fno-builtin-memcmp应去掉重复的部分
cc_params[cc_par_cnt++] = "-fno-builtin-memcmp"; // cc_params[cc_par_cnt++] = "-fno-builtin-strncasecmp";
cc_params[cc_par_cnt++] = "-fno-builtin-strstr"; // cc_params[cc_par_cnt++] = "-fno-builtin-memcmp";
cc_params[cc_par_cnt++] = "-fno-builtin-strcasestr"; }
} cc_params[cc_par_cnt++] = "-fno-builtin-strncasecmp";
cc_params[cc_par_cnt++] = "-fno-builtin-memcmp"; // 设置编译器参数列表的结束标志NULL
cc_params[cc_par_cnt] = NULL; cc_params[cc_par_cnt] = NULL;
} }
@ -358,45 +360,42 @@ static void edit_params(u32 argc, char **argv)
// 主函数,程序的入口点 // 主函数,程序的入口点
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
// 检查标准错误输出是否为终端,以及环境变量是否开启安静模式 // 检查标准错误输出是否为终端,以及环境变量是否开启安静模式
if (isatty(2) && !getenv("AFL_QUIET")) if (isatty(2) && !getenv("AFL_QUIET"))
{ {
SAYF(cCYA "afl-cc " cBRI VERSION cRST " by <lcamtuf@google.com>\n"); SAYF(cCYA "afl-cc " cBRI VERSION cRST " by <lcamtuf@google.com>\n");
} }
else else
be_quiet = 1; be_quiet = 1;
// 检查传入的参数数量是否少于2 // 检查传入的参数数量是否少于2,如果是则输出使用说明并退出
if (argc < 2) if (argc < 2)
{ {
SAYF("\n" SAYF("\n"
"This is a helper application for afl-fuzz. It serves as a drop-in replacement\n" "这是一个辅助afl-fuzz的工具程序。它可以用作gcc或clang的替代品\n"
"for gcc or clang, letting you recompile third-party code with the required\n" "让你能够使用必要的运行时检测重新编译第三方代码。\n"
"runtime instrumentation. A common use pattern would be one of the following:\n\n" "常见的使用模式如下之一:\n\n"
" CC=%s/afl-gcc ./configure\n" " CC=%s/afl-gcc ./configure\n"
" CXX=%s/afl-g++ ./configure\n\n" " CXX=%s/afl-g++ ./configure\n\n"
"You can specify custom next-stage toolchain via AFL_CC, AFL_CXX, and AFL_AS.\n" "你可以通过AFL_CC, AFL_CXX, 和 AFL_AS指定自定义的后续编译工具链。\n"
"Setting AFL_HARDEN enables hardening optimizations in the compiled code.\n\n", "设置AFL_HARDEN会在编译代码时启用hardening优化。\n\n",
BIN_PATH, BIN_PATH); BIN_PATH, BIN_PATH);
exit(1); exit(1);
} }
// 查找汇编器 // 查找汇编器根据argv[0]来确定使用的编译器是gcc还是clang
find_as(argv[0]); find_as(argv[0]);
// 编辑参数 // 编辑命令行参数,根据需要添加和调整编译器参数
edit_params(argc, argv); edit_params(argc, argv);
// 执行编译器,并传递参数 // 执行编译器,并传递编辑后的参数列表
execvp(cc_params[0], (char **)cc_params); execvp(cc_params[0], (char **)cc_params);
// 如果执行失败,输出错误信息 // 如果execvp调用失败输出错误信息并退出程序
FATAL("Oops, failed to execute '%s' - check your PATH", cc_params[0]); FATAL("Oops, failed to execute '%s' - check your PATH", cc_params[0]);
return 0; return 0;

@ -57,104 +57,108 @@
/* Get unix time in microseconds. */ /* Get unix time in microseconds. */
// 定义一个函数来获取当前时间(以微秒为单位)
static u64 get_cur_time_us(void) { static u64 get_cur_time_us(void) {
struct timeval tv; struct timeval tv; // 用于存储时间值
struct timezone tz; struct timezone tz; // 用于存储时区信息
gettimeofday(&tv, &tz); gettimeofday(&tv, &tz); // 获取当前时间
// 返回以微秒为单位的时间
return (tv.tv_sec * 1000000ULL) + tv.tv_usec; return (tv.tv_sec * 1000000ULL) + tv.tv_usec;
} }
/* 获取CPU使用时间以微秒为单位。 */
/* Get CPU usage in microseconds. */
static u64 get_cpu_usage_us(void) { static u64 get_cpu_usage_us(void) {
struct rusage u; struct rusage u; // 用于存储进程资源使用情况
getrusage(RUSAGE_SELF, &u); getrusage(RUSAGE_SELF, &u); // 获取当前进程的资源使用情况
// 返回用户态和内核态CPU使用时间之和以微秒为单位
return (u.ru_utime.tv_sec * 1000000ULL) + u.ru_utime.tv_usec + return (u.ru_utime.tv_sec * 1000000ULL) + u.ru_utime.tv_usec +
(u.ru_stime.tv_sec * 1000000ULL) + u.ru_stime.tv_usec; (u.ru_stime.tv_sec * 1000000ULL) + u.ru_stime.tv_usec;
} }
/* 测量抢占率。 */
/* Measure preemption rate. */
static u32 measure_preemption(u32 target_ms) { static u32 measure_preemption(u32 target_ms) {
static volatile u32 v1, v2; static volatile u32 v1, v2; // 定义两个静态易失变量用于循环计数
u64 st_t, en_t, st_c, en_c, real_delta, slice_delta; u64 st_t, en_t, st_c, en_c, real_delta, slice_delta; // 定义时间变量
s32 loop_repeats = 0; s32 loop_repeats = 0; // 定义循环重复次数
st_t = get_cur_time_us(); st_t = get_cur_time_us(); // 获取开始时间
st_c = get_cpu_usage_us(); st_c = get_cpu_usage_us(); // 获取开始时的CPU使用时间
repeat_loop: repeat_loop: // 定义循环标签
v1 = CTEST_BUSY_CYCLES; v1 = CTEST_BUSY_CYCLES; // 设置v1为循环次数
// 循环v1次每次v2自增1模拟CPU繁忙
while (v1--) v2++; while (v1--) v2++;
sched_yield(); sched_yield(); // 让出CPU允许其他进程运行
en_t = get_cur_time_us(); en_t = get_cur_time_us(); // 获取结束时间
// 如果实际运行时间小于目标时间,则增加循环次数并继续循环
if (en_t - st_t < target_ms * 1000) { if (en_t - st_t < target_ms * 1000) {
loop_repeats++; loop_repeats++;
goto repeat_loop; goto repeat_loop;
} }
/* Let's see what percentage of this time we actually had a chance to // 获取结束时的CPU使用时间
run, and how much time was spent in the penalty box. */
en_c = get_cpu_usage_us(); en_c = get_cpu_usage_us();
// 计算实际运行时间(以毫秒为单位)
real_delta = (en_t - st_t) / 1000; real_delta = (en_t - st_t) / 1000;
// 计算CPU使用时间以毫秒为单位
slice_delta = (en_c - st_c) / 1000; slice_delta = (en_c - st_c) / 1000;
// 返回实际运行时间占CPU使用时间的百分比作为抢占率
return real_delta * 100 / slice_delta; return real_delta * 100 / slice_delta;
} }
/* 进行基准测试。 */
/* Do the benchmark thing. */
int main(int argc, char** argv) { int main(int argc, char** argv) {
#ifdef HAVE_AFFINITY #ifdef HAVE_AFFINITY // 如果支持AFFINITY设置进程CPU亲和性
u32 cpu_cnt = sysconf(_SC_NPROCESSORS_ONLN), u32 cpu_cnt = sysconf(_SC_NPROCESSORS_ONLN), // 获取CPU核心数
idle_cpus = 0, maybe_cpus = 0, i; idle_cpus = 0, maybe_cpus = 0, i; // 初始化空闲和可能可用的CPU核心数
SAYF(cCYA "afl-gotcpu " cBRI VERSION cRST " by <lcamtuf@google.com>\n"); SAYF(cCYA "afl-gotcpu " cBRI VERSION cRST " by <lcamtuf@google.com>\n"); // 输出程序信息
// 输出测量核心抢占率的信息,包括预计所需时间
ACTF("Measuring per-core preemption rate (this will take %0.02f sec)...", ACTF("Measuring per-core preemption rate (this will take %0.02f sec)...",
((double)CTEST_CORE_TRG_MS) / 1000); ((double)CTEST_CORE_TRG_MS) / 1000);
// 对每个CPU核心进行抢占率测量
for (i = 0; i < cpu_cnt; i++) { for (i = 0; i < cpu_cnt; i++) {
s32 fr = fork(); s32 fr = fork(); // 创建子进程
if (fr < 0) PFATAL("fork failed"); if (fr < 0) PFATAL("fork failed"); // 如果fork失败则输出错误信息
if (!fr) { if (!fr) { // 子进程中
cpu_set_t c; cpu_set_t c; // 定义CPU亲和性集合
u32 util_perc; u32 util_perc; // 定义CPU利用率
CPU_ZERO(&c); CPU_ZERO(&c); // 清空CPU亲和性集合
CPU_SET(i, &c); CPU_SET(i, &c); // 设置亲和性为当前核心
// 设置进程亲和性到指定的核心
if (sched_setaffinity(0, sizeof(c), &c)) if (sched_setaffinity(0, sizeof(c), &c))
PFATAL("sched_setaffinity failed for cpu %d", i); PFATAL("sched_setaffinity failed for cpu %d", i);
util_perc = measure_preemption(CTEST_CORE_TRG_MS); util_perc = measure_preemption(CTEST_CORE_TRG_MS); // 测量抢占率
// 根据抢占率输出核心状态
if (util_perc < 110) { if (util_perc < 110) {
SAYF(" Core #%u: " cLGN "AVAILABLE " cRST "(%u%%)\n", i, util_perc); SAYF(" Core #%u: " cLGN "AVAILABLE " cRST "(%u%%)\n", i, util_perc);
@ -175,18 +179,21 @@ int main(int argc, char** argv) {
} }
// 等待所有子进程结束,并统计结果
for (i = 0; i < cpu_cnt; i++) { for (i = 0; i < cpu_cnt; i++) {
int ret; int ret;
if (waitpid(-1, &ret, 0) < 0) PFATAL("waitpid failed"); if (waitpid(-1, &ret, 0) < 0) PFATAL("waitpid failed"); // 等待子进程结束
// 根据子进程退出状态判断核心是否可用
if (WEXITSTATUS(ret) == 0) idle_cpus++; if (WEXITSTATUS(ret) == 0) idle_cpus++;
if (WEXITSTATUS(ret) <= 1) maybe_cpus++; if (WEXITSTATUS(ret) <= 1) maybe_cpus++;
} }
SAYF(cGRA "\n>>> "); SAYF(cGRA "\n>>> "); // 输出结果标题
// 根据统计结果输出最终判断
if (idle_cpus) { if (idle_cpus) {
if (maybe_cpus == idle_cpus) { if (maybe_cpus == idle_cpus) {
@ -201,24 +208,30 @@ int main(int argc, char** argv) {
} }
SAYF(cGRA " <<<" cRST "\n\n"); SAYF(cGRA " <<<" cRST "\n\n"); // 输出结果结束标志
return 0; return 0;
} }
// 如果有可能可用的核心,但没有完全空闲的核心
if (maybe_cpus) { if (maybe_cpus) {
SAYF(cYEL "CAUTION: " cRST "You may still have %u core%s available.", SAYF(cYEL "CAUTION: " cRST "You may still have %u core%s available.",
maybe_cpus, maybe_cpus > 1 ? "s" : ""); maybe_cpus, maybe_cpus > 1 ? "s" : "");
SAYF(cGRA " <<<" cRST "\n\n"); SAYF(cGRA " <<<" cRST "\n\n"); // 输出结果结束标志
return 1; return 1;
} }
// 如果所有核心都过载
SAYF(cLRD "FAIL: " cRST "All cores are overbooked."); SAYF(cLRD "FAIL: " cRST "All cores are overbooked.");
SAYF(cGRA " <<<" cRST "\n\n"); SAYF(cGRA " <<<" cRST "\n\n"); // 输出结果结束标志
return 2; return 2;
#endif
}
#else #else
u32 util_perc; u32 util_perc;

Loading…
Cancel
Save