LLDB mainline
AppleObjCRuntimeV1.cpp
Go to the documentation of this file.
1//===-- AppleObjCRuntimeV1.cpp --------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10#include "AppleObjCDeclVendor.h"
12
13#include "clang/AST/Type.h"
14
17#include "lldb/Core/Module.h"
21#include "lldb/Symbol/Symbol.h"
23#include "lldb/Target/Process.h"
25#include "lldb/Target/Target.h"
26#include "lldb/Target/Thread.h"
29#include "lldb/Utility/Log.h"
30#include "lldb/Utility/Scalar.h"
31#include "lldb/Utility/Status.h"
33
34#include <memory>
35#include <vector>
36
37using namespace lldb;
38using namespace lldb_private;
39
41
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
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::Scalar;
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
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) ==
78 return new AppleObjCRuntimeV1(process);
79 else
80 return nullptr;
81 } else
82 return nullptr;
83}
84
87 GetPluginNameStatic(), "Apple Objective-C Language Runtime - Version 1",
89 /*command_callback = */ nullptr, GetBreakpointExceptionPrecondition);
90}
91
94}
95
98 bool catch_bp, bool throw_bp) {
99 BreakpointResolverSP resolver_sp;
100
101 if (throw_bp)
102 resolver_sp = std::make_shared<BreakpointResolverName>(
103 bkpt, std::get<1>(GetExceptionThrowLocation()).AsCString(),
104 eFunctionNameTypeBase, eLanguageTypeUnknown, Breakpoint::Exact, 0,
106 // FIXME: don't do catch yet.
107 return resolver_sp;
108}
109
110struct BufStruct {
111 char contents[2048];
112};
113
114llvm::Expected<std::unique_ptr<UtilityFunction>>
116 ExecutionContext &exe_ctx) {
117 std::unique_ptr<BufStruct> buf(new BufStruct);
118
119 int strformatsize =
120 snprintf(&buf->contents[0], sizeof(buf->contents),
121 "struct __objc_class "
122 " \n"
123 "{ "
124 " \n"
125 " struct __objc_class *isa; "
126 " \n"
127 " struct __objc_class *super_class; "
128 " \n"
129 " const char *name; "
130 " \n"
131 " // rest of struct elided because unused "
132 " \n"
133 "}; "
134 " \n"
135 " "
136 " \n"
137 "struct __objc_object "
138 " \n"
139 "{ "
140 " \n"
141 " struct __objc_class *isa; "
142 " \n"
143 "}; "
144 " \n"
145 " "
146 " \n"
147 "extern \"C\" void "
148 " \n"
149 "%s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) "
150 " \n"
151 "{ "
152 " \n"
153 " struct __objc_object *obj = (struct "
154 "__objc_object*)$__lldb_arg_obj; \n"
155 " if ($__lldb_arg_obj == (void *)0) "
156 " \n"
157 " return; // nil is ok "
158 " (int)strlen(obj->isa->name); "
159 " \n"
160 "} "
161 " \n",
162 name.c_str());
163 assert(strformatsize < (int)sizeof(buf->contents));
164 UNUSED_IF_ASSERT_DISABLED(strformatsize);
165
166 return GetTargetRef().CreateUtilityFunction(buf->contents, std::move(name),
167 eLanguageTypeC, exe_ctx);
168}
169
171 ValueObject &isa_pointer) {
172 Initialize(isa_pointer.GetValueAsUnsigned(0), isa_pointer.GetProcessSP());
173}
174
176 ObjCISA isa, lldb::ProcessSP process_sp) {
177 Initialize(isa, process_sp);
178}
179
181 ObjCISA isa, lldb::ProcessSP process_sp) {
182 if (!isa || !process_sp) {
183 m_valid = false;
184 return;
185 }
186
187 m_valid = true;
188
190
191 m_isa = process_sp->ReadPointerFromMemory(isa, error);
192
193 if (error.Fail()) {
194 m_valid = false;
195 return;
196 }
197
198 uint32_t ptr_size = process_sp->GetAddressByteSize();
199
200 if (!IsPointerValid(m_isa, ptr_size)) {
201 m_valid = false;
202 return;
203 }
204
205 m_parent_isa = process_sp->ReadPointerFromMemory(m_isa + ptr_size, error);
206
207 if (error.Fail()) {
208 m_valid = false;
209 return;
210 }
211
212 if (!IsPointerValid(m_parent_isa, ptr_size, true)) {
213 m_valid = false;
214 return;
215 }
216
217 lldb::addr_t name_ptr =
218 process_sp->ReadPointerFromMemory(m_isa + 2 * ptr_size, error);
219
220 if (error.Fail()) {
221 m_valid = false;
222 return;
223 }
224
225 lldb::WritableDataBufferSP buffer_sp(new DataBufferHeap(1024, 0));
226
227 size_t count = process_sp->ReadCStringFromMemory(
228 name_ptr, (char *)buffer_sp->GetBytes(), 1024, error);
229
230 if (error.Fail()) {
231 m_valid = false;
232 return;
233 }
234
235 if (count)
236 m_name = ConstString(reinterpret_cast<const char *>(buffer_sp->GetBytes()));
237 else
238 m_name = ConstString();
239
240 m_instance_size = process_sp->ReadUnsignedIntegerFromMemory(
241 m_isa + 5 * ptr_size, ptr_size, 0, error);
242
243 if (error.Fail()) {
244 m_valid = false;
245 return;
246 }
247
248 m_process_wp = lldb::ProcessWP(process_sp);
249}
250
253 if (!m_valid)
255 ProcessSP process_sp = m_process_wp.lock();
256 if (!process_sp)
259 new AppleObjCRuntimeV1::ClassDescriptorV1(m_parent_isa, process_sp));
260}
261
264 return ClassDescriptorSP();
265}
266
268 std::function<void(ObjCLanguageRuntime::ObjCISA)> const &superclass_func,
269 std::function<bool(const char *, const char *)> const &instance_method_func,
270 std::function<bool(const char *, const char *)> const &class_method_func,
271 std::function<bool(const char *, const char *, lldb::addr_t,
272 uint64_t)> const &ivar_func) const {
273 return false;
274}
275
277 return 0;
278}
279
282 ModuleSP objc_module_sp(GetObjCModule());
283
284 if (!objc_module_sp)
286
287 static ConstString g_objc_debug_class_hash("_objc_debug_class_hash");
288
289 const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType(
290 g_objc_debug_class_hash, lldb::eSymbolTypeData);
291 if (symbol && symbol->ValueIsAddress()) {
292 Process *process = GetProcess();
293 if (process) {
294
295 lldb::addr_t objc_debug_class_hash_addr =
296 symbol->GetAddressRef().GetLoadAddress(&process->GetTarget());
297
298 if (objc_debug_class_hash_addr != LLDB_INVALID_ADDRESS) {
300 lldb::addr_t objc_debug_class_hash_ptr =
301 process->ReadPointerFromMemory(objc_debug_class_hash_addr, error);
302 if (objc_debug_class_hash_ptr != 0 &&
303 objc_debug_class_hash_ptr != LLDB_INVALID_ADDRESS) {
304 m_isa_hash_table_ptr = objc_debug_class_hash_ptr;
305 }
306 }
307 }
308 }
309 }
311}
312
314 // TODO: implement HashTableSignature...
315 Process *process = GetProcess();
316
317 if (process) {
318 // Update the process stop ID that indicates the last time we updated the
319 // map, whether it was successful or not.
321
323
324 ProcessSP process_sp = process->shared_from_this();
325
326 ModuleSP objc_module_sp(GetObjCModule());
327
328 if (!objc_module_sp)
329 return;
330
331 lldb::addr_t hash_table_ptr = GetISAHashTablePointer();
332 if (hash_table_ptr != LLDB_INVALID_ADDRESS) {
333 // Read the NXHashTable struct:
334 //
335 // typedef struct {
336 // const NXHashTablePrototype *prototype;
337 // unsigned count;
338 // unsigned nbBuckets;
339 // void *buckets;
340 // const void *info;
341 // } NXHashTable;
342
344 DataBufferHeap buffer(1024, 0);
345 if (process->ReadMemory(hash_table_ptr, buffer.GetBytes(), 20, error) ==
346 20) {
347 const uint32_t addr_size = m_process->GetAddressByteSize();
348 const ByteOrder byte_order = m_process->GetByteOrder();
349 DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(), byte_order,
350 addr_size);
351 lldb::offset_t offset = addr_size; // Skip prototype
352 const uint32_t count = data.GetU32(&offset);
353 const uint32_t num_buckets = data.GetU32(&offset);
354 const addr_t buckets_ptr = data.GetAddress(&offset);
355 if (m_hash_signature.NeedsUpdate(count, num_buckets, buckets_ptr)) {
356 m_hash_signature.UpdateSignature(count, num_buckets, buckets_ptr);
357
358 const uint32_t data_size = num_buckets * 2 * sizeof(uint32_t);
359 buffer.SetByteSize(data_size);
360
361 if (process->ReadMemory(buckets_ptr, buffer.GetBytes(), data_size,
362 error) == data_size) {
363 data.SetData(buffer.GetBytes(), buffer.GetByteSize(), byte_order);
364 offset = 0;
365 for (uint32_t bucket_idx = 0; bucket_idx < num_buckets;
366 ++bucket_idx) {
367 const uint32_t bucket_isa_count = data.GetU32(&offset);
368 const lldb::addr_t bucket_data = data.GetU32(&offset);
369
370 if (bucket_isa_count == 0)
371 continue;
372
373 ObjCISA isa;
374 if (bucket_isa_count == 1) {
375 // When we only have one entry in the bucket, the bucket data
376 // is the "isa"
377 isa = bucket_data;
378 if (isa) {
379 if (!ISAIsCached(isa)) {
380 ClassDescriptorSP descriptor_sp(
381 new ClassDescriptorV1(isa, process_sp));
382
383 if (log && log->GetVerbose())
384 LLDB_LOGF(log,
385 "AppleObjCRuntimeV1 added (ObjCISA)0x%" PRIx64
386 " from _objc_debug_class_hash to "
387 "isa->descriptor cache",
388 isa);
389
390 AddClass(isa, descriptor_sp);
391 }
392 }
393 } else {
394 // When we have more than one entry in the bucket, the bucket
395 // data is a pointer to an array of "isa" values
396 addr_t isa_addr = bucket_data;
397 for (uint32_t isa_idx = 0; isa_idx < bucket_isa_count;
398 ++isa_idx, isa_addr += addr_size) {
399 isa = m_process->ReadPointerFromMemory(isa_addr, error);
400
401 if (isa && isa != LLDB_INVALID_ADDRESS) {
402 if (!ISAIsCached(isa)) {
403 ClassDescriptorSP descriptor_sp(
404 new ClassDescriptorV1(isa, process_sp));
405
406 if (log && log->GetVerbose())
407 LLDB_LOGF(
408 log,
409 "AppleObjCRuntimeV1 added (ObjCISA)0x%" PRIx64
410 " from _objc_debug_class_hash to isa->descriptor "
411 "cache",
412 isa);
413
414 AddClass(isa, descriptor_sp);
415 }
416 }
417 }
418 }
419 }
420 }
421 }
422 }
423 }
424 } else {
426 }
427}
428
430 return nullptr;
431}
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOGF(log,...)
Definition: Log.h:366
A section + offset based address class.
Definition: Address.h:62
lldb::addr_t GetLoadAddress(Target *target) const
Get the load address.
Definition: Address.cpp:313
void SetRawAddress(lldb::addr_t addr)
Definition: Address.h:454
void Initialize(ObjCISA isa, lldb::ProcessSP process_sp)
bool Describe(std::function< void(ObjCLanguageRuntime::ObjCISA)> const &superclass_func, std::function< bool(const char *, const char *)> const &instance_method_func, std::function< bool(const char *, const char *)> const &class_method_func, std::function< bool(const char *, const char *, lldb::addr_t, uint64_t)> const &ivar_func) const override
void UpdateSignature(uint32_t count, uint32_t num_buckets, lldb::addr_t buckets_ptr)
bool NeedsUpdate(uint32_t count, uint32_t num_buckets, lldb::addr_t buckets_ptr)
DeclVendor * GetDeclVendor() override
static llvm::StringRef GetPluginNameStatic()
lldb::BreakpointResolverSP CreateExceptionResolver(const lldb::BreakpointSP &bkpt, bool catch_bp, bool throw_bp) override
bool GetDynamicTypeAndAddress(ValueObject &in_value, lldb::DynamicValueType use_dynamic, TypeAndOrName &class_type_or_name, Address &address, Value::ValueType &value_type) override
llvm::Expected< std::unique_ptr< UtilityFunction > > CreateObjectChecker(std::string, ExecutionContext &exe_ctx) override
static lldb_private::LanguageRuntime * CreateInstance(Process *process, lldb::LanguageType language)
static std::tuple< FileSpec, ConstString > GetExceptionThrowLocation()
static ObjCRuntimeVersions GetObjCVersion(Process *process, lldb::ModuleSP &objc_module_sp)
bool CouldHaveDynamicValue(ValueObject &in_value) override
A uniqued constant string class.
Definition: ConstString.h:40
A subclass of DataBuffer that stores a data buffer on the heap.
lldb::offset_t GetByteSize() const override
Get the number of bytes in the data buffer.
lldb::offset_t SetByteSize(lldb::offset_t byte_size)
Set the number of bytes in the data buffer.
An data extractor class.
Definition: DataExtractor.h:48
uint32_t GetU32(lldb::offset_t *offset_ptr) const
Extract a uint32_t value from *offset_ptr.
uint64_t GetAddress(lldb::offset_t *offset_ptr) const
Extract an address from *offset_ptr.
lldb::offset_t SetData(const void *bytes, lldb::offset_t length, lldb::ByteOrder byte_order)
Set data with a buffer that is caller owned.
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
bool GetVerbose() const
Definition: Log.cpp:314
std::shared_ptr< ClassDescriptor > ClassDescriptorSP
bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp)
virtual ClassDescriptorSP GetClassDescriptor(ValueObject &in_value)
static lldb::BreakpointPreconditionSP GetBreakpointExceptionPrecondition(lldb::LanguageType language, bool throw_bp)
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description, ABICreateInstance create_callback)
static bool UnregisterPlugin(ABICreateInstance create_callback)
A plug-in interface definition class for debugging a process.
Definition: Process.h:341
virtual size_t ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, Status &error)
Read of memory from a process.
Definition: Process.cpp:1973
lldb::ByteOrder GetByteOrder() const
Definition: Process.cpp:3596
lldb::addr_t ReadPointerFromMemory(lldb::addr_t vm_addr, Status &error)
Definition: Process.cpp:2259
uint32_t GetAddressByteSize() const
Definition: Process.cpp:3600
uint32_t GetStopID() const
Definition: Process.h:1484
Target & GetTarget()
Get the target object pointer for this module.
Definition: Process.h:1279
Process * m_process
Definition: Runtime.h:29
Process * GetProcess()
Definition: Runtime.h:22
Target & GetTargetRef()
Definition: Runtime.h:23
An error handling class.
Definition: Status.h:44
bool ValueIsAddress() const
Definition: Symbol.cpp:165
Address & GetAddressRef()
Definition: Symbol.h:72
llvm::Expected< std::unique_ptr< UtilityFunction > > CreateUtilityFunction(std::string expression, std::string name, lldb::LanguageType language, ExecutionContext &exe_ctx)
Creates and installs a UtilityFunction for the given language.
Definition: Target.cpp:2576
Sometimes you can find the name of the type corresponding to an object, but we don't have debug infor...
Definition: Type.h:745
void SetName(ConstString type_name)
Definition: Type.cpp:866
bool IsEmpty() const
Definition: Type.cpp:892
lldb::addr_t GetPointerValue(AddressType *address_type=nullptr)
lldb::ProcessSP GetProcessSP() const
Definition: ValueObject.h:338
virtual uint64_t GetValueAsUnsigned(uint64_t fail_value, bool *success=nullptr)
ValueType
Type that describes Value::m_value.
Definition: Value.h:41
@ Scalar
A raw scalar value.
uint8_t * GetBytes()
Get a pointer to the data.
Definition: DataBuffer.h:108
#define UNUSED_IF_ASSERT_DISABLED(x)
Definition: lldb-defines.h:140
#define LLDB_INVALID_ADDRESS
Definition: lldb-defines.h:82
#define UINT32_MAX
Definition: lldb-defines.h:19
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition: Log.h:331
Definition: SBAddress.h:15
std::shared_ptr< lldb_private::BreakpointResolver > BreakpointResolverSP
Definition: lldb-forward.h:325
uint64_t offset_t
Definition: lldb-types.h:85
LanguageType
Programming language type.
@ eLanguageTypeUnknown
Unknown or invalid language value.
@ eLanguageTypeC
Non-standardized C, such as K&R.
@ eLanguageTypeObjC
Objective-C.
std::shared_ptr< lldb_private::Breakpoint > BreakpointSP
Definition: lldb-forward.h:318
std::shared_ptr< lldb_private::Process > ProcessSP
Definition: lldb-forward.h:386
ByteOrder
Byte ordering definitions.
std::weak_ptr< lldb_private::Process > ProcessWP
Definition: lldb-forward.h:389
std::shared_ptr< lldb_private::WritableDataBuffer > WritableDataBufferSP
Definition: lldb-forward.h:334
uint64_t addr_t
Definition: lldb-types.h:80
std::shared_ptr< lldb_private::Module > ModuleSP
Definition: lldb-forward.h:370