void InstrProfiling::emitUses() { if (UsedVars.empty()) return; GlobalVariable *LLVMUsed = M->getGlobalVariable("llvm.used"); std::vector<Constant *> MergedVars; if (LLVMUsed) { // Collect the existing members of llvm.used. ConstantArray *Inits = cast<ConstantArray>(LLVMUsed->getInitializer()); for (unsigned I = 0, E = Inits->getNumOperands(); I != E; ++I) MergedVars.push_back(Inits->getOperand(I)); LLVMUsed->eraseFromParent(); } Type *i8PTy = Type::getInt8PtrTy(M->getContext()); // Add uses for our data. for (auto *Value : UsedVars) MergedVars.push_back( ConstantExpr::getBitCast(cast<Constant>(Value), i8PTy)); // Recreate llvm.used. ArrayType *ATy = ArrayType::get(i8PTy, MergedVars.size()); LLVMUsed = new GlobalVariable(*M, ATy, false, GlobalValue::AppendingLinkage, ConstantArray::get(ATy, MergedVars), "llvm.used"); LLVMUsed->setSection("llvm.metadata"); }
/// Given a specified llvm.global_ctors list, remove the listed elements. static void removeGlobalCtors(GlobalVariable *GCL, const BitVector &CtorsToRemove) { // Filter out the initializer elements to remove. ConstantArray *OldCA = cast<ConstantArray>(GCL->getInitializer()); SmallVector<Constant *, 10> CAList; for (unsigned I = 0, E = OldCA->getNumOperands(); I < E; ++I) if (!CtorsToRemove.test(I)) CAList.push_back(OldCA->getOperand(I)); // Create the new array initializer. ArrayType *ATy = ArrayType::get(OldCA->getType()->getElementType(), CAList.size()); Constant *CA = ConstantArray::get(ATy, CAList); // If we didn't change the number of elements, don't create a new GV. if (CA->getType() == OldCA->getType()) { GCL->setInitializer(CA); return; } // Create the new global and insert it next to the existing list. GlobalVariable *NGV = new GlobalVariable(CA->getType(), GCL->isConstant(), GCL->getLinkage(), CA, "", GCL->getThreadLocalMode()); GCL->getParent()->getGlobalList().insert(GCL->getIterator(), NGV); NGV->takeName(GCL); // Nuke the old list, replacing any uses with the new one. if (!GCL->use_empty()) { Constant *V = NGV; if (V->getType() != GCL->getType()) V = ConstantExpr::getBitCast(V, GCL->getType()); GCL->replaceAllUsesWith(V); } GCL->eraseFromParent(); }
/// runStaticConstructorsDestructors - This method is used to execute all of /// the static constructors or destructors for a module, depending on the /// value of isDtors. void ExecutionEngine::runStaticConstructorsDestructors(Module *module, bool isDtors) { const char *Name = isDtors ? "llvm.global_dtors" : "llvm.global_ctors"; // Execute global ctors/dtors for each module in the program. GlobalVariable *GV = module->getNamedGlobal(Name); // If this global has internal linkage, or if it has a use, then it must be // an old-style (llvmgcc3) static ctor with __main linked in and in use. If // this is the case, don't execute any of the global ctors, __main will do // it. if (!GV || GV->isDeclaration() || GV->hasLocalLinkage()) return; // Should be an array of '{ int, void ()* }' structs. The first value is // the init priority, which we ignore. ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer()); if (!InitList) return; for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) if (ConstantStruct *CS = dyn_cast<ConstantStruct>(InitList->getOperand(i))) { if (CS->getNumOperands() != 2) return; // Not array of 2-element structs. Constant *FP = CS->getOperand(1); if (FP->isNullValue()) break; // Found a null terminator, exit. if (ConstantExpr *CE = dyn_cast<ConstantExpr>(FP)) if (CE->isCast()) FP = CE->getOperand(0); if (Function *F = dyn_cast<Function>(FP)) { // Execute the ctor/dtor function! runFunction(F, std::vector<GenericValue>()); } } }
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)); }
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); } }
void InstrProfiling::lowerCoverageData(GlobalVariable *CoverageData) { CoverageData->setSection(getCoverageSection()); CoverageData->setAlignment(8); Constant *Init = CoverageData->getInitializer(); // We're expecting { i32, i32, i32, i32, [n x { i8*, i32, i32 }], [m x i8] } // for some C. If not, the frontend's given us something broken. assert(Init->getNumOperands() == 6 && "bad number of fields in coverage map"); assert(isa<ConstantArray>(Init->getAggregateElement(4)) && "invalid function list in coverage map"); ConstantArray *Records = cast<ConstantArray>(Init->getAggregateElement(4)); for (unsigned I = 0, E = Records->getNumOperands(); I < E; ++I) { Constant *Record = Records->getOperand(I); Value *V = const_cast<Value *>(Record->getOperand(0))->stripPointerCasts(); assert(isa<GlobalVariable>(V) && "Missing reference to function name"); GlobalVariable *Name = cast<GlobalVariable>(V); // If we have region counters for this name, we've already handled it. auto It = RegionCounters.find(Name); if (It != RegionCounters.end()) continue; // Move the name variable to the right section. Name->setSection(getNameSection()); Name->setAlignment(1); } }
void ClassHierarchyUtils::findClassHierarchy(Module& M) { // extract call hierarchy using std::type_info structures rather // than debug info. The former works even for when there are anonymous // namespaces. type_info structs can be obtained from vtable globals. // (for more info, see http://mentorembedded.github.io/cxx-abi/abi.html) for (Module::global_iterator I=M.global_begin(), E=M.global_end(); I != E; I++) { GlobalVariable* G = &*I; if (G->getName().startswith("_ZTV")) { if (G->hasInitializer()) { SDEBUG("soaap.util.classhierarchy", 3, G->dump()); ConstantArray* Ginit = cast<ConstantArray>(G->getInitializer()); // Ginit[1] is the type_info global for this vtable's type bool typeInfoFound = false; bool primaryVTable = true; for (int i=0; i<Ginit->getNumOperands(); i++) { // typeinfo will be the first global variable in the array. // It's not always at a fixed index so we have to search for it... if (GlobalVariable* TI = dyn_cast<GlobalVariable>(Ginit->getOperand(i)->stripPointerCasts())) { //TI->dump(); typeInfoToVTable[TI] = G; vTableToTypeInfo[G] = TI; processTypeInfo(TI); // process TI recursively (it contains refs to super-class TIs) typeInfoFound = true; if (primaryVTable) { primaryVTable = false; vTableToSecondaryVTableMaps[G][0] = i+1; // i+1 is also the size of the vtable header } else { // offset_to_top is at the previous index ConstantExpr* offsetValCast = cast<ConstantExpr>(Ginit->getOperand(i-1)->stripPointerCasts()); ConstantInt* offsetVal = cast<ConstantInt>(offsetValCast->getOperand(0)); int offsetToTop = offsetVal->getSExtValue(); if (offsetToTop > 0) { dbgs() << "ERROR: offsetToTop is positive!\n"; G->dump(); } else { offsetToTop *= -1; } SDEBUG("soaap.util.classhierarchy", 3, dbgs() << "offsetToTop: " << offsetToTop << "\n"); vTableToSecondaryVTableMaps[G][offsetToTop] = i+1; } } } if (!typeInfoFound) { dbgs() << "ERROR: vtable initializer is not a global variable...\n"; dbgs() << *G << " = " << *Ginit << "\n"; } } } } SDEBUG("soaap.util.classhierarchy", 3, ppClassHierarchy(classToSubclasses)); }
bool SDFix::fixDestructors2() { bool replaced = false; for (GlobalVariable& gv : module->getGlobalList()) { if (! sd_isVtableName_ref(gv.getName())) continue; else if (! gv.hasInitializer()) continue; Constant* init = gv.getInitializer(); assert(init); ConstantArray* vtable = dyn_cast<ConstantArray>(init); assert(vtable); for(unsigned i=0; i<vtable->getNumOperands(); i++) { Constant* destructor = sd_getDestructorFunction(vtable->getOperand(i)); if (destructor == NULL) continue; // get the type from its name unsigned s = destructor->getName().size(); char type = destructor->getName()[s-3]; assert('0' <= type && type <= '2'); unsigned typeInt = type - '0'; DestructorInfo di(destructor, i); if(di.isDefined) continue; // this only handles the 1 -> 2 conversion assert(typeInt == 1); Function* f1 = di.getFunction(); assert(f1); std::string gv2Name = f1->getName(); unsigned l = gv2Name.length(); gv2Name = gv2Name.replace(l-3, 1, "2"); Function* f2 = module->getFunction(gv2Name); assert(f2 && ! f2->isDeclaration()); sd_print("Replacing %s with %s inside %s\n", f1->getName().data(), gv2Name.c_str(), gv.getName().data()); f1->replaceAllUsesWith(f2); replaced = true; } } return replaced; }
/// SplitStaticCtorDtor - A module was recently split into two parts, M1/M2, and /// M1 has all of the global variables. If M2 contains any functions that are /// static ctors/dtors, we need to add an llvm.global_[cd]tors global to M2, and /// prune appropriate entries out of M1s list. static void SplitStaticCtorDtor(const char *GlobalName, Module *M1, Module *M2, DenseMap<const Value*, Value*> ValueMap) { GlobalVariable *GV = M1->getNamedGlobal(GlobalName); if (!GV || GV->isDeclaration() || GV->hasLocalLinkage() || !GV->use_empty()) return; std::vector<std::pair<Function*, int> > M1Tors, M2Tors; ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer()); if (!InitList) return; for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) { if (ConstantStruct *CS = dyn_cast<ConstantStruct>(InitList->getOperand(i))){ if (CS->getNumOperands() != 2) return; // Not array of 2-element structs. if (CS->getOperand(1)->isNullValue()) break; // Found a null terminator, stop here. ConstantInt *CI = dyn_cast<ConstantInt>(CS->getOperand(0)); int Priority = CI ? CI->getSExtValue() : 0; Constant *FP = CS->getOperand(1); if (ConstantExpr *CE = dyn_cast<ConstantExpr>(FP)) if (CE->isCast()) FP = CE->getOperand(0); if (Function *F = dyn_cast<Function>(FP)) { if (!F->isDeclaration()) M1Tors.push_back(std::make_pair(F, Priority)); else { // Map to M2's version of the function. F = cast<Function>(ValueMap[F]); M2Tors.push_back(std::make_pair(F, Priority)); } } } } GV->eraseFromParent(); if (!M1Tors.empty()) { Constant *M1Init = GetTorInit(M1Tors); new GlobalVariable(*M1, M1Init->getType(), false, GlobalValue::AppendingLinkage, M1Init, GlobalName); } GV = M2->getNamedGlobal(GlobalName); assert(GV && "Not a clone of M1?"); assert(GV->use_empty() && "llvm.ctors shouldn't have uses!"); GV->eraseFromParent(); if (!M2Tors.empty()) { Constant *M2Init = GetTorInit(M2Tors); new GlobalVariable(*M2, M2Init->getType(), false, GlobalValue::AppendingLinkage, M2Init, GlobalName); } }
static void findUsedValues(GlobalVariable *LLVMUsed, SmallPtrSetImpl<GlobalValue*> &UsedValues) { if (!LLVMUsed) return; ConstantArray *Inits = cast<ConstantArray>(LLVMUsed->getInitializer()); for (unsigned i = 0, e = Inits->getNumOperands(); i != e; ++i) if (GlobalValue *GV = dyn_cast<GlobalValue>(Inits->getOperand(i)->stripPointerCasts())) UsedValues.insert(GV); }
/// Find values that are marked as llvm.used. static void FindUsedValues(GlobalVariable *LLVMUsed, SmallPtrSet<const GlobalValue*, 8> &UsedValues) { if (LLVMUsed == 0) return; ConstantArray *Inits = cast<ConstantArray>(LLVMUsed->getInitializer()); for (unsigned i = 0, e = Inits->getNumOperands(); i != e; ++i) { Value *Operand = Inits->getOperand(i)->stripPointerCastsNoFollowAliases(); GlobalValue *GV = cast<GlobalValue>(Operand); UsedValues.insert(GV); } }
/// 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; }
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; }
/// EmitLLVMUsedList - For targets that define a TAI::UsedDirective, mark each /// global in the specified llvm.used list as being used with this directive. void AsmPrinter::EmitLLVMUsedList(Constant *List) { const char *Directive = TAI->getUsedDirective(); // Should be an array of 'sbyte*'. ConstantArray *InitList = dyn_cast<ConstantArray>(List); if (InitList == 0) return; for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) { O << Directive; EmitConstantValueOnly(InitList->getOperand(i)); O << "\n"; } }
void InstrProfiling::lowerCoverageData(GlobalVariable *CoverageNamesVar) { ConstantArray *Names = cast<ConstantArray>(CoverageNamesVar->getInitializer()); for (unsigned I = 0, E = Names->getNumOperands(); I < E; ++I) { Constant *NC = Names->getOperand(I); Value *V = NC->stripPointerCasts(); assert(isa<GlobalVariable>(V) && "Missing reference to function name"); GlobalVariable *Name = cast<GlobalVariable>(V); Name->setLinkage(GlobalValue::PrivateLinkage); ReferencedNames.push_back(Name); } }
/// EmitXXStructorList - Emit the ctor or dtor list. This just emits out the /// function pointers, ignoring the init priority. void ELFWriter::EmitXXStructorList(Constant *List, ELFSection &Xtor) { // Should be an array of '{ int, void ()* }' structs. The first value is the // init priority, which we ignore. if (!isa<ConstantArray>(List)) return; ConstantArray *InitList = cast<ConstantArray>(List); for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) if (ConstantStruct *CS = dyn_cast<ConstantStruct>(InitList->getOperand(i))){ if (CS->getNumOperands() != 2) return; // Not array of 2-element structs. if (CS->getOperand(1)->isNullValue()) return; // Found a null terminator, exit printing. // Emit the function pointer. EmitGlobalConstant(CS->getOperand(1), Xtor); } }
/// AnalyzeModule - Scan the module for global debug information. /// void MachineModuleInfo::AnalyzeModule(Module &M) { // Insert functions in the llvm.used array (but not llvm.compiler.used) into // UsedFunctions. GlobalVariable *GV = M.getGlobalVariable("llvm.used"); if (!GV || !GV->hasInitializer()) return; // Should be an array of 'i8*'. ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer()); if (InitList == 0) return; for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) if (Function *F = dyn_cast<Function>(InitList->getOperand(i)->stripPointerCasts())) UsedFunctions.insert(F); }
// 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; }
/// VisitGlobalInit - The specified lattice value corresponds to a field (or /// several) in the specified global. Merge all of the overlapping initializer /// values into LV (up-to and until it becomes overdefined). /// static bool VisitGlobalInit(LatticeValue *LV, Constant *Init, unsigned FieldOffset) { const TargetData &TD = LV->getParentGraph().getTargetData(); if (Init->isNullValue()) return LV->visitGlobalInit(Constant::getNullValue(LV->getFieldType())); if (isa<UndefValue>(Init)) return LV->visitGlobalInit(UndefValue::get(LV->getFieldType())); if (LV->getNode()->isArray() && TD.getTypeSize(Init->getType()) > LV->getNode()->getSize()) { ConstantArray *CA = cast<ConstantArray>(Init); for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i) if (VisitGlobalInit(LV, CA->getOperand(i), FieldOffset)) return true; return false; } NextStep: // Manual tail recursion if (Init->isNullValue()) return LV->visitGlobalInit(Constant::getNullValue(LV->getFieldType())); if (isa<UndefValue>(Init)) return LV->visitGlobalInit(UndefValue::get(LV->getFieldType())); if (Init->getType()->isFirstClassType()) { assert(FieldOffset == 0 && "GV Init mismatch!"); return LV->visitGlobalInit(Init); } if (const StructType *STy = dyn_cast<StructType>(Init->getType())) { const StructLayout *SL = TD.getStructLayout(STy); unsigned Field = SL->getElementContainingOffset(FieldOffset); FieldOffset -= SL->MemberOffsets[Field]; Init = cast<ConstantStruct>(Init)->getOperand(Field); goto NextStep; } else if (const ArrayType *ATy = dyn_cast<ArrayType>(Init->getType())) { unsigned ElSz = TD.getTypeSize(ATy->getElementType()); unsigned Idx = FieldOffset / ElSz; FieldOffset -= Idx*ElSz; Init = cast<ConstantArray>(Init)->getOperand(Idx); goto NextStep; } else { assert(0 && "Unexpected initializer type!"); return true; } }
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; }
// // Method: postOrderInline() // // Description: // This methods does a post order traversal of the call graph and performs // bottom-up inlining of the DSGraphs. // void BUDataStructures::postOrderInline (Module & M) { // Variables used for Tarjan SCC-finding algorithm. These are passed into // the recursive function used to find SCCs. std::vector<const Function*> Stack; std::map<const Function*, unsigned> ValMap; unsigned NextID = 1; // Do post order traversal on the global ctors. Use this information to update // the globals graph. const char *Name = "llvm.global_ctors"; GlobalVariable *GV = M.getNamedGlobal(Name); if (GV && !(GV->isDeclaration()) && !(GV->hasLocalLinkage())) { // Should be an array of '{ int, void ()* }' structs. The first value is // the init priority, which we ignore. ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer()); if (InitList) { for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) if (ConstantStruct *CS = dyn_cast<ConstantStruct>(InitList->getOperand(i))) { if (CS->getNumOperands() != 2) break; // Not array of 2-element structs. Constant *FP = CS->getOperand(1); if (FP->isNullValue()) break; // Found a null terminator, exit. if (ConstantExpr *CE = dyn_cast<ConstantExpr>(FP)) if (CE->isCast()) FP = CE->getOperand(0); Function *F = dyn_cast<Function>(FP); if (F && !F->isDeclaration() && !ValMap.count(F)) { calculateGraphs(F, Stack, NextID, ValMap); CloneAuxIntoGlobal(getDSGraph(*F)); } } GlobalsGraph->removeTriviallyDeadNodes(); GlobalsGraph->maskIncompleteMarkers(); // Mark external globals incomplete. GlobalsGraph->markIncompleteNodes(DSGraph::IgnoreGlobals); GlobalsGraph->computeExternalFlags(DSGraph::DontMarkFormalsExternal); GlobalsGraph->computeIntPtrFlags(); // // Create equivalence classes for aliasing globals so that we only need to // record one global per DSNode. // formGlobalECs(); // propogte information calculated // from the globals graph to the other graphs. for (Module::iterator F = M.begin(); F != M.end(); ++F) { if (!(F->isDeclaration())){ DSGraph *Graph = getDSGraph(*F); cloneGlobalsInto(Graph, DSGraph::DontCloneCallNodes | DSGraph::DontCloneAuxCallNodes); Graph->buildCallGraph(callgraph, GlobalFunctionList, filterCallees); Graph->maskIncompleteMarkers(); Graph->markIncompleteNodes(DSGraph::MarkFormalArgs | DSGraph::IgnoreGlobals); Graph->computeExternalFlags(DSGraph::DontMarkFormalsExternal); Graph->computeIntPtrFlags(); } } } } // // Start the post order traversal with the main() function. If there is no // main() function, don't worry; we'll have a separate traversal for inlining // graphs for functions not reachable from main(). // Function *MainFunc = M.getFunction ("main"); if (MainFunc && !MainFunc->isDeclaration()) { calculateGraphs(MainFunc, Stack, NextID, ValMap); CloneAuxIntoGlobal(getDSGraph(*MainFunc)); } // // Calculate the graphs for any functions that are unreachable from main... // for (Function &F : M) if (!F.isDeclaration() && !ValMap.count(&F)) { if (MainFunc) DEBUG(errs() << debugname << ": Function unreachable from main: " << F.getName() << "\n"); calculateGraphs(&F, Stack, NextID, ValMap); // Calculate all graphs. CloneAuxIntoGlobal(getDSGraph(F)); // Mark this graph as processed. Do this by finding all functions // in the graph that map to it, and mark them visited. // Note that this really should be handled neatly by calculateGraphs // itself, not here. However this catches the worst offenders. DSGraph *G = getDSGraph(F); for(DSGraph::retnodes_iterator RI = G->retnodes_begin(), RE = G->retnodes_end(); RI != RE; ++RI) { if (getDSGraph(*RI->first) == G) { if (!ValMap.count(RI->first)) ValMap[RI->first] = ~0U; else assert(ValMap[RI->first] == ~0U); } } } return; }
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); } } } }