17#include "llvm/ADT/Sequence.h"
18#include "llvm/Support/ErrorExtras.h"
28 return 0x00007ffffffffff8UL;
36llvm::Expected<ClassDescriptorV2::objc_class_t>
40 size_t objc_class_size = ptr_size
51 return error.takeError();
70 uint8_t flags = (uint8_t)(data_NEVER_USE & (
lldb::addr_t)3);
74 isa = abi_sp->FixCodeAddress(isa);
75 superclass = abi_sp->FixCodeAddress(superclass);
76 data_ptr = abi_sp->FixCodeAddress(data_ptr);
78 return objc_class_t{isa, superclass, cache_ptr, vtable_ptr, data_ptr, flags};
81llvm::Expected<ClassDescriptorV2::class_rw_t>
85 size_t size =
sizeof(uint32_t)
100 return error.takeError();
120 return error.takeError();
133llvm::Expected<ClassDescriptorV2::class_ro_t>
137 size_t size =
sizeof(uint32_t)
140 + (ptr_size == 8 ?
sizeof(uint32_t)
155 return error.takeError();
184 return error.takeError();
191llvm::Expected<ClassDescriptorV2::class_ro_t>
197 if (!
error.Success())
198 return error.takeError();
204 return class_rw.takeError();
210llvm::Expected<ClassDescriptorV2::method_list_t>
212 size_t size =
sizeof(uint32_t)
219 addr = abi_sp->FixCodeAddress(addr);
222 return error.takeError();
230 bool is_small = (entsize_raw & 0x80000000) != 0;
231 bool has_direct_selector = (entsize_raw & 0x40000000) != 0;
232 bool has_relative_types = (entsize_raw & 0x20000000) != 0;
233 uint16_t entsize = entsize_raw & 0xfffc;
235 addr_t first_ptr = addr + cursor;
238 entsize, is_small, has_direct_selector, has_relative_types,
243 llvm::MutableArrayRef<method_t> methods,
Process &process) {
244 std::vector<lldb::addr_t> str_addresses;
245 str_addresses.reserve(2 * methods.size());
246 for (
auto &method : methods)
247 str_addresses.push_back(method.m_name_ptr);
248 for (
auto &method : methods)
249 str_addresses.push_back(method.m_types_ptr);
251 llvm::SmallVector<std::optional<std::string>> read_result =
253 auto names = llvm::MutableArrayRef(read_result).take_front(methods.size());
254 auto types = llvm::MutableArrayRef(read_result).take_back(methods.size());
256 for (
auto [name_str, type_str, method] : llvm::zip(names, types, methods)) {
258 method.m_name = std::move(*name_str);
260 method.m_types = std::move(*type_str);
264llvm::SmallVector<ClassDescriptorV2::method_t, 0>
267 bool is_small,
bool has_direct_sel,
268 bool has_relative_types)
const {
274 const size_t num_methods = addresses.size();
276 llvm::SmallVector<uint8_t, 0> buffer(num_methods * size, 0);
278 llvm::SmallVector<Range<addr_t, size_t>> mem_ranges =
279 llvm::to_vector(llvm::map_range(llvm::seq(num_methods), [&](
size_t idx) {
283 llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> read_results =
286 llvm::SmallVector<method_t, 0> methods;
287 methods.reserve(num_methods);
288 for (
auto [addr, memory] : llvm::zip(addresses, read_results)) {
290 if (memory.size() != size)
296 methods.back().Read(extractor, process, addr, relative_string_base_addr,
297 is_small, has_direct_sel, has_relative_types);
307 bool is_small,
bool has_direct_sel,
308 bool has_relative_types) {
319 if (!has_direct_sel) {
325 m_name_ptr = relative_string_base_addr + nameref_offset;
327 if (has_relative_types)
328 m_types_ptr = relative_string_base_addr + types_offset;
341llvm::Expected<ClassDescriptorV2::ivar_list_t>
343 size_t size =
sizeof(uint32_t)
351 return error.takeError();
363llvm::Expected<ClassDescriptorV2::ivar_t>
365 size_t size =
GetSize(process);
372 return error.takeError();
388 return error.takeError();
392 return error.takeError();
396llvm::Expected<ClassDescriptorV2::relative_list_entry_t>
399 size_t size =
sizeof(uint64_t);
407 return llvm::joinErrors(
409 llvm::createStringErrorV(
410 "Failed to read relative_list_entry_t at address {0:x}", addr));
416 uint16_t image_index = raw_entry & 0xFFFF;
417 int64_t list_offset = llvm::SignExtend64<48>(raw_entry >> 16);
421llvm::Expected<ClassDescriptorV2::relative_list_list_t>
424 size_t size =
sizeof(uint32_t)
432 return llvm::joinErrors(
434 llvm::createStringErrorV(
435 "Failed to read relative_list_list_t at address {0:x}", addr));
446llvm::Expected<ClassDescriptorV2::method_list_t>
452 return method_list.takeError();
454 const size_t method_size =
456 if (method_list->m_entsize != method_size)
457 return llvm::createStringErrorV(
458 "method_list_t at address {0:x} has an entsize of {1:x}"
459 " but method size should be {2:x}",
460 method_list_ptr, method_list->m_entsize, method_size);
466 std::function<
bool(
const char *,
const char *)>
const &instance_method_func,
468 auto idx_to_method_addr = [&](uint32_t idx) {
471 llvm::SmallVector<addr_t> addresses = llvm::to_vector(llvm::map_range(
472 llvm::seq<uint32_t>(method_list.
m_count), idx_to_method_addr));
474 llvm::SmallVector<method_t, 0> methods =
479 for (
const auto &method : methods)
480 if (instance_method_func(method.m_name.c_str(), method.m_types.c_str()))
498 std::function<
bool(
const char *,
const char *)>
const &instance_method_func,
503 auto relative_method_lists =
505 if (!relative_method_lists)
506 return relative_method_lists.takeError();
508 for (uint32_t i = 0; i < relative_method_lists->m_count; i++) {
511 const lldb::addr_t entry_addr = relative_method_lists->m_first_ptr +
512 (i * relative_method_lists->m_entsize);
515 return entry.takeError();
519 const lldb::addr_t method_list_addr = entry_addr + entry->m_list_offset;
522 llvm::Expected<method_list_t> method_list =
525 return method_list.takeError();
531 if (!
m_runtime.IsSharedCacheImageLoaded(entry->m_image_index))
541 return llvm::Error::success();
546 std::function<
bool(
const char *,
const char *)>
const &instance_method_func,
547 std::function<
bool(
const char *,
const char *)>
const &class_method_func,
548 std::function<
bool(
const char *,
const char *,
lldb::addr_t,
549 uint64_t)>
const &ivar_func)
const {
565 if (
m_name != NSObject_name && superclass_func)
566 superclass_func(objc_class->m_superclass);
568 if (instance_method_func) {
570 if (class_ro->m_baseMethods_ptr & 1) {
572 instance_method_func, class_ro->m_baseMethods_ptr ^ 1)) {
577 llvm::Expected<method_list_t> base_method_list =
579 if (base_method_list)
587 if (class_method_func) {
597 std::function<
bool(
const char *,
const char *)>(
nullptr),
598 std::function<
bool(
const char *,
const char *,
lldb::addr_t,
599 uint64_t)>(
nullptr));
604 if (class_ro->m_ivars_ptr != 0) {
614 for (uint32_t i = 0, e = ivar_list->m_count; i < e; ++i) {
615 auto ivar =
ivar_t::Read(process, ivar_list->m_first_ptr +
616 (i * ivar_list->m_entsize));
622 if (ivar_func(ivar->m_name.c_str(), ivar->m_type.c_str(),
623 ivar->m_offset_ptr, ivar->m_size))
666 return m_runtime.ObjCLanguageRuntime::GetClassDescriptorFromISA(
667 objc_class->m_superclass);
703 return class_ro->m_instanceSize;
713 if (
auto *process =
m_runtime.GetProcess()) {
738 std::lock_guard<std::recursive_mutex> guard(
m_mutex);
745 if (!encoding_to_type_sp)
747 descriptor.
Describe(
nullptr,
nullptr,
nullptr, [
this, process,
749 log](
const char *name,
752 uint64_t
size) ->
bool {
753 const bool for_expression =
false;
754 const bool stop_loop =
false;
756 log,
"name = {0}, encoding = {1}, offset_ptr = {2:x}, size = {3}", name,
757 type, offset_ptr,
size);
759 encoding_to_type_sp->RealizeType(type, for_expression);
763 "name = {0}, encoding = {1}, offset_ptr = {2:x}, size = "
764 "{3}, type_size = {4}",
765 name, type, offset_ptr,
size,
766 expectedToOptional(ivar_type.
GetByteSize(
nullptr)).value_or(0));
769 const int offset_ptr_size = 4;
770 const bool is_signed =
false;
772 offset_ptr, offset_ptr_size, is_signed, offset_scalar,
error);
773 if (
error.Success() && 4 == read) {
775 offset_scalar.
SInt());
static lldb::addr_t GetClassDataMask(Process *process)
static uint8_t IS_SWIFT_STABLE
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOG_ERROR(log, error,...)
#define LLDB_LOG_VERBOSE(log,...)
EncodingToTypeSP GetEncodingToType() override
ObjCLanguageRuntime::ClassDescriptorSP GetSuperclass() override
iVarsStorage m_ivars_storage
void ProcessMethodList(std::function< bool(const char *, const char *)> const &instance_method_func, method_list_t &method_list) const
lldb::addr_t m_objc_class_ptr
llvm::SmallVector< method_t, 0 > ReadMethods(llvm::ArrayRef< lldb::addr_t > addresses, lldb::addr_t relative_string_base_addr, bool is_small, bool has_direct_sel, bool has_relative_types) const
AppleObjCRuntimeV2 & m_runtime
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
friend class lldb_private::AppleObjCRuntimeV2
ClassDescriptorV2(AppleObjCRuntimeV2 &runtime, ObjCLanguageRuntime::ObjCISA isa, const char *name)
ConstString GetClassName() override
static const uint32_t RW_REALIZED
llvm::Error ProcessRelativeMethodLists(std::function< bool(const char *, const char *)> const &instance_method_func, lldb::addr_t relative_method_list_ptr) const
void GetIVarInformation()
uint64_t GetInstanceSize() override
std::optional< uint64_t > m_last_version_updated
std::map< uint16_t, std::vector< method_list_t > > m_image_to_method_lists
static llvm::Expected< class_ro_t > Read_class_row(Process *process, const objc_class_t &objc_class)
static llvm::Expected< method_list_t > GetMethodList(Process *process, lldb::addr_t method_list_ptr)
ObjCLanguageRuntime::ClassDescriptorSP GetMetaclass() const override
lldb::LanguageType GetImplementationLanguage() const override
Determine whether this class is implemented in Swift.
Generic representation of a type in a programming language.
llvm::Expected< uint64_t > GetByteSize(ExecutionContextScope *exe_scope) const
Return the size of the type in bytes.
A uniqued constant string class.
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.
std::shared_ptr< ClassDescriptor > ClassDescriptorSP
std::shared_ptr< EncodingToType > EncodingToTypeSP
A plug-in interface definition class for debugging a process.
size_t ReadScalarIntegerFromMemory(lldb::addr_t addr, uint32_t byte_size, bool is_signed, Scalar &scalar, Status &error)
size_t ReadCStringFromMemory(lldb::addr_t vm_addr, char *cstr, size_t cstr_max_len, Status &error)
Read a NULL terminated C string from memory.
virtual size_t ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, Status &error)
Read of memory from a process.
lldb::ByteOrder GetByteOrder() const
uint64_t ReadUnsignedIntegerFromMemory(lldb::addr_t load_addr, size_t byte_size, uint64_t fail_value, Status &error)
Reads an unsigned integer of the specified byte size from process memory.
llvm::SmallVector< std::optional< std::string > > ReadCStringsFromMemory(llvm::ArrayRef< lldb::addr_t > addresses)
lldb::addr_t ReadPointerFromMemory(lldb::addr_t vm_addr, Status &error)
uint32_t GetAddressByteSize() const
llvm::SmallVector< llvm::MutableArrayRef< uint8_t > > ReadMemoryRanges(llvm::ArrayRef< Range< lldb::addr_t, size_t > > ranges, llvm::MutableArrayRef< uint8_t > buffer)
Read from multiple memory ranges and write the results into buffer.
const lldb::ABISP & GetABI()
int SInt(int fail_value=0) const
uint8_t * GetBytes()
Get a pointer to the data.
#define LLDB_INVALID_ADDRESS
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.
std::shared_ptr< lldb_private::ABI > ABISP
LanguageType
Programming language type.
@ eLanguageTypeSwift
Swift.
@ eLanguageTypeObjC
Objective-C.
lldb::addr_t m_weakIvarLayout_ptr
static llvm::Expected< class_ro_t > Read(Process *process, lldb::addr_t addr)
lldb::addr_t m_ivarLayout_ptr
lldb::addr_t m_baseProtocols_ptr
lldb::addr_t m_baseMethods_ptr
lldb::addr_t m_baseProperties_ptr
lldb::addr_t m_properties_ptr
static llvm::Expected< class_rw_t > Read(Process *process, lldb::addr_t addr)
lldb::addr_t m_method_list_ptr
static llvm::Expected< ivar_list_t > Read(Process *process, lldb::addr_t addr)
static size_t GetSize(Process *process)
lldb::addr_t m_offset_ptr
static llvm::Expected< ivar_t > Read(Process *process, lldb::addr_t addr)
bool m_has_direct_selector
bool m_has_relative_types
static llvm::Expected< method_list_t > Read(Process *process, lldb::addr_t addr)
static size_t GetSize(Process *process, bool is_small)
static void ReadNames(llvm::MutableArrayRef< method_t > methods, Process &process)
Fill in m_name and m_types efficiently by batching read requests.
bool Read(DataExtractor &extractor, Process *process, lldb::addr_t addr, lldb::addr_t relative_string_base_addr, bool is_small, bool has_direct_sel, bool has_relative_types)
static llvm::Expected< objc_class_t > Read(Process *process, lldb::addr_t addr)
static llvm::Expected< relative_list_entry_t > Read(Process *process, lldb::addr_t addr)
static llvm::Expected< relative_list_list_t > Read(Process *process, lldb::addr_t addr)