Skip to content

Commit

Permalink
Merge remote-tracking branch 'bdash/dsc-relative-selectors-mac' into …
Browse files Browse the repository at this point in the history
…dsc-proposed
  • Loading branch information
bdash committed Nov 30, 2024
2 parents f324553 + 726d6fb commit 24fd842
Show file tree
Hide file tree
Showing 6 changed files with 321 additions and 218 deletions.
18 changes: 16 additions & 2 deletions view/sharedcache/core/DSCView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,15 @@ bool DSCView::Init()
"\t\tuint64_t rosettaReadWriteSize;\t// maximum size of the Rosetta read-write region\n"
"\t\tuint32_t imagesOffset;\t\t\t// file offset to first dyld_cache_image_info\n"
"\t\tuint32_t imagesCount;\t\t\t// number of dyld_cache_image_info entries\n"
"\t\tuint32_t cacheSubType; // 0 for development, 1 for production, when cacheType is multi-cache(2)\n"
"\t\tuint64_t objcOptsOffset; // VM offset from cache_header* to ObjC optimizations header\n"
"\t\tuint64_t objcOptsSize; // size of ObjC optimizations header\n"
"\t\tuint64_t cacheAtlasOffset; // VM offset from cache_header* to embedded cache atlas for process introspection\n"
"\t\tuint64_t cacheAtlasSize; // size of embedded cache atlas\n"
"\t\tuint64_t dynamicDataOffset; // VM offset from cache_header* to the location of dyld_cache_dynamic_data_header\n"
"\t\tuint64_t dynamicDataMaxSize; // maximum size of space reserved from dynamic data\n"
"\t\tuint32_t tproMappingsOffset; // file offset to first dyld_cache_tpro_mapping_info\n"
"\t\tuint32_t tproMappingsCount; // number of dyld_cache_tpro_mapping_info entries\n"
"\t};", headerType, err);

Ref<Settings> settings = GetLoadSettings(GetTypeName());
Expand Down Expand Up @@ -732,8 +741,13 @@ bool DSCView::Init()
return false;
}

AddAutoSegment(primaryBase, 0x200, 0, 0x200, SegmentReadable);
AddAutoSection("__dsc_header", primaryBase, 0x200, ReadOnlyCodeSectionSemantics);
uint64_t headerSize = std::min(basePointer, headerType.type->GetWidth());
// Truncate the `dyld_cache_header` structure to the structure present in the cache file.
auto newStructure = StructureBuilder(headerType.type->GetStructure()).SetWidth(headerSize).Finalize();
headerType.type = TypeBuilder::StructureType(newStructure).Finalize();

AddAutoSegment(primaryBase, headerSize, 0, headerSize, SegmentReadable);
AddAutoSection("__dsc_header", primaryBase, headerSize, ReadOnlyDataSectionSemantics);
DefineType("dyld_cache_header", headerType.name, headerType.type);
DefineAutoSymbolAndVariableOrFunction(GetDefaultPlatform(), new Symbol(DataSymbol, "primary_cache_header", primaryBase), headerType.type);

Expand Down
116 changes: 64 additions & 52 deletions view/sharedcache/core/ObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -775,22 +775,57 @@ void DSCObjCProcessor::LoadProtocols(VMReader* reader, Ref<Section> listSection)
}
}

void DSCObjCProcessor::ReadMethodList(VMReader* reader, ClassBase& cls, std::string name, view_ptr_t start)
void DSCObjCProcessor::ReadListOfMethodLists(VMReader* reader, ClassBase& cls, std::string_view name, view_ptr_t start)
{
reader->Seek(start);
method_list_t head;
head.entsizeAndFlags = reader->Read32();
head.count = reader->Read32();
if (head.count > 0x1000)
{
m_logger->LogError("List of method lists at 0x%llx has an invalid count of 0x%x", start, head.count);
return;
}

for (size_t i = 0; i < head.count; ++i) {
relative_list_list_entry_t list_entry;
reader->Read(&list_entry, sizeof(list_entry));

ReadMethodList(reader, cls, name, reader->GetOffset() - sizeof(list_entry) + list_entry.listOffset);
// Reset the cursor to immediately past the list entry.
reader->Seek(start + sizeof(method_list_t) + ((i + 1) * sizeof(relative_list_list_entry_t)));
}
}

void DSCObjCProcessor::ReadMethodList(VMReader* reader, ClassBase& cls, std::string_view name, view_ptr_t start)
{
// Lower two bits indicate the type of method list.
switch (start & 0b11) {
case 0:
break;
case 1:
return ReadListOfMethodLists(reader, cls, name, start - 1);
default:
m_logger->LogDebug("ReadMethodList: Unknown method list type at 0x%llx: %d", start, start & 0x3);
return;
}

reader->Seek(start);
method_list_t head;
head.entsizeAndFlags = reader->Read32();
head.count = reader->Read32();

if (head.count > 0x1000)
{
m_logger->LogError("Method list at 0x%llx has an invalid count of 0x%x", start, head.count);
return;
}

uint64_t pointerSize = m_data->GetAddressSize();
bool relativeOffsets = (head.entsizeAndFlags & 0xFFFF0000) & 0x80000000;
bool directSelectors = (head.entsizeAndFlags & 0xFFFF0000) & 0x40000000;
auto methodSize = relativeOffsets ? 12 : pointerSize * 3;
DefineObjCSymbol(DataSymbol, m_typeNames.methodList, "method_list_" + name, start, true);
DefineObjCSymbol(DataSymbol, m_typeNames.methodList, "method_list_" + std::string(name), start, true);

for (unsigned i = 0; i < head.count; i++)
{
Expand All @@ -806,18 +841,14 @@ void DSCObjCProcessor::ReadMethodList(VMReader* reader, ClassBase& cls, std::str
// --
if (relativeOffsets)
{
if (m_customRelativeMethodSelectorBase.has_value())
{
meth.name = m_customRelativeMethodSelectorBase.value() + reader->ReadS32();
meth.types = reader->GetOffset() + reader->ReadS32();
meth.imp = reader->GetOffset() + reader->ReadS32();
}
else
{
meth.name = reader->GetOffset() + reader->ReadS32();
meth.types = reader->GetOffset() + reader->ReadS32();
meth.imp = reader->GetOffset() + reader->ReadS32();
auto selectorBaseOffset = reader->GetOffset();
if (directSelectors && m_customRelativeMethodSelectorBase.has_value()) {
selectorBaseOffset = m_customRelativeMethodSelectorBase.value();
}

meth.name = selectorBaseOffset + reader->Read32();
meth.types = reader->GetOffset() + reader->ReadS32();
meth.imp = reader->GetOffset() + reader->ReadS32();
}
else
{
Expand Down Expand Up @@ -881,14 +912,14 @@ void DSCObjCProcessor::ReadMethodList(VMReader* reader, ClassBase& cls, std::str
}
}

void DSCObjCProcessor::ReadIvarList(VMReader* reader, ClassBase& cls, std::string name, view_ptr_t start)
void DSCObjCProcessor::ReadIvarList(VMReader* reader, ClassBase& cls, std::string_view name, view_ptr_t start)
{
reader->Seek(start);
ivar_list_t head;
head.entsizeAndFlags = reader->Read32();
head.count = reader->Read32();
auto addressSize = m_data->GetAddressSize();
DefineObjCSymbol(DataSymbol, m_typeNames.ivarList, "ivar_list_" + name, start, true);
DefineObjCSymbol(DataSymbol, m_typeNames.ivarList, "ivar_list_" + std::string(name), start, true);
if (head.count > 0x1000)
{
m_logger->LogError("Ivar list at 0x%llx has an invalid count of 0x%llx", start, head.count);
Expand Down Expand Up @@ -1010,6 +1041,10 @@ void DSCObjCProcessor::GenerateClassTypes()

bool DSCObjCProcessor::ApplyMethodType(Class& cls, Method& method, bool isInstanceMethod)
{
if (!method.imp || !m_data->IsValidOffset(method.imp)) {
return false;
}

std::stringstream r(method.name);

std::string token;
Expand Down Expand Up @@ -1221,6 +1256,19 @@ void DSCObjCProcessor::ProcessObjCData(std::shared_ptr<VM> vm, std::string baseN
m_typeNames.nsuInteger = defineTypedef(m_data, {"NSUInteger"}, Type::IntegerType(addrSize, false));
m_typeNames.cgFloat = defineTypedef(m_data, {"CGFloat"}, Type::FloatType(addrSize));

Ref<Type> relativeSelectorPtr;
auto reader = VMReader(vm);
if (auto objCRelativeMethodsBaseAddr = m_cache->GetObjCRelativeMethodBaseAddress(reader)) {
m_logger->LogDebug("RelativeMethodSelector Base: 0x%llx", objCRelativeMethodsBaseAddr);
m_customRelativeMethodSelectorBase = objCRelativeMethodsBaseAddr;

auto type = TypeBuilder::PointerType(4, Type::PointerType(addrSize, Type::IntegerType(1, false)))
.SetPointerBase(RelativeToConstantPointerBaseType, objCRelativeMethodsBaseAddr)
.Finalize();
auto relativeSelectorPtrName = defineTypedef(m_data, {"relative_SEL"}, type);
relativeSelectorPtr = Type::NamedType(m_data, relativeSelectorPtrName);
}

// https://github.com/apple-oss-distributions/objc4/blob/196363c165b175ed925ef6b9b99f558717923c47/runtime/objc-abi.h
EnumerationBuilder imageInfoFlagBuilder;
imageInfoFlagBuilder.AddMemberWithValue("IsReplacement", 1 << 0);
Expand Down Expand Up @@ -1256,7 +1304,7 @@ void DSCObjCProcessor::ProcessObjCData(std::shared_ptr<VM> vm, std::string baseN
m_typeNames.imageInfo = imageInfoType.first;

StructureBuilder methodEntry;
methodEntry.AddMember(rptr_t, "name");
methodEntry.AddMember(relativeSelectorPtr ? relativeSelectorPtr : rptr_t, "name");
methodEntry.AddMember(rptr_t, "types");
methodEntry.AddMember(rptr_t, "imp");
auto type = finalizeStructureBuilder(m_data, methodEntry, "objc_method_entry_t");
Expand Down Expand Up @@ -1360,42 +1408,6 @@ void DSCObjCProcessor::ProcessObjCData(std::shared_ptr<VM> vm, std::string baseN
protocolBuilder.AddMember(Type::IntegerType(4, false), "flags");
m_typeNames.protocol = finalizeStructureBuilder(m_data, protocolBuilder, "objc_protocol_t").first;

auto reader = VMReader(vm);

if (auto addr = m_cache->GetImageStart("/usr/lib/libobjc.A.dylib"))
{
auto header = m_cache->HeaderForAddress(addr.value());
uint64_t scoffs_addr = 0;
size_t scoffs_size = 0;

for (const auto& section : header->sections)
{
char name[17];
memcpy(name, section.sectname, 16);
name[16] = 0;
if (std::string(name) == "__objc_scoffs")
{
scoffs_addr = section.addr;
scoffs_size = section.size;
break;
}
}

if (scoffs_size && scoffs_addr)
{
if (scoffs_size == 0x20)
{
m_customRelativeMethodSelectorBase = reader.ReadULong(scoffs_addr);
}
else
{
m_customRelativeMethodSelectorBase = reader.ReadULong(scoffs_addr + 8);
}
m_logger->LogDebug("RelativeMethodSelector Base: 0x%llx", m_customRelativeMethodSelectorBase.value());
}
}


m_data->BeginBulkModifySymbols();
if (auto classList = m_data->GetSectionByName(baseName + "::__objc_classlist"))
LoadClasses(&reader, classList);
Expand Down
9 changes: 7 additions & 2 deletions view/sharedcache/core/ObjC.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ namespace DSCObjC {
typedef struct {
uint64_t count;
} protocol_list_t;
struct relative_list_list_entry_t {
uint64_t imageIndex: 16;
int64_t listOffset: 48;
};
typedef struct {
view_ptr_t isa;
view_ptr_t mangledName;
Expand Down Expand Up @@ -214,8 +218,9 @@ namespace DSCObjC {
std::vector<QualifiedNameOrType> ParseEncodedType(const std::string& type);
void DefineObjCSymbol(BNSymbolType symbolType, QualifiedName typeName, const std::string& name, uint64_t addr, bool deferred);
void DefineObjCSymbol(BNSymbolType symbolType, Ref<Type> type, const std::string& name, uint64_t addr, bool deferred);
void ReadIvarList(VMReader* reader, ClassBase& cls, std::string name, view_ptr_t start);
void ReadMethodList(VMReader* reader, ClassBase& cls, std::string name, view_ptr_t start);
void ReadIvarList(VMReader* reader, ClassBase& cls, std::string_view name, view_ptr_t start);
void ReadMethodList(VMReader* reader, ClassBase& cls, std::string_view name, view_ptr_t start);
void ReadListOfMethodLists(VMReader* reader, ClassBase& cls, std::string_view name, view_ptr_t start);
void LoadClasses(VMReader* reader, Ref<Section> listSection);
void LoadCategories(VMReader* reader, Ref<Section> listSection);
void LoadProtocols(VMReader* reader, Ref<Section> listSection);
Expand Down
Loading

0 comments on commit 24fd842

Please sign in to comment.