/// 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); }
/// EmitXXStructorList - Emit the ctor or dtor list. This just prints out the /// function pointers, ignoring the init priority. void AsmPrinter::EmitXXStructorList(Constant *List) { // 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)); } }
// 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; }
/// GetConstantStringInfo - This function computes the length of a /// null-terminated C string pointed to by V. If successful, it returns true /// and returns the string in Str. If unsuccessful, it returns false. bool llvm::GetConstantStringInfo(Value *V, std::string &Str, uint64_t Offset, bool StopAtNul) { // If V is NULL then return false; if (V == NULL) return false; // Look through bitcast instructions. if (BitCastInst *BCI = dyn_cast<BitCastInst>(V)) return GetConstantStringInfo(BCI->getOperand(0), Str, Offset, StopAtNul); // If the value is not a GEP instruction nor a constant expression with a // GEP instruction, then return false because ConstantArray can't occur // any other way User *GEP = 0; if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(V)) { GEP = GEPI; } else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(V)) { if (CE->getOpcode() == Instruction::BitCast) return GetConstantStringInfo(CE->getOperand(0), Str, Offset, StopAtNul); if (CE->getOpcode() != Instruction::GetElementPtr) return false; GEP = CE; } if (GEP) { // Make sure the GEP has exactly three arguments. if (GEP->getNumOperands() != 3) return false; // Make sure the index-ee is a pointer to array of i8. const PointerType *PT = cast<PointerType>(GEP->getOperand(0)->getType()); const ArrayType *AT = dyn_cast<ArrayType>(PT->getElementType()); if (AT == 0 || AT->getElementType() != Type::Int8Ty) return false; // Check to make sure that the first operand of the GEP is an integer and // has value 0 so that we are sure we're indexing into the initializer. ConstantInt *FirstIdx = dyn_cast<ConstantInt>(GEP->getOperand(1)); if (FirstIdx == 0 || !FirstIdx->isZero()) return false; // If the second index isn't a ConstantInt, then this is a variable index // into the array. If this occurs, we can't say anything meaningful about // the string. uint64_t StartIdx = 0; if (ConstantInt *CI = dyn_cast<ConstantInt>(GEP->getOperand(2))) StartIdx = CI->getZExtValue(); else return false; return GetConstantStringInfo(GEP->getOperand(0), Str, StartIdx+Offset, StopAtNul); } // The GEP instruction, constant or instruction, must reference a global // variable that is a constant and is initialized. The referenced constant // initializer is the array that we'll use for optimization. GlobalVariable* GV = dyn_cast<GlobalVariable>(V); if (!GV || !GV->isConstant() || !GV->hasInitializer()) return false; Constant *GlobalInit = GV->getInitializer(); // Handle the ConstantAggregateZero case if (isa<ConstantAggregateZero>(GlobalInit)) { // This is a degenerate case. The initializer is constant zero so the // length of the string must be zero. Str.clear(); return true; } // Must be a Constant Array ConstantArray *Array = dyn_cast<ConstantArray>(GlobalInit); if (Array == 0 || Array->getType()->getElementType() != Type::Int8Ty) return false; // Get the number of elements in the array uint64_t NumElts = Array->getType()->getNumElements(); if (Offset > NumElts) return false; // Traverse the constant array from 'Offset' which is the place the GEP refers // to in the array. Str.reserve(NumElts-Offset); for (unsigned i = Offset; i != NumElts; ++i) { Constant *Elt = Array->getOperand(i); ConstantInt *CI = dyn_cast<ConstantInt>(Elt); if (!CI) // This array isn't suitable, non-int initializer. return false; if (StopAtNul && CI->isZero()) return true; // we found end of string, success! Str += (char)CI->getZExtValue(); } // The array isn't null terminated, but maybe this is a memcpy, not a strcpy. return true; }
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); } } } }
bool SDFix::fixDestructors() { 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); // get an idea about the virtual function regions std::vector<vtbl_pair_t> vtblRegions = findSubVtables(vtable); // for each subvtable for(unsigned vtblInd = 0; vtblInd < vtblRegions.size(); vtblInd++) { // record the destructors used in the vtable std::vector<DestructorInfo> destructors(3); vtbl_pair_t p = vtblRegions[vtblInd]; for(unsigned i=p.first; i<p.second; 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'; // store it temporarily destructors[typeInt] = DestructorInfo(destructor, i); } // deleting destructor should always be defined assert(! destructors[0].needsReplacement()); DestructorInfo* d1 = &destructors[1]; DestructorInfo* d2 = &destructors[2]; // only one of the rest could be undefined assert(! d1->needsReplacement() || ! d2->needsReplacement()); // if complete object destructor is missing... if (d1->needsReplacement()) { std::string gv2Name = d1->function->getName(); unsigned l = gv2Name.length(); gv2Name = gv2Name.replace(l-3, 1, "2"); Function* f1 = d1->getFunction(); assert(f1); Function* f2 = module->getFunction(gv2Name); assert(f2); sd_print("Replacing %s with %s inside %s\n", d1->function->getName().data(), gv2Name.c_str(), gv.getName().data()); f1->replaceAllUsesWith(f2); replaced = true; // if base object destructor is missing... } else if (d2->needsReplacement()) { std::string gv1Name = d2->function->getName(); unsigned l = gv1Name.length(); gv1Name = gv1Name.replace(l-3, 1, "1"); Function* f2 = d2->getFunction(); assert(f2); Function* f1 = module->getFunction(gv1Name); assert(f1); sd_print("Replacing %s with %s inside %s\n", d2->function->getName().data(), gv1Name.c_str(), gv.getName().data()); f2->replaceAllUsesWith(f1); replaced = true; } } } return replaced; }
// // 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; }