Coverage Report

Created: 2023-09-30 09:22

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.cpp
Line
Count
Source (jump to first uncovered line)
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
3.92k
void GNUstepObjCRuntime::Initialize() {
31
3.92k
  PluginManager::RegisterPlugin(
32
3.92k
      GetPluginNameStatic(), "GNUstep Objective-C Language Runtime - libobjc2",
33
3.92k
      CreateInstance);
34
3.92k
}
35
36
3.92k
void GNUstepObjCRuntime::Terminate() {
37
3.92k
  PluginManager::UnregisterPlugin(CreateInstance);
38
3.92k
}
39
40
static bool CanModuleBeGNUstepObjCLibrary(const ModuleSP &module_sp,
41
2.52k
                                          const llvm::Triple &TT) {
42
2.52k
  if (!module_sp)
43
0
    return false;
44
2.52k
  const FileSpec &module_file_spec = module_sp->GetFileSpec();
45
2.52k
  if (!module_file_spec)
46
0
    return false;
47
2.52k
  llvm::StringRef filename = module_file_spec.GetFilename().GetStringRef();
48
2.52k
  if (TT.isOSBinFormatELF())
49
1.69k
    return filename.starts_with("libobjc.so");
50
830
  if (TT.isOSWindows())
51
825
    return filename == "objc.dll";
52
5
  return false;
53
830
}
54
55
static bool ScanForGNUstepObjCLibraryCandidate(const ModuleList &modules,
56
1.58k
                                               const llvm::Triple &TT) {
57
1.58k
  std::lock_guard<std::recursive_mutex> guard(modules.GetMutex());
58
1.58k
  size_t num_modules = modules.GetSize();
59
4.10k
  for (size_t i = 0; i < num_modules; 
i++2.52k
) {
60
2.52k
    auto mod = modules.GetModuleAtIndex(i);
61
2.52k
    if (CanModuleBeGNUstepObjCLibrary(mod, TT))
62
0
      return true;
63
2.52k
  }
64
1.58k
  return false;
65
1.58k
}
66
67
LanguageRuntime *GNUstepObjCRuntime::CreateInstance(Process *process,
68
398k
                                                    LanguageType language) {
69
398k
  if (language != eLanguageTypeObjC)
70
378k
    return nullptr;
71
20.5k
  if (!process)
72
0
    return nullptr;
73
74
20.5k
  Target &target = process->GetTarget();
75
20.5k
  const llvm::Triple &TT = target.GetArchitecture().GetTriple();
76
20.5k
  if (TT.getVendor() == llvm::Triple::VendorType::Apple)
77
18.9k
    return nullptr;
78
79
1.58k
  const ModuleList &images = target.GetImages();
80
1.58k
  if (!ScanForGNUstepObjCLibraryCandidate(images, TT))
81
1.58k
    return nullptr;
82
83
0
  if (TT.isOSBinFormatELF()) {
84
0
    SymbolContextList eh_pers;
85
0
    RegularExpression regex("__gnustep_objc[x]*_personality_v[0-9]+");
86
0
    images.FindSymbolsMatchingRegExAndType(regex, eSymbolTypeCode, eh_pers);
87
0
    if (eh_pers.GetSize() == 0)
88
0
      return nullptr;
89
0
  } else if (TT.isOSWindows()) {
90
0
    SymbolContextList objc_mandatory;
91
0
    images.FindSymbolsWithNameAndType(ConstString("__objc_load"),
92
0
                                      eSymbolTypeCode, objc_mandatory);
93
0
    if (objc_mandatory.GetSize() == 0)
94
0
      return nullptr;
95
0
  }
96
97
0
  return new GNUstepObjCRuntime(process);
98
0
}
99
100
0
GNUstepObjCRuntime::~GNUstepObjCRuntime() = default;
101
102
GNUstepObjCRuntime::GNUstepObjCRuntime(Process *process)
103
0
    : ObjCLanguageRuntime(process), m_objc_module_sp(nullptr) {
104
0
  ReadObjCLibraryIfNeeded(process->GetTarget().GetImages());
105
0
}
106
107
bool GNUstepObjCRuntime::GetObjectDescription(Stream &str,
108
0
                                              ValueObject &valobj) {
109
  // TODO: ObjC has a generic way to do this
110
0
  return false;
111
0
}
112
bool GNUstepObjCRuntime::GetObjectDescription(
113
0
    Stream &strm, Value &value, ExecutionContextScope *exe_scope) {
114
  // TODO: ObjC has a generic way to do this
115
0
  return false;
116
0
}
117
118
0
bool GNUstepObjCRuntime::CouldHaveDynamicValue(ValueObject &in_value) {
119
0
  static constexpr bool check_cxx = false;
120
0
  static constexpr bool check_objc = true;
121
0
  return in_value.GetCompilerType().IsPossibleDynamicType(nullptr, check_cxx,
122
0
                                                          check_objc);
123
0
}
124
125
bool GNUstepObjCRuntime::GetDynamicTypeAndAddress(
126
    ValueObject &in_value, DynamicValueType use_dynamic,
127
    TypeAndOrName &class_type_or_name, Address &address,
128
0
    Value::ValueType &value_type) {
129
0
  return false;
130
0
}
131
132
TypeAndOrName
133
GNUstepObjCRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name,
134
0
                                     ValueObject &static_value) {
135
0
  CompilerType static_type(static_value.GetCompilerType());
136
0
  Flags static_type_flags(static_type.GetTypeInfo());
137
138
0
  TypeAndOrName ret(type_and_or_name);
139
0
  if (type_and_or_name.HasType()) {
140
    // The type will always be the type of the dynamic object.  If our parent's
141
    // type was a pointer, then our type should be a pointer to the type of the
142
    // dynamic object.  If a reference, then the original type should be
143
    // okay...
144
0
    CompilerType orig_type = type_and_or_name.GetCompilerType();
145
0
    CompilerType corrected_type = orig_type;
146
0
    if (static_type_flags.AllSet(eTypeIsPointer))
147
0
      corrected_type = orig_type.GetPointerType();
148
0
    ret.SetCompilerType(corrected_type);
149
0
  } else {
150
    // If we are here we need to adjust our dynamic type name to include the
151
    // correct & or * symbol
152
0
    std::string corrected_name(type_and_or_name.GetName().GetCString());
153
0
    if (static_type_flags.AllSet(eTypeIsPointer))
154
0
      corrected_name.append(" *");
155
    // the parent type should be a correctly pointer'ed or referenc'ed type
156
0
    ret.SetCompilerType(static_type);
157
0
    ret.SetName(corrected_name.c_str());
158
0
  }
159
0
  return ret;
160
0
}
161
162
BreakpointResolverSP
163
GNUstepObjCRuntime::CreateExceptionResolver(const BreakpointSP &bkpt,
164
0
                                            bool catch_bp, bool throw_bp) {
165
0
  BreakpointResolverSP resolver_sp;
166
167
0
  if (throw_bp)
168
0
    resolver_sp = std::make_shared<BreakpointResolverName>(
169
0
        bkpt, "objc_exception_throw", eFunctionNameTypeBase,
170
0
        eLanguageTypeUnknown, Breakpoint::Exact, 0, eLazyBoolNo);
171
172
0
  return resolver_sp;
173
0
}
174
175
llvm::Expected<std::unique_ptr<UtilityFunction>>
176
GNUstepObjCRuntime::CreateObjectChecker(std::string name,
177
0
                                        ExecutionContext &exe_ctx) {
178
  // TODO: This function is supposed to check whether an ObjC selector is
179
  // present for an object. Might be implemented similar as in the Apple V2
180
  // runtime.
181
0
  const char *function_template = R"(
182
0
    extern "C" void
183
0
    %s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) {}
184
0
  )";
185
186
0
  char empty_function_code[2048];
187
0
  int len = ::snprintf(empty_function_code, sizeof(empty_function_code),
188
0
                       function_template, name.c_str());
189
190
0
  assert(len < (int)sizeof(empty_function_code));
191
0
  UNUSED_IF_ASSERT_DISABLED(len);
192
193
0
  return GetTargetRef().CreateUtilityFunction(empty_function_code, name,
194
0
                                              eLanguageTypeC, exe_ctx);
195
0
}
196
197
ThreadPlanSP
198
GNUstepObjCRuntime::GetStepThroughTrampolinePlan(Thread &thread,
199
0
                                                 bool stop_others) {
200
  // TODO: Implement this properly to avoid stepping into things like PLT stubs
201
0
  return nullptr;
202
0
}
203
204
0
void GNUstepObjCRuntime::UpdateISAToDescriptorMapIfNeeded() {
205
  // TODO: Support lazily named and dynamically loaded Objective-C classes
206
0
}
207
208
0
bool GNUstepObjCRuntime::IsModuleObjCLibrary(const ModuleSP &module_sp) {
209
0
  const llvm::Triple &TT = GetTargetRef().GetArchitecture().GetTriple();
210
0
  return CanModuleBeGNUstepObjCLibrary(module_sp, TT);
211
0
}
212
213
0
bool GNUstepObjCRuntime::ReadObjCLibrary(const ModuleSP &module_sp) {
214
0
  assert(m_objc_module_sp == nullptr && "Check HasReadObjCLibrary() first");
215
0
  m_objc_module_sp = module_sp;
216
217
  // Right now we don't use this, but we might want to check for debugger
218
  // runtime support symbols like 'gdb_object_getClass' in the future.
219
0
  return true;
220
0
}
221
222
0
void GNUstepObjCRuntime::ModulesDidLoad(const ModuleList &module_list) {
223
0
  ReadObjCLibraryIfNeeded(module_list);
224
0
}