[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