1 //===-- GNUstepObjCRuntime.cpp --------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "GNUstepObjCRuntime.h" 10 11 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" 12 13 #include "lldb/Core/Module.h" 14 #include "lldb/Core/PluginManager.h" 15 #include "lldb/Core/ValueObject.h" 16 #include "lldb/Expression/UtilityFunction.h" 17 #include "lldb/Target/ExecutionContext.h" 18 #include "lldb/Target/Process.h" 19 #include "lldb/Target/Target.h" 20 #include "lldb/Utility/ArchSpec.h" 21 #include "lldb/Utility/ConstString.h" 22 23 using namespace lldb; 24 using namespace lldb_private; 25 26 LLDB_PLUGIN_DEFINE(GNUstepObjCRuntime) 27 28 char GNUstepObjCRuntime::ID = 0; 29 30 void GNUstepObjCRuntime::Initialize() { 31 PluginManager::RegisterPlugin( 32 GetPluginNameStatic(), "GNUstep Objective-C Language Runtime - libobjc2", 33 CreateInstance); 34 } 35 36 void GNUstepObjCRuntime::Terminate() { 37 PluginManager::UnregisterPlugin(CreateInstance); 38 } 39 40 LanguageRuntime *GNUstepObjCRuntime::CreateInstance(Process *process, 41 LanguageType language) { 42 if (language != eLanguageTypeObjC) 43 return nullptr; 44 if (!process) 45 return nullptr; 46 47 Target &target = process->GetTarget(); 48 const llvm::Triple &TT = target.GetArchitecture().GetTriple(); 49 if (TT.getVendor() == llvm::Triple::VendorType::Apple) 50 return nullptr; 51 52 const ModuleList &images = target.GetImages(); 53 if (TT.isOSBinFormatELF()) { 54 SymbolContextList eh_pers; 55 RegularExpression regex("__gnustep_objc[x]*_personality_v[0-9]+"); 56 images.FindSymbolsMatchingRegExAndType(regex, eSymbolTypeCode, eh_pers); 57 if (eh_pers.GetSize() == 0) 58 return nullptr; 59 } else if (TT.isOSWindows()) { 60 SymbolContextList objc_mandatory; 61 images.FindSymbolsWithNameAndType(ConstString("__objc_load"), 62 eSymbolTypeCode, objc_mandatory); 63 if (objc_mandatory.GetSize() == 0) 64 return nullptr; 65 } 66 67 return new GNUstepObjCRuntime(process); 68 } 69 70 GNUstepObjCRuntime::~GNUstepObjCRuntime() = default; 71 72 GNUstepObjCRuntime::GNUstepObjCRuntime(Process *process) 73 : ObjCLanguageRuntime(process), m_objc_module_sp(nullptr) { 74 ReadObjCLibraryIfNeeded(process->GetTarget().GetImages()); 75 } 76 77 bool GNUstepObjCRuntime::GetObjectDescription(Stream &str, 78 ValueObject &valobj) { 79 // TODO: ObjC has a generic way to do this 80 return false; 81 } 82 bool GNUstepObjCRuntime::GetObjectDescription( 83 Stream &strm, Value &value, ExecutionContextScope *exe_scope) { 84 // TODO: ObjC has a generic way to do this 85 return false; 86 } 87 88 bool GNUstepObjCRuntime::CouldHaveDynamicValue(ValueObject &in_value) { 89 static constexpr bool check_cxx = false; 90 static constexpr bool check_objc = true; 91 return in_value.GetCompilerType().IsPossibleDynamicType(nullptr, check_cxx, 92 check_objc); 93 } 94 95 bool GNUstepObjCRuntime::GetDynamicTypeAndAddress( 96 ValueObject &in_value, DynamicValueType use_dynamic, 97 TypeAndOrName &class_type_or_name, Address &address, 98 Value::ValueType &value_type) { 99 return false; 100 } 101 102 TypeAndOrName 103 GNUstepObjCRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name, 104 ValueObject &static_value) { 105 CompilerType static_type(static_value.GetCompilerType()); 106 Flags static_type_flags(static_type.GetTypeInfo()); 107 108 TypeAndOrName ret(type_and_or_name); 109 if (type_and_or_name.HasType()) { 110 // The type will always be the type of the dynamic object. If our parent's 111 // type was a pointer, then our type should be a pointer to the type of the 112 // dynamic object. If a reference, then the original type should be 113 // okay... 114 CompilerType orig_type = type_and_or_name.GetCompilerType(); 115 CompilerType corrected_type = orig_type; 116 if (static_type_flags.AllSet(eTypeIsPointer)) 117 corrected_type = orig_type.GetPointerType(); 118 ret.SetCompilerType(corrected_type); 119 } else { 120 // If we are here we need to adjust our dynamic type name to include the 121 // correct & or * symbol 122 std::string corrected_name(type_and_or_name.GetName().GetCString()); 123 if (static_type_flags.AllSet(eTypeIsPointer)) 124 corrected_name.append(" *"); 125 // the parent type should be a correctly pointer'ed or referenc'ed type 126 ret.SetCompilerType(static_type); 127 ret.SetName(corrected_name.c_str()); 128 } 129 return ret; 130 } 131 132 BreakpointResolverSP 133 GNUstepObjCRuntime::CreateExceptionResolver(const BreakpointSP &bkpt, 134 bool catch_bp, bool throw_bp) { 135 BreakpointResolverSP resolver_sp; 136 137 if (throw_bp) 138 resolver_sp = std::make_shared<BreakpointResolverName>( 139 bkpt, "objc_exception_throw", eFunctionNameTypeBase, 140 eLanguageTypeUnknown, Breakpoint::Exact, 0, eLazyBoolNo); 141 142 return resolver_sp; 143 } 144 145 llvm::Expected<std::unique_ptr<UtilityFunction>> 146 GNUstepObjCRuntime::CreateObjectChecker(std::string name, 147 ExecutionContext &exe_ctx) { 148 // TODO: This function is supposed to check whether an ObjC selector is 149 // present for an object. Might be implemented similar as in the Apple V2 150 // runtime. 151 const char *function_template = R"( 152 extern "C" void 153 %s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) {} 154 )"; 155 156 char empty_function_code[2048]; 157 int len = ::snprintf(empty_function_code, sizeof(empty_function_code), 158 function_template, name.c_str()); 159 160 assert(len < (int)sizeof(empty_function_code)); 161 UNUSED_IF_ASSERT_DISABLED(len); 162 163 return GetTargetRef().CreateUtilityFunction(empty_function_code, name, 164 eLanguageTypeC, exe_ctx); 165 } 166 167 ThreadPlanSP 168 GNUstepObjCRuntime::GetStepThroughTrampolinePlan(Thread &thread, 169 bool stop_others) { 170 // TODO: Implement this properly to avoid stepping into things like PLT stubs 171 return nullptr; 172 } 173 174 void GNUstepObjCRuntime::UpdateISAToDescriptorMapIfNeeded() { 175 // TODO: Support lazily named and dynamically loaded Objective-C classes 176 } 177 178 bool GNUstepObjCRuntime::IsModuleObjCLibrary(const ModuleSP &module_sp) { 179 if (!module_sp) 180 return false; 181 const FileSpec &module_file_spec = module_sp->GetFileSpec(); 182 if (!module_file_spec) 183 return false; 184 llvm::StringRef filename = module_file_spec.GetFilename().GetStringRef(); 185 const llvm::Triple &TT = GetTargetRef().GetArchitecture().GetTriple(); 186 if (TT.isOSBinFormatELF()) 187 return filename.starts_with("libobjc.so"); 188 if (TT.isOSWindows()) 189 return filename == "objc.dll"; 190 return false; 191 } 192 193 bool GNUstepObjCRuntime::ReadObjCLibrary(const ModuleSP &module_sp) { 194 assert(m_objc_module_sp == nullptr && "Check HasReadObjCLibrary() first"); 195 m_objc_module_sp = module_sp; 196 197 // Right now we don't use this, but we might want to check for debugger 198 // runtime support symbols like 'gdb_object_getClass' in the future. 199 return true; 200 } 201 202 void GNUstepObjCRuntime::ModulesDidLoad(const ModuleList &module_list) { 203 ReadObjCLibraryIfNeeded(module_list); 204 } 205