sgraenitz updated this revision to Diff 506989.
sgraenitz added a comment.

Check for GNUstep EH personality in ELF targets and `__objc_load` on native 
Windows


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D146154/new/

https://reviews.llvm.org/D146154

Files:
  lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
  lldb/source/Plugins/LanguageRuntime/ObjC/CMakeLists.txt
  lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/CMakeLists.txt
  
lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.cpp
  
lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.h
  lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp
  lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h
  lldb/test/Shell/Expr/objc-gnustep-print.m

Index: lldb/test/Shell/Expr/objc-gnustep-print.m
===================================================================
--- lldb/test/Shell/Expr/objc-gnustep-print.m
+++ lldb/test/Shell/Expr/objc-gnustep-print.m
@@ -27,23 +27,39 @@
 }
 @end
 
-@interface TestObj : NSObject {}
-- (int)ok;
+@interface TestObj : NSObject {
+  int _int;
+  float _float;
+  char _char;
+  void *_ptr_void;
+  NSObject *_ptr_nsobject;
+  id _id_objc;
+}
+- (void)check_ivars_zeroed;
+- (void)set_ivars;
 @end
 @implementation TestObj
-- (int)ok {
-  return self ? 0 : 1;
+- (void)check_ivars_zeroed {
+  ;
+}
+- (void)set_ivars {
+  _int = 1;
+  _float = 2.0f;
+  _char = '\3';
+  _ptr_void = (void*)4;
+  _ptr_nsobject = (NSObject*)5;
+  _id_objc = (id)6;
 }
 @end
 
-// RUN: %lldb -b -o "b objc-gnustep-print.m:35" -o "run" -o "p self" -o "p *self" -- %t | FileCheck %s --check-prefix=SELF
+// RUN: %lldb -b -o "b objc-gnustep-print.m:43" -o "run" -o "p self" -o "p *self" -- %t | FileCheck %s --check-prefix=SELF
 //
-// SELF: (lldb) b objc-gnustep-print.m:35
+// SELF: (lldb) b objc-gnustep-print.m:43
 // SELF: Breakpoint {{.*}} at objc-gnustep-print.m
 //
 // SELF: (lldb) run
 // SELF: Process {{[0-9]+}} stopped
-// SELF: -[TestObj ok](self=[[SELF_PTR:0x[0-9]+]]{{.*}}) at objc-gnustep-print.m:35
+// SELF: -[TestObj check_ivars_zeroed](self=[[SELF_PTR:0x[0-9]+]]{{.*}}) at objc-gnustep-print.m
 //
 // SELF: (lldb) p self
 // SELF: (TestObj *) $0 = [[SELF_PTR]]
@@ -54,9 +70,38 @@
 // SELF:     isa
 // SELF:     refcount
 // SELF:   }
+// SELF:   _int = 0
+// SELF:   _float = 0
+// SELF:   _char = '\0'
+// SELF:   _ptr_void = 0x{{0*}}
+// SELF:   _ptr_nsobject = nil
+// SELF:   _id_objc = nil
 // SELF: }
 
+// RUN: %lldb -b -o "b objc-gnustep-print.m:106" -o "run" -o "p t->_int" -o "p t->_float" -o "p t->_char" \
+// RUN:          -o "p t->_ptr_void" -o "p t->_ptr_nsobject" -o "p t->_id_objc" -- %t | FileCheck %s --check-prefix=IVARS_SET
+//
+// IVARS_SET: (lldb) p t->_int
+// IVARS_SET: (int) $0 = 1
+//
+// IVARS_SET: (lldb) p t->_float
+// IVARS_SET: (float) $1 = 2
+//
+// IVARS_SET: (lldb) p t->_char
+// IVARS_SET: (char) $2 = '\x03'
+//
+// IVARS_SET: (lldb) p t->_ptr_void
+// IVARS_SET: (void *) $3 = 0x{{0*}}4
+//
+// IVARS_SET: (lldb) p t->_ptr_nsobject
+// IVARS_SET: (NSObject *) $4 = 0x{{0*}}5
+//
+// IVARS_SET: (lldb) p t->_id_objc
+// IVARS_SET: (id) $5 = 0x{{0*}}6
+
 int main() {
   TestObj *t = [TestObj new];
-  return [t ok];
+  [t check_ivars_zeroed];
+  [t set_ivars];
+  return 0;
 }
Index: lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h
===================================================================
--- lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h
+++ lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h
@@ -38,7 +38,8 @@
   enum class ObjCRuntimeVersions {
     eObjC_VersionUnknown = 0,
     eAppleObjC_V1 = 1,
-    eAppleObjC_V2 = 2
+    eAppleObjC_V2 = 2,
+    eGNUstep_libobjc2 = 3,
   };
 
   typedef lldb::addr_t ObjCISA;
Index: lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp
===================================================================
--- lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp
+++ lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp
@@ -235,6 +235,22 @@
       m_isa_to_descriptor.begin(), m_isa_to_descriptor.end());
 }
 
+void ObjCLanguageRuntime::ReadObjCLibraryIfNeeded(
+    const ModuleList &module_list) {
+  if (!HasReadObjCLibrary()) {
+    std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex());
+
+    size_t num_modules = module_list.GetSize();
+    for (size_t i = 0; i < num_modules; i++) {
+      auto mod = module_list.GetModuleAtIndex(i);
+      if (IsModuleObjCLibrary(mod)) {
+        ReadObjCLibrary(mod);
+        break;
+      }
+    }
+  }
+}
+
 ObjCLanguageRuntime::ObjCISA
 ObjCLanguageRuntime::GetParentClass(ObjCLanguageRuntime::ObjCISA isa) {
   ClassDescriptorSP objc_class_sp(GetClassDescriptorFromISA(isa));
Index: lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.h
===================================================================
--- /dev/null
+++ lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.h
@@ -0,0 +1,111 @@
+//===-- GNUstepObjCRuntime.h ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_GNUSTEPOBJCRUNTIME_GNUSTEPOBJCRUNTIME_H
+#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_GNUSTEPOBJCRUNTIME_GNUSTEPOBJCRUNTIME_H
+
+#include "lldb/Target/LanguageRuntime.h"
+#include "lldb/lldb-private.h"
+
+#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+
+#include <optional>
+
+namespace lldb_private {
+
+class GNUstepObjCRuntime : public lldb_private::ObjCLanguageRuntime {
+public:
+  ~GNUstepObjCRuntime() override;
+
+  //
+  //  PluginManager, PluginInterface and LLVM RTTI implementation
+  //
+
+  static char ID;
+
+  static void Initialize();
+
+  static void Terminate();
+
+  static lldb_private::LanguageRuntime *
+  CreateInstance(Process *process, lldb::LanguageType language);
+
+  static llvm::StringRef GetPluginNameStatic() {
+    return "gnustep-objc-libobjc2";
+  }
+
+  llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+  void ModulesDidLoad(const ModuleList &module_list) override;
+
+  bool isA(const void *ClassID) const override {
+    return ClassID == &ID || ObjCLanguageRuntime::isA(ClassID);
+  }
+
+  static bool classof(const LanguageRuntime *runtime) {
+    return runtime->isA(&ID);
+  }
+
+  //
+  // LanguageRuntime implementation
+  //
+  bool GetObjectDescription(Stream &str, Value &value,
+                            ExecutionContextScope *exe_scope) override;
+
+  bool GetObjectDescription(Stream &str, ValueObject &object) override;
+
+  bool CouldHaveDynamicValue(ValueObject &in_value) override;
+
+  bool GetDynamicTypeAndAddress(ValueObject &in_value,
+                                lldb::DynamicValueType use_dynamic,
+                                TypeAndOrName &class_type_or_name,
+                                Address &address,
+                                Value::ValueType &value_type) override;
+
+  TypeAndOrName FixUpDynamicType(const TypeAndOrName &type_and_or_name,
+                                 ValueObject &static_value) override;
+
+  lldb::BreakpointResolverSP
+  CreateExceptionResolver(const lldb::BreakpointSP &bkpt, bool catch_bp,
+                          bool throw_bp) override;
+
+  lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread,
+                                                  bool stop_others) override;
+
+  //
+  // ObjCLanguageRuntime implementation
+  //
+
+  bool IsModuleObjCLibrary(const lldb::ModuleSP &module_sp) override;
+
+  bool ReadObjCLibrary(const lldb::ModuleSP &module_sp) override;
+
+  bool HasReadObjCLibrary() override { return m_objc_module_sp != nullptr; }
+
+  llvm::Expected<std::unique_ptr<UtilityFunction>>
+  CreateObjectChecker(std::string name, ExecutionContext &exe_ctx) override;
+
+  ObjCRuntimeVersions GetRuntimeVersion() const override {
+    return ObjCRuntimeVersions::eGNUstep_libobjc2;
+  }
+
+  void UpdateISAToDescriptorMapIfNeeded() override;
+
+protected:
+  // Call CreateInstance instead.
+  GNUstepObjCRuntime(Process *process);
+
+  lldb::ModuleSP m_objc_module_sp;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_GNUSTEPOBJCRUNTIME_GNUSTEPOBJCRUNTIME_H
Index: lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.cpp
===================================================================
--- /dev/null
+++ lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.cpp
@@ -0,0 +1,199 @@
+//===-- GNUstepObjCRuntime.cpp --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "GNUstepObjCRuntime.h"
+
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Expression/UtilityFunction.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/ConstString.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+LLDB_PLUGIN_DEFINE(GNUstepObjCRuntime)
+
+char GNUstepObjCRuntime::ID = 0;
+
+void GNUstepObjCRuntime::Initialize() {
+  PluginManager::RegisterPlugin(
+      GetPluginNameStatic(), "GNUstep Objective-C Language Runtime - libobjc2",
+      CreateInstance);
+}
+
+void GNUstepObjCRuntime::Terminate() {
+  PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+LanguageRuntime *GNUstepObjCRuntime::CreateInstance(Process *process,
+                                                    LanguageType language) {
+  if (language != eLanguageTypeObjC)
+    return nullptr;
+  if (!process)
+    return nullptr;
+
+  Target &target = process->GetTarget();
+  const llvm::Triple &TT = target.GetArchitecture().GetTriple();
+  if (TT.getVendor() == llvm::Triple::VendorType::Apple)
+    return nullptr;
+
+  const ModuleList &images = target.GetImages();
+  if (TT.isOSBinFormatELF()) {
+    SymbolContextList eh_pers;
+    RegularExpression regex("__gnustep_objc[x]*_personality_v[0-9]+");
+    images.FindSymbolsMatchingRegExAndType(regex, eSymbolTypeCode, eh_pers);
+    if (eh_pers.GetSize() == 0)
+      return nullptr;
+  } else if (TT.isOSWindows()) {
+    SymbolContextList objc_mandatory;
+    images.FindSymbolsWithNameAndType(ConstString("__objc_load"),
+                                      eSymbolTypeCode, objc_mandatory);
+    if (objc_mandatory.GetSize() == 0)
+      return nullptr;
+  }
+
+  return new GNUstepObjCRuntime(process);
+}
+
+GNUstepObjCRuntime::~GNUstepObjCRuntime() = default;
+
+GNUstepObjCRuntime::GNUstepObjCRuntime(Process *process)
+    : ObjCLanguageRuntime(process), m_objc_module_sp(nullptr) {
+  ReadObjCLibraryIfNeeded(process->GetTarget().GetImages());
+}
+
+bool GNUstepObjCRuntime::GetObjectDescription(Stream &str,
+                                              ValueObject &valobj) {
+  // TODO: ObjC has a generic way to do this
+  return false;
+}
+bool GNUstepObjCRuntime::GetObjectDescription(
+    Stream &strm, Value &value, ExecutionContextScope *exe_scope) {
+  // TODO: ObjC has a generic way to do this
+  return false;
+}
+
+bool GNUstepObjCRuntime::CouldHaveDynamicValue(ValueObject &in_value) {
+  static constexpr bool check_cxx = false;
+  static constexpr bool check_objc = true;
+  return in_value.GetCompilerType().IsPossibleDynamicType(nullptr, check_cxx,
+                                                          check_objc);
+}
+
+bool GNUstepObjCRuntime::GetDynamicTypeAndAddress(
+    ValueObject &in_value, DynamicValueType use_dynamic,
+    TypeAndOrName &class_type_or_name, Address &address,
+    Value::ValueType &value_type) {
+  return false;
+}
+
+TypeAndOrName
+GNUstepObjCRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name,
+                                     ValueObject &static_value) {
+  CompilerType static_type(static_value.GetCompilerType());
+  Flags static_type_flags(static_type.GetTypeInfo());
+
+  TypeAndOrName ret(type_and_or_name);
+  if (type_and_or_name.HasType()) {
+    // The type will always be the type of the dynamic object.  If our parent's
+    // type was a pointer, then our type should be a pointer to the type of the
+    // dynamic object.  If a reference, then the original type should be
+    // okay...
+    CompilerType orig_type = type_and_or_name.GetCompilerType();
+    CompilerType corrected_type = orig_type;
+    if (static_type_flags.AllSet(eTypeIsPointer))
+      corrected_type = orig_type.GetPointerType();
+    ret.SetCompilerType(corrected_type);
+  } else {
+    // If we are here we need to adjust our dynamic type name to include the
+    // correct & or * symbol
+    std::string corrected_name(type_and_or_name.GetName().GetCString());
+    if (static_type_flags.AllSet(eTypeIsPointer))
+      corrected_name.append(" *");
+    // the parent type should be a correctly pointer'ed or referenc'ed type
+    ret.SetCompilerType(static_type);
+    ret.SetName(corrected_name.c_str());
+  }
+  return ret;
+}
+
+BreakpointResolverSP
+GNUstepObjCRuntime::CreateExceptionResolver(const BreakpointSP &bkpt,
+                                            bool catch_bp, bool throw_bp) {
+  BreakpointResolverSP resolver_sp;
+
+  if (throw_bp)
+    resolver_sp = std::make_shared<BreakpointResolverName>(
+        bkpt, "objc_exception_throw", eFunctionNameTypeBase,
+        eLanguageTypeUnknown, Breakpoint::Exact, 0, eLazyBoolNo);
+
+  return resolver_sp;
+}
+
+llvm::Expected<std::unique_ptr<UtilityFunction>>
+GNUstepObjCRuntime::CreateObjectChecker(std::string name,
+                                        ExecutionContext &exe_ctx) {
+  // TODO: This function is supposed to check whether an ObjC selector is
+  // present for an object. Might be implemented similar as in the Apple V2
+  // runtime.
+  const char *function_template = R"(
+    extern "C" void
+    %s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) {}
+  )";
+
+  char empty_function_code[2048];
+  int len = ::snprintf(empty_function_code, sizeof(empty_function_code),
+                       function_template, name.c_str());
+
+  assert(len < (int)sizeof(empty_function_code));
+  UNUSED_IF_ASSERT_DISABLED(len);
+
+  return GetTargetRef().CreateUtilityFunction(empty_function_code, name,
+                                              eLanguageTypeC, exe_ctx);
+}
+
+ThreadPlanSP
+GNUstepObjCRuntime::GetStepThroughTrampolinePlan(Thread &thread,
+                                                 bool stop_others) {
+  // TODO: Implement this properly to avoid stepping into things like PLT stubs
+  return nullptr;
+}
+
+void GNUstepObjCRuntime::UpdateISAToDescriptorMapIfNeeded() {
+  // TODO: Support lazily named and dynamically loaded Objective-C classes
+}
+
+bool GNUstepObjCRuntime::IsModuleObjCLibrary(const ModuleSP &module_sp) {
+  if (!module_sp)
+    return false;
+  const FileSpec &module_file_spec = module_sp->GetFileSpec();
+  if (!module_file_spec)
+    return false;
+  llvm::StringRef filename = module_file_spec.GetFilename().GetStringRef();
+  return filename.starts_with("libobjc.so") || filename == "objc.dll";
+}
+
+bool GNUstepObjCRuntime::ReadObjCLibrary(const ModuleSP &module_sp) {
+  assert(m_objc_module_sp == nullptr && "Check HasReadObjCLibrary() first");
+  m_objc_module_sp = module_sp;
+
+  // Right now we don't use this, but we might want to check for debugger
+  // runtime support symbols like 'gdb_object_getClass' in the future.
+  return true;
+}
+
+void GNUstepObjCRuntime::ModulesDidLoad(const ModuleList &module_list) {
+  ReadObjCLibraryIfNeeded(module_list);
+}
Index: lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/CMakeLists.txt
===================================================================
--- /dev/null
+++ lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/CMakeLists.txt
@@ -0,0 +1,19 @@
+add_lldb_library(lldbPluginGNUstepObjCRuntime PLUGIN
+  GNUstepObjCRuntime.cpp
+
+  LINK_LIBS
+    lldbBreakpoint
+    lldbCore
+    lldbExpression
+    lldbHost
+    lldbInterpreter
+    lldbSymbol
+    lldbTarget
+    lldbUtility
+    lldbPluginExpressionParserClang
+    lldbPluginTypeSystemClang
+  CLANG_LIBS
+    clangAST
+  LINK_COMPONENTS
+    Support
+  )
Index: lldb/source/Plugins/LanguageRuntime/ObjC/CMakeLists.txt
===================================================================
--- lldb/source/Plugins/LanguageRuntime/ObjC/CMakeLists.txt
+++ lldb/source/Plugins/LanguageRuntime/ObjC/CMakeLists.txt
@@ -7,4 +7,6 @@
     lldbTarget
     lldbUtility
 )
+
 add_subdirectory(AppleObjCRuntime)
+add_subdirectory(GNUstepObjCRuntime)
Index: lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
===================================================================
--- lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -577,12 +577,19 @@
 
   if (process_sp && lang_opts.ObjC) {
     if (auto *runtime = ObjCLanguageRuntime::Get(*process_sp)) {
-      if (runtime->GetRuntimeVersion() ==
-          ObjCLanguageRuntime::ObjCRuntimeVersions::eAppleObjC_V2)
+      switch (runtime->GetRuntimeVersion()) {
+      case ObjCLanguageRuntime::ObjCRuntimeVersions::eAppleObjC_V2:
         lang_opts.ObjCRuntime.set(ObjCRuntime::MacOSX, VersionTuple(10, 7));
-      else
+        break;
+      case ObjCLanguageRuntime::ObjCRuntimeVersions::eObjC_VersionUnknown:
+      case ObjCLanguageRuntime::ObjCRuntimeVersions::eAppleObjC_V1:
         lang_opts.ObjCRuntime.set(ObjCRuntime::FragileMacOSX,
                                   VersionTuple(10, 7));
+        break;
+      case ObjCLanguageRuntime::ObjCRuntimeVersions::eGNUstep_libobjc2:
+        lang_opts.ObjCRuntime.set(ObjCRuntime::GNUstep, VersionTuple(2, 0));
+        break;
+      }
 
       if (runtime->HasNewLiteralsAndIndexing())
         lang_opts.DebuggerObjCLiteral = true;
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to