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