Coverage Report

Created: 2022-01-18 06:27

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- AppleObjCRuntimeV1.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 "AppleObjCRuntimeV1.h"
10
#include "AppleObjCDeclVendor.h"
11
#include "AppleObjCTrampolineHandler.h"
12
13
#include "clang/AST/Type.h"
14
15
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
16
#include "lldb/Breakpoint/BreakpointLocation.h"
17
#include "lldb/Core/Module.h"
18
#include "lldb/Core/PluginManager.h"
19
#include "lldb/Expression/FunctionCaller.h"
20
#include "lldb/Expression/UtilityFunction.h"
21
#include "lldb/Symbol/Symbol.h"
22
#include "lldb/Target/ExecutionContext.h"
23
#include "lldb/Target/Process.h"
24
#include "lldb/Target/RegisterContext.h"
25
#include "lldb/Target/Target.h"
26
#include "lldb/Target/Thread.h"
27
#include "lldb/Utility/ConstString.h"
28
#include "lldb/Utility/Log.h"
29
#include "lldb/Utility/Scalar.h"
30
#include "lldb/Utility/Status.h"
31
#include "lldb/Utility/StreamString.h"
32
33
#include <memory>
34
#include <vector>
35
36
using namespace lldb;
37
using namespace lldb_private;
38
39
char AppleObjCRuntimeV1::ID = 0;
40
41
AppleObjCRuntimeV1::AppleObjCRuntimeV1(Process *process)
42
    : AppleObjCRuntime(process), m_hash_signature(),
43
0
      m_isa_hash_table_ptr(LLDB_INVALID_ADDRESS) {}
44
45
// for V1 runtime we just try to return a class name as that is the minimum
46
// level of support required for the data formatters to work
47
bool AppleObjCRuntimeV1::GetDynamicTypeAndAddress(
48
    ValueObject &in_value, lldb::DynamicValueType use_dynamic,
49
    TypeAndOrName &class_type_or_name, Address &address,
50
0
    Value::ValueType &value_type) {
51
0
  class_type_or_name.Clear();
52
0
  value_type = Value::ValueType::Scalar;
53
0
  if (CouldHaveDynamicValue(in_value)) {
54
0
    auto class_descriptor(GetClassDescriptor(in_value));
55
0
    if (class_descriptor && class_descriptor->IsValid() &&
56
0
        class_descriptor->GetClassName()) {
57
0
      const addr_t object_ptr = in_value.GetPointerValue();
58
0
      address.SetRawAddress(object_ptr);
59
0
      class_type_or_name.SetName(class_descriptor->GetClassName());
60
0
    }
61
0
  }
62
0
  return !class_type_or_name.IsEmpty();
63
0
}
64
65
// Static Functions
66
lldb_private::LanguageRuntime *
67
AppleObjCRuntimeV1::CreateInstance(Process *process,
68
194k
                                   lldb::LanguageType language) {
69
  // FIXME: This should be a MacOS or iOS process, and we need to look for the
70
  // OBJC section to make
71
  // sure we aren't using the V1 runtime.
72
194k
  if (language == eLanguageTypeObjC) {
73
22.4k
    ModuleSP objc_module_sp;
74
75
22.4k
    if (AppleObjCRuntime::GetObjCVersion(process, objc_module_sp) ==
76
22.4k
        ObjCRuntimeVersions::eAppleObjC_V1)
77
0
      return new AppleObjCRuntimeV1(process);
78
22.4k
    else
79
22.4k
      return nullptr;
80
22.4k
  } else
81
171k
    return nullptr;
82
194k
}
83
84
3.44k
void AppleObjCRuntimeV1::Initialize() {
85
3.44k
  PluginManager::RegisterPlugin(
86
3.44k
      GetPluginNameStatic(), "Apple Objective-C Language Runtime - Version 1",
87
3.44k
      CreateInstance,
88
3.44k
      /*command_callback = */ nullptr, GetBreakpointExceptionPrecondition);
89
3.44k
}
90
91
3.43k
void AppleObjCRuntimeV1::Terminate() {
92
3.43k
  PluginManager::UnregisterPlugin(CreateInstance);
93
3.43k
}
94
95
BreakpointResolverSP
96
AppleObjCRuntimeV1::CreateExceptionResolver(const BreakpointSP &bkpt,
97
0
                                            bool catch_bp, bool throw_bp) {
98
0
  BreakpointResolverSP resolver_sp;
99
100
0
  if (throw_bp)
101
0
    resolver_sp = std::make_shared<BreakpointResolverName>(
102
0
        bkpt, std::get<1>(GetExceptionThrowLocation()).AsCString(),
103
0
        eFunctionNameTypeBase, eLanguageTypeUnknown, Breakpoint::Exact, 0,
104
0
        eLazyBoolNo);
105
  // FIXME: don't do catch yet.
106
0
  return resolver_sp;
107
0
}
108
109
struct BufStruct {
110
  char contents[2048];
111
};
112
113
llvm::Expected<std::unique_ptr<UtilityFunction>>
114
AppleObjCRuntimeV1::CreateObjectChecker(std::string name,
115
0
                                        ExecutionContext &exe_ctx) {
116
0
  std::unique_ptr<BufStruct> buf(new BufStruct);
117
118
0
  int strformatsize =
119
0
      snprintf(&buf->contents[0], sizeof(buf->contents),
120
0
               "struct __objc_class                                         "
121
0
               "           \n"
122
0
               "{                                                           "
123
0
               "           \n"
124
0
               "   struct __objc_class *isa;                                "
125
0
               "           \n"
126
0
               "   struct __objc_class *super_class;                        "
127
0
               "           \n"
128
0
               "   const char *name;                                        "
129
0
               "           \n"
130
0
               "   // rest of struct elided because unused                  "
131
0
               "           \n"
132
0
               "};                                                          "
133
0
               "           \n"
134
0
               "                                                            "
135
0
               "           \n"
136
0
               "struct __objc_object                                        "
137
0
               "           \n"
138
0
               "{                                                           "
139
0
               "           \n"
140
0
               "   struct __objc_class *isa;                                "
141
0
               "           \n"
142
0
               "};                                                          "
143
0
               "           \n"
144
0
               "                                                            "
145
0
               "           \n"
146
0
               "extern \"C\" void                                           "
147
0
               "           \n"
148
0
               "%s(void *$__lldb_arg_obj, void *$__lldb_arg_selector)       "
149
0
               "           \n"
150
0
               "{                                                           "
151
0
               "           \n"
152
0
               "   struct __objc_object *obj = (struct "
153
0
               "__objc_object*)$__lldb_arg_obj; \n"
154
0
               "   if ($__lldb_arg_obj == (void *)0)                     "
155
0
               "                                \n"
156
0
               "       return; // nil is ok                              "
157
0
               "   (int)strlen(obj->isa->name);                             "
158
0
               "           \n"
159
0
               "}                                                           "
160
0
               "           \n",
161
0
               name.c_str());
162
0
  assert(strformatsize < (int)sizeof(buf->contents));
163
0
  (void)strformatsize;
164
165
0
  return GetTargetRef().CreateUtilityFunction(buf->contents, std::move(name),
166
0
                                              eLanguageTypeC, exe_ctx);
167
0
}
168
169
AppleObjCRuntimeV1::ClassDescriptorV1::ClassDescriptorV1(
170
0
    ValueObject &isa_pointer) {
171
0
  Initialize(isa_pointer.GetValueAsUnsigned(0), isa_pointer.GetProcessSP());
172
0
}
173
174
AppleObjCRuntimeV1::ClassDescriptorV1::ClassDescriptorV1(
175
0
    ObjCISA isa, lldb::ProcessSP process_sp) {
176
0
  Initialize(isa, process_sp);
177
0
}
178
179
void AppleObjCRuntimeV1::ClassDescriptorV1::Initialize(
180
0
    ObjCISA isa, lldb::ProcessSP process_sp) {
181
0
  if (!isa || !process_sp) {
182
0
    m_valid = false;
183
0
    return;
184
0
  }
185
186
0
  m_valid = true;
187
188
0
  Status error;
189
190
0
  m_isa = process_sp->ReadPointerFromMemory(isa, error);
191
192
0
  if (error.Fail()) {
193
0
    m_valid = false;
194
0
    return;
195
0
  }
196
197
0
  uint32_t ptr_size = process_sp->GetAddressByteSize();
198
199
0
  if (!IsPointerValid(m_isa, ptr_size)) {
200
0
    m_valid = false;
201
0
    return;
202
0
  }
203
204
0
  m_parent_isa = process_sp->ReadPointerFromMemory(m_isa + ptr_size, error);
205
206
0
  if (error.Fail()) {
207
0
    m_valid = false;
208
0
    return;
209
0
  }
210
211
0
  if (!IsPointerValid(m_parent_isa, ptr_size, true)) {
212
0
    m_valid = false;
213
0
    return;
214
0
  }
215
216
0
  lldb::addr_t name_ptr =
217
0
      process_sp->ReadPointerFromMemory(m_isa + 2 * ptr_size, error);
218
219
0
  if (error.Fail()) {
220
0
    m_valid = false;
221
0
    return;
222
0
  }
223
224
0
  lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0));
225
226
0
  size_t count = process_sp->ReadCStringFromMemory(
227
0
      name_ptr, (char *)buffer_sp->GetBytes(), 1024, error);
228
229
0
  if (error.Fail()) {
230
0
    m_valid = false;
231
0
    return;
232
0
  }
233
234
0
  if (count)
235
0
    m_name = ConstString((char *)buffer_sp->GetBytes());
236
0
  else
237
0
    m_name = ConstString();
238
239
0
  m_instance_size = process_sp->ReadUnsignedIntegerFromMemory(
240
0
      m_isa + 5 * ptr_size, ptr_size, 0, error);
241
242
0
  if (error.Fail()) {
243
0
    m_valid = false;
244
0
    return;
245
0
  }
246
247
0
  m_process_wp = lldb::ProcessWP(process_sp);
248
0
}
249
250
AppleObjCRuntime::ClassDescriptorSP
251
0
AppleObjCRuntimeV1::ClassDescriptorV1::GetSuperclass() {
252
0
  if (!m_valid)
253
0
    return AppleObjCRuntime::ClassDescriptorSP();
254
0
  ProcessSP process_sp = m_process_wp.lock();
255
0
  if (!process_sp)
256
0
    return AppleObjCRuntime::ClassDescriptorSP();
257
0
  return ObjCLanguageRuntime::ClassDescriptorSP(
258
0
      new AppleObjCRuntimeV1::ClassDescriptorV1(m_parent_isa, process_sp));
259
0
}
260
261
AppleObjCRuntime::ClassDescriptorSP
262
0
AppleObjCRuntimeV1::ClassDescriptorV1::GetMetaclass() const {
263
0
  return ClassDescriptorSP();
264
0
}
265
266
bool AppleObjCRuntimeV1::ClassDescriptorV1::Describe(
267
    std::function<void(ObjCLanguageRuntime::ObjCISA)> const &superclass_func,
268
    std::function<bool(const char *, const char *)> const &instance_method_func,
269
    std::function<bool(const char *, const char *)> const &class_method_func,
270
    std::function<bool(const char *, const char *, lldb::addr_t,
271
0
                       uint64_t)> const &ivar_func) const {
272
0
  return false;
273
0
}
274
275
0
lldb::addr_t AppleObjCRuntimeV1::GetTaggedPointerObfuscator() {
276
0
  return 0;
277
0
}
278
279
0
lldb::addr_t AppleObjCRuntimeV1::GetISAHashTablePointer() {
280
0
  if (m_isa_hash_table_ptr == LLDB_INVALID_ADDRESS) {
281
0
    ModuleSP objc_module_sp(GetObjCModule());
282
283
0
    if (!objc_module_sp)
284
0
      return LLDB_INVALID_ADDRESS;
285
286
0
    static ConstString g_objc_debug_class_hash("_objc_debug_class_hash");
287
288
0
    const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType(
289
0
        g_objc_debug_class_hash, lldb::eSymbolTypeData);
290
0
    if (symbol && symbol->ValueIsAddress()) {
291
0
      Process *process = GetProcess();
292
0
      if (process) {
293
294
0
        lldb::addr_t objc_debug_class_hash_addr =
295
0
            symbol->GetAddressRef().GetLoadAddress(&process->GetTarget());
296
297
0
        if (objc_debug_class_hash_addr != LLDB_INVALID_ADDRESS) {
298
0
          Status error;
299
0
          lldb::addr_t objc_debug_class_hash_ptr =
300
0
              process->ReadPointerFromMemory(objc_debug_class_hash_addr, error);
301
0
          if (objc_debug_class_hash_ptr != 0 &&
302
0
              objc_debug_class_hash_ptr != LLDB_INVALID_ADDRESS) {
303
0
            m_isa_hash_table_ptr = objc_debug_class_hash_ptr;
304
0
          }
305
0
        }
306
0
      }
307
0
    }
308
0
  }
309
0
  return m_isa_hash_table_ptr;
310
0
}
311
312
0
void AppleObjCRuntimeV1::UpdateISAToDescriptorMapIfNeeded() {
313
  // TODO: implement HashTableSignature...
314
0
  Process *process = GetProcess();
315
316
0
  if (process) {
317
    // Update the process stop ID that indicates the last time we updated the
318
    // map, whether it was successful or not.
319
0
    m_isa_to_descriptor_stop_id = process->GetStopID();
320
321
0
    Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
322
323
0
    ProcessSP process_sp = process->shared_from_this();
324
325
0
    ModuleSP objc_module_sp(GetObjCModule());
326
327
0
    if (!objc_module_sp)
328
0
      return;
329
330
0
    lldb::addr_t hash_table_ptr = GetISAHashTablePointer();
331
0
    if (hash_table_ptr != LLDB_INVALID_ADDRESS) {
332
      // Read the NXHashTable struct:
333
      //
334
      // typedef struct {
335
      //     const NXHashTablePrototype *prototype;
336
      //     unsigned   count;
337
      //     unsigned   nbBuckets;
338
      //     void       *buckets;
339
      //     const void *info;
340
      // } NXHashTable;
341
342
0
      Status error;
343
0
      DataBufferHeap buffer(1024, 0);
344
0
      if (process->ReadMemory(hash_table_ptr, buffer.GetBytes(), 20, error) ==
345
0
          20) {
346
0
        const uint32_t addr_size = m_process->GetAddressByteSize();
347
0
        const ByteOrder byte_order = m_process->GetByteOrder();
348
0
        DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(), byte_order,
349
0
                           addr_size);
350
0
        lldb::offset_t offset = addr_size; // Skip prototype
351
0
        const uint32_t count = data.GetU32(&offset);
352
0
        const uint32_t num_buckets = data.GetU32(&offset);
353
0
        const addr_t buckets_ptr = data.GetAddress(&offset);
354
0
        if (m_hash_signature.NeedsUpdate(count, num_buckets, buckets_ptr)) {
355
0
          m_hash_signature.UpdateSignature(count, num_buckets, buckets_ptr);
356
357
0
          const uint32_t data_size = num_buckets * 2 * sizeof(uint32_t);
358
0
          buffer.SetByteSize(data_size);
359
360
0
          if (process->ReadMemory(buckets_ptr, buffer.GetBytes(), data_size,
361
0
                                  error) == data_size) {
362
0
            data.SetData(buffer.GetBytes(), buffer.GetByteSize(), byte_order);
363
0
            offset = 0;
364
0
            for (uint32_t bucket_idx = 0; bucket_idx < num_buckets;
365
0
                 ++bucket_idx) {
366
0
              const uint32_t bucket_isa_count = data.GetU32(&offset);
367
0
              const lldb::addr_t bucket_data = data.GetU32(&offset);
368
369
0
              if (bucket_isa_count == 0)
370
0
                continue;
371
372
0
              ObjCISA isa;
373
0
              if (bucket_isa_count == 1) {
374
                // When we only have one entry in the bucket, the bucket data
375
                // is the "isa"
376
0
                isa = bucket_data;
377
0
                if (isa) {
378
0
                  if (!ISAIsCached(isa)) {
379
0
                    ClassDescriptorSP descriptor_sp(
380
0
                        new ClassDescriptorV1(isa, process_sp));
381
382
0
                    if (log && log->GetVerbose())
383
0
                      LLDB_LOGF(log,
384
0
                                "AppleObjCRuntimeV1 added (ObjCISA)0x%" PRIx64
385
0
                                " from _objc_debug_class_hash to "
386
0
                                "isa->descriptor cache",
387
0
                                isa);
388
389
0
                    AddClass(isa, descriptor_sp);
390
0
                  }
391
0
                }
392
0
              } else {
393
                // When we have more than one entry in the bucket, the bucket
394
                // data is a pointer to an array of "isa" values
395
0
                addr_t isa_addr = bucket_data;
396
0
                for (uint32_t isa_idx = 0; isa_idx < bucket_isa_count;
397
0
                     ++isa_idx, isa_addr += addr_size) {
398
0
                  isa = m_process->ReadPointerFromMemory(isa_addr, error);
399
400
0
                  if (isa && isa != LLDB_INVALID_ADDRESS) {
401
0
                    if (!ISAIsCached(isa)) {
402
0
                      ClassDescriptorSP descriptor_sp(
403
0
                          new ClassDescriptorV1(isa, process_sp));
404
405
0
                      if (log && log->GetVerbose())
406
0
                        LLDB_LOGF(
407
0
                            log,
408
0
                            "AppleObjCRuntimeV1 added (ObjCISA)0x%" PRIx64
409
0
                            " from _objc_debug_class_hash to isa->descriptor "
410
0
                            "cache",
411
0
                            isa);
412
413
0
                      AddClass(isa, descriptor_sp);
414
0
                    }
415
0
                  }
416
0
                }
417
0
              }
418
0
            }
419
0
          }
420
0
        }
421
0
      }
422
0
    }
423
0
  } else {
424
0
    m_isa_to_descriptor_stop_id = UINT32_MAX;
425
0
  }
426
0
}
427
428
0
DeclVendor *AppleObjCRuntimeV1::GetDeclVendor() {
429
0
  return nullptr;
430
0
}