Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp
39644 views
1
//===-- ObjCLanguageRuntime.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
#include "clang/AST/Type.h"
9
10
#include "ObjCLanguageRuntime.h"
11
12
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
13
#include "lldb/Core/Module.h"
14
#include "lldb/Core/PluginManager.h"
15
#include "lldb/Core/ValueObject.h"
16
#include "lldb/Symbol/SymbolContext.h"
17
#include "lldb/Symbol/SymbolFile.h"
18
#include "lldb/Symbol/Type.h"
19
#include "lldb/Symbol/TypeList.h"
20
#include "lldb/Symbol/Variable.h"
21
#include "lldb/Target/ABI.h"
22
#include "lldb/Target/Target.h"
23
#include "lldb/Utility/LLDBLog.h"
24
#include "lldb/Utility/Log.h"
25
#include "lldb/Utility/Timer.h"
26
27
#include "llvm/ADT/StringRef.h"
28
#include "llvm/Support/DJB.h"
29
#include <optional>
30
31
using namespace lldb;
32
using namespace lldb_private;
33
34
char ObjCLanguageRuntime::ID = 0;
35
36
// Destructor
37
ObjCLanguageRuntime::~ObjCLanguageRuntime() = default;
38
39
ObjCLanguageRuntime::ObjCLanguageRuntime(Process *process)
40
: LanguageRuntime(process), m_impl_cache(), m_impl_str_cache(),
41
m_has_new_literals_and_indexing(eLazyBoolCalculate),
42
m_isa_to_descriptor(), m_hash_to_isa_map(), m_type_size_cache(),
43
m_isa_to_descriptor_stop_id(UINT32_MAX), m_complete_class_cache(),
44
m_negative_complete_class_cache() {}
45
46
bool ObjCLanguageRuntime::IsAllowedRuntimeValue(ConstString name) {
47
static ConstString g_self = ConstString("self");
48
static ConstString g_cmd = ConstString("_cmd");
49
return name == g_self || name == g_cmd;
50
}
51
52
bool ObjCLanguageRuntime::AddClass(ObjCISA isa,
53
const ClassDescriptorSP &descriptor_sp,
54
const char *class_name) {
55
if (isa != 0) {
56
m_isa_to_descriptor[isa] = descriptor_sp;
57
// class_name is assumed to be valid
58
m_hash_to_isa_map.insert(std::make_pair(llvm::djbHash(class_name), isa));
59
return true;
60
}
61
return false;
62
}
63
64
void ObjCLanguageRuntime::AddToMethodCache(lldb::addr_t class_addr,
65
lldb::addr_t selector,
66
lldb::addr_t impl_addr) {
67
Log *log = GetLog(LLDBLog::Step);
68
if (log) {
69
LLDB_LOGF(log,
70
"Caching: class 0x%" PRIx64 " selector 0x%" PRIx64
71
" implementation 0x%" PRIx64 ".",
72
class_addr, selector, impl_addr);
73
}
74
m_impl_cache.insert(std::pair<ClassAndSel, lldb::addr_t>(
75
ClassAndSel(class_addr, selector), impl_addr));
76
}
77
78
void ObjCLanguageRuntime::AddToMethodCache(lldb::addr_t class_addr,
79
llvm::StringRef sel_str,
80
lldb::addr_t impl_addr) {
81
Log *log = GetLog(LLDBLog::Step);
82
83
LLDB_LOG(log, "Caching: class {0} selector {1} implementation {2}.",
84
class_addr, sel_str, impl_addr);
85
86
m_impl_str_cache.insert(std::pair<ClassAndSelStr, lldb::addr_t>(
87
ClassAndSelStr(class_addr, sel_str), impl_addr));
88
}
89
90
lldb::addr_t ObjCLanguageRuntime::LookupInMethodCache(lldb::addr_t class_addr,
91
lldb::addr_t selector) {
92
MsgImplMap::iterator pos, end = m_impl_cache.end();
93
pos = m_impl_cache.find(ClassAndSel(class_addr, selector));
94
if (pos != end)
95
return (*pos).second;
96
return LLDB_INVALID_ADDRESS;
97
}
98
99
lldb::addr_t ObjCLanguageRuntime::LookupInMethodCache(lldb::addr_t class_addr,
100
llvm::StringRef sel_str) {
101
MsgImplStrMap::iterator pos, end = m_impl_str_cache.end();
102
pos = m_impl_str_cache.find(ClassAndSelStr(class_addr, sel_str));
103
if (pos != end)
104
return (*pos).second;
105
return LLDB_INVALID_ADDRESS;
106
}
107
108
lldb::TypeSP
109
ObjCLanguageRuntime::LookupInCompleteClassCache(ConstString &name) {
110
CompleteClassMap::iterator complete_class_iter =
111
m_complete_class_cache.find(name);
112
113
if (complete_class_iter != m_complete_class_cache.end()) {
114
// Check the weak pointer to make sure the type hasn't been unloaded
115
TypeSP complete_type_sp(complete_class_iter->second.lock());
116
117
if (complete_type_sp)
118
return complete_type_sp;
119
else
120
m_complete_class_cache.erase(name);
121
}
122
123
if (m_negative_complete_class_cache.count(name) > 0)
124
return TypeSP();
125
126
const ModuleList &modules = m_process->GetTarget().GetImages();
127
128
SymbolContextList sc_list;
129
modules.FindSymbolsWithNameAndType(name, eSymbolTypeObjCClass, sc_list);
130
const size_t matching_symbols = sc_list.GetSize();
131
132
if (matching_symbols) {
133
SymbolContext sc;
134
135
sc_list.GetContextAtIndex(0, sc);
136
137
ModuleSP module_sp(sc.module_sp);
138
139
if (!module_sp)
140
return TypeSP();
141
142
TypeQuery query(name.GetStringRef(), TypeQueryOptions::e_exact_match);
143
TypeResults results;
144
module_sp->FindTypes(query, results);
145
for (const TypeSP &type_sp : results.GetTypeMap().Types()) {
146
if (TypeSystemClang::IsObjCObjectOrInterfaceType(
147
type_sp->GetForwardCompilerType())) {
148
if (TypePayloadClang(type_sp->GetPayload()).IsCompleteObjCClass()) {
149
m_complete_class_cache[name] = type_sp;
150
return type_sp;
151
}
152
}
153
}
154
}
155
m_negative_complete_class_cache.insert(name);
156
return TypeSP();
157
}
158
159
size_t ObjCLanguageRuntime::GetByteOffsetForIvar(CompilerType &parent_qual_type,
160
const char *ivar_name) {
161
return LLDB_INVALID_IVAR_OFFSET;
162
}
163
164
bool ObjCLanguageRuntime::ClassDescriptor::IsPointerValid(
165
lldb::addr_t value, uint32_t ptr_size, bool allow_NULLs, bool allow_tagged,
166
bool check_version_specific) const {
167
if (!value)
168
return allow_NULLs;
169
if ((value % 2) == 1 && allow_tagged)
170
return true;
171
if ((value % ptr_size) == 0)
172
return (check_version_specific ? CheckPointer(value, ptr_size) : true);
173
else
174
return false;
175
}
176
177
ObjCLanguageRuntime::ObjCISA
178
ObjCLanguageRuntime::GetISA(ConstString name) {
179
ISAToDescriptorIterator pos = GetDescriptorIterator(name);
180
if (pos != m_isa_to_descriptor.end())
181
return pos->first;
182
return 0;
183
}
184
185
ObjCLanguageRuntime::ISAToDescriptorIterator
186
ObjCLanguageRuntime::GetDescriptorIterator(ConstString name) {
187
ISAToDescriptorIterator end = m_isa_to_descriptor.end();
188
189
if (name) {
190
UpdateISAToDescriptorMap();
191
if (m_hash_to_isa_map.empty()) {
192
// No name hashes were provided, we need to just linearly power through
193
// the names and find a match
194
for (ISAToDescriptorIterator pos = m_isa_to_descriptor.begin();
195
pos != end; ++pos) {
196
if (pos->second->GetClassName() == name)
197
return pos;
198
}
199
} else {
200
// Name hashes were provided, so use them to efficiently lookup name to
201
// isa/descriptor
202
const uint32_t name_hash = llvm::djbHash(name.GetStringRef());
203
std::pair<HashToISAIterator, HashToISAIterator> range =
204
m_hash_to_isa_map.equal_range(name_hash);
205
for (HashToISAIterator range_pos = range.first; range_pos != range.second;
206
++range_pos) {
207
ISAToDescriptorIterator pos =
208
m_isa_to_descriptor.find(range_pos->second);
209
if (pos != m_isa_to_descriptor.end()) {
210
if (pos->second->GetClassName() == name)
211
return pos;
212
}
213
}
214
}
215
}
216
return end;
217
}
218
219
std::pair<ObjCLanguageRuntime::ISAToDescriptorIterator,
220
ObjCLanguageRuntime::ISAToDescriptorIterator>
221
ObjCLanguageRuntime::GetDescriptorIteratorPair(bool update_if_needed) {
222
if (update_if_needed)
223
UpdateISAToDescriptorMapIfNeeded();
224
225
return std::pair<ObjCLanguageRuntime::ISAToDescriptorIterator,
226
ObjCLanguageRuntime::ISAToDescriptorIterator>(
227
m_isa_to_descriptor.begin(), m_isa_to_descriptor.end());
228
}
229
230
void ObjCLanguageRuntime::ReadObjCLibraryIfNeeded(
231
const ModuleList &module_list) {
232
if (!HasReadObjCLibrary()) {
233
std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex());
234
235
size_t num_modules = module_list.GetSize();
236
for (size_t i = 0; i < num_modules; i++) {
237
auto mod = module_list.GetModuleAtIndex(i);
238
if (IsModuleObjCLibrary(mod)) {
239
ReadObjCLibrary(mod);
240
break;
241
}
242
}
243
}
244
}
245
246
ObjCLanguageRuntime::ObjCISA
247
ObjCLanguageRuntime::GetParentClass(ObjCLanguageRuntime::ObjCISA isa) {
248
ClassDescriptorSP objc_class_sp(GetClassDescriptorFromISA(isa));
249
if (objc_class_sp) {
250
ClassDescriptorSP objc_super_class_sp(objc_class_sp->GetSuperclass());
251
if (objc_super_class_sp)
252
return objc_super_class_sp->GetISA();
253
}
254
return 0;
255
}
256
257
ObjCLanguageRuntime::ClassDescriptorSP
258
ObjCLanguageRuntime::GetClassDescriptorFromClassName(
259
ConstString class_name) {
260
ISAToDescriptorIterator pos = GetDescriptorIterator(class_name);
261
if (pos != m_isa_to_descriptor.end())
262
return pos->second;
263
return ClassDescriptorSP();
264
}
265
266
ObjCLanguageRuntime::ClassDescriptorSP
267
ObjCLanguageRuntime::GetClassDescriptor(ValueObject &valobj) {
268
ClassDescriptorSP objc_class_sp;
269
// if we get an invalid VO (which might still happen when playing around with
270
// pointers returned by the expression parser, don't consider this a valid
271
// ObjC object)
272
if (valobj.GetCompilerType().IsValid()) {
273
addr_t isa_pointer = valobj.GetPointerValue();
274
if (isa_pointer != LLDB_INVALID_ADDRESS) {
275
ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
276
277
Process *process = exe_ctx.GetProcessPtr();
278
if (process) {
279
Status error;
280
ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error);
281
if (isa != LLDB_INVALID_ADDRESS)
282
objc_class_sp = GetClassDescriptorFromISA(isa);
283
}
284
}
285
}
286
return objc_class_sp;
287
}
288
289
ObjCLanguageRuntime::ClassDescriptorSP
290
ObjCLanguageRuntime::GetNonKVOClassDescriptor(ValueObject &valobj) {
291
ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp(
292
GetClassDescriptor(valobj));
293
if (objc_class_sp) {
294
if (!objc_class_sp->IsKVO())
295
return objc_class_sp;
296
297
ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass());
298
if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid())
299
return non_kvo_objc_class_sp;
300
}
301
return ClassDescriptorSP();
302
}
303
304
ObjCLanguageRuntime::ClassDescriptorSP
305
ObjCLanguageRuntime::GetClassDescriptorFromISA(ObjCISA isa) {
306
if (isa) {
307
UpdateISAToDescriptorMap();
308
309
ObjCLanguageRuntime::ISAToDescriptorIterator pos =
310
m_isa_to_descriptor.find(isa);
311
if (pos != m_isa_to_descriptor.end())
312
return pos->second;
313
314
if (ABISP abi_sp = m_process->GetABI()) {
315
pos = m_isa_to_descriptor.find(abi_sp->FixCodeAddress(isa));
316
if (pos != m_isa_to_descriptor.end())
317
return pos->second;
318
}
319
}
320
return ClassDescriptorSP();
321
}
322
323
ObjCLanguageRuntime::ClassDescriptorSP
324
ObjCLanguageRuntime::GetNonKVOClassDescriptor(ObjCISA isa) {
325
if (isa) {
326
ClassDescriptorSP objc_class_sp = GetClassDescriptorFromISA(isa);
327
if (objc_class_sp && objc_class_sp->IsValid()) {
328
if (!objc_class_sp->IsKVO())
329
return objc_class_sp;
330
331
ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass());
332
if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid())
333
return non_kvo_objc_class_sp;
334
}
335
}
336
return ClassDescriptorSP();
337
}
338
339
CompilerType
340
ObjCLanguageRuntime::EncodingToType::RealizeType(const char *name,
341
bool for_expression) {
342
if (m_scratch_ast_ctx_sp)
343
return RealizeType(*m_scratch_ast_ctx_sp, name, for_expression);
344
return CompilerType();
345
}
346
347
ObjCLanguageRuntime::EncodingToType::~EncodingToType() = default;
348
349
ObjCLanguageRuntime::EncodingToTypeSP ObjCLanguageRuntime::GetEncodingToType() {
350
return nullptr;
351
}
352
353
std::optional<uint64_t>
354
ObjCLanguageRuntime::GetTypeBitSize(const CompilerType &compiler_type) {
355
void *opaque_ptr = compiler_type.GetOpaqueQualType();
356
uint64_t cached_size = m_type_size_cache.Lookup(opaque_ptr);
357
if (cached_size > 0)
358
return cached_size;
359
360
ClassDescriptorSP class_descriptor_sp =
361
GetClassDescriptorFromClassName(compiler_type.GetTypeName());
362
if (!class_descriptor_sp)
363
return {};
364
365
int32_t max_offset = INT32_MIN;
366
uint64_t sizeof_max = 0;
367
bool found = false;
368
369
for (size_t idx = 0; idx < class_descriptor_sp->GetNumIVars(); idx++) {
370
const auto &ivar = class_descriptor_sp->GetIVarAtIndex(idx);
371
int32_t cur_offset = ivar.m_offset;
372
if (cur_offset > max_offset) {
373
max_offset = cur_offset;
374
sizeof_max = ivar.m_size;
375
found = true;
376
}
377
}
378
379
uint64_t size = 8 * (max_offset + sizeof_max);
380
if (found && size > 0) {
381
m_type_size_cache.Insert(opaque_ptr, size);
382
return size;
383
}
384
385
return {};
386
}
387
388
lldb::BreakpointPreconditionSP
389
ObjCLanguageRuntime::GetBreakpointExceptionPrecondition(LanguageType language,
390
bool throw_bp) {
391
if (language != eLanguageTypeObjC)
392
return lldb::BreakpointPreconditionSP();
393
if (!throw_bp)
394
return lldb::BreakpointPreconditionSP();
395
BreakpointPreconditionSP precondition_sp(
396
new ObjCLanguageRuntime::ObjCExceptionPrecondition());
397
return precondition_sp;
398
}
399
400
// Exception breakpoint Precondition class for ObjC:
401
void ObjCLanguageRuntime::ObjCExceptionPrecondition::AddClassName(
402
const char *class_name) {
403
m_class_names.insert(class_name);
404
}
405
406
ObjCLanguageRuntime::ObjCExceptionPrecondition::ObjCExceptionPrecondition() =
407
default;
408
409
bool ObjCLanguageRuntime::ObjCExceptionPrecondition::EvaluatePrecondition(
410
StoppointCallbackContext &context) {
411
return true;
412
}
413
414
void ObjCLanguageRuntime::ObjCExceptionPrecondition::GetDescription(
415
Stream &stream, lldb::DescriptionLevel level) {}
416
417
Status ObjCLanguageRuntime::ObjCExceptionPrecondition::ConfigurePrecondition(
418
Args &args) {
419
Status error;
420
if (args.GetArgumentCount() > 0)
421
error.SetErrorString(
422
"The ObjC Exception breakpoint doesn't support extra options.");
423
return error;
424
}
425
426
std::optional<CompilerType>
427
ObjCLanguageRuntime::GetRuntimeType(CompilerType base_type) {
428
CompilerType class_type;
429
bool is_pointer_type = false;
430
431
if (TypeSystemClang::IsObjCObjectPointerType(base_type, &class_type))
432
is_pointer_type = true;
433
else if (TypeSystemClang::IsObjCObjectOrInterfaceType(base_type))
434
class_type = base_type;
435
else
436
return std::nullopt;
437
438
if (!class_type)
439
return std::nullopt;
440
441
ConstString class_name(class_type.GetTypeName());
442
if (!class_name)
443
return std::nullopt;
444
445
TypeSP complete_objc_class_type_sp = LookupInCompleteClassCache(class_name);
446
if (!complete_objc_class_type_sp)
447
return std::nullopt;
448
449
CompilerType complete_class(
450
complete_objc_class_type_sp->GetFullCompilerType());
451
if (complete_class.GetCompleteType()) {
452
if (is_pointer_type)
453
return complete_class.GetPointerType();
454
else
455
return complete_class;
456
}
457
458
return std::nullopt;
459
}
460
461