106c3fb27SDimitry Andric //===-- GNUstepObjCRuntime.cpp --------------------------------------------===// 206c3fb27SDimitry Andric // 306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 606c3fb27SDimitry Andric // 706c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 806c3fb27SDimitry Andric 906c3fb27SDimitry Andric #include "GNUstepObjCRuntime.h" 1006c3fb27SDimitry Andric 1106c3fb27SDimitry Andric #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" 1206c3fb27SDimitry Andric 1306c3fb27SDimitry Andric #include "lldb/Core/Module.h" 1406c3fb27SDimitry Andric #include "lldb/Core/PluginManager.h" 1506c3fb27SDimitry Andric #include "lldb/Core/ValueObject.h" 1606c3fb27SDimitry Andric #include "lldb/Expression/UtilityFunction.h" 1706c3fb27SDimitry Andric #include "lldb/Target/ExecutionContext.h" 1806c3fb27SDimitry Andric #include "lldb/Target/Process.h" 1906c3fb27SDimitry Andric #include "lldb/Target/Target.h" 2006c3fb27SDimitry Andric #include "lldb/Utility/ArchSpec.h" 2106c3fb27SDimitry Andric #include "lldb/Utility/ConstString.h" 2206c3fb27SDimitry Andric 2306c3fb27SDimitry Andric using namespace lldb; 2406c3fb27SDimitry Andric using namespace lldb_private; 2506c3fb27SDimitry Andric 2606c3fb27SDimitry Andric LLDB_PLUGIN_DEFINE(GNUstepObjCRuntime) 2706c3fb27SDimitry Andric 2806c3fb27SDimitry Andric char GNUstepObjCRuntime::ID = 0; 2906c3fb27SDimitry Andric 3006c3fb27SDimitry Andric void GNUstepObjCRuntime::Initialize() { 3106c3fb27SDimitry Andric PluginManager::RegisterPlugin( 3206c3fb27SDimitry Andric GetPluginNameStatic(), "GNUstep Objective-C Language Runtime - libobjc2", 3306c3fb27SDimitry Andric CreateInstance); 3406c3fb27SDimitry Andric } 3506c3fb27SDimitry Andric 3606c3fb27SDimitry Andric void GNUstepObjCRuntime::Terminate() { 3706c3fb27SDimitry Andric PluginManager::UnregisterPlugin(CreateInstance); 3806c3fb27SDimitry Andric } 3906c3fb27SDimitry Andric 408a4dda33SDimitry Andric static bool CanModuleBeGNUstepObjCLibrary(const ModuleSP &module_sp, 418a4dda33SDimitry Andric const llvm::Triple &TT) { 428a4dda33SDimitry Andric if (!module_sp) 438a4dda33SDimitry Andric return false; 448a4dda33SDimitry Andric const FileSpec &module_file_spec = module_sp->GetFileSpec(); 458a4dda33SDimitry Andric if (!module_file_spec) 468a4dda33SDimitry Andric return false; 478a4dda33SDimitry Andric llvm::StringRef filename = module_file_spec.GetFilename().GetStringRef(); 488a4dda33SDimitry Andric if (TT.isOSBinFormatELF()) 498a4dda33SDimitry Andric return filename.starts_with("libobjc.so"); 508a4dda33SDimitry Andric if (TT.isOSWindows()) 518a4dda33SDimitry Andric return filename == "objc.dll"; 528a4dda33SDimitry Andric return false; 538a4dda33SDimitry Andric } 548a4dda33SDimitry Andric 558a4dda33SDimitry Andric static bool ScanForGNUstepObjCLibraryCandidate(const ModuleList &modules, 568a4dda33SDimitry Andric const llvm::Triple &TT) { 578a4dda33SDimitry Andric std::lock_guard<std::recursive_mutex> guard(modules.GetMutex()); 588a4dda33SDimitry Andric size_t num_modules = modules.GetSize(); 598a4dda33SDimitry Andric for (size_t i = 0; i < num_modules; i++) { 608a4dda33SDimitry Andric auto mod = modules.GetModuleAtIndex(i); 618a4dda33SDimitry Andric if (CanModuleBeGNUstepObjCLibrary(mod, TT)) 628a4dda33SDimitry Andric return true; 638a4dda33SDimitry Andric } 648a4dda33SDimitry Andric return false; 658a4dda33SDimitry Andric } 668a4dda33SDimitry Andric 6706c3fb27SDimitry Andric LanguageRuntime *GNUstepObjCRuntime::CreateInstance(Process *process, 6806c3fb27SDimitry Andric LanguageType language) { 6906c3fb27SDimitry Andric if (language != eLanguageTypeObjC) 7006c3fb27SDimitry Andric return nullptr; 7106c3fb27SDimitry Andric if (!process) 7206c3fb27SDimitry Andric return nullptr; 7306c3fb27SDimitry Andric 7406c3fb27SDimitry Andric Target &target = process->GetTarget(); 7506c3fb27SDimitry Andric const llvm::Triple &TT = target.GetArchitecture().GetTriple(); 7606c3fb27SDimitry Andric if (TT.getVendor() == llvm::Triple::VendorType::Apple) 7706c3fb27SDimitry Andric return nullptr; 7806c3fb27SDimitry Andric 7906c3fb27SDimitry Andric const ModuleList &images = target.GetImages(); 808a4dda33SDimitry Andric if (!ScanForGNUstepObjCLibraryCandidate(images, TT)) 818a4dda33SDimitry Andric return nullptr; 828a4dda33SDimitry Andric 8306c3fb27SDimitry Andric if (TT.isOSBinFormatELF()) { 8406c3fb27SDimitry Andric SymbolContextList eh_pers; 8506c3fb27SDimitry Andric RegularExpression regex("__gnustep_objc[x]*_personality_v[0-9]+"); 8606c3fb27SDimitry Andric images.FindSymbolsMatchingRegExAndType(regex, eSymbolTypeCode, eh_pers); 8706c3fb27SDimitry Andric if (eh_pers.GetSize() == 0) 8806c3fb27SDimitry Andric return nullptr; 8906c3fb27SDimitry Andric } else if (TT.isOSWindows()) { 9006c3fb27SDimitry Andric SymbolContextList objc_mandatory; 9106c3fb27SDimitry Andric images.FindSymbolsWithNameAndType(ConstString("__objc_load"), 9206c3fb27SDimitry Andric eSymbolTypeCode, objc_mandatory); 9306c3fb27SDimitry Andric if (objc_mandatory.GetSize() == 0) 9406c3fb27SDimitry Andric return nullptr; 9506c3fb27SDimitry Andric } 9606c3fb27SDimitry Andric 9706c3fb27SDimitry Andric return new GNUstepObjCRuntime(process); 9806c3fb27SDimitry Andric } 9906c3fb27SDimitry Andric 10006c3fb27SDimitry Andric GNUstepObjCRuntime::~GNUstepObjCRuntime() = default; 10106c3fb27SDimitry Andric 10206c3fb27SDimitry Andric GNUstepObjCRuntime::GNUstepObjCRuntime(Process *process) 10306c3fb27SDimitry Andric : ObjCLanguageRuntime(process), m_objc_module_sp(nullptr) { 10406c3fb27SDimitry Andric ReadObjCLibraryIfNeeded(process->GetTarget().GetImages()); 10506c3fb27SDimitry Andric } 10606c3fb27SDimitry Andric 107*0fca6ea1SDimitry Andric llvm::Error GNUstepObjCRuntime::GetObjectDescription(Stream &str, 10806c3fb27SDimitry Andric ValueObject &valobj) { 109*0fca6ea1SDimitry Andric return llvm::createStringError( 110*0fca6ea1SDimitry Andric "LLDB's GNUStep runtime does not support object description"); 11106c3fb27SDimitry Andric } 112*0fca6ea1SDimitry Andric 113*0fca6ea1SDimitry Andric llvm::Error 114*0fca6ea1SDimitry Andric GNUstepObjCRuntime::GetObjectDescription(Stream &strm, Value &value, 115*0fca6ea1SDimitry Andric ExecutionContextScope *exe_scope) { 116*0fca6ea1SDimitry Andric return llvm::createStringError( 117*0fca6ea1SDimitry Andric "LLDB's GNUStep runtime does not support object description"); 11806c3fb27SDimitry Andric } 11906c3fb27SDimitry Andric 12006c3fb27SDimitry Andric bool GNUstepObjCRuntime::CouldHaveDynamicValue(ValueObject &in_value) { 12106c3fb27SDimitry Andric static constexpr bool check_cxx = false; 12206c3fb27SDimitry Andric static constexpr bool check_objc = true; 12306c3fb27SDimitry Andric return in_value.GetCompilerType().IsPossibleDynamicType(nullptr, check_cxx, 12406c3fb27SDimitry Andric check_objc); 12506c3fb27SDimitry Andric } 12606c3fb27SDimitry Andric 12706c3fb27SDimitry Andric bool GNUstepObjCRuntime::GetDynamicTypeAndAddress( 12806c3fb27SDimitry Andric ValueObject &in_value, DynamicValueType use_dynamic, 12906c3fb27SDimitry Andric TypeAndOrName &class_type_or_name, Address &address, 13006c3fb27SDimitry Andric Value::ValueType &value_type) { 13106c3fb27SDimitry Andric return false; 13206c3fb27SDimitry Andric } 13306c3fb27SDimitry Andric 13406c3fb27SDimitry Andric TypeAndOrName 13506c3fb27SDimitry Andric GNUstepObjCRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name, 13606c3fb27SDimitry Andric ValueObject &static_value) { 13706c3fb27SDimitry Andric CompilerType static_type(static_value.GetCompilerType()); 13806c3fb27SDimitry Andric Flags static_type_flags(static_type.GetTypeInfo()); 13906c3fb27SDimitry Andric 14006c3fb27SDimitry Andric TypeAndOrName ret(type_and_or_name); 14106c3fb27SDimitry Andric if (type_and_or_name.HasType()) { 14206c3fb27SDimitry Andric // The type will always be the type of the dynamic object. If our parent's 14306c3fb27SDimitry Andric // type was a pointer, then our type should be a pointer to the type of the 14406c3fb27SDimitry Andric // dynamic object. If a reference, then the original type should be 14506c3fb27SDimitry Andric // okay... 14606c3fb27SDimitry Andric CompilerType orig_type = type_and_or_name.GetCompilerType(); 14706c3fb27SDimitry Andric CompilerType corrected_type = orig_type; 14806c3fb27SDimitry Andric if (static_type_flags.AllSet(eTypeIsPointer)) 14906c3fb27SDimitry Andric corrected_type = orig_type.GetPointerType(); 15006c3fb27SDimitry Andric ret.SetCompilerType(corrected_type); 15106c3fb27SDimitry Andric } else { 15206c3fb27SDimitry Andric // If we are here we need to adjust our dynamic type name to include the 15306c3fb27SDimitry Andric // correct & or * symbol 15406c3fb27SDimitry Andric std::string corrected_name(type_and_or_name.GetName().GetCString()); 15506c3fb27SDimitry Andric if (static_type_flags.AllSet(eTypeIsPointer)) 15606c3fb27SDimitry Andric corrected_name.append(" *"); 15706c3fb27SDimitry Andric // the parent type should be a correctly pointer'ed or referenc'ed type 15806c3fb27SDimitry Andric ret.SetCompilerType(static_type); 15906c3fb27SDimitry Andric ret.SetName(corrected_name.c_str()); 16006c3fb27SDimitry Andric } 16106c3fb27SDimitry Andric return ret; 16206c3fb27SDimitry Andric } 16306c3fb27SDimitry Andric 16406c3fb27SDimitry Andric BreakpointResolverSP 16506c3fb27SDimitry Andric GNUstepObjCRuntime::CreateExceptionResolver(const BreakpointSP &bkpt, 16606c3fb27SDimitry Andric bool catch_bp, bool throw_bp) { 16706c3fb27SDimitry Andric BreakpointResolverSP resolver_sp; 16806c3fb27SDimitry Andric 16906c3fb27SDimitry Andric if (throw_bp) 17006c3fb27SDimitry Andric resolver_sp = std::make_shared<BreakpointResolverName>( 17106c3fb27SDimitry Andric bkpt, "objc_exception_throw", eFunctionNameTypeBase, 17206c3fb27SDimitry Andric eLanguageTypeUnknown, Breakpoint::Exact, 0, eLazyBoolNo); 17306c3fb27SDimitry Andric 17406c3fb27SDimitry Andric return resolver_sp; 17506c3fb27SDimitry Andric } 17606c3fb27SDimitry Andric 17706c3fb27SDimitry Andric llvm::Expected<std::unique_ptr<UtilityFunction>> 17806c3fb27SDimitry Andric GNUstepObjCRuntime::CreateObjectChecker(std::string name, 17906c3fb27SDimitry Andric ExecutionContext &exe_ctx) { 18006c3fb27SDimitry Andric // TODO: This function is supposed to check whether an ObjC selector is 18106c3fb27SDimitry Andric // present for an object. Might be implemented similar as in the Apple V2 18206c3fb27SDimitry Andric // runtime. 18306c3fb27SDimitry Andric const char *function_template = R"( 18406c3fb27SDimitry Andric extern "C" void 18506c3fb27SDimitry Andric %s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) {} 18606c3fb27SDimitry Andric )"; 18706c3fb27SDimitry Andric 18806c3fb27SDimitry Andric char empty_function_code[2048]; 18906c3fb27SDimitry Andric int len = ::snprintf(empty_function_code, sizeof(empty_function_code), 19006c3fb27SDimitry Andric function_template, name.c_str()); 19106c3fb27SDimitry Andric 19206c3fb27SDimitry Andric assert(len < (int)sizeof(empty_function_code)); 19306c3fb27SDimitry Andric UNUSED_IF_ASSERT_DISABLED(len); 19406c3fb27SDimitry Andric 19506c3fb27SDimitry Andric return GetTargetRef().CreateUtilityFunction(empty_function_code, name, 19606c3fb27SDimitry Andric eLanguageTypeC, exe_ctx); 19706c3fb27SDimitry Andric } 19806c3fb27SDimitry Andric 19906c3fb27SDimitry Andric ThreadPlanSP 20006c3fb27SDimitry Andric GNUstepObjCRuntime::GetStepThroughTrampolinePlan(Thread &thread, 20106c3fb27SDimitry Andric bool stop_others) { 20206c3fb27SDimitry Andric // TODO: Implement this properly to avoid stepping into things like PLT stubs 20306c3fb27SDimitry Andric return nullptr; 20406c3fb27SDimitry Andric } 20506c3fb27SDimitry Andric 20606c3fb27SDimitry Andric void GNUstepObjCRuntime::UpdateISAToDescriptorMapIfNeeded() { 20706c3fb27SDimitry Andric // TODO: Support lazily named and dynamically loaded Objective-C classes 20806c3fb27SDimitry Andric } 20906c3fb27SDimitry Andric 21006c3fb27SDimitry Andric bool GNUstepObjCRuntime::IsModuleObjCLibrary(const ModuleSP &module_sp) { 21106c3fb27SDimitry Andric const llvm::Triple &TT = GetTargetRef().GetArchitecture().GetTriple(); 2128a4dda33SDimitry Andric return CanModuleBeGNUstepObjCLibrary(module_sp, TT); 21306c3fb27SDimitry Andric } 21406c3fb27SDimitry Andric 21506c3fb27SDimitry Andric bool GNUstepObjCRuntime::ReadObjCLibrary(const ModuleSP &module_sp) { 21606c3fb27SDimitry Andric assert(m_objc_module_sp == nullptr && "Check HasReadObjCLibrary() first"); 21706c3fb27SDimitry Andric m_objc_module_sp = module_sp; 21806c3fb27SDimitry Andric 21906c3fb27SDimitry Andric // Right now we don't use this, but we might want to check for debugger 22006c3fb27SDimitry Andric // runtime support symbols like 'gdb_object_getClass' in the future. 22106c3fb27SDimitry Andric return true; 22206c3fb27SDimitry Andric } 22306c3fb27SDimitry Andric 22406c3fb27SDimitry Andric void GNUstepObjCRuntime::ModulesDidLoad(const ModuleList &module_list) { 22506c3fb27SDimitry Andric ReadObjCLibraryIfNeeded(module_list); 22606c3fb27SDimitry Andric } 227