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