PSNodesSeq LLVMPointerSubgraphBuilder::createVarArg(const llvm::IntrinsicInst *Inst) { // just store all the pointers from vararg argument // to the memory given in vastart() on Offset::UNKNOWN. // It is the easiest thing we can do without any further // analysis // first we need to get the vararg argument phi const llvm::Function *F = Inst->getParent()->getParent(); Subgraph& subg = subgraphs_map[F]; PSNode *arg = subg.vararg; assert(F->isVarArg() && "vastart in a non-variadic function"); assert(arg && "Don't have variadic argument in a variadic function"); // vastart will be node that will keep the memory // with pointers, its argument is the alloca, that // alloca will keep pointer to vastart PSNode *vastart = PS.create(PSNodeType::ALLOC); // vastart has only one operand which is the struct // it uses for storing the va arguments. Strip it so that we'll // get the underlying alloca inst PSNode *op = getOperand(Inst->getOperand(0)->stripInBoundsOffsets()); // the argument is usually an alloca, but it may be a load // in the case the code was transformed by -reg2mem assert((op->getType() == PSNodeType::ALLOC || op->getType() == PSNodeType::LOAD) && "Argument of vastart is invalid"); // get node with the same pointer, but with Offset::UNKNOWN // FIXME: we're leaking it // make the memory in alloca point to our memory in vastart PSNode *ptr = PS.create(PSNodeType::GEP, op, Offset::UNKNOWN); PSNode *S1 = PS.create(PSNodeType::STORE, vastart, ptr); // and also make vastart point to the vararg args PSNode *S2 = PS.create(PSNodeType::STORE, arg, vastart); vastart->addSuccessor(ptr); ptr->addSuccessor(S1); S1->addSuccessor(S2); // set paired node to S2 for vararg, so that when adding structure, // we add the whole sequence (it adds from call-node to pair-node, // because of the old system where we did not store all sequences) // FIXME: fix this vastart->setPairedNode(S2); // FIXME: we're assuming that in a sequence in the nodes_map // is always the last node the 'real' node. In this case it is not true, // so add only the 'vastart', so that we have the mapping in nodes_map addNode(Inst, vastart); return PSNodesSeq(vastart, S2); }
PSNodesSeq LLVMPointerSubgraphBuilder::createUnknownCall(const llvm::CallInst *CInst) { // This assertion must not hold if the call is wrapped // inside bitcast - it defaults to int, but is bitcased // to pointer //assert(CInst->getType()->isPointerTy()); PSNode *call = PS.create(PSNodeType::CALL, nullptr); call->setPairedNode(call); // the only thing that the node will point at call->addPointsTo(PointerUnknown); addNode(CInst, call); return std::make_pair(call, call); }
PSNode * LLVMPointerSubgraphBuilder::createAsm(const llvm::Instruction *Inst) { // we filter irrelevant calls in isRelevantCall() // and we don't have assembler there at all. If // we are here, then we got here because this // is undefined call that returns pointer. // In this case return an unknown pointer static bool warned = false; if (!warned) { llvm::errs() << "PTA: Inline assembly found, analysis may be unsound\n"; warned = true; } PSNode *n = PS.create(PSNodeType::CONSTANT, UNKNOWN_MEMORY, Offset::UNKNOWN); // it is call that returns pointer, so we'd like to have // a 'return' node that contains that pointer n->setPairedNode(n); addNode(Inst, n); return n; }