aboutsummaryrefslogblamecommitdiff
path: root/llvm_mode/LLVMInsTrim.so.cc
blob: 4d8c4719d56dfe19d1abc797d2e2d8da7c425d62 (plain) (tree)
1
2
3
4
5
6
7
8
9
10


                   

                   




                                                     

                              

                                                       


                                 
     


                                       
      





                                      
                                     

                                                   
                               

                        



                  
                      
                            



                                








                                                                  
 
                                    
 
           
                                     
                              
 











                                        
 
                                            
 
                         
 







                                                           
                          
              
     
           
      





                                      

                                                        
                                      

      

                                        
                                     
 
                                                                             





                                                              
 

                                               




                                                      
                          

                                                                       
                                                                     
      
                                                    
 






                                                      

                                                     

                                

                                                                



                                                                   
                                















                                                                                
                            


                                                                                

                              
            

                                                                            
                                                     
         
            

                                                                            
                                                                      

          









                                                                          
 

                                                                          
 





                                                                              
 











                                                                                
                    


                                                                             
       




                                                                             
        






                                                                                

                                                                                



















                                                                                
 


                                                    




                           










                                                          
                                            
 

                                                                
 






















                                          
                




















                                                                               
               
 
             






                            
             
 

           











                                                                               
           


         




                                                      
                                 




                                                             
 




                                                                         
 



                                                          
                
 

           

                                                                               
 
           
 
         
 

       
                        

                                
























                                                                              
                                                                      








                                
 
















                                                                             
 
                       
 

                                                 
 




                                                                               
 


                                                               
                            






                                                                   
 
                           
                                                       
                                                                                
















                                                                             

                              
                                                     
                                                                               







                                                                               
 


                                                                                
 
                                                  

                          


                                                                                
     
                         
      

         
                                                                         

                                                                               






                                                   
                                                 


                                                  
         



                                                                             






                                                                         
 





                                                                               

         
 

                      

       
     
 
                    
 
                         
                                                        


                                                                  
                                                          





                                                                            
 





                            





                                                          
 
                        
 






                                                                
 
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>

#include "llvm/Config/llvm-config.h"
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 5
typedef long double max_align_t;
#endif

#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#if LLVM_VERSION_MAJOR > 3 || \
    (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
  #include "llvm/IR/CFG.h"
  #include "llvm/IR/Dominators.h"
  #include "llvm/IR/DebugInfo.h"
#else
  #include "llvm/Support/CFG.h"
  #include "llvm/Analysis/Dominators.h"
  #include "llvm/DebugInfo.h"
#endif
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/IR/BasicBlock.h"
#include <unordered_set>
#include <random>
#include <list>
#include <string>
#include <fstream>

#include "MarkNodes.h"
#include "afl-llvm-common.h"
#include "llvm-ngram-coverage.h"

#include "config.h"
#include "debug.h"

using namespace llvm;

static cl::opt<bool> MarkSetOpt("markset", cl::desc("MarkSet"),
                                cl::init(false));
static cl::opt<bool> LoopHeadOpt("loophead", cl::desc("LoopHead"),
                                 cl::init(false));

namespace {

struct InsTrim : public ModulePass {

 protected:
  uint32_t function_minimum_size = 1;
  char *   skip_nozero = NULL;

 private:
  std::mt19937 generator;
  int          total_instr = 0;

  unsigned int genLabel() {

    return generator() & (MAP_SIZE - 1);

  }

 public:
  static char ID;

  InsTrim() : ModulePass(ID), generator(0) {

    initInstrumentList();

  }

  void getAnalysisUsage(AnalysisUsage &AU) const override {

    AU.addRequired<DominatorTreeWrapperPass>();

  }

#if LLVM_VERSION_MAJOR < 4
  const char *
#else
  StringRef
#endif
  getPassName() const override {

    return "InstTrim Instrumentation";

  }

#if LLVM_VERSION_MAJOR >= 4 || \
    (LLVM_VERSION_MAJOR == 4 && LLVM_VERSION_PATCH >= 1)
  #define AFL_HAVE_VECTOR_INTRINSICS 1
#endif

  bool runOnModule(Module &M) override {

    setvbuf(stdout, NULL, _IONBF, 0);

    if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {

      SAYF(cCYA "LLVMInsTrim" VERSION cRST " by csienslab\n");

    } else

      be_quiet = 1;

    if (getenv("AFL_DEBUG") != NULL) debug = 1;

    LLVMContext &C = M.getContext();

    IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
    IntegerType *Int32Ty = IntegerType::getInt32Ty(C);

#if LLVM_VERSION_MAJOR < 9
    char *neverZero_counters_str;
    if ((neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO")) != NULL)
      if (!be_quiet) OKF("LLVM neverZero activated (by hexcoder)\n");
#endif
    skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");

    if (getenv("AFL_LLVM_INSTRIM_LOOPHEAD") != NULL ||
        getenv("LOOPHEAD") != NULL) {

      LoopHeadOpt = true;

    }

    if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") ||
        getenv("AFL_LLVM_SKIPSINGLEBLOCK"))
      function_minimum_size = 2;

    unsigned int PrevLocSize = 0;
    char *       ngram_size_str = getenv("AFL_LLVM_NGRAM_SIZE");
    if (!ngram_size_str) ngram_size_str = getenv("AFL_NGRAM_SIZE");
    char *ctx_str = getenv("AFL_LLVM_CTX");

#ifdef AFL_HAVE_VECTOR_INTRINSICS
    unsigned int ngram_size = 0;
    /* Decide previous location vector size (must be a power of two) */
    VectorType *PrevLocTy;

    if (ngram_size_str)
      if (sscanf(ngram_size_str, "%u", &ngram_size) != 1 || ngram_size < 2 ||
          ngram_size > NGRAM_SIZE_MAX)
        FATAL(
            "Bad value of AFL_NGRAM_SIZE (must be between 2 and NGRAM_SIZE_MAX "
            "(%u))",
            NGRAM_SIZE_MAX);

    if (ngram_size)
      PrevLocSize = ngram_size - 1;
    else
#else
    if (ngram_size_str)
  #ifdef LLVM_VERSION_STRING
      FATAL(
          "Sorry, NGRAM branch coverage is not supported with llvm version %s!",
          LLVM_VERSION_STRING);
  #else
    #ifndef LLVM_VERSION_PATCH
      FATAL(
          "Sorry, NGRAM branch coverage is not supported with llvm version "
          "%d.%d.%d!",
          LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR, 0);
    #else
      FATAL(
          "Sorry, NGRAM branch coverage is not supported with llvm version "
          "%d.%d.%d!",
          LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR, LLVM_VERISON_PATCH);
    #endif
  #endif
#endif
      PrevLocSize = 1;

#ifdef AFL_HAVE_VECTOR_INTRINSICS
    // IntegerType *Int64Ty = IntegerType::getInt64Ty(C);
    uint64_t     PrevLocVecSize = PowerOf2Ceil(PrevLocSize);
    IntegerType *IntLocTy =
        IntegerType::getIntNTy(C, sizeof(PREV_LOC_T) * CHAR_BIT);
    if (ngram_size) PrevLocTy = VectorType::get(IntLocTy, PrevLocVecSize);
#endif

    /* 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;
    GlobalVariable *AFLContext;
    LoadInst *      PrevCtx = NULL;  // for CTX sensitive coverage

    if (ctx_str)
#ifdef __ANDROID__
      AFLContext = new GlobalVariable(
          M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx");
#else
      AFLContext = new GlobalVariable(
          M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx",
          0, GlobalVariable::GeneralDynamicTLSModel, 0, false);
#endif

#ifdef AFL_HAVE_VECTOR_INTRINSICS
    if (ngram_size)
  #ifdef __ANDROID__
      AFLPrevLoc = new GlobalVariable(
          M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage,
          /* Initializer */ nullptr, "__afl_prev_loc");
  #else
      AFLPrevLoc = new GlobalVariable(
          M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage,
          /* Initializer */ nullptr, "__afl_prev_loc",
          /* InsertBefore */ nullptr, GlobalVariable::GeneralDynamicTLSModel,
          /* AddressSpace */ 0, /* IsExternallyInitialized */ false);
  #endif
    else
#endif
#ifdef __ANDROID__
      AFLPrevLoc = new GlobalVariable(
          M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc");
#else
    AFLPrevLoc = new GlobalVariable(
        M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc", 0,
        GlobalVariable::GeneralDynamicTLSModel, 0, false);
#endif

#ifdef AFL_HAVE_VECTOR_INTRINSICS
    /* Create the vector shuffle mask for updating the previous block history.
       Note that the first element of the vector will store cur_loc, so just set
       it to undef to allow the optimizer to do its thing. */

    SmallVector<Constant *, 32> PrevLocShuffle = {UndefValue::get(Int32Ty)};

    for (unsigned I = 0; I < PrevLocSize - 1; ++I)
      PrevLocShuffle.push_back(ConstantInt::get(Int32Ty, I));

    for (unsigned I = PrevLocSize; I < PrevLocVecSize; ++I)
      PrevLocShuffle.push_back(ConstantInt::get(Int32Ty, PrevLocSize));

    Constant *PrevLocShuffleMask = ConstantVector::get(PrevLocShuffle);
#endif

    // this is our default
    MarkSetOpt = true;

    ConstantInt *Zero = ConstantInt::get(Int8Ty, 0);
    ConstantInt *One = ConstantInt::get(Int8Ty, 1);

    u64 total_rs = 0;
    u64 total_hs = 0;

    for (Function &F : M) {

      if (debug) {

        uint32_t bb_cnt = 0;

        for (auto &BB : F)
          if (BB.size() > 0) ++bb_cnt;
        SAYF(cMGN "[D] " cRST "Function %s size %zu %u\n",
             F.getName().str().c_str(), F.size(), bb_cnt);

      }

      if (!isInInstrumentList(&F)) continue;

      // if the function below our minimum size skip it (1 or 2)
      if (F.size() < function_minimum_size) { continue; }

      std::unordered_set<BasicBlock *> MS;
      if (!MarkSetOpt) {

        for (auto &BB : F) {

          MS.insert(&BB);

        }

        total_rs += F.size();

      } else {

        auto Result = markNodes(&F);
        auto RS = Result.first;
        auto HS = Result.second;

        MS.insert(RS.begin(), RS.end());
        if (!LoopHeadOpt) {

          MS.insert(HS.begin(), HS.end());
          total_rs += MS.size();

        } else {

          DenseSet<std::pair<BasicBlock *, BasicBlock *>> EdgeSet;
          DominatorTreeWrapperPass *                      DTWP =
              &getAnalysis<DominatorTreeWrapperPass>(F);
          auto DT = &DTWP->getDomTree();

          total_rs += RS.size();
          total_hs += HS.size();

          for (BasicBlock *BB : HS) {

            bool Inserted = false;
            for (auto BI = pred_begin(BB), BE = pred_end(BB); BI != BE; ++BI) {

              auto Edge = BasicBlockEdge(*BI, BB);
              if (Edge.isSingleEdge() && DT->dominates(Edge, BB)) {

                EdgeSet.insert({*BI, BB});
                Inserted = true;
                break;

              }

            }

            if (!Inserted) {

              MS.insert(BB);
              total_rs += 1;
              total_hs -= 1;

            }

          }

          for (auto I = EdgeSet.begin(), E = EdgeSet.end(); I != E; ++I) {

            auto PredBB = I->first;
            auto SuccBB = I->second;
            auto NewBB =
                SplitBlockPredecessors(SuccBB, {PredBB}, ".split", DT, nullptr,
#if LLVM_VERSION_MAJOR >= 8
                                       nullptr,
#endif
                                       false);
            MS.insert(NewBB);

          }

        }

        for (BasicBlock &BB : F) {

          if (MS.find(&BB) == MS.end()) { continue; }
          IRBuilder<> IRB(&*BB.getFirstInsertionPt());

#ifdef AFL_HAVE_VECTOR_INTRINSICS
          if (ngram_size) {

            LoadInst *PrevLoc = IRB.CreateLoad(AFLPrevLoc);
            PrevLoc->setMetadata(M.getMDKindID("nosanitize"),
                                 MDNode::get(C, None));

            Value *ShuffledPrevLoc = IRB.CreateShuffleVector(
                PrevLoc, UndefValue::get(PrevLocTy), PrevLocShuffleMask);
            Value *UpdatedPrevLoc = IRB.CreateInsertElement(
                ShuffledPrevLoc, ConstantInt::get(Int32Ty, genLabel()),
                (uint64_t)0);

            IRB.CreateStore(UpdatedPrevLoc, AFLPrevLoc)
                ->setMetadata(M.getMDKindID("nosanitize"),
                              MDNode::get(C, None));

          } else

#endif
          {

            IRB.CreateStore(ConstantInt::get(Int32Ty, genLabel()), AFLPrevLoc);

          }

        }

      }

      int has_calls = 0;
      for (BasicBlock &BB : F) {

        auto         PI = pred_begin(&BB);
        auto         PE = pred_end(&BB);
        IRBuilder<>  IRB(&*BB.getFirstInsertionPt());
        Value *      L = NULL;
        unsigned int cur_loc;

        // Context sensitive coverage
        if (ctx_str && &BB == &F.getEntryBlock()) {

          PrevCtx = IRB.CreateLoad(AFLContext);
          PrevCtx->setMetadata(M.getMDKindID("nosanitize"),
                               MDNode::get(C, None));

          // does the function have calls? and is any of the calls larger than
          // one basic block?
          has_calls = 0;
          for (auto &BB : F) {

            if (has_calls) break;
            for (auto &IN : BB) {

              CallInst *callInst = nullptr;
              if ((callInst = dyn_cast<CallInst>(&IN))) {

                Function *Callee = callInst->getCalledFunction();
                if (!Callee || Callee->size() < function_minimum_size)
                  continue;
                else {

                  has_calls = 1;
                  break;

                }

              }

            }

          }

          // if yes we store a context ID for this function in the global var
          if (has_calls) {

            ConstantInt *NewCtx = ConstantInt::get(Int32Ty, genLabel());
            StoreInst *  StoreCtx = IRB.CreateStore(NewCtx, AFLContext);
            StoreCtx->setMetadata(M.getMDKindID("nosanitize"),
                                  MDNode::get(C, None));

          }

        }  // END of ctx_str

        if (MarkSetOpt && MS.find(&BB) == MS.end()) { continue; }

        if (PI == PE) {

          cur_loc = genLabel();
          L = ConstantInt::get(Int32Ty, cur_loc);

        } else {

          auto *PN = PHINode::Create(Int32Ty, 0, "", &*BB.begin());
          DenseMap<BasicBlock *, unsigned> PredMap;
          for (auto PI = pred_begin(&BB), PE = pred_end(&BB); PI != PE; ++PI) {

            BasicBlock *PBB = *PI;
            auto        It = PredMap.insert({PBB, genLabel()});
            unsigned    Label = It.first->second;
            cur_loc = Label;
            PN->addIncoming(ConstantInt::get(Int32Ty, Label), PBB);

          }

          L = PN;

        }

        /* Load prev_loc */
        LoadInst *PrevLoc = IRB.CreateLoad(AFLPrevLoc);
        PrevLoc->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
        Value *PrevLocTrans;

#ifdef AFL_HAVE_VECTOR_INTRINSICS
        /* "For efficiency, we propose to hash the tuple as a key into the
           hit_count map as (prev_block_trans << 1) ^ curr_block_trans, where
           prev_block_trans = (block_trans_1 ^ ... ^ block_trans_(n-1)" */

        if (ngram_size)
          PrevLocTrans =
              IRB.CreateZExt(IRB.CreateXorReduce(PrevLoc), IRB.getInt32Ty());
        else
#endif
          PrevLocTrans = IRB.CreateZExt(PrevLoc, IRB.getInt32Ty());

        if (ctx_str)
          PrevLocTrans =
              IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, PrevCtx), Int32Ty);

        /* Load SHM pointer */
        LoadInst *MapPtr = IRB.CreateLoad(AFLMapPtr);
        MapPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
        Value *MapPtrIdx;
#ifdef AFL_HAVE_VECTOR_INTRINSICS
        if (ngram_size)
          MapPtrIdx = IRB.CreateGEP(
              MapPtr, IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, L), Int32Ty));
        else
#endif
          MapPtrIdx = IRB.CreateGEP(MapPtr, IRB.CreateXor(PrevLocTrans, L));

        /* Update bitmap */
        LoadInst *Counter = IRB.CreateLoad(MapPtrIdx);
        Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));

        Value *Incr = IRB.CreateAdd(Counter, One);

#if LLVM_VERSION_MAJOR < 9
        if (neverZero_counters_str !=
            NULL)  // with llvm 9 we make this the default as the bug in llvm is
                   // then fixed
#else
        if (!skip_nozero)
#endif
        {

          /* hexcoder: Realize a counter that skips zero during overflow.
           * Once this counter reaches its maximum value, it next increments to
           * 1
           *
           * Instead of
           * Counter + 1 -> Counter
           * we inject now this
           * Counter + 1 -> {Counter, OverflowFlag}
           * Counter + OverflowFlag -> Counter
           */
          auto cf = IRB.CreateICmpEQ(Incr, Zero);
          auto carry = IRB.CreateZExt(cf, Int8Ty);
          Incr = IRB.CreateAdd(Incr, carry);

        }

        IRB.CreateStore(Incr, MapPtrIdx)
            ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));

        if (ctx_str && has_calls) {

          // in CTX mode we have to restore the original context for the
          // caller - she might be calling other functions which need the
          // correct CTX
          Instruction *Inst = BB.getTerminator();
          if (isa<ReturnInst>(Inst) || isa<ResumeInst>(Inst)) {

            IRBuilder<> Post_IRB(Inst);
            StoreInst * RestoreCtx = Post_IRB.CreateStore(PrevCtx, AFLContext);
            RestoreCtx->setMetadata(M.getMDKindID("nosanitize"),
                                    MDNode::get(C, None));

          }

        }

        total_instr++;

      }

    }

    if (!be_quiet) {

      char modeline[100];
      snprintf(modeline, sizeof(modeline), "%s%s%s%s%s",
               getenv("AFL_HARDEN") ? "hardened" : "non-hardened",
               getenv("AFL_USE_ASAN") ? ", ASAN" : "",
               getenv("AFL_USE_MSAN") ? ", MSAN" : "",
               getenv("AFL_USE_CFISAN") ? ", CFISAN" : "",
               getenv("AFL_USE_UBSAN") ? ", UBSAN" : "");

      OKF("Instrumented %u locations (%llu, %llu) (%s mode)\n", total_instr,
          total_rs, total_hs, modeline);

    }

    return false;

  }

};  // end of struct InsTrim

}  // end of anonymous namespace

char InsTrim::ID = 0;

static void registerAFLPass(const PassManagerBuilder &,
                            legacy::PassManagerBase &PM) {

  PM.add(new InsTrim());

}

static RegisterStandardPasses RegisterAFLPass(
    PassManagerBuilder::EP_OptimizerLast, registerAFLPass);

static RegisterStandardPasses RegisterAFLPass0(
    PassManagerBuilder::EP_EnabledOnOptLevel0, registerAFLPass);