More work for reading the Objective-C runtime.
We can now read the relevant data structures for the method list, and use a callback mechanism to report their details to the AppleObjCTypeVendor, which constructs appropriate Clang types. llvm-svn: 164310
This commit is contained in:
parent
c727bacb38
commit
d0dcae08e5
|
@ -12,6 +12,7 @@
|
|||
|
||||
// C Includes
|
||||
// C++ Includes
|
||||
#include <functional>
|
||||
#include <map>
|
||||
|
||||
// Other libraries and framework includes
|
||||
|
@ -115,7 +116,8 @@ public:
|
|||
|
||||
// This should return true iff the interface could be completed
|
||||
virtual bool
|
||||
CompleteInterface (clang::ObjCInterfaceDecl *interface_decl)
|
||||
Describe (std::function <void (ObjCISA)> const &superclass_func,
|
||||
std::function <void (const char*, const char*)> const &method_func)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1039,12 +1039,56 @@ public:
|
|||
}
|
||||
|
||||
virtual bool
|
||||
CompleteInterface (clang::ObjCInterfaceDecl *interface_decl)
|
||||
Describe (std::function <void (ObjCLanguageRuntime::ObjCISA)> const &superclass_func,
|
||||
std::function <void (const char *, const char *)> const &method_func)
|
||||
{
|
||||
if (!m_valid)
|
||||
return false;
|
||||
|
||||
return false;
|
||||
std::auto_ptr <class_ro_t> ro;
|
||||
std::auto_ptr <class_rw_t> rw;
|
||||
|
||||
ProcessSP process_sp = m_process_wp.lock();
|
||||
|
||||
if (!process_sp)
|
||||
return false;
|
||||
|
||||
if (IsRealized())
|
||||
{
|
||||
rw.reset(new class_rw_t);
|
||||
if (!rw->Read(process_sp, m_objc_class.m_data_la))
|
||||
return false;
|
||||
|
||||
ro.reset(new class_ro_t);
|
||||
if (!ro->Read(process_sp, rw->m_ro_la))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ro.reset(new class_ro_t);
|
||||
if (!ro->Read(process_sp, m_objc_class.m_data_la))
|
||||
return false;
|
||||
}
|
||||
|
||||
superclass_func(m_objc_class.m_superclass);
|
||||
|
||||
std::auto_ptr <method_list_t> base_method_list;
|
||||
|
||||
base_method_list.reset(new method_list_t);
|
||||
if (!base_method_list->Read(process_sp, ro->m_baseMethods_la))
|
||||
return false;
|
||||
|
||||
std::auto_ptr <method_t> method;
|
||||
method.reset(new method_t);
|
||||
|
||||
for (uint32_t i = 0, e = base_method_list->m_count; i < e; ++i)
|
||||
{
|
||||
method->Read(process_sp, base_method_list->m_first_la + (i * base_method_list->m_entsize));
|
||||
|
||||
method_func(method->m_name.c_str(), method->m_types.c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
|
@ -1102,35 +1146,11 @@ protected:
|
|||
m_valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
size_t objc_class_size = ptr_size // uintptr_t isa;
|
||||
+ ptr_size // Class superclass;
|
||||
+ ptr_size // void *cache;
|
||||
+ ptr_size // IMP *vtable;
|
||||
+ ptr_size; // uintptr_t data_NEVER_USE;
|
||||
|
||||
if (!m_objc_class.Read(process_sp, m_objc_class_la))
|
||||
{
|
||||
DataBufferHeap objc_class_buf (objc_class_size, '\0');
|
||||
|
||||
process_sp->ReadMemory(m_objc_class_la, objc_class_buf.GetBytes(), objc_class_size, error);
|
||||
if (error.Fail())
|
||||
{
|
||||
m_valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
DataExtractor objc_class_extractor(objc_class_buf.GetBytes(), objc_class_size, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
|
||||
|
||||
uint32_t cursor = 0;
|
||||
|
||||
m_objc_class.m_isa = objc_class_extractor.GetAddress_unchecked(&cursor); // uintptr_t isa;
|
||||
m_objc_class.m_superclass = objc_class_extractor.GetAddress_unchecked(&cursor); // Class superclass;
|
||||
m_objc_class.m_cache_la = objc_class_extractor.GetAddress_unchecked(&cursor); // void *cache;
|
||||
m_objc_class.m_vtable_la = objc_class_extractor.GetAddress_unchecked(&cursor); // IMP *vtable;
|
||||
lldb::addr_t data_NEVER_USE = objc_class_extractor.GetAddress_unchecked(&cursor); // uintptr_t data_NEVER_USE;
|
||||
|
||||
m_objc_class.m_flags = (uint8_t)(data_NEVER_USE & (lldb::addr_t)3);
|
||||
m_objc_class.m_data_la = data_NEVER_USE & ~(lldb::addr_t)3;
|
||||
m_valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Now we just want to grab the instance size and the name.
|
||||
|
@ -1227,7 +1247,7 @@ protected:
|
|||
|
||||
m_process_wp = lldb::ProcessWP(process_sp);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
static const uint32_t RW_REALIZED = (1 << 31);
|
||||
|
||||
|
@ -1241,6 +1261,41 @@ private:
|
|||
lldb::addr_t m_vtable_la;
|
||||
lldb::addr_t m_data_la;
|
||||
uint8_t m_flags;
|
||||
|
||||
bool Read(ProcessSP &process_sp, lldb::addr_t addr)
|
||||
{
|
||||
size_t ptr_size = process_sp->GetAddressByteSize();
|
||||
|
||||
size_t objc_class_size = ptr_size // uintptr_t isa;
|
||||
+ ptr_size // Class superclass;
|
||||
+ ptr_size // void *cache;
|
||||
+ ptr_size // IMP *vtable;
|
||||
+ ptr_size; // uintptr_t data_NEVER_USE;
|
||||
|
||||
DataBufferHeap objc_class_buf (objc_class_size, '\0');
|
||||
Error error;
|
||||
|
||||
process_sp->ReadMemory(addr, objc_class_buf.GetBytes(), objc_class_size, error);
|
||||
if (error.Fail())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DataExtractor extractor(objc_class_buf.GetBytes(), objc_class_size, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
|
||||
|
||||
uint32_t cursor = 0;
|
||||
|
||||
m_isa = extractor.GetAddress_unchecked(&cursor); // uintptr_t isa;
|
||||
m_superclass = extractor.GetAddress_unchecked(&cursor); // Class superclass;
|
||||
m_cache_la = extractor.GetAddress_unchecked(&cursor); // void *cache;
|
||||
m_vtable_la = extractor.GetAddress_unchecked(&cursor); // IMP *vtable;
|
||||
lldb::addr_t data_NEVER_USE = extractor.GetAddress_unchecked(&cursor); // uintptr_t data_NEVER_USE;
|
||||
|
||||
m_flags = (uint8_t)(data_NEVER_USE & (lldb::addr_t)3);
|
||||
m_data_la = data_NEVER_USE & ~(lldb::addr_t)3;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
objc_class_t m_objc_class;
|
||||
|
@ -1264,10 +1319,55 @@ private:
|
|||
|
||||
lldb::addr_t m_weakIvarLayout_la;
|
||||
lldb::addr_t m_baseProperties_la;
|
||||
|
||||
bool Read(ProcessSP &process_sp, lldb::addr_t addr)
|
||||
{
|
||||
size_t ptr_size = process_sp->GetAddressByteSize();
|
||||
|
||||
size_t size = sizeof(uint32_t) // uint32_t flags;
|
||||
+ sizeof(uint32_t) // uint32_t instanceStart;
|
||||
+ sizeof(uint32_t) // uint32_t instanceSize;
|
||||
+ (ptr_size == 8 ? sizeof(uint32_t) : 0) // uint32_t reserved; // __LP64__ only
|
||||
+ ptr_size // const uint8_t *ivarLayout;
|
||||
+ ptr_size // const char *name;
|
||||
+ ptr_size // const method_list_t *baseMethods;
|
||||
+ ptr_size // const protocol_list_t *baseProtocols;
|
||||
+ ptr_size // const ivar_list_t *ivars;
|
||||
+ ptr_size // const uint8_t *weakIvarLayout;
|
||||
+ ptr_size; // const property_list_t *baseProperties;
|
||||
|
||||
DataBufferHeap buffer (size, '\0');
|
||||
Error error;
|
||||
|
||||
process_sp->ReadMemory(addr, buffer.GetBytes(), size, error);
|
||||
if (error.Fail())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DataExtractor extractor(buffer.GetBytes(), size, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
|
||||
|
||||
uint32_t cursor = 0;
|
||||
|
||||
m_flags = extractor.GetU32_unchecked(&cursor);
|
||||
m_instanceStart = extractor.GetU32_unchecked(&cursor);
|
||||
m_instanceSize = extractor.GetU32_unchecked(&cursor);
|
||||
if (ptr_size == 8)
|
||||
m_reserved = extractor.GetU32_unchecked(&cursor);
|
||||
else
|
||||
m_reserved = 0;
|
||||
m_ivarLayout_la = extractor.GetAddress_unchecked(&cursor);
|
||||
m_name_la = extractor.GetAddress_unchecked(&cursor);
|
||||
m_baseMethods_la = extractor.GetAddress_unchecked(&cursor);
|
||||
m_baseProtocols_la = extractor.GetAddress_unchecked(&cursor);
|
||||
m_ivars_la = extractor.GetAddress_unchecked(&cursor);
|
||||
m_weakIvarLayout_la = extractor.GetAddress_unchecked(&cursor);
|
||||
m_baseProperties_la = extractor.GetAddress_unchecked(&cursor);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
std::auto_ptr<class_ro_t> m_class_ro;
|
||||
|
||||
struct class_rw_t {
|
||||
uint32_t m_flags;
|
||||
uint32_t m_version;
|
||||
|
@ -1282,9 +1382,122 @@ private:
|
|||
|
||||
ObjCLanguageRuntime::ObjCISA m_firstSubclass;
|
||||
ObjCLanguageRuntime::ObjCISA m_nextSiblingClass;
|
||||
|
||||
bool Read(ProcessSP &process_sp, lldb::addr_t addr)
|
||||
{
|
||||
size_t ptr_size = process_sp->GetAddressByteSize();
|
||||
|
||||
size_t size = sizeof(uint32_t) // uint32_t flags;
|
||||
+ sizeof(uint32_t) // uint32_t version;
|
||||
+ ptr_size // const class_ro_t *ro;
|
||||
+ ptr_size // union { method_list_t **method_lists; method_list_t *method_list; };
|
||||
+ ptr_size // struct chained_property_list *properties;
|
||||
+ ptr_size // const protocol_list_t **protocols;
|
||||
+ ptr_size // Class firstSubclass;
|
||||
+ ptr_size; // Class nextSiblingClass;
|
||||
|
||||
DataBufferHeap buffer (size, '\0');
|
||||
Error error;
|
||||
|
||||
process_sp->ReadMemory(addr, buffer.GetBytes(), size, error);
|
||||
if (error.Fail())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DataExtractor extractor(buffer.GetBytes(), size, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
|
||||
|
||||
uint32_t cursor = 0;
|
||||
|
||||
m_flags = extractor.GetU32_unchecked(&cursor);
|
||||
m_version = extractor.GetU32_unchecked(&cursor);
|
||||
m_ro_la = extractor.GetAddress_unchecked(&cursor);
|
||||
m_method_list_la = extractor.GetAddress_unchecked(&cursor);
|
||||
m_properties_la = extractor.GetAddress_unchecked(&cursor);
|
||||
m_firstSubclass = extractor.GetAddress_unchecked(&cursor);
|
||||
m_nextSiblingClass = extractor.GetAddress_unchecked(&cursor);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
std::auto_ptr<class_rw_t> m_class_rw;
|
||||
struct method_list_t
|
||||
{
|
||||
uint32_t m_entsize;
|
||||
uint32_t m_count;
|
||||
lldb::addr_t m_first_la;
|
||||
|
||||
bool Read(ProcessSP &process_sp, lldb::addr_t addr)
|
||||
{
|
||||
size_t size = sizeof(uint32_t) // uint32_t entsize_NEVER_USE;
|
||||
+ sizeof(uint32_t); // uint32_t count;
|
||||
|
||||
DataBufferHeap buffer (size, '\0');
|
||||
Error error;
|
||||
|
||||
process_sp->ReadMemory(addr, buffer.GetBytes(), size, error);
|
||||
if (error.Fail())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DataExtractor extractor(buffer.GetBytes(), size, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
|
||||
|
||||
uint32_t cursor = 0;
|
||||
|
||||
m_entsize = extractor.GetU32_unchecked(&cursor) & ~(uint32_t)3;
|
||||
m_count = extractor.GetU32_unchecked(&cursor);
|
||||
m_first_la = addr + cursor;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct method_t
|
||||
{
|
||||
lldb::addr_t m_name_la;
|
||||
lldb::addr_t m_types_la;
|
||||
lldb::addr_t m_imp_la;
|
||||
|
||||
std::string m_name;
|
||||
std::string m_types;
|
||||
|
||||
bool Read(ProcessSP &process_sp, lldb::addr_t addr)
|
||||
{
|
||||
size_t size = sizeof(uint32_t) // uint32_t entsize_NEVER_USE;
|
||||
+ sizeof(uint32_t); // uint32_t count;
|
||||
|
||||
DataBufferHeap buffer (size, '\0');
|
||||
Error error;
|
||||
|
||||
process_sp->ReadMemory(addr, buffer.GetBytes(), size, error);
|
||||
if (error.Fail())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DataExtractor extractor(buffer.GetBytes(), size, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
|
||||
|
||||
uint32_t cursor = 0;
|
||||
|
||||
m_name_la = extractor.GetAddress_unchecked(&cursor);
|
||||
m_types_la = extractor.GetAddress_unchecked(&cursor);
|
||||
m_imp_la = extractor.GetAddress_unchecked(&cursor);
|
||||
|
||||
const size_t buffer_size = 1024;
|
||||
size_t count;
|
||||
|
||||
DataBufferHeap string_buf(buffer_size, 0);
|
||||
|
||||
count = process_sp->ReadCStringFromMemory(m_name_la, (char*)string_buf.GetBytes(), buffer_size, error);
|
||||
m_name.assign((char*)string_buf.GetBytes(), count);
|
||||
|
||||
count = process_sp->ReadCStringFromMemory(m_types_la, (char*)string_buf.GetBytes(), buffer_size, error);
|
||||
m_types.assign((char*)string_buf.GetBytes(), count);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
lldb::ProcessWP m_process_wp;
|
||||
};
|
||||
|
|
|
@ -55,28 +55,12 @@ public:
|
|||
|
||||
if (!interface_decl)
|
||||
break;
|
||||
|
||||
ObjCLanguageRuntime::ObjCISA objc_isa = (ObjCLanguageRuntime::ObjCISA)GetMetadata((uintptr_t)interface_decl);
|
||||
|
||||
if (!objc_isa)
|
||||
break;
|
||||
|
||||
clang::ObjCInterfaceDecl *non_const_interface_decl = const_cast<clang::ObjCInterfaceDecl*>(interface_decl);
|
||||
|
||||
if (non_const_interface_decl->hasExternalVisibleStorage())
|
||||
{
|
||||
ObjCLanguageRuntime::ClassDescriptorSP descriptor = m_type_vendor.m_runtime.GetClassDescriptor(objc_isa);
|
||||
|
||||
if (!descriptor)
|
||||
break;
|
||||
|
||||
if (descriptor->CompleteInterface(non_const_interface_decl))
|
||||
non_const_interface_decl->setHasExternalVisibleStorage(false);
|
||||
}
|
||||
|
||||
if (non_const_interface_decl->hasExternalVisibleStorage())
|
||||
if (!m_type_vendor.FinishDecl(non_const_interface_decl))
|
||||
break;
|
||||
|
||||
|
||||
return non_const_interface_decl->lookup(name);
|
||||
}
|
||||
while(0);
|
||||
|
@ -183,6 +167,78 @@ AppleObjCTypeVendor::AppleObjCTypeVendor(ObjCLanguageRuntime &runtime) :
|
|||
m_ast_ctx.getASTContext()->setExternalSource(external_source_owning_ptr);
|
||||
}
|
||||
|
||||
clang::ObjCInterfaceDecl*
|
||||
AppleObjCTypeVendor::GetDeclForISA(ObjCLanguageRuntime::ObjCISA isa)
|
||||
{
|
||||
ISAToInterfaceMap::const_iterator iter = m_isa_to_interface.find(isa);
|
||||
|
||||
if (iter != m_isa_to_interface.end())
|
||||
return iter->second;
|
||||
|
||||
clang::ASTContext *ast_ctx = m_ast_ctx.getASTContext();
|
||||
|
||||
ObjCLanguageRuntime::ClassDescriptorSP descriptor = m_runtime.GetClassDescriptor(isa);
|
||||
|
||||
if (!descriptor)
|
||||
return NULL;
|
||||
|
||||
const ConstString &name(descriptor->GetClassName());
|
||||
|
||||
clang::IdentifierInfo &identifier_info = ast_ctx->Idents.get(name.GetStringRef());
|
||||
|
||||
clang::ObjCInterfaceDecl *new_iface_decl = clang::ObjCInterfaceDecl::Create(*ast_ctx,
|
||||
ast_ctx->getTranslationUnitDecl(),
|
||||
clang::SourceLocation(),
|
||||
&identifier_info,
|
||||
NULL);
|
||||
|
||||
m_external_source->SetMetadata((uintptr_t)new_iface_decl, (uint64_t)isa);
|
||||
new_iface_decl->setHasExternalVisibleStorage();
|
||||
ast_ctx->getTranslationUnitDecl()->addDecl(new_iface_decl);
|
||||
|
||||
m_isa_to_interface[isa] = new_iface_decl;
|
||||
|
||||
return new_iface_decl;
|
||||
}
|
||||
|
||||
bool
|
||||
AppleObjCTypeVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl)
|
||||
{
|
||||
ObjCLanguageRuntime::ObjCISA objc_isa = (ObjCLanguageRuntime::ObjCISA)m_external_source->GetMetadata((uintptr_t)interface_decl);
|
||||
|
||||
if (!objc_isa)
|
||||
return false;
|
||||
|
||||
if (!interface_decl->hasExternalVisibleStorage())
|
||||
return true;
|
||||
|
||||
interface_decl->startDefinition();
|
||||
|
||||
ObjCLanguageRuntime::ClassDescriptorSP descriptor = m_runtime.GetClassDescriptor(objc_isa);
|
||||
|
||||
if (!descriptor)
|
||||
return false;
|
||||
|
||||
auto superclass_func = [interface_decl, this](ObjCLanguageRuntime::ObjCISA isa)
|
||||
{
|
||||
clang::ObjCInterfaceDecl *superclass_decl = GetDeclForISA(isa);
|
||||
if (!superclass_decl)
|
||||
return;
|
||||
interface_decl->setSuperClass(superclass_decl);
|
||||
};
|
||||
|
||||
auto method_func = [interface_decl, this](const char *name, const char *types)
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
if (!descriptor->Describe(superclass_func, method_func))
|
||||
return false;
|
||||
|
||||
interface_decl->setHasExternalVisibleStorage(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
AppleObjCTypeVendor::FindTypes (const ConstString &name,
|
||||
bool append,
|
||||
|
@ -206,6 +262,9 @@ AppleObjCTypeVendor::FindTypes (const ConstString &name,
|
|||
|
||||
uint32_t ret = 0;
|
||||
|
||||
// TODO Remove this return once testing is complete.
|
||||
return ret;
|
||||
|
||||
do
|
||||
{
|
||||
// See if the type is already in our ASTContext.
|
||||
|
@ -252,10 +311,7 @@ AppleObjCTypeVendor::FindTypes (const ConstString &name,
|
|||
}
|
||||
|
||||
// It's not. If it exists, we have to put it into our ASTContext.
|
||||
|
||||
// TODO Remove this break once testing is complete.
|
||||
break;
|
||||
|
||||
|
||||
ObjCLanguageRuntime::ObjCISA isa = m_runtime.GetISA(name);
|
||||
|
||||
if (!isa)
|
||||
|
@ -267,17 +323,17 @@ AppleObjCTypeVendor::FindTypes (const ConstString &name,
|
|||
break;
|
||||
}
|
||||
|
||||
clang::ObjCInterfaceDecl *new_iface_decl = clang::ObjCInterfaceDecl::Create(*ast_ctx,
|
||||
ast_ctx->getTranslationUnitDecl(),
|
||||
clang::SourceLocation(),
|
||||
&identifier_info,
|
||||
NULL);
|
||||
clang::ObjCInterfaceDecl *iface_decl = GetDeclForISA(isa);
|
||||
|
||||
m_external_source->SetMetadata((uintptr_t)new_iface_decl, (uint64_t)isa);
|
||||
new_iface_decl->setHasExternalVisibleStorage();
|
||||
ast_ctx->getTranslationUnitDecl()->addDecl(new_iface_decl);
|
||||
if (!iface_decl)
|
||||
{
|
||||
if (log)
|
||||
log->Printf("AOCTV::FT [%u] Couldn't get the Objective-C interface for isa 0x%llx",
|
||||
current_id,
|
||||
(uint64_t)isa);
|
||||
}
|
||||
|
||||
clang::QualType new_iface_type = ast_ctx->getObjCInterfaceType(new_iface_decl);
|
||||
clang::QualType new_iface_type = ast_ctx->getObjCInterfaceType(iface_decl);
|
||||
|
||||
if (log)
|
||||
{
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "lldb/lldb-private.h"
|
||||
#include "lldb/Symbol/ClangASTContext.h"
|
||||
#include "lldb/Symbol/TypeVendor.h"
|
||||
#include "lldb/Target/ObjCLanguageRuntime.h"
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
|
@ -39,9 +40,16 @@ public:
|
|||
|
||||
friend class AppleObjCExternalASTSource;
|
||||
private:
|
||||
ObjCLanguageRuntime &m_runtime;
|
||||
ClangASTContext m_ast_ctx;
|
||||
AppleObjCExternalASTSource *m_external_source;
|
||||
clang::ObjCInterfaceDecl *GetDeclForISA(ObjCLanguageRuntime::ObjCISA isa);
|
||||
bool FinishDecl(clang::ObjCInterfaceDecl *decl);
|
||||
|
||||
ObjCLanguageRuntime &m_runtime;
|
||||
ClangASTContext m_ast_ctx;
|
||||
AppleObjCExternalASTSource *m_external_source;
|
||||
|
||||
typedef llvm::DenseMap<ObjCLanguageRuntime::ObjCISA, clang::ObjCInterfaceDecl *> ISAToInterfaceMap;
|
||||
|
||||
ISAToInterfaceMap m_isa_to_interface;
|
||||
};
|
||||
|
||||
} // namespace lldb_private
|
||||
|
|
Loading…
Reference in New Issue