return true;
}
-static bool IsObjCClassReference(Value *value) {
- GlobalVariable *global_variable = dyn_cast<GlobalVariable>(value);
-
- return !(!global_variable || !global_variable->hasName() ||
- !global_variable->getName().startswith("OBJC_CLASS_REFERENCES_"));
-}
-
-// This function does not report errors; its callers are responsible.
-bool IRForTarget::RewriteObjCClassReference(Instruction *class_load) {
- lldb_private::Log *log(GetLog(LLDBLog::Expressions));
-
- LoadInst *load = dyn_cast<LoadInst>(class_load);
-
- if (!load)
- return false;
-
- // Unpack the class name from the reference. In LLVM IR, a reference to an
- // Objective-C class gets represented as
- //
- // %tmp = load ptr, ptr @OBJC_CLASS_REFERENCES_, align 4
- //
- // @OBJC_CLASS_REFERENCES_ is a reference to a character array called
- // @OBJC_CLASS_NAME_. @OBJC_CLASS_NAME contains the string.
-
- // Find the pointer's initializer and get the string from its target
-
- GlobalVariable *_objc_class_references_ =
- dyn_cast<GlobalVariable>(load->getPointerOperand());
-
- if (!_objc_class_references_ ||
- !_objc_class_references_->hasInitializer())
- return false;
-
- // Find the string's initializer (a ConstantArray) and get the string from it
-
- GlobalVariable *_objc_class_name_ =
- dyn_cast<GlobalVariable>(_objc_class_references_->getInitializer());
-
- if (!_objc_class_name_ || !_objc_class_name_->hasInitializer())
- return false;
-
- Constant *ocn_initializer = _objc_class_name_->getInitializer();
-
- ConstantDataArray *ocn_initializer_array =
- dyn_cast<ConstantDataArray>(ocn_initializer);
-
- if (!ocn_initializer_array->isString())
- return false;
-
- std::string ocn_initializer_string =
- std::string(ocn_initializer_array->getAsString());
-
- LLDB_LOG(log, "Found Objective-C class reference \"{0}\"",
- ocn_initializer_string);
-
- // Construct a call to objc_getClass
-
- if (!m_objc_getClass) {
- lldb::addr_t objc_getClass_addr;
-
- bool missing_weak = false;
- static lldb_private::ConstString g_objc_getClass_str("objc_getClass");
- objc_getClass_addr = m_execution_unit.FindSymbol(g_objc_getClass_str,
- missing_weak);
- if (objc_getClass_addr == LLDB_INVALID_ADDRESS || missing_weak)
- return false;
-
- LLDB_LOG(log, "Found objc_getClass at {0}", objc_getClass_addr);
-
- // Build the function type: %struct._objc_class *objc_getClass(i8*)
-
- Type *class_type = load->getType();
- Type *type_array[1];
- type_array[0] = llvm::Type::getInt8PtrTy(m_module->getContext());
-
- ArrayRef<Type *> ogC_arg_types(type_array, 1);
-
- llvm::FunctionType *ogC_type =
- FunctionType::get(class_type, ogC_arg_types, false);
-
- // Build the constant containing the pointer to the function
- PointerType *ogC_ptr_ty = PointerType::getUnqual(ogC_type);
- Constant *ogC_addr_int =
- ConstantInt::get(m_intptr_ty, objc_getClass_addr, false);
- m_objc_getClass = {ogC_type,
- ConstantExpr::getIntToPtr(ogC_addr_int, ogC_ptr_ty)};
- }
-
- CallInst *ogC_call = CallInst::Create(m_objc_getClass, _objc_class_name_,
- "objc_getClass", class_load);
-
- // Replace the load with the call in all users
-
- class_load->replaceAllUsesWith(ogC_call);
-
- class_load->eraseFromParent();
-
- return true;
-}
-
-bool IRForTarget::RewriteObjCClassReferences(BasicBlock &basic_block) {
- lldb_private::Log *log(GetLog(LLDBLog::Expressions));
-
- InstrList class_loads;
-
- for (Instruction &inst : basic_block) {
- if (LoadInst *load = dyn_cast<LoadInst>(&inst))
- if (IsObjCClassReference(load->getPointerOperand()))
- class_loads.push_back(&inst);
- }
-
- for (Instruction *inst : class_loads) {
- if (!RewriteObjCClassReference(inst)) {
- m_error_stream.Printf("Internal error [IRForTarget]: Couldn't change a "
- "static reference to an Objective-C class to a "
- "dynamic reference\n");
-
- LLDB_LOG(log, "Couldn't rewrite a reference to an Objective-C class");
-
- return false;
- }
- }
-
- return true;
-}
-
// This function does not report errors; its callers are responsible.
bool IRForTarget::RewritePersistentAlloc(llvm::Instruction *persistent_alloc) {
lldb_private::Log *log(GetLog(LLDBLog::Expressions));
return false;
}
-
- if (!RewriteObjCClassReferences(bb)) {
- LLDB_LOG(log, "RewriteObjCClassReferences() failed");
-
- // RewriteObjCClasses() reports its own errors, so we don't do so here
-
- return false;
- }
}
}
/// True on success; false otherwise
bool RewriteObjCSelectors(llvm::BasicBlock &basic_block);
- /// A basic block-level pass to find all Objective-C class references that
- /// use the old-style Objective-C runtime and rewrite them to use
- /// class_getClass instead of statically allocated class references.
-
- /// Replace a single old-style class reference
- ///
- /// \param[in] class_load
- /// The load of the statically-allocated selector.
- ///
- /// \return
- /// True on success; false otherwise
- bool RewriteObjCClassReference(llvm::Instruction *class_load);
-
- /// The top-level pass implementation
- ///
- /// \param[in] basic_block
- /// The basic block currently being processed.
- ///
- /// \return
- /// True on success; false otherwise
- bool RewriteObjCClassReferences(llvm::BasicBlock &basic_block);
-
/// A basic block-level pass to find all newly-declared persistent
/// variables and register them with the ClangExprDeclMap. This allows them
/// to be materialized and dematerialized like normal external variables.
/// The address of the function sel_registerName, cast to the appropriate
/// function pointer type.
llvm::FunctionCallee m_sel_registerName;
- /// The address of the function objc_getClass, cast to the appropriate
- /// function pointer type.
- llvm::FunctionCallee m_objc_getClass;
/// The type of an integer large enough to hold a pointer.
llvm::IntegerType *m_intptr_ty = nullptr;
/// The stream on which errors should be printed.