/// addObjCClass - Parse i386/ppc ObjC class data structure. void LTOModule::addObjCClass(GlobalVariable *clgv) { ConstantStruct *c = dyn_cast<ConstantStruct>(clgv->getInitializer()); if (!c) return; // second slot in __OBJC,__class is pointer to superclass name std::string superclassName; if (objcClassNameFromExpression(c->getOperand(1), superclassName)) { NameAndAttributes info; StringMap<NameAndAttributes>::value_type &entry = _undefines.GetOrCreateValue(superclassName); if (!entry.getValue().name) { const char *symbolName = entry.getKey().data(); info.name = symbolName; info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; info.isFunction = false; info.symbol = clgv; entry.setValue(info); } } // third slot in __OBJC,__class is pointer to class name std::string className; if (objcClassNameFromExpression(c->getOperand(2), className)) { StringSet::value_type &entry = _defines.GetOrCreateValue(className); entry.setValue(1); NameAndAttributes info; info.name = entry.getKey().data(); info.attributes = LTO_SYMBOL_PERMISSIONS_DATA | LTO_SYMBOL_DEFINITION_REGULAR | LTO_SYMBOL_SCOPE_DEFAULT; info.isFunction = false; info.symbol = clgv; _symbols.push_back(info); } }
static void readFuncList(GlobalVariable *Array, std::vector<Constant*> *Funcs) { if (!Array->hasInitializer()) return; Constant *Init = Array->getInitializer(); ArrayType *Ty = dyn_cast<ArrayType>(Init->getType()); if (!Ty) { errs() << "Initializer: " << *Array->getInitializer() << "\n"; report_fatal_error("ExpandCtors: Initializer is not of array type"); } if (Ty->getNumElements() == 0) return; ConstantArray *InitList = dyn_cast<ConstantArray>(Init); if (!InitList) { errs() << "Initializer: " << *Array->getInitializer() << "\n"; report_fatal_error("ExpandCtors: Unexpected initializer ConstantExpr"); } std::vector<FuncArrayEntry> FuncsToSort; for (unsigned Index = 0; Index < InitList->getNumOperands(); ++Index) { ConstantStruct *CS = cast<ConstantStruct>(InitList->getOperand(Index)); FuncArrayEntry Entry; Entry.priority = cast<ConstantInt>(CS->getOperand(0))->getZExtValue(); Entry.func = CS->getOperand(1); FuncsToSort.push_back(Entry); } std::sort(FuncsToSort.begin(), FuncsToSort.end(), compareEntries); for (std::vector<FuncArrayEntry>::iterator Iter = FuncsToSort.begin(); Iter != FuncsToSort.end(); ++Iter) { Funcs->push_back(Iter->func); } }
CtorDtorIterator::Element CtorDtorIterator::operator*() const { ConstantStruct *CS = dyn_cast<ConstantStruct>(InitList->getOperand(I)); assert(CS && "Unrecognized type in llvm.global_ctors/llvm.global_dtors"); Constant *FuncC = CS->getOperand(1); Function *Func = nullptr; // Extract function pointer, pulling off any casts. while (FuncC) { if (Function *F = dyn_cast_or_null<Function>(FuncC)) { Func = F; break; } else if (ConstantExpr *CE = dyn_cast_or_null<ConstantExpr>(FuncC)) { if (CE->isCast()) FuncC = dyn_cast_or_null<ConstantExpr>(CE->getOperand(0)); else break; } else { // This isn't anything we recognize. Bail out with Func left set to null. break; } } ConstantInt *Priority = dyn_cast<ConstantInt>(CS->getOperand(0)); Value *Data = CS->getNumOperands() == 3 ? CS->getOperand(2) : nullptr; if (Data && !isa<GlobalValue>(Data)) Data = nullptr; return Element(Priority->getZExtValue(), Func, Data); }
/// Find the llvm.global_ctors list, verifying that all initializers have an /// init priority of 65535. static GlobalVariable *findGlobalCtors(Module &M) { GlobalVariable *GV = M.getGlobalVariable("llvm.global_ctors"); if (!GV) return nullptr; // Verify that the initializer is simple enough for us to handle. We are // only allowed to optimize the initializer if it is unique. if (!GV->hasUniqueInitializer()) return nullptr; if (isa<ConstantAggregateZero>(GV->getInitializer())) return GV; ConstantArray *CA = cast<ConstantArray>(GV->getInitializer()); for (auto &V : CA->operands()) { if (isa<ConstantAggregateZero>(V)) continue; ConstantStruct *CS = cast<ConstantStruct>(V); if (isa<ConstantPointerNull>(CS->getOperand(1))) continue; // Must have a function or null ptr. if (!isa<Function>(CS->getOperand(1))) return nullptr; // Init priority must be standard. ConstantInt *CI = cast<ConstantInt>(CS->getOperand(0)); if (CI->getZExtValue() != 65535) return nullptr; } return GV; }
void ClassHierarchyUtils::findClassHierarchy(Module& M) { // Extract class hierarchy using std::type_info structures rather than debug // info. The former works even for when there are anonymous namespaces. // (for more info, see http://mentorembedded.github.io/cxx-abi/abi.html) // // Class names are usually global, except in the case of anonymous namespaces, in which case // they may be renamed during linking. This renaming is not consistent across type_info and // vtables. For example, the following are for the same class: // _ZTIN7content12_GLOBAL__N_115HeaderFlattenerE60908 and // _ZTVN7content12_GLOBAL__N_115HeaderFlattenerE60906. // // (renamed from // _ZTVN7content12_GLOBAL__N_115HeaderFlattenerE and // _ZTIN7content12_GLOBAL__N_115HeaderFlattenerE). // // VTables give us the corresponding type_info, so we process them first and store // the VT <-> TI mappings, as this will be useful later. for (Module::global_iterator I=M.global_begin(), E=M.global_end(); I != E; I++) { GlobalVariable* VT = &*I; if (VT->getName().startswith("_ZTV")) { SDEBUG("soaap.util.classhierarchy", 3, dbgs() << "Found vtable: " << VT->getName() << "\n"); if (VT->hasInitializer()) { ConstantStruct* VTinit = cast<ConstantStruct>(VT->getInitializer()); // all occurrences of a type_info object refer to this class's type_info, so we // can pick the first array ConstantArray* VTinitElem = cast<ConstantArray>(VTinit->getOperand(0)); for (int i=0; i<VTinitElem->getNumOperands(); i++) { // type_info will be the first global variable in the array. // It's not always at a fixed index so we have to search for it... // The first one corresponds to the primary vtable, all others // correspond to secondary vtables. All type_info occurrences will // be the same. if (GlobalVariable* TI = dyn_cast<GlobalVariable>(VTinitElem->getOperand(i)->stripPointerCasts())) { if (typeInfoToVTable.find(TI) != typeInfoToVTable.end()) { report_fatal_error(TI->getName() + " <-> " + VT->getName() + " mapping already exists!"); } // Record TI <-> VT mappings, as they will be useful later typeInfoToVTable[TI] = VT; vTableToTypeInfo[VT] = TI; break; // we only need to process the first one } } } else { SDEBUG("soaap.util.classhierarchy", 1, dbgs() << "WARNING: VTable " << VT->getName() << " does not have initializer\n"); } } } // Process type_info structures, recording class-hierarchy information and base offsets for (Module::global_iterator I=M.global_begin(), E=M.global_end(); I != E; I++) { GlobalVariable* G = &*I; if (G->getName().startswith("_ZTI")) { SDEBUG("soaap.util.classhierarchy", 3, dbgs() << "Found type_info: " << G->getName() << "\n"); processTypeInfo(G, M); } } SDEBUG("soaap.util.classhierarchy", 3, ppClassHierarchy(classToSubclasses)); }
// add to analyze function pointer bool PathList::extend_calledFunctionMap(Instruction *tmpfi, User *tmpuser, GlobalVariable *func_table, Function *ff) { // the first operand of GetElementPtrInst is user of the table if (tmpfi->getOperand(0) == tmpuser) { errs()<<"=====find function which calls command_table\n"; // coutn++; // if the index of the table is a constant int if (ConstantInt *cint = dyn_cast<ConstantInt>(tmpfi->getOperand(2))) { // todo: deal with the constantint index } else {// if the index is a variavle, then add all the funcitons of command_table into the CallGraph // get the initialization value of the global table if (Constant *C = func_table->getInitializer()) { llvm::ConstantArray *ca = dyn_cast<llvm::ConstantArray>(&*C); if (ca) { errs()<<"Get ConstantArray ca success.\n"; errs()<<ca->getNumOperands()<<'\n'; // get the element of the global table for (int cai = 0; cai < ca->getNumOperands(); cai++) { Constant *tmpca = ca->getOperand(cai); //tmpca->dump(); ConstantStruct *cs = dyn_cast<ConstantStruct>(&*tmpca); if (cs) { //errs()<<"get ConstantStruct cs success.\n"; //errs()<<cs->getNumOperands()<<'\n'; Constant *tmpcs = cs->getOperand(1); //tmpcs->dump(); //errs() << tmpcs->getNumOperands()<<'\n'; //tmpcs->getType()->dump(); //tmpcs->getOperand(0)->dump(); // get the funciton pointer of the element if (Function *csfunc = dyn_cast<Function>(&*(tmpcs->getOperand(0)))) { //errs() << "get function tmpcs success.\n"; // add the current funciton ff to the calledFunctionMap // as the funciton which calls function csfunc FunctionMapTy::iterator it2 = calledFunctionMap.find(csfunc); if(it2==calledFunctionMap.end()) //not find { calledFunctionMap[csfunc].push_back(std::make_pair(ff, tmpfi)); } else { it2->second.push_back(std::make_pair(ff, tmpfi)); } } } } } else return false; } else { dbgs() << "Get the initialization value of the global table failed!\n"; return false; } } } else return false; return true; }
Value *DbgStopPointInst::getDirectory() const { // Once the operand indices are verified, update this assert assert(LLVMDebugVersion == (7 << 16) && "Verify operand indices"); GlobalVariable *GV = cast<GlobalVariable>(getContext()); if (!GV->hasInitializer()) return NULL; ConstantStruct *CS = cast<ConstantStruct>(GV->getInitializer()); return CS->getOperand(4); }
void ControlFlowIntegrity::PatchDtorFunctions(void) { GlobalVariable *global_dtors = _M.getNamedGlobal("llvm.global_dtors"); // check for dtor section if (!global_dtors || !global_dtors->getOperand(0)) { return; } Constant *c = global_dtors->getInitializer(); if (!c) report_fatal_error("llvm.global_dtors without initializer!", false); ConstantArray *CA = dyn_cast<ConstantArray>(c); if (!CA) report_fatal_error("Cast to ConstantArray failed", true); for (Value *Op : ValueOpRange(*CA)) { ConstantStruct *CS = dyn_cast<ConstantStruct>(Op); if (!CS) report_fatal_error("Cast to ConstantStruct failed", true); Constant *FP = CS->getOperand(1); if (FP->isNullValue()) break; // found a NULL termintator, stop here Function *F = dyn_cast_or_null<Function>(FP); if (F == NULL) { // Strip off constant expression cast ConstantExpr *CE = dyn_cast<ConstantExpr>(FP); if (!CE) report_fatal_error("Cast to ConstantExpr failed", true); if (CE->isCast()) { FP = CE->getOperand(0); } F = dyn_cast_or_null<Function>(FP); } if (!F) report_fatal_error("Cast to Function failed", true); // set visibility to hidden (do not export), unless it is already // local (for ex. static), in which case we have to make it non-static if (F->hasLocalLinkage()) { F->setLinkage(llvm::GlobalValue::ExternalLinkage); } F->setVisibility(GlobalValue::HiddenVisibility); _FiniFunctions.insert(F->getName()); } if (global_dtors->getNumUses() > 0) report_fatal_error("llvm.global_dtors uses count is > 0!", false); global_dtors->removeFromParent(); }
static std::vector<Function*> parseGlobalCtors(GlobalVariable *GV) { if (GV->getInitializer()->isNullValue()) return std::vector<Function *>(); ConstantArray *CA = cast<ConstantArray>(GV->getInitializer()); std::vector<Function *> Result; Result.reserve(CA->getNumOperands()); for (User::op_iterator i = CA->op_begin(), e = CA->op_end(); i != e; ++i) { ConstantStruct *CS = cast<ConstantStruct>(*i); Result.push_back(dyn_cast<Function>(CS->getOperand(1))); } return Result; }
/// Given a llvm.global_ctors list that we can understand, /// return a list of the functions and null terminator as a vector. static std::vector<Function *> parseGlobalCtors(GlobalVariable *GV) { if (GV->getInitializer()->isNullValue()) return std::vector<Function *>(); ConstantArray *CA = cast<ConstantArray>(GV->getInitializer()); std::vector<Function *> Result; Result.reserve(CA->getNumOperands()); for (auto &V : CA->operands()) { ConstantStruct *CS = cast<ConstantStruct>(V); Result.push_back(dyn_cast<Function>(CS->getOperand(1))); } return Result; }
void ClassHierarchyUtils::processTypeInfo(GlobalVariable* TI) { if (find(classes.begin(), classes.end(), TI) == classes.end()) { classes.push_back(TI); // extract direct base classes from type_info if (TI->hasInitializer()) { ConstantStruct* TIinit = cast<ConstantStruct>(TI->getInitializer()); int TInumOperands = TIinit->getNumOperands(); if (TInumOperands > 2) { // we have >= 1 base class(es). if (TInumOperands == 3) { // abi::__si_class_type_info GlobalVariable* baseTI = cast<GlobalVariable>(TIinit->getOperand(2)->stripPointerCasts()); classToSubclasses[baseTI].push_back(TI); //dbgs() << " " << *baseTI << "\n"; classToBaseOffset[TI][baseTI] = 0; processTypeInfo(baseTI); } else { // abi::__vmi_class_type_info // (skip over first two additional fields, which are "flags" and "base_count") for (int i=4; i<TInumOperands; i+=2) { GlobalVariable* baseTI = cast<GlobalVariable>(TIinit->getOperand(i)->stripPointerCasts()); classToSubclasses[baseTI].push_back(TI); int offset_flags = cast<ConstantInt>(TIinit->getOperand(i+1))->getSExtValue(); SDEBUG("soaap.util.classhierarchy", 3, dbgs() << TI->getName() << " -> " << baseTI->getName() << "\n"); SDEBUG("soaap.util.classhierarchy", 3, dbgs() << " offset_flags = " << offset_flags << "\n"); int offset = offset_flags >> 8; // TODO: is this value defined as a constant somewhere? SDEBUG("soaap.util.classhierarchy", 3, dbgs() << " offset = " << offset << "\n"); classToBaseOffset[TI][baseTI] = offset; //dbgs() << " " << *baseTI << "\n"; processTypeInfo(baseTI); } } } }
void MemoryInstrumenter::lowerGlobalCtors(Module &M) { // Find llvm.global_ctors. GlobalVariable *GV = M.getNamedGlobal("llvm.global_ctors"); if (!GV) return; assert(!GV->isDeclaration() && !GV->hasLocalLinkage()); // Should be an array of '{ int, void ()* }' structs. The first value is // the init priority, which must be 65535 if the bitcode is generated using // clang. if (ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer())) { for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) { ConstantStruct *CS = dyn_cast<ConstantStruct>(InitList->getOperand(i)); assert(CS); assert(CS->getNumOperands() == 2); // Get the priority. ConstantInt *Priority = dyn_cast<ConstantInt>(CS->getOperand(0)); assert(Priority); // TODO: For now, we assume all priorities must be 65535. assert(Priority->equalsInt(65535)); // Get the constructor function. Constant *FP = CS->getOperand(1); if (FP->isNullValue()) break; // Found a null terminator, exit. // Explicitly call the constructor at the main entry. CallInst::Create(FP, "", Main->begin()->getFirstNonPHI()); } } // Clear the global_ctors array. // Use eraseFromParent() instead of removeFromParent(). GV->eraseFromParent(); }
// what a hack static Function *getStubFunctionForCtorList(Module *m, GlobalVariable *gv, std::string name) { assert(!gv->isDeclaration() && !gv->hasInternalLinkage() && "do not support old LLVM style constructor/destructor lists"); std::vector<Type *> nullary; Function *fn = Function::Create(FunctionType::get(Type::getVoidTy(m->getContext()), nullary, false), GlobalVariable::InternalLinkage, name, m); BasicBlock *bb = BasicBlock::Create(m->getContext(), "entry", fn); // From lli: // Should be an array of '{ int, void ()* }' structs. The first value is // the init priority, which we ignore. ConstantArray *arr = dyn_cast<ConstantArray>(gv->getInitializer()); if (arr) { for (unsigned i=0; i<arr->getNumOperands(); i++) { ConstantStruct *cs = cast<ConstantStruct>(arr->getOperand(i)); #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 5) // There is a third *optional* element in global_ctor elements (``i8 // @data``). assert((cs->getNumOperands() == 2 || cs->getNumOperands() == 3) && "unexpected element in ctor initializer list"); #else assert(cs->getNumOperands()==2 && "unexpected element in ctor initializer list"); #endif Constant *fp = cs->getOperand(1); if (!fp->isNullValue()) { if (llvm::ConstantExpr *ce = dyn_cast<llvm::ConstantExpr>(fp)) fp = ce->getOperand(0); if (Function *f = dyn_cast<Function>(fp)) { CallInst::Create(f, "", bb); } else { assert(0 && "unable to get function pointer from ctor initializer list"); } } } } ReturnInst::Create(m->getContext(), bb); return fn; }
// Parse i386/ppc ObjC category data structure. void LTOModule::addObjCCategory(GlobalVariable *clgv) { ConstantStruct *c = dyn_cast<ConstantStruct>(clgv->getInitializer()); if (!c) return; // second slot in __OBJC,__category is pointer to target class name std::string targetclassName; if (!objcClassNameFromExpression(c->getOperand(1), targetclassName)) return; NameAndAttributes info; StringMap<NameAndAttributes>::value_type &entry = _undefines.GetOrCreateValue(targetclassName); if (entry.getValue().name) return; const char *symbolName = entry.getKey().data(); info.name = symbolName; info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; entry.setValue(info); }
bool CheckInserter::doFinalization(Module &M) { // We couldn't directly add an element to a constant array, because doing so // changes the type of the constant array. // element type of llvm.global_ctors StructType *ST = StructType::get(IntType, PointerType::getUnqual(InitFiniType), NULL); // end with null // Move all existing elements of <GlobalName> to <Constants>. vector<Constant *> Constants; if (GlobalVariable *GlobalCtors = M.getNamedGlobal("llvm.global_ctors")) { ConstantArray *CA = cast<ConstantArray>(GlobalCtors->getInitializer()); for (unsigned j = 0; j < CA->getNumOperands(); ++j) { ConstantStruct *CS = cast<ConstantStruct>(CA->getOperand(j)); assert(CS->getType() == ST); // Assume nobody is using the highest priority, so that <F> will be the // first to run as a ctor. assert(!cast<ConstantInt>(CS->getOperand(0))->isMinValue(true)); Constants.push_back(CS); } GlobalCtors->eraseFromParent(); } // Add <F> with the highest priority. Constants.push_back(ConstantStruct::get(ST, ConstantInt::get(IntType, INT_MIN), EnterProcess, NULL)); // Create the new llvm.global_ctors. ArrayType *ArrType = ArrayType::get(ST, Constants.size()); new GlobalVariable(M, ArrType, true, GlobalValue::AppendingLinkage, ConstantArray::get(ArrType, Constants), "llvm.global_ctors"); return true; }
void PrivilegedCallAnalysis::doAnalysis(Module& M, SandboxVector& sandboxes) { // first find all methods annotated as being privileged and then check calls within sandboxes if (GlobalVariable* lga = M.getNamedGlobal("llvm.global.annotations")) { ConstantArray* lgaArray = dyn_cast<ConstantArray>(lga->getInitializer()->stripPointerCasts()); for (User::op_iterator i=lgaArray->op_begin(), e = lgaArray->op_end(); e!=i; i++) { ConstantStruct* lgaArrayElement = dyn_cast<ConstantStruct>(i->get()); // get the annotation value first GlobalVariable* annotationStrVar = dyn_cast<GlobalVariable>(lgaArrayElement->getOperand(1)->stripPointerCasts()); ConstantDataArray* annotationStrArray = dyn_cast<ConstantDataArray>(annotationStrVar->getInitializer()); StringRef annotationStrArrayCString = annotationStrArray->getAsCString(); GlobalValue* annotatedVal = dyn_cast<GlobalValue>(lgaArrayElement->getOperand(0)->stripPointerCasts()); if (isa<Function>(annotatedVal)) { Function* annotatedFunc = dyn_cast<Function>(annotatedVal); if (annotationStrArrayCString == SOAAP_PRIVILEGED) { outs() << " Found function: " << annotatedFunc->getName() << "\n"; privAnnotFuncs.push_back(annotatedFunc); } } } } // now check calls within sandboxes for (Function* privilegedFunc : privAnnotFuncs) { for (User* U : privilegedFunc->users()) { if (CallInst* C = dyn_cast<CallInst>(U)) { Function* enclosingFunc = C->getParent()->getParent(); for (Sandbox* S : sandboxes) { if (!S->hasCallgate(privilegedFunc) && S->containsFunction(enclosingFunc)) { outs() << " *** Sandbox \"" << S->getName() << "\" calls privileged function \"" << privilegedFunc->getName() << "\" that they are not allowed to. If intended, annotate this permission using the __soaap_callgates annotation.\n"; if (MDNode *N = C->getMetadata("dbg")) { // Here I is an LLVM instruction DILocation Loc(N); // DILocation is in DebugInfo.h unsigned Line = Loc.getLineNumber(); StringRef File = Loc.getFilename(); outs() << " +++ Line " << Line << " of file " << File << "\n"; } } } } } } /* for (Sandbox* S : sandboxes) { FunctionVector callgates = S->getCallgates(); for (Function* F : S->getFunctions()) { for (BasicBlock& BB : F->getBasicBlockList()) { for (Instruction& I : BB.getInstList()) { if (CallInst* C = dyn_cast<CallInst>(&I)) { if (Function* Target = C->getCalledFunction()) { if (find(privAnnotFuncs.begin(), privAnnotFuncs.end(), Target) != privAnnotFuncs.end()) { // check if this sandbox is allowed to call the privileged function DEBUG(dbgs() << " Found privileged call: "); DEBUG(C->dump()); if (find(callgates.begin(), callgates.end(), Target) == callgates.end()) { outs() << " *** Sandbox \"" << S->getName() << "\" calls privileged function \"" << Target->getName() << "\" that they are not allowed to. If intended, annotate this permission using the __soaap_callgates annotation.\n"; if (MDNode *N = C->getMetadata("dbg")) { // Here I is an LLVM instruction DILocation Loc(N); // DILocation is in DebugInfo.h unsigned Line = Loc.getLineNumber(); StringRef File = Loc.getFilename(); outs() << " +++ Line " << Line << " of file " << File << "\n"; } } } } } } } } } */ }
void ClassHierarchyUtils::processTypeInfo(GlobalVariable* TI, Module& M) { if (find(classes.begin(), classes.end(), TI) == classes.end()) { SDEBUG("soaap.util.classhierarchy", 3, dbgs() << "Adding class " << TI->getName() << "\n"); classes.push_back(TI); // First process the correspoding virtual table. We store the indexes of the primary // and secondary vtables, indexed by the corresponding subobject offset. This will allow // us to quickly jump to a particular sub-vtable. if (typeInfoToVTable.find(TI) != typeInfoToVTable.end()) { GlobalVariable* VT = typeInfoToVTable[TI]; SDEBUG("soaap.util.classhierarchy", 3, dbgs() << "Found vtable: " << VT->getName() << "\n"); ConstantStruct* VTinit = cast<ConstantStruct>(VT->getInitializer()); for (int i=0; i<VTinit->getNumOperands(); i++) { ConstantArray* VTinitElem = cast<ConstantArray>(VTinit->getOperand(i)); for (int j=0; j<VTinitElem->getNumOperands(); j++) { // Each sub-vtable is preceded by a reference to the class's type_info instance. // (See https://mentorembedded.github.io/cxx-abi/abi.html). if (TI == VTinitElem->getOperand(j)->stripPointerCasts()) { SDEBUG("soaap.util.classhierarchy", 3, dbgs() << "Found TI at index " << i << "\n"); SDEBUG("soaap.util.classhierarchy", 3, dbgs() << "Storing mapping " << VT->getName() << " <-> " << TI->getName() << "\n"); // the offset to top is the offset from the vptr pointing to this // sub-vtable, back to the top of the object. This will be negative, // but the absolute value gives us the offset from the start of the // object (i.e. first vptr), to the subobject. int offsetToTop = 0; if (ConstantExpr* offsetValCast = dyn_cast<ConstantExpr>(VTinitElem->getOperand(j-1)->stripPointerCasts())) { ConstantInt* offsetVal = cast<ConstantInt>(offsetValCast->getOperand(0)); offsetToTop = offsetVal->getSExtValue(); // will be 0 for the primary } if (offsetToTop > 0) { report_fatal_error("ERROR: offsetToTop is positive!"); } else { offsetToTop *= -1; } SDEBUG("soaap.util.classhierarchy", 3, dbgs() << "offsetToTop: " << offsetToTop << "\n") vTableToSecondaryVTableMaps[VT][offsetToTop] = pair<int, int>(i, j+1); } } } } else { SDEBUG("soaap.util.classhierarchy", 3, dbgs() << "No vtable found for " << TI->getName() << "\n"); } // Now process the type_info struct, extract direct base class info (what // their subobject offsets are, or if they are virtual then their // virtual-base-offset-offset) if (TI->hasInitializer()) { ConstantStruct* TIinit = cast<ConstantStruct>(TI->getInitializer()); int TInumOperands = TIinit->getNumOperands(); if (TInumOperands > 2) { // first two operands are vptr and type name // we have >= 1 base class(es). if (TInumOperands == 3) { // abi::__si_class_type_info: single, public, non-virtual base at // offset 0 SDEBUG("soaap.util.classhierarchy", 3, dbgs() << "abi::__si_class_type_info\n"); GlobalVariable* baseTI = cast<GlobalVariable>(TIinit->getOperand(2)->stripPointerCasts()); classToSubclasses[baseTI].push_back(TI); //dbgs() << " " << *baseTI << "\n"; classToBaseOffset[TI][baseTI] = 0; processTypeInfo(baseTI, M); } else { // abi::__vmi_class_type_info: all other cases SDEBUG("soaap.util.classhierarchy", 3, dbgs() << "abi::__vmi_class_type_info\n"); // (skip over first two additional fields, which are "flags" and "base_count") for (int i=4; i<TInumOperands; i+=2) { GlobalVariable* baseTI = cast<GlobalVariable>(TIinit->getOperand(i)->stripPointerCasts()); classToSubclasses[baseTI].push_back(TI); long offset_flags = cast<ConstantInt>(TIinit->getOperand(i+1))->getSExtValue(); SDEBUG("soaap.util.classhierarchy", 3, dbgs() << TI->getName() << " -> " << baseTI->getName() << "\n"); SDEBUG("soaap.util.classhierarchy", 3, dbgs() << " offset_flags = " << offset_flags << "\n"); ptrdiff_t offset = offset_flags >> offset_shift; SDEBUG("soaap.util.classhierarchy", 3, dbgs() << " offset = " << offset << "\n"); // If this a virtual base class, then we obtain the // vbase-offset-offset. This is the offset from the start of the // derived class's (primary) vtable to the location containing the // vbase-offset, which is the offset from the start of the object // to the virtual base's subobject. Note that virtual base // subobjects only exist once and are laid out after all other // non-virtual objects. We keep track of the vbase-offset-offset, // so that we can find the vbase offset when going down the class // hierarchy. (The vbase offset may differ every time but the // vbase-offset-offset will remain the same relative to the current // class's vtable in subclasses). if (offset_flags & virtual_mask) { // is this a virtual base class? SDEBUG("soaap.util.classhierarchy", 3, dbgs() << "virtual base class: " << baseTI->getName() << "\n"); int vbaseOffsetOffset = offset/sizeof(long); // this should be negative SDEBUG("soaap.util.classhierarchy", 3, dbgs() << "vbase-offset-offset: " << vbaseOffsetOffset << "\n"); classToVBaseOffsetOffset[TI][baseTI] = vbaseOffsetOffset; if (typeInfoToVTable.find(TI) != typeInfoToVTable.end()) { GlobalVariable* VT = typeInfoToVTable[TI]; int vbaseOffsetIdx = vTableToSecondaryVTableMaps[VT][0].second+vbaseOffsetOffset; SDEBUG("soaap.util.classhierarchy", 3, dbgs() << "vbase-offset-idx: " << vbaseOffsetIdx << "\n"); } else { SDEBUG("soaap.util.classhierarchy", 3, dbgs() << "No VTable for " << TI->getName() << "\n"); } } else { // In the non-virtual base class case, we just record the subobj // offset. This is the offset from the start of the derived // object to the base class's subobject. We use this information // together with the offset-to-top info we obtained from the // vtable to find the base class's subvtable. Note that the // relative position of the base class subobj within the current // derived object will always remain the same, even in // subclasses. classToBaseOffset[TI][baseTI] = offset; } //dbgs() << " " << *baseTI << "\n"; processTypeInfo(baseTI, M); } } } }
void TartGCPrinter::finishAssembly(AsmPrinter &AP) { unsigned nextLabel = 1; SafePointList safePoints; // Set up for emitting addresses. int pointerSize = AP.TM.getTargetData()->getPointerSize(); int addressAlignLog; if (pointerSize == sizeof(int32_t)) { addressAlignLog = 2; } else { addressAlignLog = 3; } MCStreamer & outStream = AP.OutStreamer; // Put this in the data section. outStream.SwitchSection(AP.getObjFileLowering().getDataSection()); // For each function... for (iterator FI = begin(), FE = end(); FI != FE; ++FI) { GCFunctionInfo & gcFn = **FI; // if (optShowGC) { // errs() << "GCStrategy: Function: " << gcFn.getFunction().getName() << "\n"; // } // And each safe point... for (GCFunctionInfo::iterator sp = gcFn.begin(); sp != gcFn.end(); ++sp) { StackTraceTable::FieldOffsetList fieldOffsets; StackTraceTable::TraceMethodList traceMethods; // And for each live root... for (GCFunctionInfo::live_iterator rt = gcFn.live_begin(sp); rt != gcFn.live_end(sp); ++rt) { int64_t offset = rt->StackOffset; const Constant * meta = rt->Metadata; if (meta != NULL && !meta->isNullValue()) { // Meta is non-null, so it's a value type. const ConstantArray * traceArray = cast<ConstantArray>(getGlobalValue(meta)); // For each trace descriptor in thre meta array... for (ConstantArray::const_op_iterator it = traceArray->op_begin(); it != traceArray->op_end(); ++it) { ConstantStruct * descriptor = cast<ConstantStruct>(*it); ConstantInt * fieldCount = cast<ConstantInt>(descriptor->getOperand(1)); int64_t dscOffset = toInt(descriptor->getOperand(2), AP.TM); if (fieldCount->isZero()) { // A zero field count means that this is a trace method descriptor. const Constant * traceMethod = descriptor->getOperand(3); assert(offset > -1000 && offset < 1000); assert(dscOffset > -1000 && dscOffset < 1000); traceMethods.push_back(TraceMethodEntry(offset + dscOffset, traceMethod)); } else { // Otherwise it's a field offset descriptor. const GlobalVariable * fieldOffsetsVar = cast<GlobalVariable>( descriptor->getOperand(3)->getOperand(0)); // Handle case where the array value is just a ConstantAggregateZero, which // can be generated by llvm::ConstantArray::get() if the array values // are all zero. if (const ConstantAggregateZero * zero = dyn_cast<ConstantAggregateZero>(fieldOffsetsVar->getInitializer())) { // Array should never contain duplicate offsets, so an all-zero array // can only have one entry. (void)zero; assert(fieldCount->isOne()); fieldOffsets.push_back(offset + dscOffset); } else { // Get the field offset array and add to field offsets for this // safe point. const ConstantArray * fieldOffsetArray = cast<ConstantArray>( fieldOffsetsVar->getInitializer()); for (ConstantArray::const_op_iterator el = fieldOffsetArray->op_begin(); el != fieldOffsetArray->op_end(); ++el) { fieldOffsets.push_back( offset + dscOffset + toInt(cast<llvm::Constant>(*el), AP.TM)); } } } } } else { // No metadata, so it's an object reference - just add the field offset. fieldOffsets.push_back(offset); } } // Nothing to trace? Then we're done. if (fieldOffsets.empty() && traceMethods.empty()) { continue; } // Create a folding set node and merge with any identical trace tables. std::sort(fieldOffsets.begin(), fieldOffsets.end()); llvm::FoldingSetNodeID id; StackTraceTable::ProfileEntries(id, fieldOffsets, traceMethods); void * insertPos; StackTraceTable * sTable = traceTables.FindNodeOrInsertPos(id, insertPos); if (sTable == NULL) { sTable = new StackTraceTable(fieldOffsets, traceMethods); // Generate the labels for the trace table and field offset table. sTable->fieldOffsetsLabel = AP.GetTempSymbol("gc_stack_offsets", nextLabel); sTable->traceTableLabel = AP.GetTempSymbol("gc_stack", nextLabel++); // Add to folding set traceTables.InsertNode(sTable, insertPos); // Generate the trace table outStream.AddBlankLine(); AP.EmitAlignment(addressAlignLog); // First the field offset descriptor outStream.EmitLabel(sTable->traceTableLabel); size_t traceMethodCount = sTable->traceMethods.size(); if (!sTable->fieldOffsets.empty()) { outStream.EmitIntValue(traceMethodCount == 0 ? 1 : 0, 2, 0); outStream.EmitIntValue(sTable->fieldOffsets.size(), 2, 0); outStream.EmitIntValue(0, 4, 0); outStream.EmitSymbolValue(sTable->fieldOffsetsLabel, pointerSize, 0); } // Next the trace method descriptors for (size_t i = 0; i < traceMethodCount; ++i) { const TraceMethodEntry * tm = &sTable->traceMethods[i]; const Function * method = dyn_cast<Function>(tm->method()); if (method == NULL) { method = cast<Function>(tm->method()->getOperand(0)); } outStream.EmitIntValue((i + 1 == traceMethodCount ? 1 : 0), 2, 0); outStream.EmitIntValue(0, 2, 0); outStream.EmitIntValue(tm->offset(), 4, 0); MCSymbol * methodSym = AP.Mang->getSymbol(method); outStream.EmitSymbolValue(methodSym, pointerSize, 0); } // Now emit the field offset array outStream.AddBlankLine(); AP.EmitAlignment(addressAlignLog); outStream.EmitLabel(sTable->fieldOffsetsLabel); for (StackTraceTable::FieldOffsetList::const_iterator it = fieldOffsets.begin(); it != fieldOffsets.end(); ++it) { outStream.EmitIntValue(*it, pointerSize, 0); } } safePoints.push_back(std::pair<MCSymbol *, MCSymbol *>(sp->Label, sTable->traceTableLabel)); // if (optShowGC) { // if (!sTable->fieldOffsets.empty()) { // errs() << "GCStrategy: Field offset descriptor:"; // for (StackTraceTable::FieldOffsetList::const_iterator it = sTable->fieldOffsets.begin(); // it != sTable->fieldOffsets.end(); ++it) { // errs() << " " << *it; // } // errs() << "\n"; // } // if (!sTable->traceMethods.empty()) { // errs() << "GCStrategy: Trace method descriptor: " << "\n"; // } // } } } // Finally, generate the safe point map. outStream.AddBlankLine(); MCSymbol * gcSafepointSymbol = AP.GetExternalSymbolSymbol("GC_safepoint_map"); outStream.EmitSymbolAttribute(gcSafepointSymbol, MCSA_Global); outStream.EmitLabel(gcSafepointSymbol); outStream.EmitIntValue(safePoints.size(), pointerSize, 0); for (SafePointList::const_iterator it = safePoints.begin(); it != safePoints.end(); ++it) { outStream.EmitSymbolValue(it->first, pointerSize, 0); outStream.EmitSymbolValue(it->second, pointerSize, 0); } }
SandboxVector SandboxUtils::findSandboxes(Module& M) { FunctionIntMap funcToOverhead; FunctionIntMap funcToClearances; map<Function*,string> funcToSandboxName; map<string,FunctionSet> sandboxNameToEntryPoints; StringSet ephemeralSandboxes; SandboxVector sandboxes; // function-level annotations of sandboxed code Regex *sboxPerfRegex = new Regex("perf_overhead_\\(([0-9]{1,2})\\)", true); SmallVector<StringRef, 4> matches; if (GlobalVariable* lga = M.getNamedGlobal("llvm.global.annotations")) { ConstantArray* lgaArray = dyn_cast<ConstantArray>(lga->getInitializer()->stripPointerCasts()); for (User::op_iterator i=lgaArray->op_begin(), e = lgaArray->op_end(); e!=i; i++) { ConstantStruct* lgaArrayElement = dyn_cast<ConstantStruct>(i->get()); // get the annotation value first GlobalVariable* annotationStrVar = dyn_cast<GlobalVariable>(lgaArrayElement->getOperand(1)->stripPointerCasts()); ConstantDataArray* annotationStrArray = dyn_cast<ConstantDataArray>(annotationStrVar->getInitializer()); StringRef annotationStrArrayCString = annotationStrArray->getAsCString(); GlobalValue* annotatedVal = dyn_cast<GlobalValue>(lgaArrayElement->getOperand(0)->stripPointerCasts()); if (isa<Function>(annotatedVal)) { Function* annotatedFunc = dyn_cast<Function>(annotatedVal); StringRef sandboxName; if (annotationStrArrayCString.startswith(SANDBOX_PERSISTENT) || annotationStrArrayCString.startswith(SANDBOX_EPHEMERAL)) { sandboxEntryPoints.insert(annotatedFunc); outs() << INDENT_1 << "Found sandbox entrypoint " << annotatedFunc->getName() << "\n"; outs() << INDENT_2 << "Annotation string: " << annotationStrArrayCString << "\n"; if (annotationStrArrayCString.startswith(SANDBOX_PERSISTENT)) { sandboxName = annotationStrArrayCString.substr(strlen(SANDBOX_PERSISTENT)+1); } else if (annotationStrArrayCString.startswith(SANDBOX_EPHEMERAL)) { sandboxName = annotationStrArrayCString.substr(strlen(SANDBOX_EPHEMERAL)+1); ephemeralSandboxes.insert(sandboxName); } outs() << INDENT_2 << "Sandbox name: " << sandboxName << "\n"; if (funcToSandboxName.find(annotatedFunc) != funcToSandboxName.end()) { outs() << INDENT_1 << "*** Error: Function " << annotatedFunc->getName() << " is already an entrypoint for another sandbox\n"; } else { funcToSandboxName[annotatedFunc] = sandboxName; sandboxNameToEntryPoints[sandboxName].insert(annotatedFunc); } } else if (sboxPerfRegex->match(annotationStrArrayCString, &matches)) { int overhead; outs() << INDENT_2 << "Threshold set to " << matches[1].str() << "%\n"; matches[1].getAsInteger(0, overhead); funcToOverhead[annotatedFunc] = overhead; } else if (annotationStrArrayCString.startswith(CLEARANCE)) { StringRef className = annotationStrArrayCString.substr(strlen(CLEARANCE)+1); outs() << INDENT_2 << "Sandbox has clearance for \"" << className << "\"\n"; ClassifiedUtils::assignBitIdxToClassName(className); funcToClearances[annotatedFunc] |= (1 << ClassifiedUtils::getBitIdxFromClassName(className)); } } } } // TODO: sanity check overhead and clearance annotations // Combine all annotation information for function-level sandboxes to create Sandbox instances for (pair<string,FunctionSet> p : sandboxNameToEntryPoints) { string sandboxName = p.first; FunctionSet entryPoints = p.second; int idx = assignBitIdxToSandboxName(sandboxName); int overhead = 0; int clearances = 0; bool persistent = find(ephemeralSandboxes.begin(), ephemeralSandboxes.end(), sandboxName) == ephemeralSandboxes.end(); // set overhead and clearances; any of the entry points could be annotated for (Function* entryPoint : entryPoints) { if (funcToOverhead.find(entryPoint) != funcToOverhead.end()) { overhead = funcToOverhead[entryPoint]; } if (funcToClearances.find(entryPoint) != funcToClearances.end()) { clearances = funcToClearances[entryPoint]; } } SDEBUG("soaap.util.sandbox", 3, dbgs() << INDENT_2 << "Creating new Sandbox instance for " << sandboxName << "\n"); sandboxes.push_back(new Sandbox(sandboxName, idx, entryPoints, persistent, M, overhead, clearances)); SDEBUG("soaap.util.sandbox", 3, dbgs() << INDENT_2 << "Created new Sandbox instance\n"); } /* for (map<Function*,string>::iterator I=funcToSandboxName.begin(), E=funcToSandboxName.end(); I!=E; I++) { Function* entryPoint = I->first; string sandboxName = I->second; int idx = assignBitIdxToSandboxName(sandboxName); int overhead = funcToOverhead[entryPoint]; int clearances = funcToClearances[entryPoint]; bool persistent = find(ephemeralSandboxes.begin(), ephemeralSandboxes.end(), entryPoint) == ephemeralSandboxes.end(); SDEBUG("soaap.util.sandbox", 3, dbgs() << INDENT_2 << "Creating new Sandbox instance\n"); sandboxes.push_back(new Sandbox(sandboxName, idx, entryPoint, persistent, M, overhead, clearances)); SDEBUG("soaap.util.sandbox", 3, dbgs() << INDENT_2 << "Created new Sandbox instance\n"); } */ // Handle sandboxed code regions, i.e. start_sandboxed_code(N) and end_sandboxed_code(N) blocks if (Function* SboxStart = M.getFunction("llvm.annotation.i32")) { for (User* U : SboxStart->users()) { if (IntrinsicInst* annotCall = dyn_cast<IntrinsicInst>(U)) { GlobalVariable* annotationStrVar = dyn_cast<GlobalVariable>(annotCall->getOperand(1)->stripPointerCasts()); ConstantDataArray* annotationStrValArray = dyn_cast<ConstantDataArray>(annotationStrVar->getInitializer()); StringRef annotationStrValCString = annotationStrValArray->getAsCString(); if (annotationStrValCString.startswith(SOAAP_SANDBOX_REGION_START)) { StringRef sandboxName = annotationStrValCString.substr(strlen(SOAAP_SANDBOX_REGION_START)+1); //+1 because of _ SDEBUG("soaap.util.sandbox", 3, dbgs() << INDENT_3 << "Found start of sandboxed code region: "; annotCall->dump();); InstVector sandboxedInsts; findAllSandboxedInstructions(annotCall, sandboxName, sandboxedInsts); int idx = assignBitIdxToSandboxName(sandboxName); sandboxes.push_back(new Sandbox(sandboxName, idx, sandboxedInsts, false, M)); //TODO: obtain persistent/ephemeral information in a better way (currently we obtain it from the creation point) } }
/// analyzeDestructor - Given the heap.metadata argument to swift_allocObject, /// take a look a the destructor and try to decide if it has side effects or any /// other bad effects that can prevent it from being optimized. static DtorKind analyzeDestructor(Value *P) { // If we have a null pointer for the metadata info, the dtor has no side // effects. Actually, the final release would crash. This is really only // useful for writing testcases. if (isa<ConstantPointerNull>(P->stripPointerCasts())) return DtorKind::NoSideEffects; // We have to have a known heap metadata value, reject dynamically computed // ones, or places GlobalVariable *GV = dyn_cast<GlobalVariable>(P->stripPointerCasts()); if (GV == 0 || GV->mayBeOverridden()) return DtorKind::Unknown; ConstantStruct *CS = dyn_cast_or_null<ConstantStruct>(GV->getInitializer()); if (CS == 0 || CS->getNumOperands() == 0) return DtorKind::Unknown; // FIXME: Would like to abstract the dtor slot (#0) out from this to somewhere // unified. enum { DTorSlotOfHeapMetadata = 0 }; Function *DtorFn =dyn_cast<Function>(CS->getOperand(DTorSlotOfHeapMetadata)); if (DtorFn == 0 || DtorFn->mayBeOverridden() || DtorFn->hasExternalLinkage()) return DtorKind::Unknown; // Okay, we have a body, and we can trust it. If the function is marked // readonly, then we know it can't have any interesting side effects, so we // don't need to analyze it at all. if (DtorFn->onlyReadsMemory()) return DtorKind::NoSideEffects; // The first argument is the object being destroyed. assert(DtorFn->arg_size() == 1 && !DtorFn->isVarArg() && "expected a single object argument to destructors"); Value *ThisObject = &*DtorFn->arg_begin(); // Scan the body of the function, looking for anything scary. for (BasicBlock &BB : *DtorFn) { for (Instruction &I : BB) { // Note that the destructor may not be in any particular canonical form. switch (classifyInstruction(I)) { // These instructions should not reach here based on the pass ordering. // i.e. LLVMARCOpt -> LLVMContractOpt. case RT_RetainN: case RT_UnknownRetainN: case RT_BridgeRetainN: case RT_ReleaseN: case RT_UnknownReleaseN: case RT_BridgeReleaseN: llvm_unreachable("These are only created by LLVMARCContract !"); case RT_NoMemoryAccessed: case RT_AllocObject: case RT_FixLifetime: case RT_CheckUnowned: // Skip over random instructions that don't touch memory in the caller. continue; case RT_RetainUnowned: case RT_BridgeRetain: // x = swift_bridgeRetain(y) case RT_Retain: { // swift_retain(obj) // Ignore retains of the "self" object, no resurrection is possible. Value *ThisRetainedObject = cast<CallInst>(I).getArgOperand(0); if (ThisRetainedObject->stripPointerCasts() == ThisObject->stripPointerCasts()) continue; // Otherwise, we may be retaining something scary. break; } case RT_Release: { // If we get to a release that is provably to this object, then we can // ignore it. Value *ThisReleasedObject = cast<CallInst>(I).getArgOperand(0); if (ThisReleasedObject->stripPointerCasts() == ThisObject->stripPointerCasts()) continue; // Otherwise, we may be retaining something scary. break; } case RT_ObjCRelease: case RT_ObjCRetain: case RT_UnknownRetain: case RT_UnknownRelease: case RT_BridgeRelease: // Objective-C retain and release can have arbitrary side effects. break; case RT_Unknown: // Ignore all instructions with no side effects. if (!I.mayHaveSideEffects()) continue; // store, memcpy, memmove *to* the object can be dropped. if (StoreInst *SI = dyn_cast<StoreInst>(&I)) { if (SI->getPointerOperand()->stripInBoundsOffsets() == ThisObject) continue; } if (MemIntrinsic *MI = dyn_cast<MemIntrinsic>(&I)) { if (MI->getDest()->stripInBoundsOffsets() == ThisObject) continue; } // Otherwise, we can't remove the deallocation completely. break; } // Okay, the function has some side effects, if it doesn't capture the // object argument, at least that is something. return DtorFn->doesNotCapture(0) ? DtorKind::NoEscape : DtorKind::Unknown; } } // If we didn't find any side effects, we win. return DtorKind::NoSideEffects; }
void ControlFlowIntegrity::ParseAnnotations(void) { GlobalVariable *global_ctors = _M.getNamedGlobal("llvm.global.annotations"); // check for ctor section if (!global_ctors || !global_ctors->getOperand(0)) { return; } Constant *c = global_ctors->getInitializer(); if (!c) report_fatal_error("llvm.global.annotations without initializer!", false); ConstantArray *CA = dyn_cast<ConstantArray>(c); if (!CA) report_fatal_error("Cast to ConstantArray failed", true); for (Value *Op : ValueOpRange(*CA)) { ConstantStruct *CS = dyn_cast<ConstantStruct>(Op); if (!CS) report_fatal_error("Cast to ConstantStruct failed", true); Constant *FP = CS->getOperand(0); if (FP->isNullValue()) break; // found a NULL termintator, stop here ConstantExpr *CE; Function *F = dyn_cast_or_null<Function>(FP); if (F == NULL) { // Strip off constant expression cast CE = dyn_cast<ConstantExpr>(FP); if (!CE) report_fatal_error("Cast to ConstantExpr failed", true); if (CE->isCast()) { FP = CE->getOperand(0); F = dyn_cast_or_null<Function>(FP); } } if (!F) report_fatal_error("Cast to Function failed", true); Constant *SP = CS->getOperand(1); if (SP->isNullValue()) break; // found a NULL termintator, stop here // Strip off constant expression cast CE = dyn_cast<ConstantExpr>(SP); if (!CE) report_fatal_error("Cast to ConstantExpr failed", true); if (CE->isCast()) { SP = CE->getOperand(0); } Value *V = SP->getOperand(0); GlobalVariable *GV = dyn_cast_or_null<GlobalVariable>(V); if (!GV) report_fatal_error("Cast to GlobalVariable failed", false); assert(GV && "cast to GlobalVariable failed"); Constant *cval = GV->getInitializer(); const StringRef s = (cast<ConstantDataArray>(cval))->getAsCString(); if (s == ANNOTATION_IGNORE_BLOCK) { _IgnoredBlocksFunctions.insert(F->getName()); } } if (global_ctors->getNumUses() > 0) report_fatal_error("llvm.global.annotations uses count is > 0", false); }
bool SpDefUseInstrumenter::runOnModule(Module &M) { cerr << "instrument: --- Def-Use pair Spectrum ---\n"; Function *Main = M.getFunction("main"); LLVMContext &C = M.getContext(); if (Main == 0) { cerr << "WARNING: cannot insert def-use instrumentation into a module" << " with no main function!\n"; return false; // No main, no instrumentation! } // Add library function prototype Constant *SpFn = M.getOrInsertFunction("_updateSpectrum", Type::getVoidTy(C), Type::getInt32Ty(C), // spectrum index Type::getInt32Ty(C), // component index NULL); unsigned spectrumIndex = IndexManager::getSpectrumIndex(); unsigned nDefs = 0; unsigned nUses = 0; // Loop through all functions within module for (Module::iterator F = M.begin(), ME = M.end(); F != ME; ++F) { // skip function declarations if(F->isDeclaration()) continue; // skip the _registerAll function if(F->getName()=="_registerAll") continue; // Loop through all basic blocks within function for (Function::iterator B = F->begin(), FE = F->end(); B != FE; ++B) { //skip dead blocks //is this really safe?? BasicBlock *bb = B; if (B!=F->begin() && (pred_begin(bb)==pred_end(bb))) continue; //skip dead blocks // Loop through all instructions within basic block for (BasicBlock::iterator I = B->begin(), BE = B->end(); I != BE; I++) { if(isa<DbgDeclareInst>(*I)) { // extract source file information from debug intrinsic DbgDeclareInst &DDI = cast<DbgDeclareInst>(*I); std::string file, dir; std::string name; GlobalVariable *gv = cast<GlobalVariable>(DDI.getVariable()); if(!gv->hasInitializer()) continue; ConstantStruct *cs = cast<ConstantStruct>(gv->getInitializer()); llvm::GetConstantStringInfo(cs->getOperand(2), name); unsigned int line = unsigned(cast<ConstantInt>(cs->getOperand(4))->getZExtValue()); Value *V = cast<Value>(cs->getOperand(3)); GlobalVariable *gv2 = cast<GlobalVariable>(cast<ConstantExpr>(V)->getOperand(0)); if(!gv2->hasInitializer()) continue; ConstantStruct *cs2 = cast<ConstantStruct>(gv2->getInitializer()); llvm::GetConstantStringInfo(cs2->getOperand(3), file); llvm::GetConstantStringInfo(cs2->getOperand(4), dir); // get the allocation instruction of the variable definition AllocaInst *AI; if(isa<AllocaInst>(DDI.getAddress())) { AI = cast<AllocaInst>(DDI.getAddress()); } else if (isa<BitCastInst>(DDI.getAddress())) { AI = cast<AllocaInst>(cast<BitCastInst>(DDI.getAddress())->getOperand(0)); } else { continue; } nDefs++; // add calls to lib function for each use of the variable int currUses = 0; for(AllocaInst::use_iterator U = AI->use_begin(), UE = AI->use_end(); U != UE; ++U) { if(isa<Instruction>(*U)) { User *user = *U; Instruction *insertInst = (Instruction*)user; // find most likely context location of use int useline = line; std::string usefile = file, usedir = dir; BasicBlock *parent = insertInst->getParent(); BasicBlock::iterator inst = parent->begin(); while(((Instruction *)inst) != insertInst && inst != parent->end()) { /*TODO: solve DbgStopPointInst problem*/ /*if(isa<DbgStopPointInst>(*inst)) { DbgStopPointInst &DSPI = cast<DbgStopPointInst>(*inst); llvm::GetConstantStringInfo(DSPI.getDirectory(), usedir); llvm::GetConstantStringInfo(DSPI.getFileName(), usefile); useline = DSPI.getLine(); }*/ inst++; } std::stringstream usename; usename << name << "(use_" << currUses << ")"; // add source context of this invariant to context file ContextManager::addSpectrumContext( spectrumIndex, // spectrumIndex nUses, // componentIndex usedir, // path usefile, // file useline, // line usename.str()); // name currUses++; std::vector<Value*> Args(2); Args[0] = ConstantInt::get(Type::getInt32Ty(C), spectrumIndex); Args[1] = ConstantInt::get(Type::getInt32Ty(C), nUses++); CallInst::Create(SpFn, Args.begin(), Args.end(), "", insertInst); } } } } } } // add the registration of the instrumented spectrum points in the _registerAll() function addSpectrumRegistration(M, spectrumIndex, nUses, "Def-Use_Pairs"); std::cerr << "instrument: " << nDefs << " defines with a total number of " << nUses << " uses instrumented\n"; // notify change of program return true; }