@@ -775,22 +775,57 @@ void DSCObjCProcessor::LoadProtocols(VMReader* reader, Ref<Section> listSection)
775775 }
776776}
777777
778- void DSCObjCProcessor::ReadMethodList (VMReader* reader, ClassBase& cls, std::string name, view_ptr_t start)
778+ void DSCObjCProcessor::ReadListOfMethodLists (VMReader* reader, ClassBase& cls, std::string_view name, view_ptr_t start)
779779{
780780 reader->Seek (start);
781781 method_list_t head;
782782 head.entsizeAndFlags = reader->Read32 ();
783783 head.count = reader->Read32 ();
784+ if (head.count > 0x1000 )
785+ {
786+ m_logger->LogError (" List of method lists at 0x%llx has an invalid count of 0x%x" , start, head.count );
787+ return ;
788+ }
789+
790+ for (size_t i = 0 ; i < head.count ; ++i) {
791+ relative_list_list_entry_t list_entry;
792+ reader->Read (&list_entry, sizeof (list_entry));
793+
794+ ReadMethodList (reader, cls, name, reader->GetOffset () - sizeof (list_entry) + list_entry.listOffset );
795+ // Reset the cursor to immediately past the list entry.
796+ reader->Seek (start + sizeof (method_list_t ) + ((i + 1 ) * sizeof (relative_list_list_entry_t )));
797+ }
798+ }
799+
800+ void DSCObjCProcessor::ReadMethodList (VMReader* reader, ClassBase& cls, std::string_view name, view_ptr_t start)
801+ {
802+ // Lower two bits indicate the type of method list.
803+ switch (start & 0b11 ) {
804+ case 0 :
805+ break ;
806+ case 1 :
807+ return ReadListOfMethodLists (reader, cls, name, start - 1 );
808+ default :
809+ m_logger->LogDebug (" ReadMethodList: Unknown method list type at 0x%llx: %d" , start, start & 0x3 );
810+ return ;
811+ }
812+
813+ reader->Seek (start);
814+ method_list_t head;
815+ head.entsizeAndFlags = reader->Read32 ();
816+ head.count = reader->Read32 ();
817+
784818 if (head.count > 0x1000 )
785819 {
786820 m_logger->LogError (" Method list at 0x%llx has an invalid count of 0x%x" , start, head.count );
787821 return ;
788822 }
823+
789824 uint64_t pointerSize = m_data->GetAddressSize ();
790825 bool relativeOffsets = (head.entsizeAndFlags & 0xFFFF0000 ) & 0x80000000 ;
791826 bool directSelectors = (head.entsizeAndFlags & 0xFFFF0000 ) & 0x40000000 ;
792827 auto methodSize = relativeOffsets ? 12 : pointerSize * 3 ;
793- DefineObjCSymbol (DataSymbol, m_typeNames.methodList , " method_list_" + name, start, true );
828+ DefineObjCSymbol (DataSymbol, m_typeNames.methodList , " method_list_" + std::string ( name) , start, true );
794829
795830 for (unsigned i = 0 ; i < head.count ; i++)
796831 {
@@ -806,18 +841,14 @@ void DSCObjCProcessor::ReadMethodList(VMReader* reader, ClassBase& cls, std::str
806841 // --
807842 if (relativeOffsets)
808843 {
809- if (m_customRelativeMethodSelectorBase.has_value ())
810- {
811- meth.name = m_customRelativeMethodSelectorBase.value () + reader->ReadS32 ();
812- meth.types = reader->GetOffset () + reader->ReadS32 ();
813- meth.imp = reader->GetOffset () + reader->ReadS32 ();
814- }
815- else
816- {
817- meth.name = reader->GetOffset () + reader->ReadS32 ();
818- meth.types = reader->GetOffset () + reader->ReadS32 ();
819- meth.imp = reader->GetOffset () + reader->ReadS32 ();
844+ auto selectorBaseOffset = reader->GetOffset ();
845+ if (directSelectors && m_customRelativeMethodSelectorBase.has_value ()) {
846+ selectorBaseOffset = m_customRelativeMethodSelectorBase.value ();
820847 }
848+
849+ meth.name = selectorBaseOffset + reader->Read32 ();
850+ meth.types = reader->GetOffset () + reader->ReadS32 ();
851+ meth.imp = reader->GetOffset () + reader->ReadS32 ();
821852 }
822853 else
823854 {
@@ -881,14 +912,14 @@ void DSCObjCProcessor::ReadMethodList(VMReader* reader, ClassBase& cls, std::str
881912 }
882913}
883914
884- void DSCObjCProcessor::ReadIvarList (VMReader* reader, ClassBase& cls, std::string name, view_ptr_t start)
915+ void DSCObjCProcessor::ReadIvarList (VMReader* reader, ClassBase& cls, std::string_view name, view_ptr_t start)
885916{
886917 reader->Seek (start);
887918 ivar_list_t head;
888919 head.entsizeAndFlags = reader->Read32 ();
889920 head.count = reader->Read32 ();
890921 auto addressSize = m_data->GetAddressSize ();
891- DefineObjCSymbol (DataSymbol, m_typeNames.ivarList , " ivar_list_" + name, start, true );
922+ DefineObjCSymbol (DataSymbol, m_typeNames.ivarList , " ivar_list_" + std::string ( name) , start, true );
892923 if (head.count > 0x1000 )
893924 {
894925 m_logger->LogError (" Ivar list at 0x%llx has an invalid count of 0x%llx" , start, head.count );
@@ -1010,6 +1041,10 @@ void DSCObjCProcessor::GenerateClassTypes()
10101041
10111042bool DSCObjCProcessor::ApplyMethodType (Class& cls, Method& method, bool isInstanceMethod)
10121043{
1044+ if (!method.imp || !m_data->IsValidOffset (method.imp )) {
1045+ return false ;
1046+ }
1047+
10131048 std::stringstream r (method.name );
10141049
10151050 std::string token;
@@ -1221,6 +1256,19 @@ void DSCObjCProcessor::ProcessObjCData(std::shared_ptr<VM> vm, std::string baseN
12211256 m_typeNames.nsuInteger = defineTypedef (m_data, {" NSUInteger" }, Type::IntegerType (addrSize, false ));
12221257 m_typeNames.cgFloat = defineTypedef (m_data, {" CGFloat" }, Type::FloatType (addrSize));
12231258
1259+ Ref<Type> relativeSelectorPtr;
1260+ auto reader = VMReader (vm);
1261+ if (auto objCRelativeMethodsBaseAddr = m_cache->GetObjCRelativeMethodBaseAddress (reader)) {
1262+ m_logger->LogDebug (" RelativeMethodSelector Base: 0x%llx" , objCRelativeMethodsBaseAddr);
1263+ m_customRelativeMethodSelectorBase = objCRelativeMethodsBaseAddr;
1264+
1265+ auto type = TypeBuilder::PointerType (4 , Type::PointerType (addrSize, Type::IntegerType (1 , false )))
1266+ .SetPointerBase (RelativeToConstantPointerBaseType, objCRelativeMethodsBaseAddr)
1267+ .Finalize ();
1268+ auto relativeSelectorPtrName = defineTypedef (m_data, {" relative_SEL" }, type);
1269+ relativeSelectorPtr = Type::NamedType (m_data, relativeSelectorPtrName);
1270+ }
1271+
12241272 // https://github.com/apple-oss-distributions/objc4/blob/196363c165b175ed925ef6b9b99f558717923c47/runtime/objc-abi.h
12251273 EnumerationBuilder imageInfoFlagBuilder;
12261274 imageInfoFlagBuilder.AddMemberWithValue (" IsReplacement" , 1 << 0 );
@@ -1256,7 +1304,7 @@ void DSCObjCProcessor::ProcessObjCData(std::shared_ptr<VM> vm, std::string baseN
12561304 m_typeNames.imageInfo = imageInfoType.first ;
12571305
12581306 StructureBuilder methodEntry;
1259- methodEntry.AddMember (rptr_t , " name" );
1307+ methodEntry.AddMember (relativeSelectorPtr ? relativeSelectorPtr : rptr_t , " name" );
12601308 methodEntry.AddMember (rptr_t , " types" );
12611309 methodEntry.AddMember (rptr_t , " imp" );
12621310 auto type = finalizeStructureBuilder (m_data, methodEntry, " objc_method_entry_t" );
@@ -1360,42 +1408,6 @@ void DSCObjCProcessor::ProcessObjCData(std::shared_ptr<VM> vm, std::string baseN
13601408 protocolBuilder.AddMember (Type::IntegerType (4 , false ), " flags" );
13611409 m_typeNames.protocol = finalizeStructureBuilder (m_data, protocolBuilder, " objc_protocol_t" ).first ;
13621410
1363- auto reader = VMReader (vm);
1364-
1365- if (auto addr = m_cache->GetImageStart (" /usr/lib/libobjc.A.dylib" ))
1366- {
1367- auto header = m_cache->HeaderForAddress (addr.value ());
1368- uint64_t scoffs_addr = 0 ;
1369- size_t scoffs_size = 0 ;
1370-
1371- for (const auto & section : header->sections )
1372- {
1373- char name[17 ];
1374- memcpy (name, section.sectname , 16 );
1375- name[16 ] = 0 ;
1376- if (std::string (name) == " __objc_scoffs" )
1377- {
1378- scoffs_addr = section.addr ;
1379- scoffs_size = section.size ;
1380- break ;
1381- }
1382- }
1383-
1384- if (scoffs_size && scoffs_addr)
1385- {
1386- if (scoffs_size == 0x20 )
1387- {
1388- m_customRelativeMethodSelectorBase = reader.ReadULong (scoffs_addr);
1389- }
1390- else
1391- {
1392- m_customRelativeMethodSelectorBase = reader.ReadULong (scoffs_addr + 8 );
1393- }
1394- m_logger->LogDebug (" RelativeMethodSelector Base: 0x%llx" , m_customRelativeMethodSelectorBase.value ());
1395- }
1396- }
1397-
1398-
13991411 m_data->BeginBulkModifySymbols ();
14001412 if (auto classList = m_data->GetSectionByName (baseName + " ::__objc_classlist" ))
14011413 LoadClasses (&reader, classList);
0 commit comments