Coverage Report

Created: 2022-01-15 10:30

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- AppleObjCTrampolineHandler.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 "AppleObjCTrampolineHandler.h"
10
#include "AppleThreadPlanStepThroughObjCTrampoline.h"
11
12
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
13
#include "lldb/Breakpoint/StoppointCallbackContext.h"
14
#include "lldb/Core/Debugger.h"
15
#include "lldb/Core/Module.h"
16
#include "lldb/Core/StreamFile.h"
17
#include "lldb/Core/Value.h"
18
#include "lldb/Expression/DiagnosticManager.h"
19
#include "lldb/Expression/FunctionCaller.h"
20
#include "lldb/Expression/UserExpression.h"
21
#include "lldb/Expression/UtilityFunction.h"
22
#include "lldb/Symbol/Symbol.h"
23
#include "lldb/Target/ABI.h"
24
#include "lldb/Target/ExecutionContext.h"
25
#include "lldb/Target/Process.h"
26
#include "lldb/Target/RegisterContext.h"
27
#include "lldb/Target/Target.h"
28
#include "lldb/Target/Thread.h"
29
#include "lldb/Target/ThreadPlanRunToAddress.h"
30
#include "lldb/Utility/ConstString.h"
31
#include "lldb/Utility/FileSpec.h"
32
#include "lldb/Utility/Log.h"
33
34
#include "llvm/ADT/STLExtras.h"
35
36
#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
37
38
#include <memory>
39
40
using namespace lldb;
41
using namespace lldb_private;
42
43
const char *AppleObjCTrampolineHandler::g_lookup_implementation_function_name =
44
    "__lldb_objc_find_implementation_for_selector";
45
const char *AppleObjCTrampolineHandler::
46
    g_lookup_implementation_with_stret_function_code =
47
        "                               \n\
48
extern \"C\"                                                                 \n\
49
{                                                                            \n\
50
    extern void *class_getMethodImplementation(void *objc_class, void *sel); \n\
51
    extern void *class_getMethodImplementation_stret(void *objc_class,       \n\
52
                                                     void *sel);             \n\
53
    extern void * object_getClass (id object);                               \n\
54
    extern void * sel_getUid(char *name);                                    \n\
55
    extern int printf(const char *format, ...);                              \n\
56
}                                                                            \n\
57
extern \"C\" void * __lldb_objc_find_implementation_for_selector (           \n\
58
                                                    void *object,            \n\
59
                                                    void *sel,               \n\
60
                                                    int is_stret,            \n\
61
                                                    int is_super,            \n\
62
                                                    int is_super2,           \n\
63
                                                    int is_fixup,            \n\
64
                                                    int is_fixed,            \n\
65
                                                    int debug)               \n\
66
{                                                                            \n\
67
    struct __lldb_imp_return_struct                                          \n\
68
    {                                                                        \n\
69
        void *class_addr;                                                    \n\
70
        void *sel_addr;                                                      \n\
71
        void *impl_addr;                                                     \n\
72
    };                                                                       \n\
73
                                                                             \n\
74
    struct __lldb_objc_class {                                               \n\
75
        void *isa;                                                           \n\
76
        void *super_ptr;                                                     \n\
77
    };                                                                       \n\
78
    struct __lldb_objc_super {                                               \n\
79
        void *receiver;                                                      \n\
80
        struct __lldb_objc_class *class_ptr;                                 \n\
81
    };                                                                       \n\
82
    struct __lldb_msg_ref {                                                  \n\
83
        void *dont_know;                                                     \n\
84
        void *sel;                                                           \n\
85
    };                                                                       \n\
86
                                                                             \n\
87
    struct __lldb_imp_return_struct return_struct;                           \n\
88
                                                                             \n\
89
    if (debug)                                                               \n\
90
        printf (\"\\n*** Called with obj: 0x%p sel: 0x%p is_stret: %d is_super: %d, \"\n\
91
                \"is_super2: %d, is_fixup: %d, is_fixed: %d\\n\",            \n\
92
                 object, sel, is_stret, is_super, is_super2, is_fixup, is_fixed);\n\
93
    if (is_super)                                                            \n\
94
    {                                                                        \n\
95
        if (is_super2)                                                       \n\
96
        {                                                                    \n\
97
            return_struct.class_addr = ((__lldb_objc_super *) object)->class_ptr->super_ptr;\n\
98
        }                                                                    \n\
99
        else                                                                 \n\
100
        {                                                                    \n\
101
            return_struct.class_addr = ((__lldb_objc_super *) object)->class_ptr;\n\
102
        }                                                                    \n\
103
    }                                                                        \n\
104
    else                                                                     \n\
105
    {                                                                        \n\
106
        // This code seems a little funny, but has its reasons...            \n\
107
                                                                             \n\
108
        // The call to [object class] is here because if this is a           \n\
109
        // class, and has not been called into yet, we need to do            \n\
110
        // something to force the class to initialize itself.                \n\
111
        // Then the call to object_getClass will actually return the         \n\
112
        // correct class, either the class if object is a class              \n\
113
        // instance, or the meta-class if it is a class pointer.             \n\
114
        void *class_ptr = (void *) [(id) object class];                      \n\
115
        return_struct.class_addr = (id)  object_getClass((id) object);       \n\
116
        if (debug)                                                           \n\
117
        {                                                                    \n\
118
            if (class_ptr == object)                                         \n\
119
            {                                                                \n\
120
                printf (\"Found a class object, need to use the meta class %p -> %p\\n\",\n\
121
                        class_ptr, return_struct.class_addr);                \n\
122
            }                                                                \n\
123
            else                                                             \n\
124
            {                                                                \n\
125
                 printf (\"[object class] returned: %p object_getClass: %p.\\n\", \n\
126
                 class_ptr, return_struct.class_addr);                       \n\
127
            }                                                                \n\
128
        }                                                                    \n\
129
    }                                                                        \n\
130
                                                                             \n\
131
    if (is_fixup)                                                            \n\
132
    {                                                                        \n\
133
        if (is_fixed)                                                        \n\
134
        {                                                                    \n\
135
            return_struct.sel_addr = ((__lldb_msg_ref *) sel)->sel;          \n\
136
        }                                                                    \n\
137
        else                                                                 \n\
138
        {                                                                    \n\
139
            char *sel_name = (char *) ((__lldb_msg_ref *) sel)->sel;         \n\
140
            return_struct.sel_addr = sel_getUid (sel_name);                  \n\
141
            if (debug)                                                       \n\
142
                printf (\"\\n*** Got fixed up selector: %p for name %s.\\n\",\n\
143
                        return_struct.sel_addr, sel_name);                   \n\
144
        }                                                                    \n\
145
    }                                                                        \n\
146
    else                                                                     \n\
147
    {                                                                        \n\
148
        return_struct.sel_addr = sel;                                        \n\
149
    }                                                                        \n\
150
                                                                             \n\
151
    if (is_stret)                                                            \n\
152
    {                                                                        \n\
153
        return_struct.impl_addr =                                            \n\
154
          class_getMethodImplementation_stret (return_struct.class_addr,     \n\
155
                                               return_struct.sel_addr);      \n\
156
    }                                                                        \n\
157
    else                                                                     \n\
158
    {                                                                        \n\
159
        return_struct.impl_addr =                                            \n\
160
            class_getMethodImplementation (return_struct.class_addr,         \n\
161
                                           return_struct.sel_addr);          \n\
162
    }                                                                        \n\
163
    if (debug)                                                               \n\
164
        printf (\"\\n*** Returning implementation: %p.\\n\",                 \n\
165
                          return_struct.impl_addr);                          \n\
166
                                                                             \n\
167
    return return_struct.impl_addr;                                          \n\
168
}                                                                            \n\
169
";
170
const char *
171
    AppleObjCTrampolineHandler::g_lookup_implementation_no_stret_function_code =
172
        "                      \n\
173
extern \"C\"                                                                 \n\
174
{                                                                            \n\
175
    extern void *class_getMethodImplementation(void *objc_class, void *sel); \n\
176
    extern void * object_getClass (id object);                               \n\
177
    extern void * sel_getUid(char *name);                                    \n\
178
    extern int printf(const char *format, ...);                              \n\
179
}                                                                            \n\
180
extern \"C\" void * __lldb_objc_find_implementation_for_selector (void *object,                                 \n\
181
                                                    void *sel,               \n\
182
                                                    int is_stret,            \n\
183
                                                    int is_super,            \n\
184
                                                    int is_super2,           \n\
185
                                                    int is_fixup,            \n\
186
                                                    int is_fixed,            \n\
187
                                                    int debug)               \n\
188
{                                                                            \n\
189
    struct __lldb_imp_return_struct                                          \n\
190
    {                                                                        \n\
191
        void *class_addr;                                                    \n\
192
        void *sel_addr;                                                      \n\
193
        void *impl_addr;                                                     \n\
194
    };                                                                       \n\
195
                                                                             \n\
196
    struct __lldb_objc_class {                                               \n\
197
        void *isa;                                                           \n\
198
        void *super_ptr;                                                     \n\
199
    };                                                                       \n\
200
    struct __lldb_objc_super {                                               \n\
201
        void *receiver;                                                      \n\
202
        struct __lldb_objc_class *class_ptr;                                 \n\
203
    };                                                                       \n\
204
    struct __lldb_msg_ref {                                                  \n\
205
        void *dont_know;                                                     \n\
206
        void *sel;                                                           \n\
207
    };                                                                       \n\
208
                                                                             \n\
209
    struct __lldb_imp_return_struct return_struct;                           \n\
210
                                                                             \n\
211
    if (debug)                                                               \n\
212
        printf (\"\\n*** Called with obj: 0x%p sel: 0x%p is_stret: %d is_super: %d, \"                          \n\
213
                \"is_super2: %d, is_fixup: %d, is_fixed: %d\\n\",            \n\
214
                 object, sel, is_stret, is_super, is_super2, is_fixup, is_fixed);                               \n\
215
    if (is_super)                                                            \n\
216
    {                                                                        \n\
217
        if (is_super2)                                                       \n\
218
        {                                                                    \n\
219
            return_struct.class_addr = ((__lldb_objc_super *) object)->class_ptr->super_ptr;                    \n\
220
        }                                                                    \n\
221
        else                                                                 \n\
222
        {                                                                    \n\
223
            return_struct.class_addr = ((__lldb_objc_super *) object)->class_ptr;                               \n\
224
        }                                                                    \n\
225
    }                                                                        \n\
226
    else                                                                     \n\
227
    {                                                                        \n\
228
        // This code seems a little funny, but has its reasons...            \n\
229
        // The call to [object class] is here because if this is a class, and has not been called into          \n\
230
        // yet, we need to do something to force the class to initialize itself.                                \n\
231
        // Then the call to object_getClass will actually return the correct class, either the class            \n\
232
        // if object is a class instance, or the meta-class if it is a class pointer.                           \n\
233
        void *class_ptr = (void *) [(id) object class];                      \n\
234
        return_struct.class_addr = (id)  object_getClass((id) object);       \n\
235
        if (debug)                                                           \n\
236
        {                                                                    \n\
237
            if (class_ptr == object)                                         \n\
238
            {                                                                \n\
239
                printf (\"Found a class object, need to return the meta class %p -> %p\\n\",                    \n\
240
                        class_ptr, return_struct.class_addr);                \n\
241
            }                                                                \n\
242
            else                                                             \n\
243
            {                                                                \n\
244
                 printf (\"[object class] returned: %p object_getClass: %p.\\n\",                               \n\
245
                 class_ptr, return_struct.class_addr);                       \n\
246
            }                                                                \n\
247
        }                                                                    \n\
248
    }                                                                        \n\
249
                                                                             \n\
250
    if (is_fixup)                                                            \n\
251
    {                                                                        \n\
252
        if (is_fixed)                                                        \n\
253
        {                                                                    \n\
254
            return_struct.sel_addr = ((__lldb_msg_ref *) sel)->sel;          \n\
255
        }                                                                    \n\
256
        else                                                                 \n\
257
        {                                                                    \n\
258
            char *sel_name = (char *) ((__lldb_msg_ref *) sel)->sel;         \n\
259
            return_struct.sel_addr = sel_getUid (sel_name);                  \n\
260
            if (debug)                                                       \n\
261
                printf (\"\\n*** Got fixed up selector: %p for name %s.\\n\",\n\
262
                        return_struct.sel_addr, sel_name);                   \n\
263
        }                                                                    \n\
264
    }                                                                        \n\
265
    else                                                                     \n\
266
    {                                                                        \n\
267
        return_struct.sel_addr = sel;                                        \n\
268
    }                                                                        \n\
269
                                                                             \n\
270
    return_struct.impl_addr =                                                \n\
271
      class_getMethodImplementation (return_struct.class_addr,               \n\
272
                                     return_struct.sel_addr);                \n\
273
    if (debug)                                                               \n\
274
        printf (\"\\n*** Returning implementation: 0x%p.\\n\",               \n\
275
          return_struct.impl_addr);                                          \n\
276
                                                                             \n\
277
    return return_struct.impl_addr;                                          \n\
278
}                                                                            \n\
279
";
280
281
AppleObjCTrampolineHandler::AppleObjCVTables::VTableRegion::VTableRegion(
282
    AppleObjCVTables *owner, lldb::addr_t header_addr)
283
    : m_valid(true), m_owner(owner), m_header_addr(header_addr),
284
0
      m_code_start_addr(0), m_code_end_addr(0), m_next_region(0) {
285
0
  SetUpRegion();
286
0
}
287
288
2.57k
AppleObjCTrampolineHandler::~AppleObjCTrampolineHandler() = default;
289
290
0
void AppleObjCTrampolineHandler::AppleObjCVTables::VTableRegion::SetUpRegion() {
291
  // The header looks like:
292
  //
293
  //   uint16_t headerSize
294
  //   uint16_t descSize
295
  //   uint32_t descCount
296
  //   void * next
297
  //
298
  // First read in the header:
299
300
0
  char memory_buffer[16];
301
0
  ProcessSP process_sp = m_owner->GetProcessSP();
302
0
  if (!process_sp)
303
0
    return;
304
0
  DataExtractor data(memory_buffer, sizeof(memory_buffer),
305
0
                     process_sp->GetByteOrder(),
306
0
                     process_sp->GetAddressByteSize());
307
0
  size_t actual_size = 8 + process_sp->GetAddressByteSize();
308
0
  Status error;
309
0
  size_t bytes_read =
310
0
      process_sp->ReadMemory(m_header_addr, memory_buffer, actual_size, error);
311
0
  if (bytes_read != actual_size) {
312
0
    m_valid = false;
313
0
    return;
314
0
  }
315
316
0
  lldb::offset_t offset = 0;
317
0
  const uint16_t header_size = data.GetU16(&offset);
318
0
  const uint16_t descriptor_size = data.GetU16(&offset);
319
0
  const size_t num_descriptors = data.GetU32(&offset);
320
321
0
  m_next_region = data.GetAddress(&offset);
322
323
  // If the header size is 0, that means we've come in too early before this
324
  // data is set up.
325
  // Set ourselves as not valid, and continue.
326
0
  if (header_size == 0 || num_descriptors == 0) {
327
0
    m_valid = false;
328
0
    return;
329
0
  }
330
331
  // Now read in all the descriptors:
332
  // The descriptor looks like:
333
  //
334
  // uint32_t offset
335
  // uint32_t flags
336
  //
337
  // Where offset is either 0 - in which case it is unused, or it is
338
  // the offset of the vtable code from the beginning of the
339
  // descriptor record.  Below, we'll convert that into an absolute
340
  // code address, since I don't want to have to compute it over and
341
  // over.
342
343
  // Ingest the whole descriptor array:
344
0
  const lldb::addr_t desc_ptr = m_header_addr + header_size;
345
0
  const size_t desc_array_size = num_descriptors * descriptor_size;
346
0
  DataBufferSP data_sp(new DataBufferHeap(desc_array_size, '\0'));
347
0
  uint8_t *dst = (uint8_t *)data_sp->GetBytes();
348
349
0
  DataExtractor desc_extractor(dst, desc_array_size, process_sp->GetByteOrder(),
350
0
                               process_sp->GetAddressByteSize());
351
0
  bytes_read = process_sp->ReadMemory(desc_ptr, dst, desc_array_size, error);
352
0
  if (bytes_read != desc_array_size) {
353
0
    m_valid = false;
354
0
    return;
355
0
  }
356
357
  // The actual code for the vtables will be laid out consecutively, so I also
358
  // compute the start and end of the whole code block.
359
360
0
  offset = 0;
361
0
  m_code_start_addr = 0;
362
0
  m_code_end_addr = 0;
363
364
0
  for (size_t i = 0; i < num_descriptors; i++) {
365
0
    lldb::addr_t start_offset = offset;
366
0
    uint32_t voffset = desc_extractor.GetU32(&offset);
367
0
    uint32_t flags = desc_extractor.GetU32(&offset);
368
0
    lldb::addr_t code_addr = desc_ptr + start_offset + voffset;
369
0
    m_descriptors.push_back(VTableDescriptor(flags, code_addr));
370
371
0
    if (m_code_start_addr == 0 || code_addr < m_code_start_addr)
372
0
      m_code_start_addr = code_addr;
373
0
    if (code_addr > m_code_end_addr)
374
0
      m_code_end_addr = code_addr;
375
376
0
    offset = start_offset + descriptor_size;
377
0
  }
378
  // Finally, a little bird told me that all the vtable code blocks
379
  // are the same size.  Let's compute the blocks and if they are all
380
  // the same add the size to the code end address:
381
0
  lldb::addr_t code_size = 0;
382
0
  bool all_the_same = true;
383
0
  for (size_t i = 0; i < num_descriptors - 1; i++) {
384
0
    lldb::addr_t this_size =
385
0
        m_descriptors[i + 1].code_start - m_descriptors[i].code_start;
386
0
    if (code_size == 0)
387
0
      code_size = this_size;
388
0
    else {
389
0
      if (this_size != code_size)
390
0
        all_the_same = false;
391
0
      if (this_size > code_size)
392
0
        code_size = this_size;
393
0
    }
394
0
  }
395
0
  if (all_the_same)
396
0
    m_code_end_addr += code_size;
397
0
}
398
399
bool AppleObjCTrampolineHandler::AppleObjCVTables::VTableRegion::
400
0
    AddressInRegion(lldb::addr_t addr, uint32_t &flags) {
401
0
  if (!IsValid())
402
0
    return false;
403
404
0
  if (addr < m_code_start_addr || addr > m_code_end_addr)
405
0
    return false;
406
407
0
  std::vector<VTableDescriptor>::iterator pos, end = m_descriptors.end();
408
0
  for (pos = m_descriptors.begin(); pos != end; pos++) {
409
0
    if (addr <= (*pos).code_start) {
410
0
      flags = (*pos).flags;
411
0
      return true;
412
0
    }
413
0
  }
414
0
  return false;
415
0
}
416
417
void AppleObjCTrampolineHandler::AppleObjCVTables::VTableRegion::Dump(
418
0
    Stream &s) {
419
0
  s.Printf("Header addr: 0x%" PRIx64 " Code start: 0x%" PRIx64
420
0
           " Code End: 0x%" PRIx64 " Next: 0x%" PRIx64 "\n",
421
0
           m_header_addr, m_code_start_addr, m_code_end_addr, m_next_region);
422
0
  size_t num_elements = m_descriptors.size();
423
0
  for (size_t i = 0; i < num_elements; i++) {
424
0
    s.Indent();
425
0
    s.Printf("Code start: 0x%" PRIx64 " Flags: %d\n",
426
0
             m_descriptors[i].code_start, m_descriptors[i].flags);
427
0
  }
428
0
}
429
430
AppleObjCTrampolineHandler::AppleObjCVTables::AppleObjCVTables(
431
    const ProcessSP &process_sp, const ModuleSP &objc_module_sp)
432
    : m_process_wp(), m_trampoline_header(LLDB_INVALID_ADDRESS),
433
      m_trampolines_changed_bp_id(LLDB_INVALID_BREAK_ID),
434
2.57k
      m_objc_module_sp(objc_module_sp) {
435
2.57k
  if (process_sp)
436
2.57k
    m_process_wp = process_sp;
437
2.57k
}
438
439
2.57k
AppleObjCTrampolineHandler::AppleObjCVTables::~AppleObjCVTables() {
440
2.57k
  ProcessSP process_sp = GetProcessSP();
441
2.57k
  if (process_sp) {
442
2.57k
    if (m_trampolines_changed_bp_id != LLDB_INVALID_BREAK_ID)
443
0
      process_sp->GetTarget().RemoveBreakpointByID(m_trampolines_changed_bp_id);
444
2.57k
  }
445
2.57k
}
446
447
2.57k
bool AppleObjCTrampolineHandler::AppleObjCVTables::InitializeVTableSymbols() {
448
2.57k
  if (m_trampoline_header != LLDB_INVALID_ADDRESS)
449
0
    return true;
450
451
2.57k
  ProcessSP process_sp = GetProcessSP();
452
2.57k
  if (process_sp) {
453
2.57k
    Target &target = process_sp->GetTarget();
454
455
2.57k
    if (!m_objc_module_sp) {
456
0
      for (ModuleSP module_sp : target.GetImages().Modules()) {
457
0
        if (ObjCLanguageRuntime::Get(*process_sp)
458
0
                ->IsModuleObjCLibrary(module_sp)) {
459
0
          m_objc_module_sp = module_sp;
460
0
          break;
461
0
        }
462
0
      }
463
0
    }
464
465
2.57k
    if (m_objc_module_sp) {
466
2.57k
      ConstString trampoline_name("gdb_objc_trampolines");
467
2.57k
      const Symbol *trampoline_symbol =
468
2.57k
          m_objc_module_sp->FindFirstSymbolWithNameAndType(trampoline_name,
469
2.57k
                                                           eSymbolTypeData);
470
2.57k
      if (trampoline_symbol != nullptr) {
471
0
        m_trampoline_header = trampoline_symbol->GetLoadAddress(&target);
472
0
        if (m_trampoline_header == LLDB_INVALID_ADDRESS)
473
0
          return false;
474
475
        // Next look up the "changed" symbol and set a breakpoint on that...
476
0
        ConstString changed_name("gdb_objc_trampolines_changed");
477
0
        const Symbol *changed_symbol =
478
0
            m_objc_module_sp->FindFirstSymbolWithNameAndType(changed_name,
479
0
                                                             eSymbolTypeCode);
480
0
        if (changed_symbol != nullptr) {
481
0
          const Address changed_symbol_addr = changed_symbol->GetAddress();
482
0
          if (!changed_symbol_addr.IsValid())
483
0
            return false;
484
485
0
          lldb::addr_t changed_addr =
486
0
              changed_symbol_addr.GetOpcodeLoadAddress(&target);
487
0
          if (changed_addr != LLDB_INVALID_ADDRESS) {
488
0
            BreakpointSP trampolines_changed_bp_sp =
489
0
                target.CreateBreakpoint(changed_addr, true, false);
490
0
            if (trampolines_changed_bp_sp) {
491
0
              m_trampolines_changed_bp_id = trampolines_changed_bp_sp->GetID();
492
0
              trampolines_changed_bp_sp->SetCallback(RefreshTrampolines, this,
493
0
                                                     true);
494
0
              trampolines_changed_bp_sp->SetBreakpointKind(
495
0
                  "objc-trampolines-changed");
496
0
              return true;
497
0
            }
498
0
          }
499
0
        }
500
0
      }
501
2.57k
    }
502
2.57k
  }
503
2.57k
  return false;
504
2.57k
}
505
506
bool AppleObjCTrampolineHandler::AppleObjCVTables::RefreshTrampolines(
507
    void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id,
508
0
    lldb::user_id_t break_loc_id) {
509
0
  AppleObjCVTables *vtable_handler = (AppleObjCVTables *)baton;
510
0
  if (vtable_handler->InitializeVTableSymbols()) {
511
    // The Update function is called with the address of an added region.  So we
512
    // grab that address, and
513
    // feed it into ReadRegions.  Of course, our friend the ABI will get the
514
    // values for us.
515
0
    ExecutionContext exe_ctx(context->exe_ctx_ref);
516
0
    Process *process = exe_ctx.GetProcessPtr();
517
0
    const ABI *abi = process->GetABI().get();
518
519
0
    TypeSystemClang *clang_ast_context =
520
0
        ScratchTypeSystemClang::GetForTarget(process->GetTarget());
521
0
    if (!clang_ast_context)
522
0
      return false;
523
524
0
    ValueList argument_values;
525
0
    Value input_value;
526
0
    CompilerType clang_void_ptr_type =
527
0
        clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
528
529
0
    input_value.SetValueType(Value::ValueType::Scalar);
530
    // input_value.SetContext (Value::eContextTypeClangType,
531
    // clang_void_ptr_type);
532
0
    input_value.SetCompilerType(clang_void_ptr_type);
533
0
    argument_values.PushValue(input_value);
534
535
0
    bool success =
536
0
        abi->GetArgumentValues(exe_ctx.GetThreadRef(), argument_values);
537
0
    if (!success)
538
0
      return false;
539
540
    // Now get a pointer value from the zeroth argument.
541
0
    Status error;
542
0
    DataExtractor data;
543
0
    error = argument_values.GetValueAtIndex(0)->GetValueAsData(&exe_ctx, data,
544
0
                                                               nullptr);
545
0
    lldb::offset_t offset = 0;
546
0
    lldb::addr_t region_addr = data.GetAddress(&offset);
547
548
0
    if (region_addr != 0)
549
0
      vtable_handler->ReadRegions(region_addr);
550
0
  }
551
0
  return false;
552
0
}
553
554
2.57k
bool AppleObjCTrampolineHandler::AppleObjCVTables::ReadRegions() {
555
  // The no argument version reads the  start region from the value of
556
  // the gdb_regions_header, and gets started from there.
557
558
2.57k
  m_regions.clear();
559
2.57k
  if (!InitializeVTableSymbols())
560
2.57k
    return false;
561
0
  Status error;
562
0
  ProcessSP process_sp = GetProcessSP();
563
0
  if (process_sp) {
564
0
    lldb::addr_t region_addr =
565
0
        process_sp->ReadPointerFromMemory(m_trampoline_header, error);
566
0
    if (error.Success())
567
0
      return ReadRegions(region_addr);
568
0
  }
569
0
  return false;
570
0
}
571
572
bool AppleObjCTrampolineHandler::AppleObjCVTables::ReadRegions(
573
0
    lldb::addr_t region_addr) {
574
0
  ProcessSP process_sp = GetProcessSP();
575
0
  if (!process_sp)
576
0
    return false;
577
578
0
  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
579
580
  // We aren't starting at the trampoline symbol.
581
0
  InitializeVTableSymbols();
582
0
  lldb::addr_t next_region = region_addr;
583
584
  // Read in the sizes of the headers.
585
0
  while (next_region != 0) {
586
0
    m_regions.push_back(VTableRegion(this, next_region));
587
0
    if (!m_regions.back().IsValid()) {
588
0
      m_regions.clear();
589
0
      return false;
590
0
    }
591
0
    if (log) {
592
0
      StreamString s;
593
0
      m_regions.back().Dump(s);
594
0
      LLDB_LOGF(log, "Read vtable region: \n%s", s.GetData());
595
0
    }
596
597
0
    next_region = m_regions.back().GetNextRegionAddr();
598
0
  }
599
600
0
  return true;
601
0
}
602
603
bool AppleObjCTrampolineHandler::AppleObjCVTables::IsAddressInVTables(
604
425
    lldb::addr_t addr, uint32_t &flags) {
605
425
  region_collection::iterator pos, end = m_regions.end();
606
425
  for (pos = m_regions.begin(); pos != end; 
pos++0
) {
607
0
    if ((*pos).AddressInRegion(addr, flags))
608
0
      return true;
609
0
  }
610
425
  return false;
611
425
}
612
613
const AppleObjCTrampolineHandler::DispatchFunction
614
    AppleObjCTrampolineHandler::g_dispatch_functions[] = {
615
        // NAME                              STRET  SUPER  SUPER2  FIXUP TYPE
616
        {"objc_msgSend", false, false, false, DispatchFunction::eFixUpNone},
617
        {"objc_msgSend_fixup", false, false, false,
618
         DispatchFunction::eFixUpToFix},
619
        {"objc_msgSend_fixedup", false, false, false,
620
         DispatchFunction::eFixUpFixed},
621
        {"objc_msgSend_stret", true, false, false,
622
         DispatchFunction::eFixUpNone},
623
        {"objc_msgSend_stret_fixup", true, false, false,
624
         DispatchFunction::eFixUpToFix},
625
        {"objc_msgSend_stret_fixedup", true, false, false,
626
         DispatchFunction::eFixUpFixed},
627
        {"objc_msgSend_fpret", false, false, false,
628
         DispatchFunction::eFixUpNone},
629
        {"objc_msgSend_fpret_fixup", false, false, false,
630
         DispatchFunction::eFixUpToFix},
631
        {"objc_msgSend_fpret_fixedup", false, false, false,
632
         DispatchFunction::eFixUpFixed},
633
        {"objc_msgSend_fp2ret", false, false, true,
634
         DispatchFunction::eFixUpNone},
635
        {"objc_msgSend_fp2ret_fixup", false, false, true,
636
         DispatchFunction::eFixUpToFix},
637
        {"objc_msgSend_fp2ret_fixedup", false, false, true,
638
         DispatchFunction::eFixUpFixed},
639
        {"objc_msgSendSuper", false, true, false, DispatchFunction::eFixUpNone},
640
        {"objc_msgSendSuper_stret", true, true, false,
641
         DispatchFunction::eFixUpNone},
642
        {"objc_msgSendSuper2", false, true, true, DispatchFunction::eFixUpNone},
643
        {"objc_msgSendSuper2_fixup", false, true, true,
644
         DispatchFunction::eFixUpToFix},
645
        {"objc_msgSendSuper2_fixedup", false, true, true,
646
         DispatchFunction::eFixUpFixed},
647
        {"objc_msgSendSuper2_stret", true, true, true,
648
         DispatchFunction::eFixUpNone},
649
        {"objc_msgSendSuper2_stret_fixup", true, true, true,
650
         DispatchFunction::eFixUpToFix},
651
        {"objc_msgSendSuper2_stret_fixedup", true, true, true,
652
         DispatchFunction::eFixUpFixed},
653
};
654
655
// This is the table of ObjC "accelerated dispatch" functions.  They are a set
656
// of objc methods that are "seldom overridden" and so the compiler replaces the
657
// objc_msgSend with a call to one of the dispatch functions.  That will check
658
// whether the method has been overridden, and directly call the Foundation 
659
// implementation if not.  
660
// This table is supposed to be complete.  If ones get added in the future, we
661
// will have to add them to the table.
662
const char *AppleObjCTrampolineHandler::g_opt_dispatch_names[] = {
663
    "objc_alloc",
664
    "objc_autorelease",
665
    "objc_release",
666
    "objc_retain",
667
    "objc_alloc_init",
668
    "objc_allocWithZone",
669
    "objc_opt_class",
670
    "objc_opt_isKindOfClass",
671
    "objc_opt_new",
672
    "objc_opt_respondsToSelector",
673
    "objc_opt_self",
674
};
675
676
AppleObjCTrampolineHandler::AppleObjCTrampolineHandler(
677
    const ProcessSP &process_sp, const ModuleSP &objc_module_sp)
678
    : m_process_wp(), m_objc_module_sp(objc_module_sp),
679
      m_lookup_implementation_function_code(nullptr),
680
      m_impl_fn_addr(LLDB_INVALID_ADDRESS),
681
      m_impl_stret_fn_addr(LLDB_INVALID_ADDRESS),
682
2.57k
      m_msg_forward_addr(LLDB_INVALID_ADDRESS) {
683
2.57k
  if (process_sp)
684
2.57k
    m_process_wp = process_sp;
685
  // Look up the known resolution functions:
686
687
2.57k
  ConstString get_impl_name("class_getMethodImplementation");
688
2.57k
  ConstString get_impl_stret_name("class_getMethodImplementation_stret");
689
2.57k
  ConstString msg_forward_name("_objc_msgForward");
690
2.57k
  ConstString msg_forward_stret_name("_objc_msgForward_stret");
691
692
2.57k
  Target *target = process_sp ? &process_sp->GetTarget() : 
nullptr0
;
693
2.57k
  const Symbol *class_getMethodImplementation =
694
2.57k
      m_objc_module_sp->FindFirstSymbolWithNameAndType(get_impl_name,
695
2.57k
                                                       eSymbolTypeCode);
696
2.57k
  const Symbol *class_getMethodImplementation_stret =
697
2.57k
      m_objc_module_sp->FindFirstSymbolWithNameAndType(get_impl_stret_name,
698
2.57k
                                                       eSymbolTypeCode);
699
2.57k
  const Symbol *msg_forward = m_objc_module_sp->FindFirstSymbolWithNameAndType(
700
2.57k
      msg_forward_name, eSymbolTypeCode);
701
2.57k
  const Symbol *msg_forward_stret =
702
2.57k
      m_objc_module_sp->FindFirstSymbolWithNameAndType(msg_forward_stret_name,
703
2.57k
                                                       eSymbolTypeCode);
704
705
2.57k
  if (class_getMethodImplementation)
706
2.57k
    m_impl_fn_addr =
707
2.57k
        class_getMethodImplementation->GetAddress().GetOpcodeLoadAddress(
708
2.57k
            target);
709
2.57k
  if (class_getMethodImplementation_stret)
710
2.57k
    m_impl_stret_fn_addr =
711
2.57k
        class_getMethodImplementation_stret->GetAddress().GetOpcodeLoadAddress(
712
2.57k
            target);
713
2.57k
  if (msg_forward)
714
2.57k
    m_msg_forward_addr = msg_forward->GetAddress().GetOpcodeLoadAddress(target);
715
2.57k
  if (msg_forward_stret)
716
2.57k
    m_msg_forward_stret_addr =
717
2.57k
        msg_forward_stret->GetAddress().GetOpcodeLoadAddress(target);
718
719
  // FIXME: Do some kind of logging here.
720
2.57k
  if (m_impl_fn_addr == LLDB_INVALID_ADDRESS) {
721
    // If we can't even find the ordinary get method implementation function,
722
    // then we aren't going to be able to
723
    // step through any method dispatches.  Warn to that effect and get out of
724
    // here.
725
0
    if (process_sp->CanJIT()) {
726
0
      process_sp->GetTarget().GetDebugger().GetErrorStream().Printf(
727
0
          "Could not find implementation lookup function \"%s\""
728
0
          " step in through ObjC method dispatch will not work.\n",
729
0
          get_impl_name.AsCString());
730
0
    }
731
0
    return;
732
2.57k
  } else if (m_impl_stret_fn_addr == LLDB_INVALID_ADDRESS) {
733
    // It there is no stret return lookup function, assume that it is the same
734
    // as the straight lookup:
735
0
    m_impl_stret_fn_addr = m_impl_fn_addr;
736
    // Also we will use the version of the lookup code that doesn't rely on the
737
    // stret version of the function.
738
0
    m_lookup_implementation_function_code =
739
0
        g_lookup_implementation_no_stret_function_code;
740
2.57k
  } else {
741
2.57k
    m_lookup_implementation_function_code =
742
2.57k
        g_lookup_implementation_with_stret_function_code;
743
2.57k
  }
744
745
  // Look up the addresses for the objc dispatch functions and cache
746
  // them.  For now I'm inspecting the symbol names dynamically to
747
  // figure out how to dispatch to them.  If it becomes more
748
  // complicated than this we can turn the g_dispatch_functions char *
749
  // array into a template table, and populate the DispatchFunction
750
  // map from there.
751
752
54.1k
  
for (size_t i = 0; 2.57k
i != llvm::array_lengthof(g_dispatch_functions);
i++51.5k
) {
753
51.5k
    ConstString name_const_str(g_dispatch_functions[i].name);
754
51.5k
    const Symbol *msgSend_symbol =
755
51.5k
        m_objc_module_sp->FindFirstSymbolWithNameAndType(name_const_str,
756
51.5k
                                                         eSymbolTypeCode);
757
51.5k
    if (msgSend_symbol && msgSend_symbol->ValueIsAddress()) {
758
      // FIXME: Make g_dispatch_functions static table of
759
      // DispatchFunctions, and have the map be address->index.
760
      // Problem is we also need to lookup the dispatch function.  For
761
      // now we could have a side table of stret & non-stret dispatch
762
      // functions.  If that's as complex as it gets, we're fine.
763
764
51.5k
      lldb::addr_t sym_addr =
765
51.5k
          msgSend_symbol->GetAddressRef().GetOpcodeLoadAddress(target);
766
767
51.5k
      m_msgSend_map.insert(std::pair<lldb::addr_t, int>(sym_addr, i));
768
51.5k
    }
769
51.5k
  }
770
  
771
  // Similarly, cache the addresses of the "optimized dispatch" function.
772
30.9k
  for (size_t i = 0; i != llvm::array_lengthof(g_opt_dispatch_names); 
i++28.3k
) {
773
28.3k
    ConstString name_const_str(g_opt_dispatch_names[i]);
774
28.3k
    const Symbol *msgSend_symbol =
775
28.3k
        m_objc_module_sp->FindFirstSymbolWithNameAndType(name_const_str,
776
28.3k
                                                         eSymbolTypeCode);
777
28.3k
    if (msgSend_symbol && msgSend_symbol->ValueIsAddress()) {
778
28.3k
      lldb::addr_t sym_addr =
779
28.3k
          msgSend_symbol->GetAddressRef().GetOpcodeLoadAddress(target);
780
781
28.3k
      m_opt_dispatch_map.emplace(sym_addr, i);
782
28.3k
    }
783
28.3k
  }
784
785
  // Build our vtable dispatch handler here:
786
2.57k
  m_vtables_up =
787
2.57k
      std::make_unique<AppleObjCVTables>(process_sp, m_objc_module_sp);
788
2.57k
  if (m_vtables_up)
789
2.57k
    m_vtables_up->ReadRegions();
790
2.57k
}
791
792
lldb::addr_t
793
AppleObjCTrampolineHandler::SetupDispatchFunction(Thread &thread,
794
34
                                                  ValueList &dispatch_values) {
795
34
  ThreadSP thread_sp(thread.shared_from_this());
796
34
  ExecutionContext exe_ctx(thread_sp);
797
34
  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
798
799
34
  lldb::addr_t args_addr = LLDB_INVALID_ADDRESS;
800
34
  FunctionCaller *impl_function_caller = nullptr;
801
802
  // Scope for mutex locker:
803
34
  {
804
34
    std::lock_guard<std::mutex> guard(m_impl_function_mutex);
805
806
    // First stage is to make the ClangUtility to hold our injected function:
807
808
34
    if (!m_impl_code) {
809
7
      if (m_lookup_implementation_function_code != nullptr) {
810
7
        auto utility_fn_or_error = exe_ctx.GetTargetRef().CreateUtilityFunction(
811
7
            m_lookup_implementation_function_code,
812
7
            g_lookup_implementation_function_name, eLanguageTypeC, exe_ctx);
813
7
        if (!utility_fn_or_error) {
814
0
          LLDB_LOG_ERROR(
815
0
              log, utility_fn_or_error.takeError(),
816
0
              "Failed to get Utility Function for implementation lookup: {0}.");
817
0
          return args_addr;
818
0
        }
819
7
        m_impl_code = std::move(*utility_fn_or_error);
820
7
      } else {
821
0
        LLDB_LOGF(log, "No method lookup implementation code.");
822
0
        return LLDB_INVALID_ADDRESS;
823
0
      }
824
825
      // Next make the runner function for our implementation utility function.
826
7
      TypeSystemClang *clang_ast_context = ScratchTypeSystemClang::GetForTarget(
827
7
          thread.GetProcess()->GetTarget());
828
7
      if (!clang_ast_context)
829
0
        return LLDB_INVALID_ADDRESS;
830
831
7
      CompilerType clang_void_ptr_type =
832
7
          clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
833
7
      Status error;
834
835
7
      impl_function_caller = m_impl_code->MakeFunctionCaller(
836
7
          clang_void_ptr_type, dispatch_values, thread_sp, error);
837
7
      if (error.Fail()) {
838
0
        LLDB_LOGF(log,
839
0
                  "Error getting function caller for dispatch lookup: \"%s\".",
840
0
                  error.AsCString());
841
0
        return args_addr;
842
0
      }
843
27
    } else {
844
27
      impl_function_caller = m_impl_code->GetFunctionCaller();
845
27
    }
846
34
  }
847
848
  // Now write down the argument values for this particular call.
849
  // This looks like it might be a race condition if other threads
850
  // were calling into here, but actually it isn't because we allocate
851
  // a new args structure for this call by passing args_addr =
852
  // LLDB_INVALID_ADDRESS...
853
854
34
  DiagnosticManager diagnostics;
855
34
  if (!impl_function_caller->WriteFunctionArguments(
856
34
          exe_ctx, args_addr, dispatch_values, diagnostics)) {
857
0
    if (log) {
858
0
      LLDB_LOGF(log, "Error writing function arguments.");
859
0
      diagnostics.Dump(log);
860
0
    }
861
0
    return args_addr;
862
0
  }
863
864
34
  return args_addr;
865
34
}
866
867
const AppleObjCTrampolineHandler::DispatchFunction *
868
471
AppleObjCTrampolineHandler::FindDispatchFunction(lldb::addr_t addr) {
869
471
  MsgsendMap::iterator pos;
870
471
  pos = m_msgSend_map.find(addr);
871
471
  if (pos != m_msgSend_map.end()) {
872
46
    return &g_dispatch_functions[(*pos).second];
873
46
  }
874
425
  return nullptr;
875
471
}
876
877
void
878
AppleObjCTrampolineHandler::ForEachDispatchFunction(
879
    std::function<void(lldb::addr_t, 
880
10
                       const DispatchFunction &)> callback) {
881
200
  for (auto elem : m_msgSend_map) {
882
200
    callback(elem.first, g_dispatch_functions[elem.second]);
883
200
  }
884
10
}
885
886
ThreadPlanSP
887
AppleObjCTrampolineHandler::GetStepThroughDispatchPlan(Thread &thread,
888
471
                                                       bool stop_others) {
889
471
  ThreadPlanSP ret_plan_sp;
890
471
  lldb::addr_t curr_pc = thread.GetRegisterContext()->GetPC();
891
892
471
  DispatchFunction vtable_dispatch = {"vtable", false, false, false,
893
471
                                      DispatchFunction::eFixUpFixed};
894
895
  // First step is to look and see if we are in one of the known ObjC
896
  // dispatch functions.  We've already compiled a table of same, so
897
  // consult it.
898
899
471
  const DispatchFunction *this_dispatch = FindDispatchFunction(curr_pc);
900
  
901
  // Next check to see if we are in a vtable region:
902
903
471
  if (!this_dispatch && 
m_vtables_up425
) {
904
425
    uint32_t flags;
905
425
    if (m_vtables_up->IsAddressInVTables(curr_pc, flags)) {
906
0
      vtable_dispatch.stret_return =
907
0
          (flags & AppleObjCVTables::eOBJC_TRAMPOLINE_STRET) ==
908
0
          AppleObjCVTables::eOBJC_TRAMPOLINE_STRET;
909
0
      this_dispatch = &vtable_dispatch;
910
0
    }
911
425
  }
912
913
471
  if (this_dispatch) {
914
46
    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
915
916
    // We are decoding a method dispatch.  First job is to pull the
917
    // arguments out:
918
919
46
    lldb::StackFrameSP thread_cur_frame = thread.GetStackFrameAtIndex(0);
920
921
46
    const ABI *abi = nullptr;
922
46
    ProcessSP process_sp(thread.CalculateProcess());
923
46
    if (process_sp)
924
46
      abi = process_sp->GetABI().get();
925
46
    if (abi == nullptr)
926
0
      return ret_plan_sp;
927
928
46
    TargetSP target_sp(thread.CalculateTarget());
929
930
46
    TypeSystemClang *clang_ast_context =
931
46
        ScratchTypeSystemClang::GetForTarget(*target_sp);
932
46
    if (!clang_ast_context)
933
0
      return ret_plan_sp;
934
935
46
    ValueList argument_values;
936
46
    Value void_ptr_value;
937
46
    CompilerType clang_void_ptr_type =
938
46
        clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
939
46
    void_ptr_value.SetValueType(Value::ValueType::Scalar);
940
    // void_ptr_value.SetContext (Value::eContextTypeClangType,
941
    // clang_void_ptr_type);
942
46
    void_ptr_value.SetCompilerType(clang_void_ptr_type);
943
944
46
    int obj_index;
945
46
    int sel_index;
946
947
    // If this is a struct return dispatch, then the first argument is
948
    // the return struct pointer, and the object is the second, and
949
    // the selector is the third.  Otherwise the object is the first
950
    // and the selector the second.
951
46
    if (this_dispatch->stret_return) {
952
0
      obj_index = 1;
953
0
      sel_index = 2;
954
0
      argument_values.PushValue(void_ptr_value);
955
0
      argument_values.PushValue(void_ptr_value);
956
0
      argument_values.PushValue(void_ptr_value);
957
46
    } else {
958
46
      obj_index = 0;
959
46
      sel_index = 1;
960
46
      argument_values.PushValue(void_ptr_value);
961
46
      argument_values.PushValue(void_ptr_value);
962
46
    }
963
964
46
    bool success = abi->GetArgumentValues(thread, argument_values);
965
46
    if (!success)
966
0
      return ret_plan_sp;
967
968
46
    lldb::addr_t obj_addr =
969
46
        argument_values.GetValueAtIndex(obj_index)->GetScalar().ULongLong();
970
46
    if (obj_addr == 0x0) {
971
3
      LLDB_LOGF(
972
3
          log,
973
3
          "Asked to step to dispatch to nil object, returning empty plan.");
974
3
      return ret_plan_sp;
975
3
    }
976
977
43
    ExecutionContext exe_ctx(thread.shared_from_this());
978
43
    Process *process = exe_ctx.GetProcessPtr();
979
    // isa_addr will store the class pointer that the method is being
980
    // dispatched to - so either the class directly or the super class
981
    // if this is one of the objc_msgSendSuper flavors.  That's mostly
982
    // used to look up the class/selector pair in our cache.
983
984
43
    lldb::addr_t isa_addr = LLDB_INVALID_ADDRESS;
985
43
    lldb::addr_t sel_addr =
986
43
        argument_values.GetValueAtIndex(sel_index)->GetScalar().ULongLong();
987
988
    // Figure out the class this is being dispatched to and see if
989
    // we've already cached this method call, If so we can push a
990
    // run-to-address plan directly.  Otherwise we have to figure out
991
    // where the implementation lives.
992
993
43
    if (this_dispatch->is_super) {
994
12
      if (this_dispatch->is_super2) {
995
        // In the objc_msgSendSuper2 case, we don't get the object
996
        // directly, we get a structure containing the object and the
997
        // class to which the super message is being sent.  So we need
998
        // to dig the super out of the class and use that.
999
1000
12
        Value super_value(*(argument_values.GetValueAtIndex(obj_index)));
1001
12
        super_value.GetScalar() += process->GetAddressByteSize();
1002
12
        super_value.ResolveValue(&exe_ctx);
1003
1004
12
        if (super_value.GetScalar().IsValid()) {
1005
1006
          // isa_value now holds the class pointer.  The second word of the
1007
          // class pointer is the super-class pointer:
1008
12
          super_value.GetScalar() += process->GetAddressByteSize();
1009
12
          super_value.ResolveValue(&exe_ctx);
1010
12
          if (super_value.GetScalar().IsValid())
1011
12
            isa_addr = super_value.GetScalar().ULongLong();
1012
0
          else {
1013
0
            LLDB_LOGF(log, "Failed to extract the super class value from the "
1014
0
                           "class in objc_super.");
1015
0
          }
1016
12
        } else {
1017
0
          LLDB_LOGF(log, "Failed to extract the class value from objc_super.");
1018
0
        }
1019
12
      } else {
1020
        // In the objc_msgSendSuper case, we don't get the object
1021
        // directly, we get a two element structure containing the
1022
        // object and the super class to which the super message is
1023
        // being sent.  So the class we want is the second element of
1024
        // this structure.
1025
1026
0
        Value super_value(*(argument_values.GetValueAtIndex(obj_index)));
1027
0
        super_value.GetScalar() += process->GetAddressByteSize();
1028
0
        super_value.ResolveValue(&exe_ctx);
1029
1030
0
        if (super_value.GetScalar().IsValid()) {
1031
0
          isa_addr = super_value.GetScalar().ULongLong();
1032
0
        } else {
1033
0
          LLDB_LOGF(log, "Failed to extract the class value from objc_super.");
1034
0
        }
1035
0
      }
1036
31
    } else {
1037
      // In the direct dispatch case, the object->isa is the class pointer we
1038
      // want.
1039
1040
      // This is a little cheesy, but since object->isa is the first field,
1041
      // making the object value a load address value and resolving it will get
1042
      // the pointer sized data pointed to by that value...
1043
1044
      // Note, it isn't a fatal error not to be able to get the
1045
      // address from the object, since this might be a "tagged
1046
      // pointer" which isn't a real object, but rather some word
1047
      // length encoded dingus.
1048
1049
31
      Value isa_value(*(argument_values.GetValueAtIndex(obj_index)));
1050
1051
31
      isa_value.SetValueType(Value::ValueType::LoadAddress);
1052
31
      isa_value.ResolveValue(&exe_ctx);
1053
31
      if (isa_value.GetScalar().IsValid()) {
1054
31
        isa_addr = isa_value.GetScalar().ULongLong();
1055
31
      } else {
1056
0
        LLDB_LOGF(log, "Failed to extract the isa value from object.");
1057
0
      }
1058
31
    }
1059
1060
    // Okay, we've got the address of the class for which we're resolving this,
1061
    // let's see if it's in our cache:
1062
43
    lldb::addr_t impl_addr = LLDB_INVALID_ADDRESS;
1063
1064
43
    if (isa_addr != LLDB_INVALID_ADDRESS) {
1065
43
      if (log) {
1066
0
        LLDB_LOGF(log,
1067
0
                  "Resolving call for class - 0x%" PRIx64
1068
0
                  " and selector - 0x%" PRIx64,
1069
0
                  isa_addr, sel_addr);
1070
0
      }
1071
43
      ObjCLanguageRuntime *objc_runtime =
1072
43
          ObjCLanguageRuntime::Get(*thread.GetProcess());
1073
43
      assert(objc_runtime != nullptr);
1074
1075
0
      impl_addr = objc_runtime->LookupInMethodCache(isa_addr, sel_addr);
1076
43
    }
1077
1078
43
    if (impl_addr != LLDB_INVALID_ADDRESS) {
1079
      // Yup, it was in the cache, so we can run to that address directly.
1080
1081
9
      LLDB_LOGF(log, "Found implementation address in cache: 0x%" PRIx64,
1082
9
                impl_addr);
1083
1084
9
      ret_plan_sp = std::make_shared<ThreadPlanRunToAddress>(thread, impl_addr,
1085
9
                                                             stop_others);
1086
34
    } else {
1087
      // We haven't seen this class/selector pair yet.  Look it up.
1088
34
      StreamString errors;
1089
34
      Address impl_code_address;
1090
1091
34
      ValueList dispatch_values;
1092
1093
      // We've will inject a little function in the target that takes the
1094
      // object, selector and some flags,
1095
      // and figures out the implementation.  Looks like:
1096
      //      void *__lldb_objc_find_implementation_for_selector (void *object,
1097
      //                                                          void *sel,
1098
      //                                                          int is_stret,
1099
      //                                                          int is_super,
1100
      //                                                          int is_super2,
1101
      //                                                          int is_fixup,
1102
      //                                                          int is_fixed,
1103
      //                                                          int debug)
1104
      // So set up the arguments for that call.
1105
1106
34
      dispatch_values.PushValue(*(argument_values.GetValueAtIndex(obj_index)));
1107
34
      dispatch_values.PushValue(*(argument_values.GetValueAtIndex(sel_index)));
1108
1109
34
      Value flag_value;
1110
34
      CompilerType clang_int_type =
1111
34
          clang_ast_context->GetBuiltinTypeForEncodingAndBitSize(
1112
34
              lldb::eEncodingSint, 32);
1113
34
      flag_value.SetValueType(Value::ValueType::Scalar);
1114
      // flag_value.SetContext (Value::eContextTypeClangType, clang_int_type);
1115
34
      flag_value.SetCompilerType(clang_int_type);
1116
1117
34
      if (this_dispatch->stret_return)
1118
0
        flag_value.GetScalar() = 1;
1119
34
      else
1120
34
        flag_value.GetScalar() = 0;
1121
34
      dispatch_values.PushValue(flag_value);
1122
1123
34
      if (this_dispatch->is_super)
1124
6
        flag_value.GetScalar() = 1;
1125
28
      else
1126
28
        flag_value.GetScalar() = 0;
1127
34
      dispatch_values.PushValue(flag_value);
1128
1129
34
      if (this_dispatch->is_super2)
1130
6
        flag_value.GetScalar() = 1;
1131
28
      else
1132
28
        flag_value.GetScalar() = 0;
1133
34
      dispatch_values.PushValue(flag_value);
1134
1135
34
      switch (this_dispatch->fixedup) {
1136
34
      case DispatchFunction::eFixUpNone:
1137
34
        flag_value.GetScalar() = 0;
1138
34
        dispatch_values.PushValue(flag_value);
1139
34
        dispatch_values.PushValue(flag_value);
1140
34
        break;
1141
0
      case DispatchFunction::eFixUpFixed:
1142
0
        flag_value.GetScalar() = 1;
1143
0
        dispatch_values.PushValue(flag_value);
1144
0
        flag_value.GetScalar() = 1;
1145
0
        dispatch_values.PushValue(flag_value);
1146
0
        break;
1147
0
      case DispatchFunction::eFixUpToFix:
1148
0
        flag_value.GetScalar() = 1;
1149
0
        dispatch_values.PushValue(flag_value);
1150
0
        flag_value.GetScalar() = 0;
1151
0
        dispatch_values.PushValue(flag_value);
1152
0
        break;
1153
34
      }
1154
34
      if (log && 
log->GetVerbose()0
)
1155
0
        flag_value.GetScalar() = 1;
1156
34
      else
1157
34
        flag_value.GetScalar() = 0; // FIXME - Set to 0 when debugging is done.
1158
34
      dispatch_values.PushValue(flag_value);
1159
1160
34
      ret_plan_sp = std::make_shared<AppleThreadPlanStepThroughObjCTrampoline>(
1161
34
          thread, *this, dispatch_values, isa_addr, sel_addr);
1162
34
      if (log) {
1163
0
        StreamString s;
1164
0
        ret_plan_sp->GetDescription(&s, eDescriptionLevelFull);
1165
0
        LLDB_LOGF(log, "Using ObjC step plan: %s.\n", s.GetData());
1166
0
      }
1167
34
    }
1168
43
  }
1169
  
1170
  // Finally, check if we have hit an "optimized dispatch" function.  This will
1171
  // either directly call the base implementation or dispatch an objc_msgSend
1172
  // if the method has been overridden.  So we just do a "step in/step out",
1173
  // setting a breakpoint on objc_msgSend, and if we hit the msgSend, we 
1174
  // will automatically step in again.  That's the job of the 
1175
  // AppleThreadPlanStepThroughDirectDispatch.
1176
468
  if (!this_dispatch && 
!ret_plan_sp425
) {
1177
425
    MsgsendMap::iterator pos;
1178
425
    pos = m_opt_dispatch_map.find(curr_pc);
1179
425
    if (pos != m_opt_dispatch_map.end()) {
1180
10
      const char *opt_name = g_opt_dispatch_names[(*pos).second];
1181
10
      ret_plan_sp = std::make_shared<AppleThreadPlanStepThroughDirectDispatch>(
1182
10
          thread, *this, opt_name);
1183
10
    }
1184
425
  }
1185
1186
468
  return ret_plan_sp;
1187
471
}
1188
1189
FunctionCaller *
1190
34
AppleObjCTrampolineHandler::GetLookupImplementationFunctionCaller() {
1191
34
  return m_impl_code->GetFunctionCaller();
1192
34
}