1.3.3.4.1.1.10. 对整数ßà指针指令的处理
IntToPtrInst代表把一个整数转换到一个指针。由于Value是IntToPtrInst的基类之一,如果这个Value只有一个用户(llvm的User类),hasOneUse返回true。如果该用户是ICmpInst——整数/指针比较语句,那么566行的NumBoringIntToPtr用于统计这种事件。在其他情况,由于得到的指针所指向的内存对象未知,在571行进行标记。
562 void GraphBuilder::visitIntToPtrInst(IntToPtrInst&I) {
563 DSNode *N = createNode();
564 if(I.hasOneUse()) {
565 if(isa<ICmpInst>(*(I.use_begin()))) {
566 NumBoringIntToPtr++;
567 return;
568 }
569 } else {
570 N->setIntToPtrMarker();
571 N->setUnknownMarker();
572 }
573 setDestTo(I,N);
574 }
类似的,PtrToIntInst代表把一个指针转换到一个整数。586行的DenseSet是llvm定义的容器,其在588行的insert方法返回std::pair<iterator, bool>,在插入成功或对象已在容器中时,返回pair的第二个元素是true。那么587行while循环的作用就是沿着用户链,发掘类型为BranchInst的用户,进行统计。NumBoringIntToPtr统记了仅用在cmp的inttoptr的数目。
576 void GraphBuilder::visitPtrToIntInst(PtrToIntInst&I) {
577 DSNode* N = getValueDest(I.getOperand(0)).getNode();
578 if(I.hasOneUse()) {
579 if(isa<ICmpInst>(*(I.use_begin()))) {
580 NumBoringIntToPtr++;
581 return;
582 }
583 }
584 if(I.hasOneUse()) {
585 Value *V = dyn_cast<Value>(*(I.use_begin()));
586 DenseSet<Value *> Seen;
587 while(V&& V->hasOneUse() &&
588 Seen.insert(V).second) {
589 if(isa<LoadInst>(V))
590 break;
591 if(isa<StoreInst>(V))
592 break;
593 if(isa<CallInst>(V))
594 break;
595 V =dyn_cast<Value>(*(V->use_begin()));
596 }
597 if(isa<BranchInst>(V)){
598 NumBoringIntToPtr++;
599 return;
600 }
601 }
602 if(N)
603 N->setPtrToIntMarker();
604 }
1.3.3.4.1.1.11. 对bitcast指令的处理
BitCastInst代表一个空操作转换,因为这个转换没有比特位的改变。显然对于DSA,这个转换在涉及指针时才有价值。
607 void GraphBuilder::visitBitCastInst(BitCastInst&I) {
608 if (!isa<PointerType>(I.getType())) return; // Only pointers
609 DSNodeHandle Ptr = getValueDest(I.getOperand(0));
610 if (Ptr.isNull()) return;
611 setDestTo(I,Ptr);
612 }
1.3.3.4.1.1.12. 对insertvalue指令的处理
InsertValueInst向一个聚集类型(struct/class/union或数组)值的一个数据成员插入值,并返回更新后的聚集类型值。InsertValueInst带至少三个参数,第一个是聚集类型值,第二个是插入的值,第三个是指示插入位置的常量。
648 void GraphBuilder::visitInsertValueInst(InsertValueInst&I) {
649 setDestTo(I,createNode()->setAllocaMarker());
650
651 Type *StoredTy =I.getInsertedValueOperand()->getType();
652 DSNodeHandle Dest = getValueDest(&I);
653 Dest.mergeWith(getValueDest(I.getAggregateOperand()));
654
655 // Mark that thenode is written to...
656 Dest.getNode()->setModifiedMarker();
657 Type* STy =I.getAggregateOperand()->getType();
658
659 unsigned Offset = getValueOffset(STy,I.getIndices(), TD);
660
661 // Ensure atype-record exists...
662 Dest.getNode()->mergeTypeInfo(StoredTy, Offset);
663
664 // Avoid addingedges from null, or processing non-"pointer" stores
665 if (isa<PointerType>(StoredTy))
666 Dest.addEdgeTo(getValueDest(I.getInsertedValueOperand()));
667 }
在649行,为InsertValueInst创建了DSNodeHandle,并指向同一行构建的标记为alloca的DSNode(代表其在栈上构建的返回值)。这个DSNodeHandle在652行通过getValueDesc给出。接着在653行,它与第一个参数的节点发生了简并(因为它们的指针域都要指向相同的地方)。因为llvm IR要求操作数的类型必须严格匹配,因此662行确保要保存的值的类型存在于结构体指定的位置上(至于这个位置所代表的多个类型是否相容就是另一个问题了)。最后,如果插入的值是个指针,在666行让Dest有指向该指针指向对象的一条边。
1.3.3.4.1.1.13. 对extractvalue指令的处理
ExtractValueInst则是InsertValueInst的相反操作——从一个聚集类型值的指定域提取值。它也类似地带至少三个参数,第一个是聚集类型值,第二个是提取的值,第三个是指示提取位置的常量。
669 void GraphBuilder::visitExtractValueInst(ExtractValueInst&I) {
670 DSNodeHandle Ptr = getValueDest(I.getAggregateOperand());
671
672 // Make that thenode is read from...
673 Ptr.getNode()->setReadMarker();
674 Type* STy =I.getAggregateOperand()->getType();
675
676 unsigned Offset = getValueOffset(STy,I.getIndices(), TD);
677
678 // Ensure atyperecord exists...
679 Ptr.getNode()->mergeTypeInfo(I.getType(), Offset);
680
681 if (isa<PointerType>(I.getType()))
682 setDestTo(I,getLink(Ptr));
683 }
这里的处理与InsertValueInst类似,且更简单。
1.3.3.4.1.1.14. 对GetElementPtr指令的处理
参考1.3.3.2.2.2. 对GetElementPtr指令的处理一节。
1.3.3.4.1.1.15. 对调用指令的处理
在llvm IR中,CallInst来自call指令,InvokeInst来自invoke指令。两者都是对函数的调用,主要的区别在于,invoke指令会创建与一个标记的关联,该关联被运行时用于回滚栈。不过,对于DSA这两者没有区别。
904 void GraphBuilder::visitCallInst(CallInst&CI) {
904 visitCallSite(&CI);
904 }
904 void GraphBuilder::visitInvokeInst(InvokeInst&II) {
904 visitCallSite(&II);
904 }
要以相同的方式处理CallInst及InvokeInst,就要用到CallSite。它是llvm专门提供的一个便利的封装类。Intrinsic函数由1143行的visitIntrinsic处理。而对于内联汇编函数,采用保守的处理,把所有的指针视为互为别名,进行简并,并缩合返回值节点,如果它是指针。
1135 void GraphBuilder::visitCallSite(CallSite CS){
1136 //
1137 // Get the calledvalue. Strip off any casts which arelossless.
1138 //
1139 Value *Callee =CS.getCalledValue()->stripPointerCasts();
1140
1141 // Special case handlingof certain libc allocation functions here.
1142 if (Function *F =dyn_cast<Function>(Callee))
1143 if (F->isIntrinsic() && visitIntrinsic(CS, F))
1144 return;
1145
1146 //Can't do muchabout inline asm (yet!)
1147 if (isa<InlineAsm> (Callee)) {
1148 ++NumAsmCall;
1149 DSNodeHandle RetVal;
1150 Instruction *I = CS.getInstruction();
1151 if (isa<PointerType >(I->getType()))
1152 RetVal = getValueDest(I);
1153
1154 // Calculatethe arguments vector...
1155 for(CallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end(); I != E; ++I)
1156 if (isa<PointerType >((*I)->getType()))
1157 RetVal.mergeWith(getValueDest(*I));
1158 if (!RetVal.isNull())
1159 RetVal.getNode()->foldNodeCompletely();
1160 return;
1161 }
1162
1163 // Set up thereturn value...
1164 DSNodeHandle RetVal;
1165 Instruction *I = CS.getInstruction();
1166 if (isa<PointerType>(I->getType()))
1167 RetVal = getValueDest(I);
1168
1169 DSNode *CalleeNode = 0;
1170 if (!isa<Function>(Callee)) {
1171 CalleeNode = getValueDest(Callee).getNode();
1172 if (CalleeNode == 0) {
1173 DEBUG(errs() << "WARNING:Program is calling through a null pointer?\n" << *I);
1174 return; // Calling a nullpointer?
1175 }
1176 }
1177
1178 // NOTE: Thiscode is identical to 'DSGraph::getDSCallSiteForCallSite',
1179 // the reasonit's duplicated is because this calls getValueDest instead
1180 // ofgetNodeForValue to get the DSNodes for the arguments. Since we're in
1181 // local it'spossible that we need to create a DSNode for the argument, as
1182 // opposed togetNodeForValue which simply retrieves the existing node.
1183
1184
1185 //Get theFunctionType for the called function
1186 constFunctionType *CalleeFuncType = DSCallSite::FunctionTypeOfCallSite(CS);
1187 int NumFixedArgs =CalleeFuncType->getNumParams();
1188
1189 // Sanitycheck--this really, really shouldn't happen
1190 if (!CalleeFuncType->isVarArg())
1191 assert(CS.arg_size()== static_cast<unsigned>(NumFixedArgs)&&
1192 "Too many arguments/incorrectfunction signature!");
1193
1194 std::vector<DSNodeHandle> Args;
1195 Args.reserve(CS.arg_size());
1196 DSNodeHandle VarArgNH;
1197
1198 // Calculate thearguments vector...
1199 // Add all fixedpointer arguments, then merge the rest together
1200 for(CallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end();
1201 I != E; ++I)
1202 if(isa<PointerType>((*I)->getType())) {
1203 DSNodeHandle ArgNode = getValueDest(*I);
1204 if (I - CS.arg_begin() < NumFixedArgs){
1205 Args.push_back(ArgNode);
1206 } else {
1207 VarArgNH.mergeWith(ArgNode);
1208 }
1209 }
1210
1211 // Add a newfunction call entry...
1212 if (CalleeNode) {
1213 ++NumIndirectCall;
1214 G.getFunctionCalls().push_back(DSCallSite(CS, RetVal, VarArgNH,CalleeNode,
1215 Args));
1216 } else {
1217 ++NumDirectCall;
1218 G.getFunctionCalls().push_back(DSCallSite(CS,RetVal, VarArgNH,
1219 cast<Function>(Callee),
1220 Args));
1221 }
1222
1223
1224 }
在DSGraph值专门有一个域FunctionCalls记录有关函数调用的DSA节点。这个域的类型是std::list<DSCallSite>,而类型DSCallSite有如下成员:
160 typedefstd::set<CallSite> MappedSites_t;
161 private:
162 CallSite Site; //Actual call site
163 constFunction *CalleeF; // The functioncalled (direct call)
164 DSNodeHandle CalleeN; // Thefunction node called (indirect call)
165 DSNodeHandle RetVal; //Returned value
166 DSNodeHandle VarArgVal; // Mergedvar-arg val
167 std::vector<DSNodeHandle> CallArgs; // The pointer arguments
168 MappedSites_t MappedSites; // Themerged callsites
这些成员的含义,注释已经说得很清楚。1214及1218行调用了下面这两个构造函数:
199 DSCallSite(CallSite CS, const DSNodeHandle &rv, constDSNodeHandle &va,
200 DSNode *Callee,std::vector<DSNodeHandle> &Args)
201 : Site(CS), CalleeF(0), CalleeN(Callee),RetVal(rv), VarArgVal(va) {
202 assert(Callee&& "Null callee node specified for call site!");
203 Args.swap(CallArgs);
204 }
205 DSCallSite(CallSite CS, const DSNodeHandle &rv, constDSNodeHandle &va,
206 constFunction *Callee, std::vector<DSNodeHandle> &Args)
207 : Site(CS), CalleeF(Callee), RetVal(rv),VarArgVal(va) {
208 assert(Callee&& "Null callee function specified for call site!");
209 Args.swap(CallArgs);
210 }
在1214行CalleeNode被设置到CalleeN,而在1218行,Callee被设置到CalleeF。
1.3.3.4.1.1.16. 对其他指令的处理
根据基类InstVisitor的安排,所有没有重载的visit*函数,都最终会进入visitInstruction函数。对于DSA,只关心Inst的类型。如果它是指针类型,意味着其返回值与其指针类型的操作数可能互为别名,于是将它们简并起来。
1229 void GraphBuilder::visitInstruction(Instruction&Inst) {
1230 DSNodeHandle CurNode;
1231 if (isa<PointerType>(Inst.getType()))
1232 CurNode = getValueDest(&Inst);
1233 for(User::op_iterator I = Inst.op_begin(), E = Inst.op_end(); I != E; ++I)
1234 if(isa<PointerType>((*I)->getType()))
1235 CurNode.mergeWith(getValueDest(*I));
1236
1237 if (DSNode *N = CurNode.getNode())
1238 N->setUnknownMarker();
1239 }
如果CurNode不是指向null,把这个DSNode标记为unknown,而不是Incomplete。这是Chris在论文中强调过的。