[Lldb-commits] [lldb] 0b62647 - [lldb][gnustep] Add minimal GNUstepObjCRuntime plugin for LanguageTypeObjC on non-Apple platforms
Stefan Gränitz via lldb-commits
lldb-commits at lists.llvm.org
Wed May 17 04:56:46 PDT 2023
Author: Stefan Gränitz
Date: 2023-05-17T13:56:01+02:00
New Revision: 0b6264738f3d3688719b23c5d272725d3d9bf4e0
URL: https://github.com/llvm/llvm-project/commit/0b6264738f3d3688719b23c5d272725d3d9bf4e0
DIFF: https://github.com/llvm/llvm-project/commit/0b6264738f3d3688719b23c5d272725d3d9bf4e0.diff
LOG: [lldb][gnustep] Add minimal GNUstepObjCRuntime plugin for LanguageTypeObjC on non-Apple platforms
This is the next patch after D146058. We can now parse expressions to print instance variables from ObjC classes. Until now the expression parser would bail out with an error like this:
```
error: expression failed to parse:
error: Error [IRForTarget]: Couldn't find Objective-C indirect ivar symbol OBJC_IVAR_$_TestObj._int
```
Reviewed By: aprantl
Differential Revision: https://reviews.llvm.org/D146154
Added:
lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/CMakeLists.txt
lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.cpp
lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.h
Modified:
lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
lldb/source/Plugins/LanguageRuntime/ObjC/CMakeLists.txt
lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp
lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h
lldb/test/Shell/Expr/objc-gnustep-print.m
Removed:
################################################################################
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index 79666ffadb088..8d8af21e19949 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -587,12 +587,19 @@ ClangExpressionParser::ClangExpressionParser(
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;
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/CMakeLists.txt b/lldb/source/Plugins/LanguageRuntime/ObjC/CMakeLists.txt
index d6de9dcc31bca..e8b9415241c88 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/CMakeLists.txt
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/CMakeLists.txt
@@ -7,4 +7,6 @@ add_lldb_library(lldbPluginObjCRuntime
lldbTarget
lldbUtility
)
+
add_subdirectory(AppleObjCRuntime)
+add_subdirectory(GNUstepObjCRuntime)
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/CMakeLists.txt b/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/CMakeLists.txt
new file mode 100644
index 0000000000000..1da3ac58ec9f5
--- /dev/null
+++ b/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
+ )
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.cpp
new file mode 100644
index 0000000000000..fb2656ef1385e
--- /dev/null
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.cpp
@@ -0,0 +1,204 @@
+//===-- 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();
+ const llvm::Triple &TT = GetTargetRef().GetArchitecture().GetTriple();
+ if (TT.isOSBinFormatELF())
+ return filename.starts_with("libobjc.so");
+ if (TT.isOSWindows())
+ return filename == "objc.dll";
+ return false;
+}
+
+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);
+}
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.h b/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.h
new file mode 100644
index 0000000000000..b22088807f97d
--- /dev/null
+++ b/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
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp
index e28f224101bb8..214642f654e24 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp
@@ -235,6 +235,22 @@ ObjCLanguageRuntime::GetDescriptorIteratorPair(bool update_if_needed) {
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));
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h
index f968a090c0f7b..06eec22054b44 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h
@@ -38,7 +38,8 @@ class ObjCLanguageRuntime : public LanguageRuntime {
enum class ObjCRuntimeVersions {
eObjC_VersionUnknown = 0,
eAppleObjC_V1 = 1,
- eAppleObjC_V2 = 2
+ eAppleObjC_V2 = 2,
+ eGNUstep_libobjc2 = 3,
};
typedef lldb::addr_t ObjCISA;
diff --git a/lldb/test/Shell/Expr/objc-gnustep-print.m b/lldb/test/Shell/Expr/objc-gnustep-print.m
index 565a96f15a3f7..3f13bf1234cbd 100644
--- a/lldb/test/Shell/Expr/objc-gnustep-print.m
+++ b/lldb/test/Shell/Expr/objc-gnustep-print.m
@@ -27,23 +27,39 @@ + (id)new {
}
@end
- at interface TestObj : NSObject {}
-- (int)ok;
+ at 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-9a-f]+]]{{.*}}) at objc-gnustep-print.m:35
+// SELF: -[TestObj check_ivars_zeroed](self=[[SELF_PTR:0x[0-9a-f]+]]{{.*}}) at objc-gnustep-print.m
//
// SELF: (lldb) p self
// SELF: (TestObj *) [[SELF_PTR]]
@@ -54,9 +70,38 @@ - (int)ok {
// 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) 1
+//
+// IVARS_SET: (lldb) p t->_float
+// IVARS_SET: (float) 2
+//
+// IVARS_SET: (lldb) p t->_char
+// IVARS_SET: (char) '\x03'
+//
+// IVARS_SET: (lldb) p t->_ptr_void
+// IVARS_SET: (void *) 0x{{0*}}4
+//
+// IVARS_SET: (lldb) p t->_ptr_nsobject
+// IVARS_SET: (NSObject *) 0x{{0*}}5
+//
+// IVARS_SET: (lldb) p t->_id_objc
+// IVARS_SET: (id) 0x{{0*}}6
+
int main() {
TestObj *t = [TestObj new];
- return [t ok];
+ [t check_ivars_zeroed];
+ [t set_ivars];
+ return 0;
}
More information about the lldb-commits
mailing list