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)40*8a4dda33SDimitry Andric static bool CanModuleBeGNUstepObjCLibrary(const ModuleSP &module_sp,
41*8a4dda33SDimitry Andric                                           const llvm::Triple &TT) {
42*8a4dda33SDimitry Andric   if (!module_sp)
43*8a4dda33SDimitry Andric     return false;
44*8a4dda33SDimitry Andric   const FileSpec &module_file_spec = module_sp->GetFileSpec();
45*8a4dda33SDimitry Andric   if (!module_file_spec)
46*8a4dda33SDimitry Andric     return false;
47*8a4dda33SDimitry Andric   llvm::StringRef filename = module_file_spec.GetFilename().GetStringRef();
48*8a4dda33SDimitry Andric   if (TT.isOSBinFormatELF())
49*8a4dda33SDimitry Andric     return filename.starts_with("libobjc.so");
50*8a4dda33SDimitry Andric   if (TT.isOSWindows())
51*8a4dda33SDimitry Andric     return filename == "objc.dll";
52*8a4dda33SDimitry Andric   return false;
53*8a4dda33SDimitry Andric }
54*8a4dda33SDimitry Andric 
ScanForGNUstepObjCLibraryCandidate(const ModuleList & modules,const llvm::Triple & TT)55*8a4dda33SDimitry Andric static bool ScanForGNUstepObjCLibraryCandidate(const ModuleList &modules,
56*8a4dda33SDimitry Andric                                                const llvm::Triple &TT) {
57*8a4dda33SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(modules.GetMutex());
58*8a4dda33SDimitry Andric   size_t num_modules = modules.GetSize();
59*8a4dda33SDimitry Andric   for (size_t i = 0; i < num_modules; i++) {
60*8a4dda33SDimitry Andric     auto mod = modules.GetModuleAtIndex(i);
61*8a4dda33SDimitry Andric     if (CanModuleBeGNUstepObjCLibrary(mod, TT))
62*8a4dda33SDimitry Andric       return true;
63*8a4dda33SDimitry Andric   }
64*8a4dda33SDimitry Andric   return false;
65*8a4dda33SDimitry Andric }
66*8a4dda33SDimitry 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();
80*8a4dda33SDimitry Andric   if (!ScanForGNUstepObjCLibraryCandidate(images, TT))
81*8a4dda33SDimitry Andric     return nullptr;
82*8a4dda33SDimitry 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)10706c3fb27SDimitry Andric bool GNUstepObjCRuntime::GetObjectDescription(Stream &str,
10806c3fb27SDimitry Andric                                               ValueObject &valobj) {
10906c3fb27SDimitry Andric   // TODO: ObjC has a generic way to do this
11006c3fb27SDimitry Andric   return false;
11106c3fb27SDimitry Andric }
GetObjectDescription(Stream & strm,Value & value,ExecutionContextScope * exe_scope)11206c3fb27SDimitry Andric bool GNUstepObjCRuntime::GetObjectDescription(
11306c3fb27SDimitry Andric     Stream &strm, Value &value, ExecutionContextScope *exe_scope) {
11406c3fb27SDimitry Andric   // TODO: ObjC has a generic way to do this
11506c3fb27SDimitry Andric   return false;
11606c3fb27SDimitry Andric }
11706c3fb27SDimitry Andric 
CouldHaveDynamicValue(ValueObject & in_value)11806c3fb27SDimitry Andric bool GNUstepObjCRuntime::CouldHaveDynamicValue(ValueObject &in_value) {
11906c3fb27SDimitry Andric   static constexpr bool check_cxx = false;
12006c3fb27SDimitry Andric   static constexpr bool check_objc = true;
12106c3fb27SDimitry Andric   return in_value.GetCompilerType().IsPossibleDynamicType(nullptr, check_cxx,
12206c3fb27SDimitry Andric                                                           check_objc);
12306c3fb27SDimitry Andric }
12406c3fb27SDimitry Andric 
GetDynamicTypeAndAddress(ValueObject & in_value,DynamicValueType use_dynamic,TypeAndOrName & class_type_or_name,Address & address,Value::ValueType & value_type)12506c3fb27SDimitry Andric bool GNUstepObjCRuntime::GetDynamicTypeAndAddress(
12606c3fb27SDimitry Andric     ValueObject &in_value, DynamicValueType use_dynamic,
12706c3fb27SDimitry Andric     TypeAndOrName &class_type_or_name, Address &address,
12806c3fb27SDimitry Andric     Value::ValueType &value_type) {
12906c3fb27SDimitry Andric   return false;
13006c3fb27SDimitry Andric }
13106c3fb27SDimitry Andric 
13206c3fb27SDimitry Andric TypeAndOrName
FixUpDynamicType(const TypeAndOrName & type_and_or_name,ValueObject & static_value)13306c3fb27SDimitry Andric GNUstepObjCRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name,
13406c3fb27SDimitry Andric                                      ValueObject &static_value) {
13506c3fb27SDimitry Andric   CompilerType static_type(static_value.GetCompilerType());
13606c3fb27SDimitry Andric   Flags static_type_flags(static_type.GetTypeInfo());
13706c3fb27SDimitry Andric 
13806c3fb27SDimitry Andric   TypeAndOrName ret(type_and_or_name);
13906c3fb27SDimitry Andric   if (type_and_or_name.HasType()) {
14006c3fb27SDimitry Andric     // The type will always be the type of the dynamic object.  If our parent's
14106c3fb27SDimitry Andric     // type was a pointer, then our type should be a pointer to the type of the
14206c3fb27SDimitry Andric     // dynamic object.  If a reference, then the original type should be
14306c3fb27SDimitry Andric     // okay...
14406c3fb27SDimitry Andric     CompilerType orig_type = type_and_or_name.GetCompilerType();
14506c3fb27SDimitry Andric     CompilerType corrected_type = orig_type;
14606c3fb27SDimitry Andric     if (static_type_flags.AllSet(eTypeIsPointer))
14706c3fb27SDimitry Andric       corrected_type = orig_type.GetPointerType();
14806c3fb27SDimitry Andric     ret.SetCompilerType(corrected_type);
14906c3fb27SDimitry Andric   } else {
15006c3fb27SDimitry Andric     // If we are here we need to adjust our dynamic type name to include the
15106c3fb27SDimitry Andric     // correct & or * symbol
15206c3fb27SDimitry Andric     std::string corrected_name(type_and_or_name.GetName().GetCString());
15306c3fb27SDimitry Andric     if (static_type_flags.AllSet(eTypeIsPointer))
15406c3fb27SDimitry Andric       corrected_name.append(" *");
15506c3fb27SDimitry Andric     // the parent type should be a correctly pointer'ed or referenc'ed type
15606c3fb27SDimitry Andric     ret.SetCompilerType(static_type);
15706c3fb27SDimitry Andric     ret.SetName(corrected_name.c_str());
15806c3fb27SDimitry Andric   }
15906c3fb27SDimitry Andric   return ret;
16006c3fb27SDimitry Andric }
16106c3fb27SDimitry Andric 
16206c3fb27SDimitry Andric BreakpointResolverSP
CreateExceptionResolver(const BreakpointSP & bkpt,bool catch_bp,bool throw_bp)16306c3fb27SDimitry Andric GNUstepObjCRuntime::CreateExceptionResolver(const BreakpointSP &bkpt,
16406c3fb27SDimitry Andric                                             bool catch_bp, bool throw_bp) {
16506c3fb27SDimitry Andric   BreakpointResolverSP resolver_sp;
16606c3fb27SDimitry Andric 
16706c3fb27SDimitry Andric   if (throw_bp)
16806c3fb27SDimitry Andric     resolver_sp = std::make_shared<BreakpointResolverName>(
16906c3fb27SDimitry Andric         bkpt, "objc_exception_throw", eFunctionNameTypeBase,
17006c3fb27SDimitry Andric         eLanguageTypeUnknown, Breakpoint::Exact, 0, eLazyBoolNo);
17106c3fb27SDimitry Andric 
17206c3fb27SDimitry Andric   return resolver_sp;
17306c3fb27SDimitry Andric }
17406c3fb27SDimitry Andric 
17506c3fb27SDimitry Andric llvm::Expected<std::unique_ptr<UtilityFunction>>
CreateObjectChecker(std::string name,ExecutionContext & exe_ctx)17606c3fb27SDimitry Andric GNUstepObjCRuntime::CreateObjectChecker(std::string name,
17706c3fb27SDimitry Andric                                         ExecutionContext &exe_ctx) {
17806c3fb27SDimitry Andric   // TODO: This function is supposed to check whether an ObjC selector is
17906c3fb27SDimitry Andric   // present for an object. Might be implemented similar as in the Apple V2
18006c3fb27SDimitry Andric   // runtime.
18106c3fb27SDimitry Andric   const char *function_template = R"(
18206c3fb27SDimitry Andric     extern "C" void
18306c3fb27SDimitry Andric     %s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) {}
18406c3fb27SDimitry Andric   )";
18506c3fb27SDimitry Andric 
18606c3fb27SDimitry Andric   char empty_function_code[2048];
18706c3fb27SDimitry Andric   int len = ::snprintf(empty_function_code, sizeof(empty_function_code),
18806c3fb27SDimitry Andric                        function_template, name.c_str());
18906c3fb27SDimitry Andric 
19006c3fb27SDimitry Andric   assert(len < (int)sizeof(empty_function_code));
19106c3fb27SDimitry Andric   UNUSED_IF_ASSERT_DISABLED(len);
19206c3fb27SDimitry Andric 
19306c3fb27SDimitry Andric   return GetTargetRef().CreateUtilityFunction(empty_function_code, name,
19406c3fb27SDimitry Andric                                               eLanguageTypeC, exe_ctx);
19506c3fb27SDimitry Andric }
19606c3fb27SDimitry Andric 
19706c3fb27SDimitry Andric ThreadPlanSP
GetStepThroughTrampolinePlan(Thread & thread,bool stop_others)19806c3fb27SDimitry Andric GNUstepObjCRuntime::GetStepThroughTrampolinePlan(Thread &thread,
19906c3fb27SDimitry Andric                                                  bool stop_others) {
20006c3fb27SDimitry Andric   // TODO: Implement this properly to avoid stepping into things like PLT stubs
20106c3fb27SDimitry Andric   return nullptr;
20206c3fb27SDimitry Andric }
20306c3fb27SDimitry Andric 
UpdateISAToDescriptorMapIfNeeded()20406c3fb27SDimitry Andric void GNUstepObjCRuntime::UpdateISAToDescriptorMapIfNeeded() {
20506c3fb27SDimitry Andric   // TODO: Support lazily named and dynamically loaded Objective-C classes
20606c3fb27SDimitry Andric }
20706c3fb27SDimitry Andric 
IsModuleObjCLibrary(const ModuleSP & module_sp)20806c3fb27SDimitry Andric bool GNUstepObjCRuntime::IsModuleObjCLibrary(const ModuleSP &module_sp) {
20906c3fb27SDimitry Andric   const llvm::Triple &TT = GetTargetRef().GetArchitecture().GetTriple();
210*8a4dda33SDimitry Andric   return CanModuleBeGNUstepObjCLibrary(module_sp, TT);
21106c3fb27SDimitry Andric }
21206c3fb27SDimitry Andric 
ReadObjCLibrary(const ModuleSP & module_sp)21306c3fb27SDimitry Andric bool GNUstepObjCRuntime::ReadObjCLibrary(const ModuleSP &module_sp) {
21406c3fb27SDimitry Andric   assert(m_objc_module_sp == nullptr && "Check HasReadObjCLibrary() first");
21506c3fb27SDimitry Andric   m_objc_module_sp = module_sp;
21606c3fb27SDimitry Andric 
21706c3fb27SDimitry Andric   // Right now we don't use this, but we might want to check for debugger
21806c3fb27SDimitry Andric   // runtime support symbols like 'gdb_object_getClass' in the future.
21906c3fb27SDimitry Andric   return true;
22006c3fb27SDimitry Andric }
22106c3fb27SDimitry Andric 
ModulesDidLoad(const ModuleList & module_list)22206c3fb27SDimitry Andric void GNUstepObjCRuntime::ModulesDidLoad(const ModuleList &module_list) {
22306c3fb27SDimitry Andric   ReadObjCLibraryIfNeeded(module_list);
22406c3fb27SDimitry Andric }
225