Path: blob/main/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.cpp
39690 views
//===-- GNUstepObjCRuntime.cpp --------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "GNUstepObjCRuntime.h"910#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"1112#include "lldb/Core/Module.h"13#include "lldb/Core/PluginManager.h"14#include "lldb/Core/ValueObject.h"15#include "lldb/Expression/UtilityFunction.h"16#include "lldb/Target/ExecutionContext.h"17#include "lldb/Target/Process.h"18#include "lldb/Target/Target.h"19#include "lldb/Utility/ArchSpec.h"20#include "lldb/Utility/ConstString.h"2122using namespace lldb;23using namespace lldb_private;2425LLDB_PLUGIN_DEFINE(GNUstepObjCRuntime)2627char GNUstepObjCRuntime::ID = 0;2829void GNUstepObjCRuntime::Initialize() {30PluginManager::RegisterPlugin(31GetPluginNameStatic(), "GNUstep Objective-C Language Runtime - libobjc2",32CreateInstance);33}3435void GNUstepObjCRuntime::Terminate() {36PluginManager::UnregisterPlugin(CreateInstance);37}3839static bool CanModuleBeGNUstepObjCLibrary(const ModuleSP &module_sp,40const llvm::Triple &TT) {41if (!module_sp)42return false;43const FileSpec &module_file_spec = module_sp->GetFileSpec();44if (!module_file_spec)45return false;46llvm::StringRef filename = module_file_spec.GetFilename().GetStringRef();47if (TT.isOSBinFormatELF())48return filename.starts_with("libobjc.so");49if (TT.isOSWindows())50return filename == "objc.dll";51return false;52}5354static bool ScanForGNUstepObjCLibraryCandidate(const ModuleList &modules,55const llvm::Triple &TT) {56std::lock_guard<std::recursive_mutex> guard(modules.GetMutex());57size_t num_modules = modules.GetSize();58for (size_t i = 0; i < num_modules; i++) {59auto mod = modules.GetModuleAtIndex(i);60if (CanModuleBeGNUstepObjCLibrary(mod, TT))61return true;62}63return false;64}6566LanguageRuntime *GNUstepObjCRuntime::CreateInstance(Process *process,67LanguageType language) {68if (language != eLanguageTypeObjC)69return nullptr;70if (!process)71return nullptr;7273Target &target = process->GetTarget();74const llvm::Triple &TT = target.GetArchitecture().GetTriple();75if (TT.getVendor() == llvm::Triple::VendorType::Apple)76return nullptr;7778const ModuleList &images = target.GetImages();79if (!ScanForGNUstepObjCLibraryCandidate(images, TT))80return nullptr;8182if (TT.isOSBinFormatELF()) {83SymbolContextList eh_pers;84RegularExpression regex("__gnustep_objc[x]*_personality_v[0-9]+");85images.FindSymbolsMatchingRegExAndType(regex, eSymbolTypeCode, eh_pers);86if (eh_pers.GetSize() == 0)87return nullptr;88} else if (TT.isOSWindows()) {89SymbolContextList objc_mandatory;90images.FindSymbolsWithNameAndType(ConstString("__objc_load"),91eSymbolTypeCode, objc_mandatory);92if (objc_mandatory.GetSize() == 0)93return nullptr;94}9596return new GNUstepObjCRuntime(process);97}9899GNUstepObjCRuntime::~GNUstepObjCRuntime() = default;100101GNUstepObjCRuntime::GNUstepObjCRuntime(Process *process)102: ObjCLanguageRuntime(process), m_objc_module_sp(nullptr) {103ReadObjCLibraryIfNeeded(process->GetTarget().GetImages());104}105106llvm::Error GNUstepObjCRuntime::GetObjectDescription(Stream &str,107ValueObject &valobj) {108return llvm::createStringError(109"LLDB's GNUStep runtime does not support object description");110}111112llvm::Error113GNUstepObjCRuntime::GetObjectDescription(Stream &strm, Value &value,114ExecutionContextScope *exe_scope) {115return llvm::createStringError(116"LLDB's GNUStep runtime does not support object description");117}118119bool GNUstepObjCRuntime::CouldHaveDynamicValue(ValueObject &in_value) {120static constexpr bool check_cxx = false;121static constexpr bool check_objc = true;122return in_value.GetCompilerType().IsPossibleDynamicType(nullptr, check_cxx,123check_objc);124}125126bool GNUstepObjCRuntime::GetDynamicTypeAndAddress(127ValueObject &in_value, DynamicValueType use_dynamic,128TypeAndOrName &class_type_or_name, Address &address,129Value::ValueType &value_type) {130return false;131}132133TypeAndOrName134GNUstepObjCRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name,135ValueObject &static_value) {136CompilerType static_type(static_value.GetCompilerType());137Flags static_type_flags(static_type.GetTypeInfo());138139TypeAndOrName ret(type_and_or_name);140if (type_and_or_name.HasType()) {141// The type will always be the type of the dynamic object. If our parent's142// type was a pointer, then our type should be a pointer to the type of the143// dynamic object. If a reference, then the original type should be144// okay...145CompilerType orig_type = type_and_or_name.GetCompilerType();146CompilerType corrected_type = orig_type;147if (static_type_flags.AllSet(eTypeIsPointer))148corrected_type = orig_type.GetPointerType();149ret.SetCompilerType(corrected_type);150} else {151// If we are here we need to adjust our dynamic type name to include the152// correct & or * symbol153std::string corrected_name(type_and_or_name.GetName().GetCString());154if (static_type_flags.AllSet(eTypeIsPointer))155corrected_name.append(" *");156// the parent type should be a correctly pointer'ed or referenc'ed type157ret.SetCompilerType(static_type);158ret.SetName(corrected_name.c_str());159}160return ret;161}162163BreakpointResolverSP164GNUstepObjCRuntime::CreateExceptionResolver(const BreakpointSP &bkpt,165bool catch_bp, bool throw_bp) {166BreakpointResolverSP resolver_sp;167168if (throw_bp)169resolver_sp = std::make_shared<BreakpointResolverName>(170bkpt, "objc_exception_throw", eFunctionNameTypeBase,171eLanguageTypeUnknown, Breakpoint::Exact, 0, eLazyBoolNo);172173return resolver_sp;174}175176llvm::Expected<std::unique_ptr<UtilityFunction>>177GNUstepObjCRuntime::CreateObjectChecker(std::string name,178ExecutionContext &exe_ctx) {179// TODO: This function is supposed to check whether an ObjC selector is180// present for an object. Might be implemented similar as in the Apple V2181// runtime.182const char *function_template = R"(183extern "C" void184%s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) {}185)";186187char empty_function_code[2048];188int len = ::snprintf(empty_function_code, sizeof(empty_function_code),189function_template, name.c_str());190191assert(len < (int)sizeof(empty_function_code));192UNUSED_IF_ASSERT_DISABLED(len);193194return GetTargetRef().CreateUtilityFunction(empty_function_code, name,195eLanguageTypeC, exe_ctx);196}197198ThreadPlanSP199GNUstepObjCRuntime::GetStepThroughTrampolinePlan(Thread &thread,200bool stop_others) {201// TODO: Implement this properly to avoid stepping into things like PLT stubs202return nullptr;203}204205void GNUstepObjCRuntime::UpdateISAToDescriptorMapIfNeeded() {206// TODO: Support lazily named and dynamically loaded Objective-C classes207}208209bool GNUstepObjCRuntime::IsModuleObjCLibrary(const ModuleSP &module_sp) {210const llvm::Triple &TT = GetTargetRef().GetArchitecture().GetTriple();211return CanModuleBeGNUstepObjCLibrary(module_sp, TT);212}213214bool GNUstepObjCRuntime::ReadObjCLibrary(const ModuleSP &module_sp) {215assert(m_objc_module_sp == nullptr && "Check HasReadObjCLibrary() first");216m_objc_module_sp = module_sp;217218// Right now we don't use this, but we might want to check for debugger219// runtime support symbols like 'gdb_object_getClass' in the future.220return true;221}222223void GNUstepObjCRuntime::ModulesDidLoad(const ModuleList &module_list) {224ReadObjCLibraryIfNeeded(module_list);225}226227228