// 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<const Type*> nullary; Function *fn = Function::Create(FunctionType::get(Type::getVoidTy(getGlobalContext()), nullary, false), GlobalVariable::InternalLinkage, name, m); BasicBlock *bb = BasicBlock::Create(getGlobalContext(), "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)); assert(cs->getNumOperands()==2 && "unexpected element in ctor initializer list"); 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(getGlobalContext(), bb); return fn; }
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; }
//---------------------------------------------------------------------------- bool FxCompiler::GetConstant (const TokenArray& tokens, const std::string& name, Shader::VariableType type, ConstantArray& constants) { std::string::size_type begin, end; if (tokens[5].size() < 4 || tokens[5][0] != 'c' || tokens[5][1] != '[' || (end = tokens[5].find("]", 0)) == std::string::npos) { ReportError("Expecting 'c[register]' token", &tokens); return false; } // Get the base register for the constant. begin = 2; // character after '[' std::string number = tokens[5].substr(begin, end - begin); int baseRegister = atoi(number.c_str()); if (baseRegister == 0 && number != "0") { ReportError("Invalid base register", &tokens); return false; } // Get the number of registers used by the constant. int numRegistersUsed; if (tokens[5].find(",", 0) == std::string::npos) { // The constant uses one register. numRegistersUsed = 1; } else { // The constant uses more than one register. numRegistersUsed = atoi(tokens[6].c_str()); if (numRegistersUsed == 0) { ReportError("Invalid number of registers", &tokens); return false; } } Constant constant; constant.Name = name; constant.Type = type; constant.BaseRegister = baseRegister; constant.NumRegistersUsed = numRegistersUsed; constants.push_back(constant); 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; }
//---------------------------------------------------------------------------- bool FxCompiler::UpdateShader (Shader* shader, const Program& program, InputArray& inputs, OutputArray& outputs, ConstantArray& constants, SamplerArray& samplers) { int numInputs = (int)inputs.size(); if (numInputs != shader->GetNumInputs()) { ReportError("Mismatch in number of inputs.\n"); return false; } int numOutputs = (int)outputs.size(); if (numOutputs != shader->GetNumOutputs()) { ReportError("Mismatch in number of outputs.\n"); return false; } int numConstants = (int)constants.size(); if (numConstants != shader->GetNumConstants()) { ReportError("Mismatch in number of constants.\n"); return false; } int numSamplers = (int)samplers.size(); if (numSamplers != shader->GetNumSamplers()) { ReportError("Mismatch in number of samplers.\n"); return false; } std::string message; int i; for (i = 0; i < numInputs; ++i) { Input& input = inputs[i]; if (input.Name != shader->GetInputName(i)) { message = "Mismatch in input names '" + input.Name + "' and '" + shader->GetInputName(i); ReportError(message); return false; } if (input.Type != shader->GetInputType(i)) { message = "Mismatch in input types '" + msVTName[input.Type] + "' and '" + msVTName[shader->GetInputType(i)]; ReportError(message); return false; } if (input.Semantic != shader->GetInputSemantic(i)) { message = "Mismatch in input semantics '" + msVSName[input.Semantic] + "' and '" + msVSName[shader->GetInputSemantic(i)]; ReportError(message); return false; } } for (i = 0; i < numOutputs; ++i) { Output& output = outputs[i]; if (output.Name != shader->GetOutputName(i)) { message = "Mismatch in output names '" + output.Name + "' and '" + shader->GetOutputName(i); ReportError(message); return false; } if (output.Type != shader->GetOutputType(i)) { message = "Mismatch in output types '" + msVTName[output.Type] + "' and '" + msVTName[shader->GetOutputType(i)]; ReportError(message); return false; } if (output.Semantic != shader->GetOutputSemantic(i)) { message = "Mismatch in output semantics '" + msVSName[output.Semantic] + "' and '" + msVSName[shader->GetOutputSemantic(i)]; ReportError(message); return false; } } for (i = 0; i < numConstants; ++i) { Constant& constant = constants[i]; if (constant.Name != shader->GetConstantName(i)) { message = "Mismatch in constant names '" + constant.Name + "' and '" + shader->GetConstantName(i); ReportError(message); return false; } if (constant.NumRegistersUsed != shader->GetNumRegistersUsed(i)) { char number0[8], number1[8]; sprintf(number0, "%d", constant.NumRegistersUsed); sprintf(number1, "%d", shader->GetNumRegistersUsed(i)); message = "Mismatch in constant registers used '" + std::string(number0) + "' and '" + std::string(number1); ReportError(message); return false; } shader->SetBaseRegister(mActiveProfile, i, constant.BaseRegister); } for (i = 0; i < numSamplers; ++i) { Sampler& sampler = samplers[i]; if (sampler.Name != shader->GetSamplerName(i)) { message = "Mismatch in sampler names '" + sampler.Name + "' and '" + shader->GetSamplerName(i); ReportError(message); return false; } if (sampler.Type != shader->GetSamplerType(i)) { message = "Mismatch in sampler types '" + msSTName[sampler.Type] + "' and '" + msSTName[shader->GetSamplerType(i)]; ReportError(message); return false; } shader->SetTextureUnit(mActiveProfile, i, sampler.Unit); } shader->SetProgram(mActiveProfile, program.Text); return true; }
//---------------------------------------------------------------------------- bool FxCompiler::Process (const Program& program, InputArray& inputs, OutputArray& outputs, ConstantArray& constants, SamplerArray& samplers) { // Variable lines are one of the following: // var TYPE NAME : $vin.SEMANTIC : inputType : index : 1 // var TYPE NAME : $vout.SEMANTIC : outputType : index : 1 // var TYPE NAME : : c[REGISTER] : index : 1 // var TYPE NAME : : c[REGISTER], NUMREG : index : 1 // var TYPE NAME : : texunit UNITNUMBER : -1 : 1 // The last field is "used", a value of "0" or "1". However, the parser // stored in 'program' only those variables with a used value "1". The // all-capitals identifiers are needed by the Wild Magic FX system. TokenArrays::const_iterator iter = program.Variables.begin(); TokenArrays::const_iterator end = program.Variables.end(); for (/**/; iter != end; ++iter) { const TokenArray& tokens = *iter; // The token array has 10 or 11 tokens. if (tokens.size() < 10 || tokens.size() > 11) { ReportError("Invalid number of tokens", &tokens); return false; } // Get the variable type. Shader::VariableType vartype = Shader::VT_NONE; Shader::SamplerType samtype = Shader::ST_NONE; std::string::size_type begin = tokens[1].find("sampler", 0); if (begin != std::string::npos) { SamplerTypeMap::iterator iter = mSamplerTypes.find(tokens[1]); if (iter == mSamplerTypes.end()) { ReportError("Invalid sampler type", &tokens); return false; } samtype = iter->second; } else { VariableTypeMap::iterator iter = mVariableTypes.find(tokens[1]); if (iter == mVariableTypes.end()) { ReportError("Invalid variable type", &tokens); return false; } vartype = iter->second; } // Get the variable name. std::string name = tokens[2]; // Test whether the variable is a singleton or was declared as an // array. If it is an array, we need to determine how many registers // it uses. This requires processing variable lines with the same // variable index. bool varArray; begin = name.find("[", 0); if (begin != std::string::npos) { varArray = true; name = name.substr(0, begin); // strip off "[register]" } else { varArray = false; } // Get the separator before the classifier. if (tokens[3] != ":") { ReportError("Expecting separator character at index 3", &tokens); return false; } // Get the classifier. begin = tokens[4].find("$vin.", 0); if (begin != std::string::npos) { // The variable is a shader input. if (!GetInput(tokens, name, vartype, inputs)) { return false; } continue; } begin = tokens[4].find("$vout.", 0); if (begin != std::string::npos) { // The variable is a shader output. if (!GetOutput(tokens, name, vartype, outputs)) { return false; } continue; } if (tokens[4] == ":") { begin = tokens[1].find("sampler", 0); if (begin != std::string::npos) { // The variable is a shader sampler. if (!GetSampler(tokens, name, samtype, samplers)) { return false; } } else { // The variable is a shader constant. if (varArray) { if (constants.size() > 0 && name == constants.back().Name) { // This is another occurrence of the array variable. // Just increment the register count. ++constants.back().NumRegistersUsed; } else { // Create the constant with the first occurrence of // the array variable. if (!GetConstant(tokens, name, vartype, constants)) { return false; } } } else { if (!GetConstant(tokens, name, vartype, constants)) { return false; } } } continue; } ReportError("Failed to find classifier", &tokens); return false; } return true; }
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) } }
/** * This function creates a module constructor function to create the * map from function keys to function names. This function will be * automatically called when the module is loaded. * * The code was generated by using clang on a test file. The test * file looked like (foo.cc): * __attribute__((constructor)) * static void init() * { * } * * Then, run: * 1. clang -S -emit-llvm -c foo.cc * 2. llc -march=cpp foo.bc -o foo.lc * The output foo.lc provides code for generating a ctor using LLVM. * */ void BytesFlops::initializeKeyMap(Module& module) { if ( module.getFunction("func_key_map_ctor") ) return; LLVMContext& ctx = module.getContext(); // Type Definitions std::vector<Type*>StructTy_1_fields; StructTy_1_fields.push_back(IntegerType::get(ctx, 32)); std::vector<Type*>FuncTy_3_args; FunctionType* FuncTy_3 = FunctionType::get( /*Result=*/ Type::getVoidTy(ctx), /*Params=*/ FuncTy_3_args, /*isVarArg=*/ false); PointerType* PointerTy_2 = PointerType::get(FuncTy_3, 0); StructTy_1_fields.push_back(PointerTy_2); StructType * StructTy_1 = StructType::get(ctx, StructTy_1_fields, /*isPacked=*/false); ArrayType* ArrayTy_0 = NULL; // Function Declarations func_map_ctor = Function::Create( /*Type=*/FuncTy_3, /*Linkage=*/GlobalValue::InternalLinkage, /*Name=*/"func_key_map_ctor", &module); func_map_ctor->setCallingConv(CallingConv::C); AttributeSet func__ZL4initv_PAL; SmallVector<AttributeSet, 4> Attrs; AttributeSet PAS; AttrBuilder B; B.addAttribute(Attribute::NoUnwind); B.addAttribute(Attribute::UWTable); PAS = AttributeSet::get(ctx, ~0U, B); Attrs.push_back(PAS); func__ZL4initv_PAL = AttributeSet::get(ctx, Attrs); func_map_ctor->setAttributes(func__ZL4initv_PAL); // Global Variable Declarations // Constant Definitions std::vector<Constant*> ctor_elems; std::vector<Constant*> const_struct_8_fields; ConstantInt* const_int32_9 = ConstantInt::get(ctx, APInt(32, StringRef("65535"), 10)); const_struct_8_fields.push_back(const_int32_9); const_struct_8_fields.push_back(func_map_ctor); Constant* const_struct_8 = ConstantStruct::get(StructTy_1, const_struct_8_fields); ctor_elems.push_back(const_struct_8); GlobalVariable* llvm_global_ctors; /** * Add our constructor to the list of global constructors for the * module. It's possible that a module already contains a ctor. */ GlobalVariable* current_ctors = module.getGlobalVariable("llvm.global_ctors"); if ( !current_ctors ) { ArrayTy_0 = ArrayType::get(StructTy_1, 1); } else { // there are existing ctors, and the initializer points to them. // add ours to the initializer list (actually, we create a new // initializer list and add the existing ones to it). Constant * initializer = current_ctors->getInitializer(); ConstantArray * ar = llvm::dyn_cast<ConstantArray>(initializer); assert( ar ); int cnt = 0; Constant * elt = ar->getAggregateElement(cnt); // add existing ctors to new initializer list, and get rid // of the old one. while ( elt ) { assert( llvm::dyn_cast<ConstantStruct>(elt) ); ctor_elems.push_back(elt); cnt++; elt = ar->getAggregateElement(cnt); } ArrayTy_0 = ArrayType::get(StructTy_1, ctor_elems.size()); current_ctors->eraseFromParent(); } llvm_global_ctors = new GlobalVariable(/*Module=*/module, /*Type=*/ ArrayTy_0, /*isConstant=*/ false, /*Linkage=*/ GlobalValue::AppendingLinkage, /*Initializer=*/0, // has initializer, specified below /*Name=*/ "llvm.global_ctors"); Constant* ctor_array = ConstantArray::get(ArrayTy_0, ctor_elems); // Global Variable Definitions llvm_global_ctors->setInitializer(ctor_array); }
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"; } } } } } } } } } */ }