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
Initialize()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
Terminate()3606c3fb27SDimitry Andric void GNUstepObjCRuntime::Terminate() {
3706c3fb27SDimitry Andric PluginManager::UnregisterPlugin(CreateInstance);
3806c3fb27SDimitry Andric }
3906c3fb27SDimitry Andric
CanModuleBeGNUstepObjCLibrary(const ModuleSP & module_sp,const llvm::Triple & TT)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
ScanForGNUstepObjCLibraryCandidate(const ModuleList & modules,const llvm::Triple & TT)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
CreateInstance(Process * process,LanguageType language)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
GNUstepObjCRuntime(Process * process)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
GetObjectDescription(Stream & str,ValueObject & valobj)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
GetObjectDescription(Stream & strm,Value & value,ExecutionContextScope * exe_scope)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
CouldHaveDynamicValue(ValueObject & in_value)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
GetDynamicTypeAndAddress(ValueObject & in_value,DynamicValueType use_dynamic,TypeAndOrName & class_type_or_name,Address & address,Value::ValueType & value_type)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
FixUpDynamicType(const TypeAndOrName & type_and_or_name,ValueObject & static_value)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
CreateExceptionResolver(const BreakpointSP & bkpt,bool catch_bp,bool throw_bp)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>>
CreateObjectChecker(std::string name,ExecutionContext & exe_ctx)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
GetStepThroughTrampolinePlan(Thread & thread,bool stop_others)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
UpdateISAToDescriptorMapIfNeeded()20606c3fb27SDimitry Andric void GNUstepObjCRuntime::UpdateISAToDescriptorMapIfNeeded() {
20706c3fb27SDimitry Andric // TODO: Support lazily named and dynamically loaded Objective-C classes
20806c3fb27SDimitry Andric }
20906c3fb27SDimitry Andric
IsModuleObjCLibrary(const ModuleSP & module_sp)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
ReadObjCLibrary(const ModuleSP & module_sp)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
ModulesDidLoad(const ModuleList & module_list)22406c3fb27SDimitry Andric void GNUstepObjCRuntime::ModulesDidLoad(const ModuleList &module_list) {
22506c3fb27SDimitry Andric ReadObjCLibraryIfNeeded(module_list);
22606c3fb27SDimitry Andric }
227