Coverage Report

Created: 2022-01-25 06:29

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