首先是afl-clang-fast.c文件

里面大部分都是编译的参数,就不详细讲了,在main函数体里面可以看到主要是这三个函数

find_obj(argv[0]);edit_params(argc, argv);execvp(cc_params[0], (char**)cc_params);//execvp函数的第一个参数是要执行的文件名,第二个参数是参数列表。execvp(cc_params[0], (char**)cc_params);

edit_params

其中:edit_params:把argv的内容复制给cc_params(这个参数后面会传递给真实的cc)。

#ifdef USE_TRACE_PCcc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";cc_params[cc_par_cnt++] = "-mllvm";cc_params[cc_par_cnt++] = "-sanitizer-coverage-block-threshold=0";//'trace-pc-guard' mode:使用原生的 LLVM instrumentation callbacksWARNF("Disabling AFLGO features..\n");
#elsecc_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);//传统模式:使用afl-llvm-pass.so注入来插桩。
#endif /* ^USE_TRACE_PC */cc_params[cc_par_cnt++] = "-Qunused-arguments";/* Detect stray -v calls from ./configure scripts. *///接下来扫描参数数组,设置对应的标志位if (argc == 1 && !strcmp(argv[1], "-v")) maybe_linking = 0;

然后下面就是设置一些参数

//设置一些优化选项与对内置函数的检查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); })";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)";if (maybe_linking) {if (x_set) {//如果x_set被设置了,添加参数:-x nonecc_params[cc_par_cnt++] = "-x"; //-x代表指定字典cc_params[cc_par_cnt++] = "none";//值为None}switch (bit_mode) {//根据不同的bit_mode来设置对应的afl-llvm-rt,并检查是否可读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);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);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;

这些代码都是在afl-llvm-rt.o.c中有实现

afl-llvm-pass.so.cc

runOnModule()

,然后看那个pass文件,里面都是处理BB以及距离的,这里主要看runOnModule()函数

bool AFLCoverage::runOnModule(Module &M) {bool is_aflgo = false;bool is_aflgo_preprocessing = false;//因为要编译两次,所以这个函数也会执行两次,,第一次就是预处理,,第二次计算距离if (!TargetsFile.empty() && !DistanceFile.empty()) {FATAL("Cannot specify both '-targets' and '-distance'!");return false;}std::list<std::string> targets;std::map<std::string, int> bb_to_dis;//bb距离std::vector<std::string> basic_blocks;//第一次指定的targets,和outdir俩文件夹,第二次指定distance=distance.cfg.txtif (!TargetsFile.empty()) {//目标文件不为空,,哪个文件的多少行if (OutDirectory.empty()) {FATAL("Provide output directory '-outdir <directory>'");return false;}std::ifstream targetsfile(TargetsFile);//读取文件std::string line;while (std::getline(targetsfile, line))targets.push_back(line);//遍历共有多少个目标,放到列表里targetsfile.close();is_aflgo_preprocessing = true;//预处理阶段} else if (!DistanceFile.empty()) {std::ifstream cf(DistanceFile);if (cf.is_open()) {std::string line;while (getline(cf, line)) {std::size_t pos = line.find(",");std::string bb_name = line.substr(0, pos);//取出名字跟距离 格式: parser.c:13085,68int bb_dis = (int) (100.0 * atof(line.substr(pos + 1, line.length()).c_str()));bb_to_dis.emplace(bb_name, bb_dis);//插入map,,当键不存在时候才插入basic_blocks.push_back(bb_name);//基本块名字}cf.close();is_aflgo = true;} else {FATAL("Unable to find %s.", DistanceFile.c_str());return false;}}/* Show a banner */char be_quiet = 0;if (isatty(2) && !getenv("AFL_QUIET")) {if (is_aflgo || is_aflgo_preprocessing)SAYF(cCYA "aflgo-llvm-pass (yeah!) " cBRI VERSION cRST " (%s mode)\n",(is_aflgo_preprocessing ? "preprocessing" : "distance instrumentation"));elseSAYF(cCYA "afl-llvm-pass " cBRI VERSION cRST " by <lszekeres@google.com>\n");} else be_quiet = 1;/* Decide instrumentation ratio */char* inst_ratio_str = getenv("AFL_INST_RATIO");unsigned int inst_ratio = 100;if (inst_ratio_str) {if (sscanf(inst_ratio_str, "%u", &inst_ratio) != 1 || !inst_ratio ||inst_ratio > 100)FATAL("Bad value of AFL_INST_RATIO (must be between 1 and 100)");}/* Default: Not selective */char* is_selective_str = getenv("AFLGO_SELECTIVE");unsigned int is_selective = 0;if (is_selective_str && sscanf(is_selective_str, "%u", &is_selective) != 1)FATAL("Bad value of AFLGO_SELECTIVE (must be 0 or 1)");char* dinst_ratio_str = getenv("AFLGO_INST_RATIO");unsigned int dinst_ratio = 100;if (dinst_ratio_str) {if (sscanf(dinst_ratio_str, "%u", &dinst_ratio) != 1 || !dinst_ratio ||dinst_ratio > 100)FATAL("Bad value of AFLGO_INST_RATIO (must be between 1 and 100)");}/* Instrument all the things! */int inst_blocks = 0;//预处理阶段,也就是生成CFG文件,和一些函数名称,基本块名称信息if (is_aflgo_preprocessing) {std::ofstream bbnames(OutDirectory + "/BBnames.txt", std::ofstream::out | std::ofstream::app);std::ofstream bbcalls(OutDirectory + "/BBcalls.txt", std::ofstream::out | std::ofstream::app);std::ofstream fnames(OutDirectory + "/Fnames.txt", std::ofstream::out | std::ofstream::app);std::ofstream ftargets(OutDirectory + "/Ftargets.txt", std::ofstream::out | std::ofstream::app);/* Create dot-files directory */std::string dotfiles(OutDirectory + "/dot-files");//放CG,CFG的文件if (sys::fs::create_directory(dotfiles)) {FATAL("Could not create directory %s.", dotfiles.c_str());}for (auto &F : M) {bool has_BBs = false;std::string funcName = F.getName().str();/* Black list of function names */if (isBlacklisted(&F)) {continue;}bool is_target = false;//successors可以用来获取一个基本块的后继基本块for (auto &BB : F) {//一个函数里的所有BBstd::string bb_name("");//bbname格式:buf.c:10std::string filename;unsigned line;//这个循环是处理一个BB里面的每一行,然后写入BBname.txt,和BBcalls.txt,BBcall包含bbname和调用函数for (auto &I : BB) {getDebugLoc(&I, filename, line);//获取IR行号,名称/* Don't worry about external libs */static const std::string Xlibs("/usr/");if (filename.empty() || line == 0 || !filename.compare(0, Xlibs.size(), Xlibs))continue;if (bb_name.empty()) {std::size_t found = filename.find_last_of("/\\");if (found != std::string::npos)filename = filename.substr(found + 1);bb_name = filename + ":" + std::to_string(line);//类似 main.c : 10}if (!is_target) {for (auto &target : targets) {//从目标文件std::size_t found = target.find_last_of("/\\");//这样的反斜杠一般是用来找文件路径的if (found != std::string::npos) //目标文件格式为valid.c:2640,,,所以不存在target = target.substr(found + 1);//如果存在std::size_t pos = target.find_last_of(":");std::string target_file = target.substr(0, pos);//前面是文件名称,后面是行unsigned int target_line = atoi(target.substr(pos + 1).c_str());if (!target_file.compare(filename) && target_line == line)//用来比较找到的BB是否是是目标块is_target = true;}}if (auto *c = dyn_cast<CallInst>(&I)) {//CallInst没有复制构造函数,因为它不是按值传递的。std::size_t found = filename.find_last_of("/\\");if (found != std::string::npos)filename = filename.substr(found + 1);if (auto *CalledF = c->getCalledFunction()) {//对IR解码获得被调用函数的名称if (!isBlacklisted(CalledF))bbcalls << bb_name << "," << CalledF->getName().str() << "\n";//写入BBcall文件,格式类似:buf.c:1013,xmlBufAdd}}}//如果没有bb_name不是空的,,就设置个bb那么,然后写入文件,将has_BBs置为true;if (!bb_name.empty()) {BB.setName(bb_name + ":");if (!BB.hasName()) {std::string newname = bb_name + ":";Twine t(newname);SmallString<256> NameData;StringRef NameRef = t.toStringRef(NameData);MallocAllocator Allocator;BB.setValueName(ValueName::Create(NameRef, Allocator));}bbnames << BB.getName().str() << "\n";//写入BBnames.txt文件has_BBs = true;#ifdef AFLGO_TRACINGauto *TI = BB.getTerminator();     //获得出口                                                                                                                                                                                                    IRBuilder<> Builder(TI);Value *bbnameVal = Builder.CreateGlobalStringPtr(bb_name);//添加全局字符串Type *Args[] = {Type::getInt8PtrTy(M.getContext()) //uint8_t* bb_name};FunctionType *FTy = FunctionType::get(Type::getVoidTy(M.getContext()), Args, false);//构建函数签名,,,参数分别是:返回值类型,参数,Constant *instrumented = M.getOrInsertFunction("llvm_profiling_call", FTy);//将函数插入moduleBuilder.CreateCall(instrumented, {bbnameVal});//将bbnameVal传递给函数instrumented调用
#endif}}if (has_BBs) {/* Print CFG */std::string cfgFileName = dotfiles + "/cfg." + funcName + ".dot";std::error_code EC;raw_fd_ostream cfgFile(cfgFileName, EC, sys::fs::F_None);//打开指定的文件(cfgFileName)进行写入。如果发生错误,则将有关错误的信息输入EC,并应立即销毁这个streamif (!EC) {WriteGraph(cfgFile, &F, true);//写入图文件}if (is_target)ftargets << F.getName().str() << "\n";fnames << F.getName().str() << "\n";}}} else {/* Distance instrumentation */                                                                //距离插桩阶段LLVMContext &C = M.getContext();//获取LLVMContext,获取进程上下文IntegerType *Int8Ty  = IntegerType::getInt8Ty(C);IntegerType *Int32Ty = IntegerType::getInt32Ty(C);IntegerType *Int64Ty = IntegerType::getInt64Ty(C);#ifdef __x86_64__IntegerType *LargestType = Int64Ty;ConstantInt *MapCntLoc = ConstantInt::get(LargestType, MAP_SIZE + 8);
#elseIntegerType *LargestType = Int32Ty;ConstantInt *MapCntLoc = ConstantInt::get(LargestType, MAP_SIZE + 4);
#endifConstantInt *MapDistLoc = ConstantInt::get(LargestType, MAP_SIZE);ConstantInt *One = ConstantInt::get(LargestType, 1);/* Get globals for the SHM region and the previous location. Note that__afl_prev_loc is thread-local. */GlobalVariable *AFLMapPtr =new GlobalVariable(M, PointerType::get(Int8Ty, 0), false,GlobalValue::ExternalLinkage, 0, "__afl_area_ptr");GlobalVariable *AFLPrevLoc = new GlobalVariable(M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc",0, GlobalVariable::GeneralDynamicTLSModel, 0, false);//TLS for (auto &F : M) {int distance = -1;for (auto &BB : F) {distance = -1;/* get distance for each BB */if (is_aflgo) {std::string bb_name;for (auto &I : BB) {//找到BB里面任意一行就breakstd::string filename;unsigned line;getDebugLoc(&I, filename, line);//得到一个基本块里面的一些行if (filename.empty() || line == 0)continue;std::size_t found = filename.find_last_of("/\\");if (found != std::string::npos)filename = filename.substr(found + 1);bb_name = filename + ":" + std::to_string(line);break;}//拿到当前bb的距离,,因为同属于一个基本块的距离都是0,所以取谁都一样,,而且前面写入也是从找到的第一个if (!bb_name.empty()) {if (find(basic_blocks.begin(), basic_blocks.end(), bb_name) == basic_blocks.end()) {//判断IR里面的基本块是否在距离文件中if (is_selective)continue;} else {/* Find distance for BB */if (AFL_R(100) < dinst_ratio) {std::map<std::string,int>::iterator it;for (it = bb_to_dis.begin(); it != bb_to_dis.end(); ++it)if (it->first.compare(bb_name) == 0)//相同distance = it->second;//print("distance is %8d",distance);}}}}BasicBlock::iterator IP = BB.getFirstInsertionPt();//入口::获得插入点IRBuilder<> IRB(&(*IP));//开始插入if (AFL_R(100) >= inst_ratio) continue;//根据当前设置的插桩比率,判断是否继续插桩/* Make up cur_loc */unsigned int cur_loc = AFL_R(MAP_SIZE);//当前位置(random()) % 0xffff  ConstantInt *CurLoc = ConstantInt::get(Int32Ty, cur_loc);//随机创建当前BB的ID/* Load prev_loc */LoadInst *PrevLoc = IRB.CreateLoad(AFLPrevLoc);PrevLoc->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));Value *PrevLocCasted = IRB.CreateZExt(PrevLoc, IRB.getInt32Ty());//获取上一个基本块的ID/* Load SHM pointer */LoadInst *MapPtr = IRB.CreateLoad(AFLMapPtr);//获取共享内存的地址MapPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));Value *MapPtrIdx =IRB.CreateGEP(MapPtr, IRB.CreateXor(PrevLocCasted, CurLoc));//获取共享内存中指定index的地址/* Update bitmap */LoadInst *Counter = IRB.CreateLoad(MapPtrIdx);//获取共享内存中指定index的地址的值Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));Value *Incr = IRB.CreateAdd(Counter, ConstantInt::get(Int8Ty, 1));//该地址上对应的插桩计数器 +1IRB.CreateStore(Incr, MapPtrIdx)->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));//写入新的值,并更新共享内存/* Set prev_loc to cur_loc >> 1 */  //设置上一个位置为当前位置的一半,,可以认为也就是退回上个分叉的状态(路径区分)StoreInst *Store =IRB.CreateStore(ConstantInt::get(Int32Ty, cur_loc >> 1), AFLPrevLoc);Store->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));//插入store指令,更新 __afl_prev_locif (distance >= 0) {//有距离就将距离插桩到共享内存中ConstantInt *Distance =ConstantInt::get(LargestType, (unsigned) distance);//当前BB的距离/* Add distance to shm[MAPSIZE] */Value *MapDistPtr = IRB.CreateBitCast(IRB.CreateGEP(MapPtr, MapDistLoc), LargestType->getPointerTo());//获取指定的共享内存的地址LoadInst *MapDist = IRB.CreateLoad(MapDistPtr);//获取指定的共享内存的地址的值MapDist->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));Value *IncrDist = IRB.CreateAdd(MapDist, Distance);//插入距离IRB.CreateStore(IncrDist, MapDistPtr)->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));//写入距离,并更新内存/* Increase count at shm[MAPSIZE + (4 or 8)] */Value *MapCntPtr = IRB.CreateBitCast(IRB.CreateGEP(MapPtr, MapCntLoc), LargestType->getPointerTo());//MapCntLoc = MAP_SIZE+4 or +8LoadInst *MapCnt = IRB.CreateLoad(MapCntPtr);MapCnt->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));Value *IncrCnt = IRB.CreateAdd(MapCnt, One);IRB.CreateStore(IncrCnt, MapCntPtr)->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));}inst_blocks++;//插桩计数+1,,也是下面用来判断是否插桩的依据}//扫描下一个块}}/* Say something nice. *///quiet模式就是不打印一些东西if (!is_aflgo_preprocessing && !be_quiet) {if (!inst_blocks) WARNF("No instrumentation targets found.");else OKF("Instrumented %u locations (%s mode, ratio %u%%, dist. ratio %u%%).",inst_blocks,getenv("AFL_HARDEN")? "hardened": ((getenv("AFL_USE_ASAN") || getenv("AFL_USE_MSAN"))? "ASAN/MSAN" : "non-hardened"),inst_ratio, dinst_ratio);}return true;@[TOC]}

afl-llvm-rt.o.c

__afl_map_shm

尝试通过仅执行目标二进制文件一次来优化性能,在main()之前停止它,然后克隆此“主”进程以获取稳定提供fuzz目标。**************************/
//__afl_map_shm + __afl_start_forkserver  ==>deferred instrumentation
/* SHM setup. */
//初始化共享内存
static void __afl_map_shm(void) {u8 *id_str = getenv(SHM_ENV_VAR);//读取环境变量 SHM_ENV_VAR 获取id  #define SHM_ENV_VAR         "__AFL_SHM_ID"/* If we're running under AFL, attach to the appropriate region, replacing theearly-stage __afl_area_initial region that is needed to allow some reallyhacky .init code to work correctly in projects such as OpenSSL. */if (id_str) {u32 shm_id = atoi(id_str);__afl_area_ptr = shmat(shm_id, NULL, 0);//获取shm地址,赋给 __afl_area_ptr/* Whooooops. */if (__afl_area_ptr == (void *)-1) _exit(1);//异常则退出/* Write something into the bitmap so that even with low AFL_INST_RATIO,our parent doesn't give up on us. */__afl_area_ptr[0] = 1;//位图写入}}

__afl_start_forkserver

/* Fork server logic. */
//首先写入4字节到状态管道,通知fuzzer已经准备完成,然后根据读取控制管道的四字节通过子进程的状态,是否执行fuzz,如果子进程暂停了就重启,最后暂停了,对比一下是否运行成功
//大概就是子进程的一次fuzzer过程
static void __afl_start_forkserver(void) {static u8 tmp[4];s32 child_pid;u8  child_stopped = 0;//如果没有父进程,认为是在执行程序/* Phone home and tell the parent that we're OK. If parent isn't there,assume we're not running in forkserver mode and just execute program. */if (write(FORKSRV_FD + 1, tmp, 4) != 4) return;//写入4字节到状态管道,通知 fuzzer已准备完成 #define FORKSRV_FD          198句柄while (1) {u32 was_killed;int status;/* Wait for parent by reading from the pipe. Abort if read fails. */if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);//通过从管道中读取来等待父级。如果读取失败则中止。//当子进程超时,父进程会kill掉子进程/* If we stopped the child in persistent mode, but there was a racecondition and afl-fuzz already issued SIGKILL, write off the oldprocess. *///处于persistent mode且子进程已被killed,注销旧的进程。if (child_stopped && was_killed) {//暂停了而且被杀掉了child_stopped = 0;if (waitpid(child_pid, &status, 0) < 0) _exit(1);//waitpid会暂时停止进程的执行,直到有信号来到或子进程结束。出错了就退出}if (!child_stopped) {//暂停了而且被杀掉了//一旦被唤醒,克隆进程/* Once woken up, create a clone of our process. */child_pid = fork();//重新forkif (child_pid < 0) _exit(1);/* In child process: close fds, resume execution. */if (!child_pid) {//如果是fork的子进程close(FORKSRV_FD);//关闭句柄close(FORKSRV_FD + 1);return;//然后返回执行真正的程序}} else {//暂停了,但是没有kill/* Special handling for persistent mode: if the child is alive butcurrently stopped, simply restart it with SIGCONT. */kill(child_pid, SIGCONT);//子进程暂停了就重启它child_stopped = 0;}/* In parent process: write PID to pipe, then wait for child. */if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) _exit(1);在父进程(fork-server)中,向afl-fuzzer写4字节(子进程pid)到管道,告知fuzzer//读取子进程退出状态if (waitpid(child_pid, &status, is_persistent ? WUNTRACED : 0) < 0)_exit(1);/* In persistent mode, the child stops itself with SIGSTOP to indicatea successful run. In this case, we want to wake it up without forkingagain. *///子进程收到停止信号,此时子进程可能是停止或结束。if (WIFSTOPPED(status)) child_stopped = 1;//WIFSTOPPED(status) 宏确定返回值是否对应于一个暂停子进程,因为在 persistent mode 里子进程会通过 SIGSTOP 信号来暂停自己,并以此指示运行成功,//我们需要通过 SIGCONT信号来唤醒子进程继续执行,不需要再进行一次fuzz,/* Relay wait status to pipe, then loop back. */if (write(FORKSRV_FD + 1, &status, 4) != 4) _exit(1);//向状态管道写入4个字节,通知AFL本次执行结束}}

__afl_manual_init

以上的两个函数在这里面执行,然后这个函数又在自动初始化里面调用

void __afl_manual_init(void) {//D__AFL_INIT 在afl-clang-fast.c 268行定义static u8 init_done;if (!init_done) {//没有初始化就__afl_map_shm();//共享内存初始化。__afl_start_forkserver();//执行forkserverinit_done = 1;}}

__sanitizer_cov_trace_pc_guard

//需要设置   AFL_TRACE_PC=1
void __sanitizer_cov_trace_pc_guard(uint32_t* guard) {//该功能的主要特点是会在每个edge插入桩代码__afl_area_ptr[*guard]++;//将在每个basic block edge(边界)被调用,其实就是通过(*guard)索引到共享内存对应的计数位置,然后计数加一。
}

__sanitizer_cov_trace_pc_guard_init

//guard初始化
void __sanitizer_cov_trace_pc_guard_init(uint32_t* start, uint32_t* stop) {/***首先获取插桩的密度,并设置guard的头尾为start和stop,并设置guard指向他的值*****/u32 inst_ratio = 100;u8* x;if (start == stop || *start) return;//初始化x = getenv("AFL_INST_RATIO");if (x) inst_ratio = atoi(x);if (!inst_ratio || inst_ratio > 100) {fprintf(stderr, "[-] ERROR: Invalid AFL_INST_RATIO (must be 1-100).\n");abort();}/* Make sure that the first element in the range is always set - we use thatto avoid duplicate calls (which can happen as an artifact of the underlyingimplementation in LLVM). */*(start++) = R(MAP_SIZE - 1) + 1;//guardwhile (start < stop) {//start - end = 程序里总计的edge数if (R(100) < inst_ratio) *start = R(MAP_SIZE - 1) + 1;else *start = 0;//不插桩的地方设为0start++;}}

这以上是AFL里面原有的思想,就是deferred instrumentation , persistent mode,trace_pc_guard

writeBB llvm_profiling_call

inline __attribute__((always_inline))//强制内联,,调用函数的时候,汇编代码直接就成了被调用函数的一部分
void writeBB(const char* bbname) {strcat(edgeStr, bbname);//将bbname拼接到EdgeStr上size_t cksum=(size_t)hash32(bbname, strlen(edgeStr), 0xa5b35705);//校验和,用来判断边(BBname)唯一性的if(!hashset_is_member(edgeSet,(void*)cksum)) {//cksum不在set中fprintf(filefd, "[BB]: %s\n", bbname);//就将BB写入文件中hashset_add(edgeSet, (void*)cksum);//并且将当前的校验值加入到集合中}strcpy(edgeStr, bbname);//更新edgeStr的内容fflush(filefd);
}void llvm_profiling_call(const char* bbname)__attribute__((visibility("default")));void llvm_profiling_call(const char* bbname) {//在pass里面调用if (filefd != NULL) {//文件句柄不为空就直接写入writeBB(bbname);} else if (getenv("AFLGO_PROFILER_FILE")) {filefd = fopen(getenv("AFLGO_PROFILER_FILE"), "a+");if (filefd != NULL) {strcpy(edgeStr, "START");edgeSet = hashset_create();fprintf(filefd, "--------------------------\n");writeBB(bbname);}}
}

其中使用到的set是
AFLGO增加的一些hashset的函数,是hashset.h文件函数的实现

hashset.h

  struct hashset_st {size_t nbits;//init default :3size_t mask;//init default 7size_t capacity;//init default 1<<3 = 8size_t *items;//init default ptrsize_t nitems;//init default 0size_t n_deleted_items;//init default 0};/* create hashset instance */hashset_t hashset_create(void);//创建/* destroy hashset instance */void hashset_destroy(hashset_t set);//销毁size_t hashset_num_items(hashset_t set);//元素个数/* add item into the hashset.** @note 0 and 1 is special values, meaning nil and deleted items. the*       function will return -1 indicating error.** returns zero if the item already in the set and non-zero otherwise*/int hashset_add(hashset_t set, void *item);//(包含hashset_add_member()和maybe_rehash()):增加一个元素,值存在就不加进去,并重新给items分配空间,并把旧值放进去/* remove item from the hashset** returns non-zero if the item was removed and zero if the item wasn't* exist*/int hashset_remove(hashset_t set, void *item);//从元素中删除item,删除之后值置为1/* check if existence of the item** returns non-zero if the item exists and zero otherwise*/int hashset_is_member(hashset_t set, void *item);//item是否在set中

AFLGO插桩代码分析记录相关推荐

  1. Android 性能优化 之 插桩日志分析

    目录 为了更加精确的追踪方法调用,优化性能,可以通过 Debug 类生成插桩日志,在 Profiler 面板中导入后进行分析. 一.生成插桩日志 1. 工具类封装 2. 示例中调用 3. 模拟耗时 二 ...

  2. 动态二进制插桩原理与实战

    二进制插桩~ 说点什么 插桩是啥 为啥要插桩 源代码插桩 二进制插桩 如何插桩 两种主要方式和三种执行模式 方式1: 方式2: 第一种模式: 第二种模式: 第三种模式: 插桩实例 Pin 动态二进制插 ...

  3. vm磁盘映射 不能启动_iOS 启动优化之Clang插桩实现二进制重排

    前言 原文作者:李斌同学 原文链接:https://juejin.im/post/6844904130406793224 自从抖音团队分享了这篇 抖音研发实践:基于二进制文件重排的解决方案 APP启动 ...

  4. 字节码插桩框架ASM(一)

    本文大纲: ams是做什么的 asm使用 1.ASM是做什么的? 简单来说,asm是用来进行字节码插桩的.什么是字节码插桩? 字节码插桩就是修改节码文件(.class). 如同 gson框架是用来做操 ...

  5. linux静态插桩工具PEBIL

    文章目录 引言 论文学习 摘要及简介 设计与实现 插桩代码效率 实验结果及其他 具体使用 引言 PEBIL是San Diego Supercomputer Center某实验室研发的工具,用来对ELF ...

  6. 动态二进制插桩的原理和基本实现过程(Pin/DynamoRIO/Frida)

    英文原文全文 http://deniable.org/reversing/binary-instrumentation 译转自https://www.4hou.com/binary/13026.htm ...

  7. Android程序员的硬通货——ASM字节码插桩

    作者:享学课堂Lance老师 转载请声明出处! 一.什么是插桩 QQ空间曾经发布的<热修复解决方案>中利用 Javaassist库实现向类的构造函数中插入一段代码解决 CLASS_ISPR ...

  8. 使用插桩技术解决慢查询测试问题

    原文由zlulu发表于TesterHome社区,原文链接 缘起 前段时间,我负责测试的系统在生产环境运行出现问题.该系统对于响应时间要求较高,问题发生的时候并发很高,出现大量请求超时,超时请求比例随时 ...

  9. java 插桩 工具_一个基于Eclipse的通用Java程序插桩工具.pdf

    第38卷第7期 计算机科学 V01.38NO.7 Science 2011 2011年7月 Computer July 一个基于Eclipse的通用Java程序插桩工具 郑晓梅 (南京中医药大学信息技 ...

  10. 【网上的都不靠谱?还是得改源码】用Javasisst的字节码插桩技术,彻底解决Gson转Map时,Int变成double问题...

    一.探究原由 首先申明一下,我们要解决的问题有两个: Json串转Map时,int变double问题 Json串转对象时,对象属性中的Map,int变double问题 然后,我们来了解一下,Gson实 ...

最新文章

  1. 微信小游戏开发教程-2D游戏原理讲解
  2. HttpModule与HttpHandler详解(转)
  3. spring中的BeanPostProcessor
  4. PS亮度蒙版扩展插件:Lumenzia for Mac 支持ps2021
  5. 计算机主机内有哪些部件常用的,智慧职教: 计算机系统由什么组成?计算机主机内有哪些部件?常用的计算机外设有哪些...
  6. 【flink】RocksDB介绍以及Flink对RocksDB的支持
  7. matlab中的count函数,Excel 中COUNT函数的使用详解,详情介绍
  8. java基础之static
  9. Atitit.异常机制的设计原理
  10. 【专题】CSDN下载频道3月热门资源top100汇总
  11. ISO27001:2013体系认证
  12. linux命令行启动新终端,12个让您震撼的Linux终端命令
  13. 远程计算机上不接受445端口,服务器禁止远程445端口
  14. 【经典递归问题 汉诺塔 求解】
  15. 记录Win10因为管理员权限而出现的访问COM口被占用的问题
  16. HTML5 小组 北京站 沙龙
  17. 张成分析(spanning test):portfolio_analysis.Spanning_test
  18. 将中国标准时间转化为yyyy-MM-dd 00:00:00格式
  19. 轨迹规划-贝塞尔曲线
  20. ❤️数据可视化❤️:基于Echarts + GeoJson实现的地图视觉映射散点(气泡)组件【15】 - 江西省

热门文章

  1. Matlab fftshift 详解
  2. 基于MATLAB的幂级数求和与展开(Taylor和Fourier算法)
  3. 无线打印机服务器安装教程,网络打印服务器怎么安装和使用?
  4. 记一次rm -rf之后的数据恢复操作
  5. 拉格朗日插值的优缺点_拉格朗日插值法与牛顿插值法比较
  6. 词根词缀学单词/优秀词典推荐
  7. 利用poi3.8中SXSSFWorkbook实现大数据量导出excel
  8. jsp页面中插入jsp代码片段
  9. python数学实验与建模pdf_Python数学实验与建模(4)
  10. 克拉克变换(Clarke Transformation)