Example #1
0
void GraphBuilder::visitVAStartNode(DSNode* N) {
  assert(N && "Null node as argument");
  assert(FB && "No function for this graph?");
  Module *M = FB->getParent();
  assert(M && "No module for function");
  Triple TargetTriple(M->getTargetTriple());
  Triple::ArchType Arch = TargetTriple.getArch();

  // Fetch the VANode associated with the func containing the call to va_start
  DSNodeHandle & VANH = G.getVANodeFor(*FB);
  // Make sure this NodeHandle has a node to go with it
  if (VANH.isNull()) VANH.mergeWith(createNode());

  // Create a dsnode for an array of pointers to the VAInfo for this func
  DSNode * VAArray = createNode();
  VAArray->setArrayMarker();
  VAArray->foldNodeCompletely();
  VAArray->setLink(0,VANH);

  //VAStart modifies its argument
  N->setModifiedMarker();

  // For the architectures we support, build dsnodes that match
  // how we know va_list is used.
  switch (Arch) {
  case Triple::x86:
    // On x86, we have:
    // va_list as a pointer to an array of pointers to the variable arguments
    if (N->getSize() < 1)
      N->growSize(1);
    N->setLink(0, VAArray);
    break;
  case Triple::x86_64:
    // On x86_64, we have va_list as a struct {i32, i32, i8*, i8* }
    // The first i8* is where arguments generally go, but the second i8* can
    // be used also to pass arguments by register.
    // We model this by having both the i8*'s point to an array of pointers
    // to the arguments.
    if (N->getSize() < 24)
      N->growSize(24); //sizeof the va_list struct mentioned above
    N->setLink(8,VAArray); //first i8*
    N->setLink(16,VAArray); //second i8*
    break;
  default:
    // FIXME: For now we abort if we don't know how to handle this arch
    // Either add support for other architectures, or at least mark the
    // nodes unknown/incomplete or whichever results in the correct
    // conservative behavior in the general case
    assert(0 && "VAstart not supported on this architecture!");
    //XXX: This might be good enough in those cases that we don't know
    //what the arch does
    N->setIncompleteMarker()->setUnknownMarker()->foldNodeCompletely();
  }

  // XXX: We used to set the alloca marker for the DSNode passed to va_start.
  // Seems to me that you could allocate the va_list on the heap, so ignoring
  // for now.
  N->setModifiedMarker()->setVAStartMarker();
}
Example #2
0
///
/// Method: visitIntrinsic()
///
/// Description:
///   Generate correct DSNodes for calls to LLVM intrinsic functions.
///
/// Inputs:
///   CS - The CallSite representing the call or invoke to the intrinsic.
///   F  - A pointer to the function called by the call site.
///
/// Return value:
///   true  - This intrinsic is properly handled by this method.
///   false - This intrinsic is not recognized by DSA.
///
bool GraphBuilder::visitIntrinsic(CallSite CS, Function *F) {
  ++NumIntrinsicCall;

  //
  // If this is a debug intrinsic, then don't do any special processing.
  //
  if (isa<DbgInfoIntrinsic>(CS.getInstruction()))
    return true;

  switch (F->getIntrinsicID()) {
  case Intrinsic::vastart: {
    visitVAStartInst(CS);
    return true;
  }
  case Intrinsic::vacopy: {
    // Simply merge the two arguments to va_copy.
    // This results in loss of precision on the temporaries used to manipulate
    // the va_list, and so isn't a big deal.  In theory we would build a
    // separate graph for this (like the one created in visitVAStartNode)
    // and only merge the node containing the variable arguments themselves.
    DSNodeHandle destNH = getValueDest(CS.getArgument(0));
    DSNodeHandle srcNH = getValueDest(CS.getArgument(1));
    destNH.mergeWith(srcNH);
    return true;
  }
  case Intrinsic::stacksave: {
    DSNode * Node = createNode();
    Node->setAllocaMarker()->setIncompleteMarker()->setUnknownMarker();
    Node->foldNodeCompletely();
    setDestTo (*(CS.getInstruction()), Node);
    return true;
  }
  case Intrinsic::stackrestore:
    getValueDest(CS.getInstruction()).getNode()->setAllocaMarker()
      ->setIncompleteMarker()
      ->setUnknownMarker()
      ->foldNodeCompletely();
    return true;
  case Intrinsic::vaend:
  case Intrinsic::memcpy: 
  case Intrinsic::memmove: {
    // Merge the first & second arguments, and mark the memory read and
    // modified.
    DSNodeHandle RetNH = getValueDest(*CS.arg_begin());
    RetNH.mergeWith(getValueDest(*(CS.arg_begin()+1)));
    if (DSNode *N = RetNH.getNode())
      N->setModifiedMarker()->setReadMarker();
    return true;
  }
  case Intrinsic::memset:
    // Mark the memory modified.
    if (DSNode *N = getValueDest(*CS.arg_begin()).getNode())
      N->setModifiedMarker();
    return true;

  case Intrinsic::eh_exception: {
    DSNode * Node = createNode();
    Node->setIncompleteMarker();
    Node->foldNodeCompletely();
    setDestTo (*(CS.getInstruction()), Node);
    return true;
  }

  case Intrinsic::eh_selector: {
    for (CallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end();
         I != E; ++I) {
      if (isa<PointerType>((*I)->getType())) {
        DSNodeHandle Ptr = getValueDest(*I);
        if(Ptr.getNode()) {
          Ptr.getNode()->setReadMarker();
          Ptr.getNode()->setIncompleteMarker();
        }
      }
    }
    return true;
  }
  case Intrinsic::eh_typeid_for: {
    DSNodeHandle Ptr = getValueDest(*CS.arg_begin());
    Ptr.getNode()->setReadMarker();
    Ptr.getNode()->setIncompleteMarker();
    return true;
  }

  case Intrinsic::prefetch:
    return true;

  case Intrinsic::objectsize:
    return true;

    //
    // The return address/frame address aliases with the stack, 
    // is type-unknown, and should
    // have the unknown flag set since we don't know where it goes.
    //
  case Intrinsic::returnaddress:
  case Intrinsic::frameaddress: {
    DSNode * Node = createNode();
    Node->setAllocaMarker()->setIncompleteMarker()->setUnknownMarker();
    Node->foldNodeCompletely();
    setDestTo (*(CS.getInstruction()), Node);
    return true;
  }

  // Process lifetime intrinsics
  case Intrinsic::lifetime_start:
  case Intrinsic::lifetime_end:
  case Intrinsic::invariant_start:
  case Intrinsic::invariant_end:
    return true;

  default: {
    //ignore pointer free intrinsics
    if (!isa<PointerType>(F->getReturnType())) {
      bool hasPtr = false;
      for (Function::const_arg_iterator I = F->arg_begin(), E = F->arg_end();
           I != E && !hasPtr; ++I)
        if (isa<PointerType>(I->getType()))
          hasPtr = true;
      if (!hasPtr)
        return true;
    }

    DEBUG(errs() << "[dsa:local] Unhandled intrinsic: " << F->getName() << "\n");
    assert(0 && "Unhandled intrinsic");
    return false;
  }
  }
}
Example #3
0
//
// Function: MergeConstantInitIntoNode()
//
// Description:
//  Merge the specified constant into the specified DSNode.
//
void
GraphBuilder::MergeConstantInitIntoNode(DSNodeHandle &NH,
                                        Type* Ty,
                                        Constant *C) {
  //
  // Ensure a type-record exists...
  //
  DSNode *NHN = NH.getNode();
  //NHN->mergeTypeInfo(Ty, NH.getOffset());

  //
  // If we've found something of pointer type, create or find its DSNode and
  // make a link from the specified DSNode to the new DSNode describing the
  // pointer we've just found.
  //
  if (isa<PointerType>(Ty)) {
    NHN->mergeTypeInfo(Ty, NH.getOffset());
    NH.addEdgeTo(getValueDest(C));
    return;
  }

  //
  // If the type of the object (array element, structure field, etc.) is an
  // integer or floating point type, then just ignore it.  It has no DSNode.
  //
  if (Ty->isIntOrIntVectorTy() || Ty->isFPOrFPVectorTy()) return;

  //
  // Handle aggregate constants.
  //
  if (ConstantArray *CA = dyn_cast<ConstantArray>(C)) {
    //
    // For an array, we don't worry about different elements pointing to
    // different objects; we essentially pretend that all array elements alias.
    //
    Type * ElementType = cast<ArrayType>(Ty)->getElementType();
    for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i) {
      Constant * ConstElement = cast<Constant>(CA->getOperand(i));
      MergeConstantInitIntoNode(NH, ElementType, ConstElement);
    }
  } else if (ConstantStruct *CS = dyn_cast<ConstantStruct>(C)) {
    //
    // For a structure, we need to merge each element of the constant structure
    // into the specified DSNode.  However, we must also handle structures that
    // end with a zero-length array ([0 x sbyte]); this is a common C idiom
    // that continues to plague the world.
    //
    //NHN->mergeTypeInfo(Ty, NH.getOffset());

    const StructLayout *SL = TD.getStructLayout(cast<StructType>(Ty));

    for (unsigned i = 0, e = CS->getNumOperands(); i != e; ++i) {
      DSNode *NHN = NH.getNode();
      if (SL->getElementOffset(i) < SL->getSizeInBytes()) {
        //
        // Get the type and constant value of this particular element of the
        // constant structure.
        //
        Type * ElementType = cast<StructType>(Ty)->getElementType(i);
        Constant * ConstElement = cast<Constant>(CS->getOperand(i));

        //
        // Get the offset (in bytes) into the memory object that we're
        // analyzing.
        //
        unsigned offset = NH.getOffset()+(unsigned)SL->getElementOffset(i);
        NHN->mergeTypeInfo(ElementType, offset);
        //
        // Create a new DSNodeHandle.  This DSNodeHandle will point to the same
        // DSNode as the one we're constructing for our caller; however, it
        // will point into a different offset into that DSNode.
        //
        DSNodeHandle NewNH (NHN, offset);
        assert ((NHN->isNodeCompletelyFolded() || (NewNH.getOffset() == offset))
                && "Need to resize DSNode!");

        //
        // Recursively merge in this element of the constant struture into the
        // DSNode.
        //
        MergeConstantInitIntoNode(NewNH, ElementType, ConstElement);
      } else if (SL->getElementOffset(i) == SL->getSizeInBytes()) {
        //
        // If this is one of those cute structures that ends with a zero-length
        // array, just fold the DSNode now and get it over with.
        //
        DEBUG(errs() << "Zero size element at end of struct\n" );
        NHN->foldNodeCompletely();
      } else {
        assert(0 && "type was smaller than offsets of struct layout indicate");
      }
    }
  } else if (isa<ConstantAggregateZero>(C) || isa<UndefValue>(C)) {
    //
    // Undefined values and NULL pointers have no DSNodes, so they do nothing.
    //
  } else {
    assert(0 && "Unknown constant type!");
  }
}