[Lldb-commits] [lldb] r282657 - Fixed TestObjCStructArgument/i386; expressions can now call ObjC class methods.
Sean Callanan via lldb-commits
lldb-commits at lists.llvm.org
Wed Sep 28 17:45:33 PDT 2016
Author: spyffe
Date: Wed Sep 28 19:45:33 2016
New Revision: 282657
URL: http://llvm.org/viewvc/llvm-project?rev=282657&view=rev
Log:
Fixed TestObjCStructArgument/i386; expressions can now call ObjC class methods.
<rdar://problem/28502241>
Modified:
lldb/trunk/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp
lldb/trunk/source/Plugins/ExpressionParser/Clang/IRForTarget.h
Modified: lldb/trunk/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp?rev=282657&r1=282656&r2=282657&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp (original)
+++ lldb/trunk/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp Wed Sep 28 19:45:33 2016
@@ -73,7 +73,8 @@ IRForTarget::IRForTarget(lldb_private::C
const char *func_name)
: ModulePass(ID), m_resolve_vars(resolve_vars), m_func_name(func_name),
m_module(NULL), m_decl_map(decl_map), m_CFStringCreateWithBytes(NULL),
- m_sel_registerName(NULL), m_intptr_ty(NULL), m_error_stream(error_stream),
+ m_sel_registerName(NULL), m_objc_getClass(NULL), m_intptr_ty(NULL),
+ m_error_stream(error_stream),
m_execution_unit(execution_unit), m_result_store(NULL),
m_result_is_pointer(false), m_reloc_placeholder(NULL),
m_entry_instruction_finder(FindEntryInstruction) {}
@@ -944,6 +945,172 @@ bool IRForTarget::RewriteObjCSelectors(B
return true;
}
+static bool IsObjCClassReference(Value *value) {
+ GlobalVariable *global_variable = dyn_cast<GlobalVariable>(value);
+
+ if (!global_variable || !global_variable->hasName() ||
+ !global_variable->getName().startswith("OBJC_CLASS_REFERENCES_"))
+ return false;
+
+ return true;
+}
+
+// This function does not report errors; its callers are responsible.
+bool IRForTarget::RewriteObjCClassReference(Instruction *class_load) {
+ lldb_private::Log *log(
+ lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_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 %struct._objc_class*,
+ // %struct._objc_class** @OBJC_CLASS_REFERENCES_, align 4
+ //
+ // @"OBJC_CLASS_REFERENCES_ is a bitcast of a character array called
+ // @OBJC_CLASS_NAME_.
+ // @OBJC_CLASS_NAME contains the string.
+
+ // Find the pointer's initializer (a ConstantExpr with opcode BitCast)
+ // 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;
+
+ Constant *ocr_initializer = _objc_class_references_->getInitializer();
+
+ ConstantExpr *ocr_initializer_expr = dyn_cast<ConstantExpr>(ocr_initializer);
+
+ if (!ocr_initializer_expr ||
+ ocr_initializer_expr->getOpcode() != Instruction::BitCast)
+ return false;
+
+ Value *ocr_initializer_base = ocr_initializer_expr->getOperand(0);
+
+ if (!ocr_initializer_base)
+ return false;
+
+ // Find the string's initializer (a ConstantArray) and get the string from it
+
+ GlobalVariable *_objc_class_name_ =
+ dyn_cast<GlobalVariable>(ocr_initializer_base);
+
+ 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 = ocn_initializer_array->getAsString();
+
+ if (log)
+ log->Printf("Found Objective-C class reference \"%s\"",
+ ocn_initializer_string.c_str());
+
+ // Construct a call to objc_getClass
+
+ if (!m_objc_getClass) {
+ lldb::addr_t objc_getClass_addr;
+
+ static lldb_private::ConstString g_objc_getClass_str("objc_getClass");
+ objc_getClass_addr = m_execution_unit.FindSymbol(g_objc_getClass_str);
+ if (objc_getClass_addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ if (log)
+ log->Printf("Found objc_getClass at 0x%" PRIx64,
+ 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::Type *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 = ConstantExpr::getIntToPtr(ogC_addr_int, ogC_ptr_ty);
+ }
+
+ Value *argument_array[1];
+
+ Constant *ocn_pointer = ConstantExpr::getBitCast(
+ _objc_class_name_, Type::getInt8PtrTy(m_module->getContext()));
+
+ argument_array[0] = ocn_pointer;
+
+ ArrayRef<Value *> ogC_arguments(argument_array, 1);
+
+ CallInst *ogC_call = CallInst::Create(m_objc_getClass, ogC_arguments,
+ "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(
+ lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+
+ BasicBlock::iterator ii;
+
+ typedef SmallVector<Instruction *, 2> InstrList;
+ typedef InstrList::iterator InstrIterator;
+
+ InstrList class_loads;
+
+ for (ii = basic_block.begin(); ii != basic_block.end(); ++ii) {
+ Instruction &inst = *ii;
+
+ if (LoadInst *load = dyn_cast<LoadInst>(&inst))
+ if (IsObjCClassReference(load->getPointerOperand()))
+ class_loads.push_back(&inst);
+ }
+
+ InstrIterator iter;
+
+ for (iter = class_loads.begin(); iter != class_loads.end(); ++iter) {
+ if (!RewriteObjCClassReference(*iter)) {
+ m_error_stream.Printf("Internal error [IRForTarget]: Couldn't change a "
+ "static reference to an Objective-C class to a "
+ "dynamic reference\n");
+
+ if (log)
+ log->PutCString(
+ "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(
@@ -2023,6 +2190,15 @@ bool IRForTarget::runOnModule(Module &ll
return false;
}
+
+ if (!RewriteObjCClassReferences(*bbi)) {
+ if (log)
+ log->Printf("RewriteObjCClassReferences() failed");
+
+ // RewriteObjCClasses() reports its own errors, so we don't do so here
+
+ return false;
+ }
}
}
Modified: lldb/trunk/source/Plugins/ExpressionParser/Clang/IRForTarget.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/IRForTarget.h?rev=282657&r1=282656&r2=282657&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ExpressionParser/Clang/IRForTarget.h (original)
+++ lldb/trunk/source/Plugins/ExpressionParser/Clang/IRForTarget.h Wed Sep 28 19:45:33 2016
@@ -330,6 +330,34 @@ private:
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] selector_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
@@ -542,6 +570,10 @@ private:
///sel_registerName, cast to the
///appropriate
/// function pointer type
+ llvm::Constant *m_objc_getClass; ///< The address of the function
+ ///objc_getClass, cast to the
+ ///appropriate
+ /// function pointer type
llvm::IntegerType
*m_intptr_ty; ///< The type of an integer large enough to hold a pointer.
lldb_private::Stream
More information about the lldb-commits
mailing list