Skip to content

Commit

Permalink
[SharedCache] Optimize parsing of slide info
Browse files Browse the repository at this point in the history
Slide info is parsed and applied on the main thread, below the
`SharedCache` constructor, when a shared cache is opened. Time spent
applying the slide is time that the main thread is blocked. This
collection of optimizations cuts the time spent applying the slide
roughly in half (125ms to 65ms on a macOS shared cache).

The individual changes are:
1. Avoid building the rewrites vector unless `SLIDEINFO_DEBUG_TAGS` is
   enabled. Building the vector was the single most expensive operation
   in the function.
2. Read slide pointers via `ReadULong` rather than the variable-length
   `Read` method. The compiler isn't able to eliminate the call to
   `memcpy` in the variable-length `Read` function, and the function
   call overhead is significant given the small size of the read and
   number of times it is called.
3. Update `ParseAndApplySlideInfoForFile` to take a pointer rather than
   a `std::shared_ptr`. This method doesn't need to manipulate the
   ownership of the object so the `shared_ptr` is unnecessary.
  • Loading branch information
bdash committed Jan 15, 2025
1 parent 17158e9 commit a554405
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 22 deletions.
41 changes: 21 additions & 20 deletions view/sharedcache/core/SharedCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -976,7 +976,7 @@ std::shared_ptr<VM> SharedCache::GetVMMap(bool mapPages)
{
vm->MapPages(m_dscView, m_dscView->GetFile()->GetSessionId(), mapping.address, mapping.fileOffset, mapping.size, cache.path,
[this, vm=vm](std::shared_ptr<MMappedFileAccessor> mmap){
ParseAndApplySlideInfoForFile(mmap);
ParseAndApplySlideInfoForFile(mmap.get());
});
}
}
Expand Down Expand Up @@ -1026,13 +1026,12 @@ std::string to_hex_string(uint64_t value)
}


void SharedCache::ParseAndApplySlideInfoForFile(std::shared_ptr<MMappedFileAccessor> file)
void SharedCache::ParseAndApplySlideInfoForFile(MMappedFileAccessor* file)
{
if (file->SlideInfoWasApplied())
return;

WillMutateState();
std::vector<std::pair<uint64_t, uint64_t>> rewrites;

dyld_cache_header baseHeader;
file->Read(&baseHeader, 0, sizeof(dyld_cache_header));
Expand Down Expand Up @@ -1139,6 +1138,10 @@ void SharedCache::ParseAndApplySlideInfoForFile(std::shared_ptr<MMappedFileAcces
return;
}

#ifdef SLIDEINFO_DEBUG_TAGS
std::vector<std::pair<uint64_t, uint64_t>> rewrites;
#endif

for (const auto& [off, mapping] : mappings)
{
m_logger->LogDebug("Slide Info Version: %d", mapping.slideInfoVersion);
Expand Down Expand Up @@ -1190,7 +1193,7 @@ void SharedCache::ParseAndApplySlideInfoForFile(std::shared_ptr<MMappedFileAcces
value += slideAmount;
}
pageOffset += delta;
rewrites.emplace_back(loc, value);
file->WritePointer(loc, value);
}
catch (MappingReadException& ex)
{
Expand Down Expand Up @@ -1260,23 +1263,22 @@ void SharedCache::ParseAndApplySlideInfoForFile(std::shared_ptr<MMappedFileAcces
loc += delta * sizeof(dyld_cache_slide_pointer3);
try
{
dyld_cache_slide_pointer3 slideInfo;
file->Read(&slideInfo, loc, sizeof(slideInfo));
dyld_cache_slide_pointer3 slideInfo = { .raw = file->ReadULong(loc) };
delta = slideInfo.plain.offsetToNextPointer;

if (slideInfo.auth.authenticated)
{
uint64_t value = slideInfo.auth.offsetFromSharedCacheBase;
value += mapping.slideInfoV3.auth_value_add;
rewrites.emplace_back(loc, value);
file->WritePointer(loc, value);
}
else
{
uint64_t value51 = slideInfo.plain.pointerValue;
uint64_t top8Bits = value51 & 0x0007F80000000000;
uint64_t bottom43Bits = value51 & 0x000007FFFFFFFFFF;
uint64_t value = (uint64_t)top8Bits << 13 | bottom43Bits;
rewrites.emplace_back(loc, value);
file->WritePointer(loc, value);
}
}
catch (MappingReadException& ex)
Expand Down Expand Up @@ -1315,18 +1317,17 @@ void SharedCache::ParseAndApplySlideInfoForFile(std::shared_ptr<MMappedFileAcces
loc += delta * sizeof(dyld_cache_slide_pointer5);
try
{
dyld_cache_slide_pointer5 slideInfo;
file->Read(&slideInfo, loc, sizeof(slideInfo));
dyld_cache_slide_pointer5 slideInfo = { .raw = file->ReadULong(loc) };
delta = slideInfo.regular.next;
if (slideInfo.auth.auth)
{
uint64_t value = mapping.slideInfoV5.value_add + slideInfo.auth.runtimeOffset;
rewrites.emplace_back(loc, value);
file->WritePointer(loc, value);
}
else
{
uint64_t value = mapping.slideInfoV5.value_add + slideInfo.regular.runtimeOffset;
rewrites.emplace_back(loc, value);
file->WritePointer(loc, value);
}
}
catch (MappingReadException& ex)
Expand All @@ -1343,10 +1344,10 @@ void SharedCache::ParseAndApplySlideInfoForFile(std::shared_ptr<MMappedFileAcces
}
}
}

#ifdef SLIDEINFO_DEBUG_TAGS
for (const auto& [loc, value] : rewrites)
{
file->WritePointer(loc, value);
#ifdef SLIDEINFO_DEBUG_TAGS
uint64_t vmAddr = 0;
{
for (uint64_t off = baseHeader.mappingOffset; off < baseHeader.mappingOffset + baseHeader.mappingCount * sizeof(dyld_cache_mapping_info); off += sizeof(dyld_cache_mapping_info))
Expand All @@ -1367,9 +1368,9 @@ void SharedCache::ParseAndApplySlideInfoForFile(std::shared_ptr<MMappedFileAcces
type = m_dscView->GetTagType("slideinfo");
}
m_dscView->AddAutoDataTag(vmAddr, new Tag(type, "0x" + to_hex_string(file->ReadULong(loc)) + " => 0x" + to_hex_string(value)));
#endif
}
m_logger->LogDebug("Applied slide info for %s (0x%llx rewrites)", file->Path().c_str(), rewrites.size());
#endif
file->SetSlideInfoWasApplied(true);
}

Expand Down Expand Up @@ -1582,7 +1583,7 @@ bool SharedCache::LoadSectionAtAddress(uint64_t address)
}
m_logger->LogInfo("Loading stub island %s @ 0x%llx", stubIsland.prettyName.c_str(), stubIsland.start);
auto targetFile = vm->MappingAtAddress(stubIsland.start).first.fileAccessor->lock();
ParseAndApplySlideInfoForFile(targetFile);
ParseAndApplySlideInfoForFile(targetFile.get());
auto reader = VMReader(vm);
auto buff = reader.ReadBuffer(stubIsland.start, stubIsland.size);
auto rawViewEnd = m_dscView->GetParentView()->GetEnd();
Expand Down Expand Up @@ -1622,7 +1623,7 @@ bool SharedCache::LoadSectionAtAddress(uint64_t address)
}
m_logger->LogInfo("Loading dyld data %s", dyldData.prettyName.c_str());
auto targetFile = vm->MappingAtAddress(dyldData.start).first.fileAccessor->lock();
ParseAndApplySlideInfoForFile(targetFile);
ParseAndApplySlideInfoForFile(targetFile.get());
auto reader = VMReader(vm);
auto buff = reader.ReadBuffer(dyldData.start, dyldData.size);
auto rawViewEnd = m_dscView->GetParentView()->GetEnd();
Expand Down Expand Up @@ -1661,7 +1662,7 @@ bool SharedCache::LoadSectionAtAddress(uint64_t address)
}
m_logger->LogInfo("Loading non-image region %s", region.prettyName.c_str());
auto targetFile = vm->MappingAtAddress(region.start).first.fileAccessor->lock();
ParseAndApplySlideInfoForFile(targetFile);
ParseAndApplySlideInfoForFile(targetFile.get());
auto reader = VMReader(vm);
auto buff = reader.ReadBuffer(region.start, region.size);
auto rawViewEnd = m_dscView->GetParentView()->GetEnd();
Expand Down Expand Up @@ -1700,7 +1701,7 @@ bool SharedCache::LoadSectionAtAddress(uint64_t address)
m_logger->LogDebug("Partial loading image %s", targetHeader.installName.c_str());

auto targetFile = vm->MappingAtAddress(targetSegment->start).first.fileAccessor->lock();
ParseAndApplySlideInfoForFile(targetFile);
ParseAndApplySlideInfoForFile(targetFile.get());
auto buff = reader.ReadBuffer(targetSegment->start, targetSegment->size);
m_dscView->GetParentView()->GetParentView()->WriteBuffer(
m_dscView->GetParentView()->GetParentView()->GetEnd(), buff);
Expand Down Expand Up @@ -1858,7 +1859,7 @@ bool SharedCache::LoadImageWithInstallName(std::string installName, bool skipObj
}

auto targetFile = vm->MappingAtAddress(region.start).first.fileAccessor->lock();
ParseAndApplySlideInfoForFile(targetFile);
ParseAndApplySlideInfoForFile(targetFile.get());

auto rawViewEnd = m_dscView->GetParentView()->GetEnd();

Expand Down
4 changes: 2 additions & 2 deletions view/sharedcache/core/SharedCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ namespace SharedCacheCore {

struct MappingInfo
{
std::shared_ptr<MMappedFileAccessor> file;
MMappedFileAccessor* file;
dyld_cache_mapping_info mappingInfo;
uint32_t slideInfoVersion;
dyld_cache_slide_info_v2 slideInfoV2;
Expand Down Expand Up @@ -582,7 +582,7 @@ namespace SharedCacheCore {
static uint64_t FastGetBackingCacheCount(BinaryNinja::Ref<BinaryNinja::BinaryView> dscView);
bool SaveToDSCView();

void ParseAndApplySlideInfoForFile(std::shared_ptr<MMappedFileAccessor> file);
void ParseAndApplySlideInfoForFile(MMappedFileAccessor* file);
std::optional<uint64_t> GetImageStart(std::string installName);
std::optional<SharedCacheMachOHeader> HeaderForAddress(uint64_t);
bool LoadImageWithInstallName(std::string installName, bool skipObjC);
Expand Down

0 comments on commit a554405

Please sign in to comment.