Coverage Report

Created: 2023-09-21 18:56

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