bool PNaClSjLjEH::runOnModule(Module &M) {
  Type *JmpBufTy = ArrayType::get(Type::getInt8Ty(M.getContext()),
                                  kPNaClJmpBufSize);

  // Define "struct ExceptionFrame".
  StructType *ExceptionFrameTy = StructType::create(M.getContext(),
                                                    "ExceptionFrame");
  Type *ExceptionFrameFields[] = {
    JmpBufTy,  // jmp_buf
    ExceptionFrameTy->getPointerTo(),  // struct ExceptionFrame *next
    Type::getInt32Ty(M.getContext())  // Exception info (clause list ID)
  };
  ExceptionFrameTy->setBody(ExceptionFrameFields);

  ExceptionInfoWriter ExcInfoWriter(&M.getContext());
  for (Module::iterator Func = M.begin(), E = M.end(); Func != E; ++Func) {
    FuncRewriter Rewriter(ExceptionFrameTy, &ExcInfoWriter, Func);
    Rewriter.expandFunc();
  }
  ExcInfoWriter.defineGlobalVariables(&M);
  return true;
}
Example #2
0
Function *GCOVProfiler::insertCounterWriteout(
    ArrayRef<std::pair<GlobalVariable *, MDNode *> > CountersBySP) {
  FunctionType *WriteoutFTy = FunctionType::get(Type::getVoidTy(*Ctx), false);
  Function *WriteoutF = M->getFunction("__llvm_gcov_writeout");
  if (!WriteoutF)
    WriteoutF = Function::Create(WriteoutFTy, GlobalValue::InternalLinkage,
                                 "__llvm_gcov_writeout", M);
  WriteoutF->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
  WriteoutF->addFnAttr(Attribute::NoInline);
  if (Options.NoRedZone)
    WriteoutF->addFnAttr(Attribute::NoRedZone);

  BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", WriteoutF);
  IRBuilder<> Builder(BB);

  Constant *StartFile = getStartFileFunc();
  Constant *EmitFunction = getEmitFunctionFunc();
  Constant *EmitArcs = getEmitArcsFunc();
  Constant *SummaryInfo = getSummaryInfoFunc();
  Constant *EndFile = getEndFileFunc();

  NamedMDNode *CUNodes = M->getNamedMetadata("llvm.dbg.cu");
  if (!CUNodes) {
    Builder.CreateRetVoid();
    return WriteoutF;
  }

  // Collect the relevant data into a large constant data structure that we can
  // walk to write out everything.
  StructType *StartFileCallArgsTy = StructType::create(
      {Builder.getInt8PtrTy(), Builder.getInt8PtrTy(), Builder.getInt32Ty()});
  StructType *EmitFunctionCallArgsTy = StructType::create(
      {Builder.getInt32Ty(), Builder.getInt8PtrTy(), Builder.getInt32Ty(),
       Builder.getInt8Ty(), Builder.getInt32Ty()});
  StructType *EmitArcsCallArgsTy = StructType::create(
      {Builder.getInt32Ty(), Builder.getInt64Ty()->getPointerTo()});
  StructType *FileInfoTy =
      StructType::create({StartFileCallArgsTy, Builder.getInt32Ty(),
                          EmitFunctionCallArgsTy->getPointerTo(),
                          EmitArcsCallArgsTy->getPointerTo()});

  Constant *Zero32 = Builder.getInt32(0);
  // Build an explicit array of two zeros for use in ConstantExpr GEP building.
  Constant *TwoZero32s[] = {Zero32, Zero32};

  SmallVector<Constant *, 8> FileInfos;
  for (int i : llvm::seq<int>(0, CUNodes->getNumOperands())) {
    auto *CU = cast<DICompileUnit>(CUNodes->getOperand(i));

    // Skip module skeleton (and module) CUs.
    if (CU->getDWOId())
      continue;

    std::string FilenameGcda = mangleName(CU, GCovFileType::GCDA);
    uint32_t CfgChecksum = FileChecksums.empty() ? 0 : FileChecksums[i];
    auto *StartFileCallArgs = ConstantStruct::get(
        StartFileCallArgsTy, {Builder.CreateGlobalStringPtr(FilenameGcda),
                              Builder.CreateGlobalStringPtr(ReversedVersion),
                              Builder.getInt32(CfgChecksum)});

    SmallVector<Constant *, 8> EmitFunctionCallArgsArray;
    SmallVector<Constant *, 8> EmitArcsCallArgsArray;
    for (int j : llvm::seq<int>(0, CountersBySP.size())) {
      auto *SP = cast_or_null<DISubprogram>(CountersBySP[j].second);
      uint32_t FuncChecksum = Funcs.empty() ? 0 : Funcs[j]->getFuncChecksum();
      EmitFunctionCallArgsArray.push_back(ConstantStruct::get(
          EmitFunctionCallArgsTy,
          {Builder.getInt32(j),
           Options.FunctionNamesInData
               ? Builder.CreateGlobalStringPtr(getFunctionName(SP))
               : Constant::getNullValue(Builder.getInt8PtrTy()),
           Builder.getInt32(FuncChecksum),
           Builder.getInt8(Options.UseCfgChecksum),
           Builder.getInt32(CfgChecksum)}));

      GlobalVariable *GV = CountersBySP[j].first;
      unsigned Arcs = cast<ArrayType>(GV->getValueType())->getNumElements();
      EmitArcsCallArgsArray.push_back(ConstantStruct::get(
          EmitArcsCallArgsTy,
          {Builder.getInt32(Arcs), ConstantExpr::getInBoundsGetElementPtr(
                                       GV->getValueType(), GV, TwoZero32s)}));
    }
    // Create global arrays for the two emit calls.
    int CountersSize = CountersBySP.size();
    assert(CountersSize == (int)EmitFunctionCallArgsArray.size() &&
           "Mismatched array size!");
    assert(CountersSize == (int)EmitArcsCallArgsArray.size() &&
           "Mismatched array size!");
    auto *EmitFunctionCallArgsArrayTy =
        ArrayType::get(EmitFunctionCallArgsTy, CountersSize);
    auto *EmitFunctionCallArgsArrayGV = new GlobalVariable(
        *M, EmitFunctionCallArgsArrayTy, /*isConstant*/ true,
        GlobalValue::InternalLinkage,
        ConstantArray::get(EmitFunctionCallArgsArrayTy,
                           EmitFunctionCallArgsArray),
        Twine("__llvm_internal_gcov_emit_function_args.") + Twine(i));
    auto *EmitArcsCallArgsArrayTy =
        ArrayType::get(EmitArcsCallArgsTy, CountersSize);
    EmitFunctionCallArgsArrayGV->setUnnamedAddr(
        GlobalValue::UnnamedAddr::Global);
    auto *EmitArcsCallArgsArrayGV = new GlobalVariable(
        *M, EmitArcsCallArgsArrayTy, /*isConstant*/ true,
        GlobalValue::InternalLinkage,
        ConstantArray::get(EmitArcsCallArgsArrayTy, EmitArcsCallArgsArray),
        Twine("__llvm_internal_gcov_emit_arcs_args.") + Twine(i));
    EmitArcsCallArgsArrayGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);

    FileInfos.push_back(ConstantStruct::get(
        FileInfoTy,
        {StartFileCallArgs, Builder.getInt32(CountersSize),
         ConstantExpr::getInBoundsGetElementPtr(EmitFunctionCallArgsArrayTy,
                                                EmitFunctionCallArgsArrayGV,
                                                TwoZero32s),
         ConstantExpr::getInBoundsGetElementPtr(
             EmitArcsCallArgsArrayTy, EmitArcsCallArgsArrayGV, TwoZero32s)}));
  }

  // If we didn't find anything to actually emit, bail on out.
  if (FileInfos.empty()) {
    Builder.CreateRetVoid();
    return WriteoutF;
  }

  // To simplify code, we cap the number of file infos we write out to fit
  // easily in a 32-bit signed integer. This gives consistent behavior between
  // 32-bit and 64-bit systems without requiring (potentially very slow) 64-bit
  // operations on 32-bit systems. It also seems unreasonable to try to handle
  // more than 2 billion files.
  if ((int64_t)FileInfos.size() > (int64_t)INT_MAX)
    FileInfos.resize(INT_MAX);

  // Create a global for the entire data structure so we can walk it more
  // easily.
  auto *FileInfoArrayTy = ArrayType::get(FileInfoTy, FileInfos.size());
  auto *FileInfoArrayGV = new GlobalVariable(
      *M, FileInfoArrayTy, /*isConstant*/ true, GlobalValue::InternalLinkage,
      ConstantArray::get(FileInfoArrayTy, FileInfos),
      "__llvm_internal_gcov_emit_file_info");
  FileInfoArrayGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);

  // Create the CFG for walking this data structure.
  auto *FileLoopHeader =
      BasicBlock::Create(*Ctx, "file.loop.header", WriteoutF);
  auto *CounterLoopHeader =
      BasicBlock::Create(*Ctx, "counter.loop.header", WriteoutF);
  auto *FileLoopLatch = BasicBlock::Create(*Ctx, "file.loop.latch", WriteoutF);
  auto *ExitBB = BasicBlock::Create(*Ctx, "exit", WriteoutF);

  // We always have at least one file, so just branch to the header.
  Builder.CreateBr(FileLoopHeader);

  // The index into the files structure is our loop induction variable.
  Builder.SetInsertPoint(FileLoopHeader);
  PHINode *IV =
      Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2);
  IV->addIncoming(Builder.getInt32(0), BB);
  auto *FileInfoPtr =
      Builder.CreateInBoundsGEP(FileInfoArrayGV, {Builder.getInt32(0), IV});
  auto *StartFileCallArgsPtr = Builder.CreateStructGEP(FileInfoPtr, 0);
  Builder.CreateCall(
      StartFile,
      {Builder.CreateLoad(Builder.CreateStructGEP(StartFileCallArgsPtr, 0)),
       Builder.CreateLoad(Builder.CreateStructGEP(StartFileCallArgsPtr, 1)),
       Builder.CreateLoad(Builder.CreateStructGEP(StartFileCallArgsPtr, 2))});
  auto *NumCounters =
      Builder.CreateLoad(Builder.CreateStructGEP(FileInfoPtr, 1));
  auto *EmitFunctionCallArgsArray =
      Builder.CreateLoad(Builder.CreateStructGEP(FileInfoPtr, 2));
  auto *EmitArcsCallArgsArray =
      Builder.CreateLoad(Builder.CreateStructGEP(FileInfoPtr, 3));
  auto *EnterCounterLoopCond =
      Builder.CreateICmpSLT(Builder.getInt32(0), NumCounters);
  Builder.CreateCondBr(EnterCounterLoopCond, CounterLoopHeader, FileLoopLatch);

  Builder.SetInsertPoint(CounterLoopHeader);
  auto *JV = Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2);
  JV->addIncoming(Builder.getInt32(0), FileLoopHeader);
  auto *EmitFunctionCallArgsPtr =
      Builder.CreateInBoundsGEP(EmitFunctionCallArgsArray, {JV});
  Builder.CreateCall(
      EmitFunction,
      {Builder.CreateLoad(Builder.CreateStructGEP(EmitFunctionCallArgsPtr, 0)),
       Builder.CreateLoad(Builder.CreateStructGEP(EmitFunctionCallArgsPtr, 1)),
       Builder.CreateLoad(Builder.CreateStructGEP(EmitFunctionCallArgsPtr, 2)),
       Builder.CreateLoad(Builder.CreateStructGEP(EmitFunctionCallArgsPtr, 3)),
       Builder.CreateLoad(
           Builder.CreateStructGEP(EmitFunctionCallArgsPtr, 4))});
  auto *EmitArcsCallArgsPtr =
      Builder.CreateInBoundsGEP(EmitArcsCallArgsArray, {JV});
  Builder.CreateCall(
      EmitArcs,
      {Builder.CreateLoad(Builder.CreateStructGEP(EmitArcsCallArgsPtr, 0)),
       Builder.CreateLoad(Builder.CreateStructGEP(EmitArcsCallArgsPtr, 1))});
  auto *NextJV = Builder.CreateAdd(JV, Builder.getInt32(1));
  auto *CounterLoopCond = Builder.CreateICmpSLT(NextJV, NumCounters);
  Builder.CreateCondBr(CounterLoopCond, CounterLoopHeader, FileLoopLatch);
  JV->addIncoming(NextJV, CounterLoopHeader);

  Builder.SetInsertPoint(FileLoopLatch);
  Builder.CreateCall(SummaryInfo, {});
  Builder.CreateCall(EndFile, {});
  auto *NextIV = Builder.CreateAdd(IV, Builder.getInt32(1));
  auto *FileLoopCond =
      Builder.CreateICmpSLT(NextIV, Builder.getInt32(FileInfos.size()));
  Builder.CreateCondBr(FileLoopCond, FileLoopHeader, ExitBB);
  IV->addIncoming(NextIV, FileLoopLatch);

  Builder.SetInsertPoint(ExitBB);
  Builder.CreateRetVoid();

  return WriteoutF;
}
static bool ExpandVarArgCall(Module *M, InstType *Call, DataLayout *DL) {
  FunctionType *FuncType = cast<FunctionType>(
      Call->getCalledValue()->getType()->getPointerElementType());
  if (!FuncType->isFunctionVarArg())
    return false;
  if (auto *F = dyn_cast<Function>(Call->getCalledValue()))
    if (isEmscriptenJSArgsFunc(M, F->getName()))
      return false;

  Function *F = Call->getParent()->getParent();
  LLVMContext &Ctx = M->getContext();

  SmallVector<AttributeSet, 8> Attrs;
  Attrs.push_back(Call->getAttributes().getFnAttributes());
  Attrs.push_back(Call->getAttributes().getRetAttributes());

  // Split argument list into fixed and variable arguments.
  SmallVector<Value *, 8> FixedArgs;
  SmallVector<Value *, 8> VarArgs;
  SmallVector<Type *, 8> VarArgsTypes;
  for (unsigned I = 0, E = FuncType->getNumParams(); I < E; ++I) {
    FixedArgs.push_back(Call->getArgOperand(I));
    // AttributeSets use 1-based indexing.
    Attrs.push_back(Call->getAttributes().getParamAttributes(I + 1));
  }
  for (unsigned I = FuncType->getNumParams(), E = Call->getNumArgOperands();
       I < E; ++I) {
    Value *ArgVal = Call->getArgOperand(I);
    VarArgs.push_back(ArgVal);
    bool isByVal = Call->getAttributes().hasAttribute(I + 1, Attribute::ByVal);
    // For "byval" arguments we must dereference the pointer.
    VarArgsTypes.push_back(isByVal ? ArgVal->getType()->getPointerElementType()
                                   : ArgVal->getType());
  }
  if (VarArgsTypes.size() == 0) {
    // Some buggy code (e.g. 176.gcc in Spec2k) uses va_arg on an
    // empty argument list, which gives undefined behaviour in C.  To
    // work around such programs, we create a dummy varargs buffer on
    // the stack even though there are no arguments to put in it.
    // This allows va_arg to read an undefined value from the stack
    // rather than crashing by reading from an uninitialized pointer.
    // An alternative would be to pass a null pointer to catch the
    // invalid use of va_arg.
    VarArgsTypes.push_back(Type::getInt32Ty(Ctx));
  }

  // Create struct type for packing variable arguments into.
  StructType *VarArgsTy = StructType::get(Ctx, VarArgsTypes);

  // Allocate space for the variable argument buffer.  Do this at the
  // start of the function so that we don't leak space if the function
  // is called in a loop.
  IRBuilder<> IRB(F->getEntryBlock().getFirstInsertionPt());
  auto *Buf = IRB.CreateAlloca(VarArgsTy, nullptr, "vararg_buffer");

  // Call llvm.lifetime.start/end intrinsics to indicate that Buf is
  // only used for the duration of the function call, so that the
  // stack space can be reused elsewhere.
  auto LifetimeStart = Intrinsic::getDeclaration(M, Intrinsic::lifetime_start);
  auto LifetimeEnd = Intrinsic::getDeclaration(M, Intrinsic::lifetime_end);
  auto *I8Ptr = Type::getInt8Ty(Ctx)->getPointerTo();
  auto *BufPtr = IRB.CreateBitCast(Buf, I8Ptr, "vararg_lifetime_bitcast");
  auto *BufSize =
      ConstantInt::get(Ctx, APInt(64, DL->getTypeAllocSize(VarArgsTy)));
  IRB.CreateCall2(LifetimeStart, BufSize, BufPtr);

  // Copy variable arguments into buffer.
  int Index = 0;
  IRB.SetInsertPoint(Call);
  for (Value *Arg : VarArgs) {
    Value *Indexes[] = {ConstantInt::get(Ctx, APInt(32, 0)),
                        ConstantInt::get(Ctx, APInt(32, Index))};
    Value *Ptr = IRB.CreateInBoundsGEP(Buf, Indexes, "vararg_ptr");
    bool isByVal = Call->getAttributes().hasAttribute(
        FuncType->getNumParams() + Index + 1, Attribute::ByVal);
    if (isByVal)
      IRB.CreateMemCpy(Ptr, Arg, DL->getTypeAllocSize(
                                     Arg->getType()->getPointerElementType()),
                       /*Align=*/1);
    else
      IRB.CreateStore(Arg, Ptr);
    ++Index;
  }

  // Cast function to new type to add our extra pointer argument.
  SmallVector<Type *, 8> ArgTypes(FuncType->param_begin(),
                                  FuncType->param_end());
  ArgTypes.push_back(VarArgsTy->getPointerTo());
  FunctionType *NFTy = FunctionType::get(FuncType->getReturnType(), ArgTypes,
                                         /*isVarArg=*/false);
  Value *CastFunc = IRB.CreateBitCast(Call->getCalledValue(),
                                      NFTy->getPointerTo(), "vararg_func");

  // Create the converted function call.
  FixedArgs.push_back(Buf);
  Instruction *NewCall;
  if (auto *C = dyn_cast<CallInst>(Call)) {
    auto *N = IRB.CreateCall(CastFunc, FixedArgs);
    N->setAttributes(AttributeSet::get(Ctx, Attrs));
    NewCall = N;
    IRB.CreateCall2(LifetimeEnd, BufSize, BufPtr);
  } else if (auto *C = dyn_cast<InvokeInst>(Call)) {
    auto *N = IRB.CreateInvoke(CastFunc, C->getNormalDest(), C->getUnwindDest(),
                               FixedArgs, C->getName());
    N->setAttributes(AttributeSet::get(Ctx, Attrs));
    (IRBuilder<>(C->getNormalDest()->getFirstInsertionPt()))
        .CreateCall2(LifetimeEnd, BufSize, BufPtr);
    (IRBuilder<>(C->getUnwindDest()->getFirstInsertionPt()))
        .CreateCall2(LifetimeEnd, BufSize, BufPtr);
    NewCall = N;
  } else {
    llvm_unreachable("not a call/invoke");
  }

  NewCall->takeName(Call);
  Call->replaceAllUsesWith(NewCall);
  Call->eraseFromParent();

  return true;
}
Example #4
0
int main() {
    InitializeNativeTarget();
    LLVMContext& Context = getGlobalContext();
    Module *M = new Module("test C++ exception handling ", Context);


    StructType* MyStructType = StructType::create(Context, "struct.MyStruct");
    Type* MyStructFields[] = {
        Type::getInt32Ty(Context),
        Type::getInt32Ty(Context)
    };
    MyStructType->setBody(MyStructFields);

    GlobalValue* throwFunc = cast<GlobalValue>(M->getOrInsertFunction("throwMyStruct", Type::getVoidTy(Context), NULL));
    GlobalValue* MyStructTypeInfo = cast<GlobalValue>(M->getOrInsertGlobal("MyStructTypeInfo", Type::getInt8Ty(Context)));

    Function* gxx_personality = Function::Create(FunctionType::get(Type::getInt32Ty(Context), true), Function::ExternalLinkage, "__gxx_personality_v0", M);
    Function* begin_catch     = Function::Create(FunctionType::get(Type::getInt8PtrTy(Context), Type::getInt8PtrTy(Context), false), Function::ExternalLinkage, "__cxa_begin_catch", M);
    Function* end_catch       = Function::Create(FunctionType::get(Type::getVoidTy(Context), false), Function::ExternalLinkage, "__cxa_end_catch", M);

    Function* testExceptions = cast<Function>(M->getOrInsertFunction("testExceptions", Type::getInt32Ty(Context), NULL));

    BasicBlock* entryBB   = BasicBlock::Create(Context, "", testExceptions);
    BasicBlock* landPadBB = BasicBlock::Create(Context, "landPad", testExceptions);
    BasicBlock* noErrorBB = BasicBlock::Create(Context, "noError", testExceptions);


    IRBuilder<> builder(entryBB);

    Value* invokeThrow = builder.CreateInvoke(throwFunc, noErrorBB, landPadBB);

    builder.SetInsertPoint(noErrorBB);
    builder.CreateRet( builder.getInt32(666) ); // should never happen

    //writing landingpad! <<<<<<<

    builder.SetInsertPoint(landPadBB);

    Value* gxx_personality_i8 = builder.CreateBitCast(gxx_personality, Type::getInt8PtrTy(Context));
    Type* caughtType = StructType::get(builder.getInt8PtrTy(), builder.getInt32Ty(), NULL);

    LandingPadInst* caughtResult = builder.CreateLandingPad(caughtType, gxx_personality_i8, 1);

    // we can catch any C++ exception we want
    // but now we are catching MyStruct
    caughtResult->addClause(MyStructTypeInfo);

    //we are sure to catch MyStruct so no other checks are needed
    //if throwMyStruct() throws anything but MyStruct it won't pass to the current landingpad BB

    Value* thrownExctn  = builder.CreateExtractValue(caughtResult, 0);
    Value* thrownObject = builder.CreateCall(begin_catch, thrownExctn);
    Value* object       = builder.CreateBitCast(thrownObject, MyStructType->getPointerTo());
    Value* resultPtr    = builder.CreateStructGEP(object, 1);
    Value* result       = builder.CreateLoad(resultPtr);

    builder.CreateCall(end_catch);

    builder.CreateRet( result ); // << z.y

    TargetOptions Opts;
    Opts.JITExceptionHandling = true; // DO NOT FORGET THIS OPTION !!!!!!11


    ExecutionEngine* EE = EngineBuilder(M)
                        .setEngineKind(EngineKind::JIT)
                        .setTargetOptions(Opts)
                        .create();

    EE->addGlobalMapping(throwFunc, reinterpret_cast<void*>(&throwMyStruct));
    EE->addGlobalMapping(MyStructTypeInfo, MyStruct::getTypeInfo());

    verifyFunction(*testExceptions);
    outs() << *testExceptions;

    std::vector<GenericValue> noArgs;
    GenericValue gv = EE->runFunction(testExceptions, noArgs);

    outs() << "\ntestExceptions result: " << gv.IntVal << "\n";

    delete EE;
    llvm_shutdown();
    return 0;
}