You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
google_AFL/src/llvm_mode/afl-clang-fast.c

605 lines
23 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
Copyright 2015 Google LLC All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
american fuzzy lop - LLVM-mode wrapper for clang
------------------------------------------------
Written by Laszlo Szekeres <lszekeres@google.com> and
Michal Zalewski <lcamtuf@google.com>
LLVM integration design comes from Laszlo Szekeres.
This program is a drop-in replacement for clang, similar in most respects
to ../afl-gcc. It tries to figure out compilation mode, adds a bunch
of flags, and then calls the real compiler.
*/
#define AFL_MAIN
#include "../config.h"
#include "../types.h"
#include "../debug.h"
#include "../alloc-inl.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
static u8* obj_path; /* Path to runtime libraries */
static u8** cc_params; /* Parameters passed to the real CC */
static u32 cc_par_cnt = 1; /* Param count, including argv0 */
/*
尝试查找运行时库。如果失败,则中止程序。
*/
static void find_obj(u8* argv0) {
u8 *afl_path = getenv("AFL_PATH"); // 获取环境变量 AFL_PATH 的值
u8 *slash, *tmp; // 定义用于存储路径分隔符和临时路径的变量
if (afl_path) { // 如果 AFL_PATH 环境变量存在
tmp = alloc_printf("%s/afl-llvm-rt.o", afl_path); // 构造运行时库的路径
if (!access(tmp, R_OK)) { // 检查路径是否可读
obj_path = afl_path; // 如果可读,设置 obj_path 为 AFL_PATH
ck_free(tmp); // 释放临时路径的内存
return; // 返回,结束函数
}
ck_free(tmp); // 如果路径不可读,释放临时路径的内存
}
slash = strrchr(argv0, '/'); // 查找 argv0 中最后一个斜杠的位置
if (slash) { // 如果找到斜杠
u8 *dir; // 定义用于存储目录路径的变量
*slash = 0; // 将斜杠位置置为字符串结束符,以便提取目录路径
dir = ck_strdup(argv0); // 复制 argv0 的目录路径
*slash = '/'; // 恢复斜杠
tmp = alloc_printf("%s/afl-llvm-rt.o", dir); // 构造运行时库的路径
if (!access(tmp, R_OK)) { // 检查路径是否可读
obj_path = dir; // 如果可读,设置 obj_path 为当前目录
ck_free(tmp); // 释放临时路径的内存
return; // 返回,结束函数
}
ck_free(tmp); // 如果路径不可读,释放临时路径的内存
ck_free(dir); // 释放目录路径的内存
}
// 检查默认的 AFL_PATH 目录下是否存在 'afl-llvm-rt.o' 文件
if (!access(AFL_PATH "/afl-llvm-rt.o", R_OK)) {
obj_path = AFL_PATH; // 如果存在,设置 obj_path 为 AFL_PATH
return; // 返回,结束函数
}
// 如果以上方法都未找到运行时库,抛出致命错误
FATAL("Unable to find 'afl-llvm-rt.o' or 'afl-llvm-pass.so'. Please set AFL_PATH");
}
/*
复制 argv 到 cc_params并进行必要的编辑。
*/
static void edit_params(u32 argc, char** argv) {
u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0; // 初始化标志变量
u8 *name; // 定义用于存储程序名的变量
// 为 cc_params 分配足够的内存,以容纳传入的参数加上额外的空间
cc_params = ck_alloc((argc + 128) * sizeof(u8*));
// 提取程序名
name = strrchr(argv[0], '/'); // 查找 argv0 中最后一个斜杠的位置
if (!name) name = argv[0]; else name++; // 如果没有斜杠,使用完整的 argv[0]
// 根据程序名确定使用的编译器
if (!strcmp(name, "afl-clang-fast++")) { // 如果程序名是 afl-clang-fast++
u8* alt_cxx = getenv("AFL_CXX"); // 获取环境变量 AFL_CXX 的值
cc_params[0] = alt_cxx ? alt_cxx : (u8*)"clang++"; // 如果存在则使用其值,否则默认使用 clang++
} else { // 如果程序名不是 afl-clang-fast++
u8* alt_cc = getenv("AFL_CC"); // 获取环境变量 AFL_CC 的值
cc_params[0] = alt_cc ? alt_cc : (u8*)"clang"; // 如果存在则使用其值,否则默认使用 clang
}
#ifdef USE_TRACE_PC // 如果定义了 USE_TRACE_PC
// 添加用于 sanitization 的覆盖率参数
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard"; // 启用 trace-pc-guard 插桩
#ifndef __ANDROID__ // 如果不是 Android 平台
cc_params[cc_par_cnt++] = "-mllvm"; // 添加 LLVM 相关参数
cc_params[cc_par_cnt++] = "-sanitizer-coverage-block-threshold=0"; // 设置目标覆盖率的阈值为 0
#endif
#else // 如果没有定义 USE_TRACE_PC
// 添加 LLVM 插件的加载参数
cc_params[cc_par_cnt++] = "-Xclang"; // 添加 Clang 参数
cc_params[cc_par_cnt++] = "-load"; // 指定加载插件
cc_params[cc_par_cnt++] = "-Xclang"; // 添加 Clang 参数
cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-pass.so", obj_path);
// 追加 AFL 关键依赖项 afl-llvm-pass.so 到 cc_params用于插桩分析
#endif /* ^USE_TRACE_PC */
cc_params[cc_par_cnt++] = "-Qunused-arguments";
// 添加一个参数,告诉编译器忽略未使用的命令行参数
while (--argc) { // 循环处理剩余的命令行参数
u8* cur = *(++argv); // 获取当前参数
if (!strcmp(cur, "-m32")) bit_mode = 32; // 如果参数是 -m32设置 bit_mode 为 32
if (!strcmp(cur, "armv7a-linux-androideabi")) bit_mode = 32; // 针对特定架构的设置
if (!strcmp(cur, "-m64")) bit_mode = 64; // 如果参数是 -m64设置 bit_mode 为 64
if (!strcmp(cur, "-x")) x_set = 1; // 如果参数为 -x设置 x_set 为 1表示启用此选项
// 检查是否使用地址或内存的安全检测
if (!strcmp(cur, "-fsanitize=address") ||
!strcmp(cur, "-fsanitize=memory")) asan_set = 1;
// 检查是否启用了 FORTIFY_SOURCE
if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1;
// 如果链接器选项是 -Wl,-z,defs 或 -Wl,--no-undefined跳过该参数
if (!strcmp(cur, "-Wl,-z,defs") ||
!strcmp(cur, "-Wl,--no-undefined")) continue;
cc_params[cc_par_cnt++] = cur; // 将当前参数添加到 cc_params
}
// 如果环境变量 AFL_HARDEN 存在
if (getenv("AFL_HARDEN")) {
cc_params[cc_par_cnt++] = "-fstack-protector-all"; // 启用所有堆栈保护
// 如果未启用 FORTIFY_SOURCE添加定义以启用其功能
if (!fortify_set)
cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2";
}
// 如果尚未启用 AddressSanitizer
if (!asan_set) {
// 检查是否设置了使用 AddressSanitizer 的环境变量
if (getenv("AFL_USE_ASAN")) {
// 检查 MSAN 和 ASAN 互斥
if (getenv("AFL_USE_MSAN"))
FATAL("ASAN and MSAN are mutually exclusive");
// 检查 AFL_HARDEN 是否与 ASAN 互斥
if (getenv("AFL_HARDEN"))
FATAL("ASAN and AFL_HARDEN are mutually exclusive");
cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE"; // 取消定义 FORTIFY_SOURCE
cc_params[cc_par_cnt++] = "-fsanitize=address"; // 启用 AddressSanitizer
}
// 检查是否设置了使用 MemorySanitizer 的环境变量
else if (getenv("AFL_USE_MSAN")) {
// 检查 ASAN 和 MSAN 互斥
if (getenv("AFL_USE_ASAN"))
FATAL("ASAN and MSAN are mutually exclusive");
// 检查 AFL_HARDEN 是否与 MSAN 互斥
if (getenv("AFL_HARDEN"))
FATAL("MSAN and AFL_HARDEN are mutually exclusive");
cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE"; // 取消定义 FORTIFY_SOURCE
cc_params[cc_par_cnt++] = "-fsanitize=memory"; // 启用 MemorySanitizer
}
}
// 如果定义了 USE_TRACE_PC
#ifdef USE_TRACE_PC
// 检查 AFL_INST_RATIO 环境变量是否可用
if (getenv("AFL_INST_RATIO"))
FATAL("AFL_INST_RATIO not available at compile time with 'trace-pc'.");
#endif /* USE_TRACE_PC */
// 如果未设置 AFL_DONT_OPTIMIZE则启用优化选项
if (!getenv("AFL_DONT_OPTIMIZE")) {
cc_params[cc_par_cnt++] = "-g"; // 添加调试信息
cc_params[cc_par_cnt++] = "-O3"; // 启用高优化级别
cc_params[cc_par_cnt++] = "-funroll-loops"; // 启用循环展开
}
// 如果设置了 AFL_NO_BUILTIN则禁用特定的内置函数
if (getenv("AFL_NO_BUILTIN")) {
cc_params[cc_par_cnt++] = "-fno-builtin-strcmp"; // 禁用 strcmp 的内置实现
cc_params[cc_par_cnt++] = "-fno-builtin-strncmp"; // 禁用 strncmp 的内置实现
cc_params[cc_par_cnt++] = "-fno-builtin-strcasecmp"; // 禁用 strcasecmp 的内置实现
cc_params[cc_par_cnt++] = "-fno-builtin-strncasecmp"; // 禁用 strncasecmp 的内置实现
cc_params[cc_par_cnt++] = "-fno-builtin-memcmp"; // 禁用 memcmp 的内置实现
}
// 添加 AFL 控制宏,确保手动控制和编译器的定义
cc_params[cc_par_cnt++] = "-D__AFL_HAVE_MANUAL_CONTROL=1"; // 指示支持手动控制
cc_params[cc_par_cnt++] = "-D__AFL_COMPILER=1"; // 编译器标识
cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1"; // 表示为不安全的生产模式
/*
当用户尝试通过在程序末尾添加单行来使用持久化或延迟的 forkserver 模式时,
我们想可靠地将签名注入二进制文件 (以便被 afl-fuzz 拿到)
并想调用运行时 .o 文件中的函数。由于以下三个原因,这非常复杂:
1) 我们需要说服编译器不要优化掉签名。
这是利用 __attribute__((used)) 实现的。
2) 我们需要说服链接器,在调用 -Wl,--gc-sections 时,
不要做同样的事情。 这是通过强制赋值给 'volatile' 指针来实现的。
3) 我们需要在全局命名空间中声明 __afl_persistent_loop()
但在类的方法中做到这一点是困难的 - :: 和 extern "C"
是禁止的,且 __attribute__((alias(...))) 无效。因此使用了 __asm__ 别名技巧。
*/
// 定义一个宏,用于处理 AFL 循环的持久化
cc_params[cc_par_cnt++] = "-D__AFL_LOOP(_A)="
// 开始一个代码块,其中静态的、易失的字符指针用于存放持久化的信号
"({ static volatile char *_B __attribute__((used)); "
" _B = (char*)\"" PERSIST_SIG "\"; "; // 将持久化信号字符串赋值给指针 _B
#ifdef __APPLE__ // 根据系统平台选择合适的函数名称
"__attribute__((visibility(\"default\"))) "
"int _L(unsigned int) __asm__(\"___afl_persistent_loop\"); " // Apple 平台下的持久化函数
#else
"__attribute__((visibility(\"default\"))) "
"int _L(unsigned int) __asm__(\"__afl_persistent_loop\"); " // 其他平台下的持久化函数
#endif /* ^__APPLE__ */
"_L(_A); })"; // 调用持久化函数,并结束代码块
// 定义一个宏,用于初始化 AFL
cc_params[cc_par_cnt++] = "-D__AFL_INIT()="
"do { static volatile char *_A __attribute__((used)); "
" _A = (char*)\"" DEFER_SIG "\"; "; // 将延迟信号字符串赋值给指针 _A
#ifdef __APPLE__ // 根据系统平台选择合适的初始化函数名称
"__attribute__((visibility(\"default\"))) "
"void _I(void) __asm__(\"___afl_manual_init\"); " // Apple 平台下的初始化函数
#else
"__attribute__((visibility(\"default\"))) "
"void _I(void) __asm__(\"__afl_manual_init\"); " // 其他平台下的初始化函数
#endif /* ^__APPLE__ */
"_I(); } while (0)"; // 调用初始化函数,并结束循环结构
// 如果 x_set 被设置,添加参数来指示关闭类型检查
if (x_set) {
cc_params[cc_par_cnt++] = "-x"; // 添加-x参数
cc_params[cc_par_cnt++] = "none"; // 指示后续没有特定类型
}
// 如果不是在 Android 平台下
#ifndef __ANDROID__
switch (bit_mode) { // 根据位数选择合适的运行时库
case 0: // 如果未设置位模式
cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt.o", obj_path); // 使用默认的 afl-llvm-rt.o 路径
break;
case 32: // 如果设置了 32 位模式
cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-32.o", obj_path); // 使用 32 位运行时库路径
// 检查路径是否可读,如果不可读则抛出错误
if (access(cc_params[cc_par_cnt - 1], R_OK))
FATAL("-m32 is not supported by your compiler"); // 抛出错误信息
break;
case 64: // 如果设置了 64 位模式
cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-64.o", obj_path); // 使用 64 位运行时库路径
/* 查找运行时库的路径。如果找不到,则中止程序。 */
static void find_obj(u8* argv0) {
// 获取环境变量 AFL_PATH
u8 *afl_path = getenv("AFL_PATH");
u8 *slash, *tmp;
// 如果找到 AFL_PATH
if (afl_path) {
// 生成 afl-llvm-rt.o 的完整路径
tmp = alloc_printf("%s/afl-llvm-rt.o", afl_path);
// 检查文件是否可读
if (!access(tmp, R_OK)) {
obj_path = afl_path; // 设置对象路径为 AFL_PATH
ck_free(tmp); // 释放临时路径内存
return; // 找到文件,结束函数
}
ck_free(tmp); // 释放临时路径内存
}
// 查找 argv0 中最后一个 '/' 的位置
slash = strrchr(argv0, '/');
// 如果找到 '/'
if (slash) {
u8 *dir;
*slash = 0; // 将 '/' 替换为结束符,以获取目录
dir = ck_strdup(argv0); // 复制目录名
*slash = '/'; // 恢复原来的 '/' 字符
// 生成 afl-llvm-rt.o 的完整路径
tmp = alloc_printf("%s/afl-llvm-rt.o", dir);
// 检查文件是否可读
if (!access(tmp, R_OK)) {
obj_path = dir; // 设置对象路径为找到的目录
ck_free(tmp); // 释放临时路径内存
return; // 找到文件,结束函数
}
ck_free(tmp); // 释放临时路径内存
ck_free(dir); // 释放目录名内存
}
// 检查默认路径下的 afl-llvm-rt.o 是否可读
if (!access(AFL_PATH "/afl-llvm-rt.o", R_OK)) {
obj_path = AFL_PATH; // 设置对象路径为默认的 AFL_PATH
return; // 找到文件,结束函数
}
// 如果都找不到,则抛出致命错误
FATAL("Unable to find 'afl-llvm-rt.o' or 'afl-llvm-pass.so'. Please set AFL_PATH");
}
/* 复制 argv 到 cc_params并进行必要的编辑。 */
static void edit_params(u32 argc, char** argv) {
// 初始化标志变量
u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0;
u8 *name;
// 分配空间以存储参数
cc_params = ck_alloc((argc + 128) * sizeof(u8*));
// 获取执行的程序名称
name = strrchr(argv[0], '/');
if (!name) name = argv[0]; else name++;
// 根据程序名称选择合适的编译器
if (!strcmp(name, "afl-clang-fast++")) {
u8* alt_cxx = getenv("AFL_CXX"); // 获取环境变量 AFL_CXX
cc_params[0] = alt_cxx ? alt_cxx : (u8*)"clang++"; // 设置 C++ 编译器
} else {
u8* alt_cc = getenv("AFL_CC"); // 获取环境变量 AFL_CC
cc_params[0] = alt_cc ? alt_cc : (u8*)"clang"; // 设置 C 编译器
}
#ifdef USE_TRACE_PC
// 启用跟踪 PC 的覆盖率
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
#ifndef __ANDROID__
cc_params[cc_par_cnt++] = "-mllvm"; // LLVM 选项
cc_params[cc_par_cnt++] = "-sanitizer-coverage-block-threshold=0"; // 设定阈值
#endif
#else
// 加载 afl-llvm-pass.so 插件
cc_params[cc_par_cnt++] = "-Xclang";
cc_params[cc_par_cnt++] = "-load";
cc_params[cc_par_cnt++] = "-Xclang";
cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-pass.so", obj_path);
#endif /* ^USE_TRACE_PC */
cc_params[cc_par_cnt++] = "-Qunused-arguments"; // 忽略未使用的参数
// 循环处理输入参数
while (--argc) {
u8* cur = *(++argv); // 获取当前参数
// 检查位模式
if (!strcmp(cur, "-m32")) bit_mode = 32;
if (!strcmp(cur, "armv7a-linux-androideabi")) bit_mode = 32;
if (!strcmp(cur, "-m64")) bit_mode = 64;
// 检查其他编译选项
if (!strcmp(cur, "-x")) x_set = 1;
// 检查是否启用地址/内存的 sanitization
if (!strcmp(cur, "-fsanitize=address") ||
!strcmp(cur, "-fsanitize=memory")) asan_set = 1;
// 检查 FORTIFY_SOURCE 是否启用
if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1;
// 跳过某些链接器选项
if (!strcmp(cur, "-Wl,-z,defs") ||
!strcmp(cur, "-Wl,--no-undefined")) continue;
// 将当前参数添加到 cc_params
cc_params[cc_par_cnt++] = cur;
}
// 如果启用了硬化选项
if (getenv("AFL_HARDEN")) {
cc_params[cc_par_cnt++] = "-fstack-protector-all"; // 启用栈保护
// 如果没有启用 FORTIFY_SOURCE 则添加对应宏定义
if (!fortify_set)
cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2";
}
// 检查地址或内存 sanitization 的设置
if (!asan_set) {
if (getenv("AFL_USE_ASAN")) {
if (getenv("AFL_USE_MSAN"))
FATAL("ASAN and MSAN are mutually exclusive"); // 互斥检查
if (getenv("AFL_HARDEN"))
FATAL("ASAN and AFL_HARDEN are mutually exclusive"); // 互斥检查
cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE"; // 禁用 FORTIFY_SOURCE
cc_params[cc_par_cnt++] = "-fsanitize=address"; // 启用地址条件检测
} else if (getenv("AFL_USE_MSAN")) {
if (getenv("AFL_USE_ASAN"))
FATAL("ASAN and MSAN are mutually exclusive"); // 互斥检查
if (getenv("AFL_HARDEN"))
FATAL("MSAN and AFL_HARDEN are mutually exclusive"); // 互斥检查
cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE"; // 禁用 FORTIFY_SOURCE
cc_params[cc_par_cnt++] = "-fsanitize=memory"; // 启用内存条件检测
}
}
#ifdef USE_TRACE_PC
// 检查 AFL_INST_RATIO 环境变量的设置
if (getenv("AFL_INST_RATIO"))
FATAL("AFL_INST_RATIO not available at compile time with 'trace-pc'.");
#endif /* USE_TRACE_PC */
// 检查是否不优化
if (!getenv("AFL_DONT_OPTIMIZE")) {
cc_params[cc_par_cnt++] = "-g"; // 启用调试信息
cc_params[cc_par_cnt++] = "-O3"; // 启用最高级别的优化
cc_params[cc_par_cnt++] = "-funroll-loops"; // 循环展开以提高性能
}
// 检查是否禁用内置函数的使用
if (getenv("AFL_NO_BUILTIN")) {
// 禁用特定的内置字符串比较和内存比较函数
cc_params[cc_par_cnt++] = "-fno-builtin-strcmp";
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-memcmp";
}
// 添加 AFL 相关的宏定义
cc_params[cc_par_cnt++] = "-D__AFL_HAVE_MANUAL_CONTROL=1"; // 手动控制
cc_params[cc_par_cnt++] = "-D__AFL_COMPILER=1"; // 标记为 AFL 编译器
cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1"; // 不适合生产的模糊构建模式
// 添加 AFL 循环的实现
cc_params[cc_par_cnt++] = "-D__AFL_LOOP(_A)="
"({ static volatile char *_B __attribute__((used)); "
" _B = (char*)\"" PERSIST_SIG "\"; "
#ifdef __APPLE__
"__attribute__((visibility(\"default\"))) "
"int _L(unsigned int) __asm__(\"___afl_persistent_loop\"); "
#else
"__attribute__((visibility(\"default\"))) "
"int _L(unsigned int) __asm__(\"__afl_persistent_loop\"); "
#endif /* ^__APPLE__ */
"_L(_A); })"; // 定义 AFL 循环的宏
// 添加 AFL 初始化函数的实现
cc_params[cc_par_cnt++] = "-D__AFL_INIT()="
"do { static volatile char *_A __attribute__((used)); "
" _A = (char*)\"" DEFER_SIG "\"; "
#ifdef __APPLE__
"__attribute__((visibility(\"default\"))) "
"void _I(void) __asm__(\"___afl_manual_init\"); "
#else
"__attribute__((visibility(\"default\"))) "
"void _I(void) __asm__(\"__afl_manual_init\"); "
#endif /* ^__APPLE__ */
"_I(); } while (0)"; // 定义 AFL 初始化的宏
// 如果启用 -x 选项
if (x_set) {
cc_params[cc_par_cnt++] = "-x"; // 添加 -x 选项
cc_params[cc_par_cnt++] = "none"; // 设置为 none表示不对输入进行特定语言解析
}
#ifndef __ANDROID__
// 根据位模式选择不同的运行时库文件
switch (bit_mode) {
case 0:
cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt.o", obj_path); // 默认情况下使用通用的运行时文件
break;
case 32:
cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-32.o", obj_path); // 使用 32 位版本的运行时文件
// 检查此文件是否可读
if (access(cc_params[cc_par_cnt - 1], R_OK))
FATAL("-m32 is not supported by your compiler"); // 如果不可读则报错
break;
case 64:
cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-64.o", obj_path); // 使用 64 位版本的运行时文件
// 检查此文件是否可读
if (access(cc_params[cc_par_cnt - 1], R_OK))
FATAL("-m64 is not supported by your compiler"); // 如果不可读则报错
break;
}
// 结束参数数组,以空指针结尾
cc_params[cc_par_cnt] = NULL;
/* 主入口点 */
int main(int argc, char** argv) {
// 检查标准错误是否连接到终端且 AFL_QUIET 环境变量未设置
if (isatty(2) && !getenv("AFL_QUIET")) {
#ifdef USE_TRACE_PC
// 如果启用了 USE_TRACE_PC打印版本信息
SAYF(cCYA "afl-clang-fast [tpcg] " cBRI VERSION cRST " by <lszekeres@google.com>\n");
#else
// 否则,仅打印版本信息
SAYF(cCYA "afl-clang-fast " cBRI VERSION cRST " by <lszekeres@google.com>\n");
#endif /* ^USE_TRACE_PC */
}
// 如果参数数量小于 2打印帮助信息并退出
if (argc < 2) {
SAYF("\n"
"This is a helper application for afl-fuzz. It serves as a drop-in replacement\n"
"for clang, letting you recompile third-party code with the required runtime\n"
"instrumentation. A common use pattern would be one of the following:\n\n"
" CC=%s/afl-clang-fast ./configure\n"
" CXX=%s/afl-clang-fast++ ./configure\n\n"
"In contrast to the traditional afl-clang tool, this version is implemented as\n"
"an LLVM pass and tends to offer improved performance with slow programs.\n\n"
"You can specify custom next-stage toolchain via AFL_CC and AFL_CXX. Setting\n"
"AFL_HARDEN enables hardening optimizations in the compiled code.\n\n",
BIN_PATH, BIN_PATH);
exit(1); // 退出程序,返回错误码 1
}
#ifndef __ANDROID__
// 在非 Android 平台下调用 find_obj 函数查找运行时库
find_obj(argv[0]);
#endif
// 调用 edit_params 函数处理命令行参数并设置编译参数
edit_params(argc, argv);
// 使用 execvp 执行指定的编译器命令
execvp(cc_params[0], (char**)cc_params);
// 如果 execvp 失败,抛出致命错误并打印相关信息
FATAL("Oops, failed to execute '%s' - check your PATH", cc_params[0]);
return 0; // 正常结束程序
}