zoukankan      html  css  js  c++  java
  • KLEE——main.cpp

    初识程序分析的小白,后续将有更多KLEE的代码笔记,想要交流请绑定~
    转载请注明出处:https://www.cnblogs.com/linkJ/
    从main函数开始,分析KLEE的执行流程
    主要函数笔记:

    int main(int argc, char **argv, char **envp) {
    atexit(llvm_shutdown);  // Call llvm_shutdown() on exit.
    
    llvm::InitializeNativeTarget();
    
    parseArguments(argc, argv);//在屏幕打印klee的版本以及输入的命令行参数
      sys::PrintStackTraceOnErrorSignal();
    
      if (Watchdog) {
    //当指定-maxtime的时候,用Watchdog来监控执行的时间
    }
      sys::SetInterruptFunction(interrupt_handle);//当ctrl-c的时候,运行终止
      // Load the bytecode...
      std::string errorMsg;
      LLVMContext ctx;
      Module *mainModule = klee::loadModule(ctx, InputFile, errorMsg);//读取输入的.bc
      if (WithPOSIXRuntime) {//指定了posixruntime就
        int r = initEnv(mainModule);//对入口函数的参数和环境信息进行初始化
        if (r != 0)
          return r;
      }
      std::string LibraryDir = KleeHandler::getRunTimeLibraryPath(argv[0]);//获取RuntimeLibraryPath
      Interpreter::ModuleOptions Opts(LibraryDir.c_str(), EntryPoint,//对Module进行一些操作
                                      /*Optimize=*/OptimizeModule,
                                      /*CheckDivZero=*/CheckDivZero,
                                      /*CheckOvershift=*/CheckOvershift);
    
      switch (Libc) {//根据对libc参数的指定来链接相应的库
      case NoLibc: /* silence compiler warning */
      case KleeLibc:
      case UcLibc:
        mainModule = linkWithUclibc(mainModule, LibraryDir);
        break;
      }
      if (WithPOSIXRuntime) {
        //mianModule链接相应的posix-runtime库
      }
      // Get the desired main function.  klee_main initializes uClibc
      // locale and other data and then calls main.
      Function *mainFn = mainModule->getFunction(EntryPoint);//获取入口函数为mainFn
    //argc以及argv的复制
      std::vector<bool> replayPath;
    
      if (ReplayPathFile != "") {
        KleeHandler::loadPathFile(ReplayPathFile, replayPath);
      }
    
      Interpreter::InterpreterOptions IOpts;
      IOpts.MakeConcreteSymbolic = MakeConcreteSymbolic;//确认是否正确对具体程序符号化
    //创建handler,interpreter,并setInterpreter
      KleeHandler *handler = new KleeHandler(pArgc, pArgv);
      Interpreter *interpreter =
        theInterpreter = Interpreter::create(ctx, IOpts, handler);//返回Executor(ctx,IOpts,handler)
      handler->setInterpreter(interpreter);//打印参数、PID信息到info文件
      const Module *finalModule =
        interpreter->setModule(mainModule, Opts);//调用Executor::setmodule,好像是形成了assembly.bc吧,绑定了各种信息
      externalsAndGlobalsCheck(finalModule);//对函数、基本块、指令、全局变量等进行安全性检测,类似于静态分析的感觉??
    
      if (ReplayPathFile != "") {
        interpreter->setReplayPath(&replayPath);
      }
    //打印时间信息
    //判断ReplayKTestDir和ReplayKTestFile是否为空(××di定位这些种子都是啥,谁给他的 )
    非空则
        //将所有的ReplayKTestFile中的种子都放到KTests中
        //××这里的种子是怎么给的????
        每次从KTests取一个种子进行
              interpreter->setReplayKTest(out);//确认KTest是否可用
              llvm::errs() << "KLEE: replaying: " << *it << " (" << kTest_numBytes(out)
                       << " bytes)"
                       << " (" << ++i << "/" << kTestFiles.size() << ")
    ";
              // XXX should put envp in .ktest ?
              interpreter->runFunctionAsMain(mainFn, out->numArgs, out->args, pEnvp);//调用Executor中的函数,这是每个KTest都执行一次
              if (interrupted) break;
        循环结束,设置ReplayKTest为空:interpreter->setReplayKTest(0);
    如果没有提供ReplayKTest,即ReplayKTestDir为空line1420
        就将SeedOutFile的每个KTest都放到seeds中。
        根据SeedOutDir中的内容从KTest_fromFile中取KTest放进seeds中。
        if (!seeds.empty()) {
          klee_message("KLEE: using %lu seeds
    ", seeds.size());
          interpreter->useSeeds(&seeds);//设置usingSeeds为seeds
        }
     
        interpreter->runFunctionAsMain(mainFn, pArgc, pArgv, pEnvp);//函数调用,仅此一次
    
        while (!seeds.empty()) {
          kTest_free(seeds.back());
          seeds.pop_back();
        }
    
    记录时间
    打印信息:各种统计信息
    

    class KleeHandler : public InterpreterHandler
    KleeHandler::KleeHandler(int argc, char **argv)
    创建输出目录以及相应文件 info warning.txt *.test等,获取各种路径以及文件
    定义了一些函数
    

    -----------------------Executor.cpp------------------------------------------------------

    Executor::Executor(LLVMContext &ctx, const InterpreterOptions &opts,
    InterpreterHandler *ih)
    : Interpreter(opts), kmodule(0), interpreterHandler(ih), searcher(0),
      externalDispatcher(new ExternalDispatcher(ctx)), statsTracker(0),
      pathWriter(0), symPathWriter(0), specialFunctionHandler(0),
      processTree(0), replayKTest(0), replayPath(0), usingSeeds(0),
      atMemoryLimit(false), inhibitForking(false), haltExecution(false),
      ivcEnabled(false),
      coreSolverTimeout(MaxCoreSolverTime != 0 && MaxInstructionTime != 0
                            ? std::min(MaxCoreSolverTime, MaxInstructionTime)
                            : std::max(MaxCoreSolverTime, MaxInstructionTime)),
      debugInstFile(0), debugLogBuffer(debugBufferString) {
      //Executor类的对象初始化,以上是其变量初始化,具体都是什么意思再说。
      if (coreSolverTimeout) UseForkedCoreSolver = true;
      Solver *coreSolver = klee::createCoreSolver(CoreSolverToUse);
      if (!coreSolver) {
        klee_error("Failed to create core solver
    ");
      }
    
      Solver *solver = constructSolverChain(
          coreSolver,
          interpreterHandler->getOutputFilename(ALL_QUERIES_SMT2_FILE_NAME),
          interpreterHandler->getOutputFilename(SOLVER_QUERIES_SMT2_FILE_NAME),
          interpreterHandler->getOutputFilename(ALL_QUERIES_KQUERY_FILE_NAME),
          interpreterHandler->getOutputFilename(SOLVER_QUERIES_KQUERY_FILE_NAME));
    
      this->solver = new TimingSolver(solver, EqualitySubstitution);//初始化求解器solver,定义了很多方法,如evaluate,mustBeTrue,getValue等。
      memory = new MemoryManager(&arrayCache);//memory在哪里初始化的?memory是Executor类的 MemoryManager变量,定义了allocate函数,细节不清楚
    设置debug相关信息以及err message的写入
        }
      }
    }
    

    const Module *Executor::setModule(llvm::Module *module,
                                  const ModuleOptions &opts) {
      assert(!kmodule && module && "can only register one module"); // XXX gross
     
      kmodule = new KModule(module);//转化为KModule
    
      // Initialize the context.
    #if LLVM_VERSION_CODE <= LLVM_VERSION(3, 1)
      TargetData *TD = kmodule->targetData;
    #else
      DataLayout *TD = kmodule->targetData;//不知道代表何种含义
    #endif
      Context::initialize(TD->isLittleEndian(),
                          (Expr::Width) TD->getPointerSizeInBits());
    
      specialFunctionHandler = new SpecialFunctionHandler(*this);
    
      specialFunctionHandler->prepare();//遍历handlerInfo中的函数,加入了一些函数的属性信息,NoReturn属性
      kmodule->prepare(opts, interpreterHandler);//将module中的信息都升级为KFunction、KInstruction,写入到assembly.ll中
      specialFunctionHandler->bind();//遍历handlerInfo中的函数,绑定函数及其hasReturnValue信息
    //跟踪状态,输出klee-out-*中的istate和states文件,各种统计信息(如覆盖率)吧
      if (StatsTracker::useStatistics() || userSearcherRequiresMD2U()) {
        statsTracker =
          new StatsTracker(*this,
                           interpreterHandler->getOutputFilename("assembly.ll"),
                           userSearcherRequiresMD2U());
      }
     
      return module;
    }
    

    ---------runFunctionAsMain()----------

    void Executor::runFunctionAsMain(Function *f,
                int argc,
                char **argv,
                char **envp) {
    定义了局部变量:
        std::vector<ref<Expr> > arguments;//存储argc,argv地址和环境配置的向量
        创建Expr向量arguments
        创建MemoryObject* argvMO,为argv和envp参数分配空间并压到arguments中
          argvMO =
            memory->allocate((argc + 1 + envc + 1 + 1) * NumPtrBytes,
                               /*isLocal=*/false, /*isGlobal=*/true,
                               /*allocSite=*/first, /*alignment=*/8);
    
        //创建ExecutionState *state实例
        ExecutionState *state = new ExecutionState(kmodule->functionMap[f]);
        bindArgument(kf,i,*state,arguments)
        //创建ObjectState *argvOS实例,将arvMO与argvMO放进state.Address space中
        ObjectState *argvOS = bindObjectInState(*state, argvMO, false);
        对每个argv,
        //创建Memoryobject对象arg,分配空间
            MemoryObject *arg =
                memory->allocate(len + 1, /*isLocal=*/false, /*isGlobal=*/true,
                                 /*allocSite=*/state->pc->inst, /*alignment=*/8);
        //同时创建ObjectState对象os,绑定state和arg
           ObjectState *os = bindObjectInState(*state, arg, false);
           for (j=0; j<len+1; j++)
              os->write8(j, s[j]);
      //向argvOS中写入初始化argv/envp c-string
           argvOS->write(i * NumPtrBytes, arg->getBaseExpr());
        initializeGlobals(*state)
       以state为参创建PTree类型实例processTree,state->ptreeNode=processTree->root
       run(*state)
       各种释放
    }
    

    void Executor::run(ExecutionState &initialState) {
      bindModuleConstants();//将Module中每个函数的每条指令都绑定常量
      initTimers();
    
      states.insert(&initialState);//将initialState加入到states中
    
      if (usingSeeds) {
        std::vector<SeedInfo> &v = seedMap[&initialState];//当state遇到符号分支的时候,满足约束的种子会被加入到seedMap[state]中
    //初始的时候,所有KTest都放在initialstate的seedMap[initialState]中
        for (std::vector<KTest*>::const_iterator it = usingSeeds->begin(),
               ie = usingSeeds->end(); it != ie; ++it)
          v.push_back(SeedInfo(*it));
    
        int lastNumSeeds = usingSeeds->size()+10;
        double lastTime, startTime = lastTime = util::getWallTime();
        ExecutionState *lastState = 0;
        while (!seedMap.empty()) {//seedMap非空。seedMap是在Executor类中的变量。里面到底存了多少东西不是很清楚,感觉就是seedMap[initialState],其他没看到往里放,应该会在executeInstruction的时候放进新的元素吧??
    
          std::map<ExecutionState*, std::vector<SeedInfo> >::iterator it =
            seedMap.upper_bound(lastState);//迭代seedMap中的元素
          lastState = it->first;
          unsigned numSeeds = it->second.size();
          ExecutionState &state = *lastState;//创建state引用,指向lastState
          KInstruction *ki = state.pc;//ki指向state的当前指令
          stepInstruction(state);//states的instructions计数加1,pc下移
    
          executeInstruction(state, ki);//按照指令的操作符类型,进行相应的处理
          processTimers(&state, MaxInstructionTime * numSeeds);
          updateStates(&state);//将addedState加入到states,并将removedStates从states中移出,清空added/removedState
    
          if ((stats::instructions % 1000) == 0) {//每当一共执行的指令到1000的倍数
          对当前state剩余的seed以及states中剩余的state进行信息提示
        }
        //seedMap为空
        klee_message("seeding done (%d states remain)", (int) states.size());
    
       设置state的权重都为1
    
      searcher = constructUserSearcher(*this);//创建searcher
    
      std::vector<ExecutionState *> newStates(states.begin(), states.end());
      searcher->update(0, newStates, std::vector<ExecutionState *>());
    
      while (!states.empty() && !haltExecution) {//如果states非空
        ExecutionState &state = searcher->selectState();//选择一个state
        KInstruction *ki = state.pc;//获取state的当前指令
        stepInstruction(state);//指令下移
    
        executeInstruction(state, ki);//执行指令
        processTimers(&state, MaxInstructionTime);
    
        checkMemoryUsage();//检查内存使用
    
        updateStates(&state);//更新states
      }
    
      delete searcher;
      searcher = 0;
    
      doDumpStates();
    }
    

    后面是一些对指令的处理操作,如ret,br,switch等

  • 相关阅读:
    简单工厂模式
    单例模式
    Quartz.NET总结(三)Quartz 配置
    Quartz.NET总结(二)CronTrigger和Cron表达式
    ORACLE跨数据库查询的方法
    github使用个人总结
    ffmpeg 下载安装和简单应用
    Python 安装与环境变量配置
    Sublime text 3 汉化教程
    给大家分享两套WordPress收费主题
  • 原文地址:https://www.cnblogs.com/linkJ/p/9585125.html
Copyright © 2011-2022 走看看