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