Skip to content

Commit f5b572b

Browse files
bdashemesare
authored andcommitted
[SharedCache] Make it faster to look up which image contains an address
`MemoryRegion` now tracks the start address of the image to which it belongs. `SharedCache::HeaderForAddress` uses the existing address range map to quickly find the `MemoryRegion` for a given address, and from there can look up the image via its start address. Some extra logic is added to `CacheInfo::Load` to populate the image start address on `MemoryRegion` when loading from metadata that predates this change. The result is that `HeaderForAddress` is no longer the most expensive part of `FindSymbolAtAddrAndApplyToAddr`.
1 parent e49368b commit f5b572b

File tree

2 files changed

+44
-22
lines changed

2 files changed

+44
-22
lines changed

view/sharedcache/core/SharedCache.cpp

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,6 +1015,7 @@ void SharedCache::PerformInitialLoad(std::lock_guard<std::mutex>& lock)
10151015
sectionRegion.prettyName = imageHeader.value().identifierPrefix + "::" + std::string(segName);
10161016
sectionRegion.start = segment.vmaddr;
10171017
sectionRegion.size = segment.vmsize;
1018+
sectionRegion.imageStart = start.second;
10181019
uint32_t flags = SegmentFlagsFromMachOProtections(segment.initprot, segment.maxprot);
10191020

10201021
// if we're positive we have an entry point for some reason, force the segment
@@ -1529,18 +1530,16 @@ const SharedCacheMachOHeader* SharedCache::HeaderForAddress(uint64_t address)
15291530
if (auto it = m_cacheInfo->headers.find(address); it != m_cacheInfo->headers.end())
15301531
return &it->second;
15311532

1532-
// We _could_ mark each page with the image start? :grimacing emoji:
1533-
// But that'd require mapping pages :grimacing emoji: :grimacing emoji:
1534-
// There's not really any other hacks that could make this faster, that I can think of...
1535-
for (const auto& [start, header] : m_cacheInfo->headers)
1536-
{
1537-
for (const auto& segment : header.segments)
1538-
{
1539-
if (segment.vmaddr <= address && segment.vmaddr + segment.vmsize > address)
1540-
return &header;
1541-
}
1542-
}
1543-
return {};
1533+
auto it = m_cacheInfo->memoryRegions.find(address);
1534+
if (it == m_cacheInfo->memoryRegions.end())
1535+
return nullptr;
1536+
1537+
if (auto headerAddress = it->second.imageStart)
1538+
return HeaderForAddress(headerAddress);
1539+
1540+
// Found a region, but its `imageStart` was 0. This should mean it doesn't belong to an image.
1541+
assert(it->second.type != MemoryRegion::Type::Image);
1542+
return nullptr;
15441543
}
15451544

15461545
std::string SharedCache::NameForAddress(uint64_t address)
@@ -1561,16 +1560,9 @@ std::string SharedCache::ImageNameForAddress(uint64_t address)
15611560

15621561
bool SharedCache::LoadImageContainingAddress(uint64_t address, bool skipObjC)
15631562
{
1564-
for (const auto& [start, header] : m_cacheInfo->headers)
1565-
{
1566-
for (const auto& segment : header.segments)
1567-
{
1568-
if (segment.vmaddr <= address && segment.vmaddr + segment.vmsize > address)
1569-
{
1570-
std::lock_guard lock(m_mutex);
1571-
return LoadImageWithInstallName(lock, header.installName, skipObjC);
1572-
}
1573-
}
1563+
if (auto header = HeaderForAddress(address)) {
1564+
std::lock_guard lock(m_mutex);
1565+
return LoadImageWithInstallName(lock, header->installName, skipObjC);
15741566
}
15751567

15761568
return false;
@@ -3387,6 +3379,29 @@ std::optional<SharedCache::CacheInfo> SharedCache::CacheInfo::Load(Deserializati
33873379
cacheInfo.MSL(objcOptimizationDataRange);
33883380
cacheInfo.MSL(baseFilePath);
33893381
cacheInfo.MSL_CAST(cacheFormat, uint8_t, SharedCacheFormat);
3382+
3383+
// Older metadata may be missing the `imageStart` field on `MemoryRegion`.
3384+
bool regionsMissingImageStart =
3385+
std::any_of(cacheInfo.memoryRegions.begin(), cacheInfo.memoryRegions.end(), [](const auto& pair) {
3386+
const auto& region = pair.second;
3387+
return region.type == MemoryRegion::Type::Image && region.imageStart == 0;
3388+
});
3389+
3390+
if (regionsMissingImageStart)
3391+
{
3392+
for (const auto& [start, header] : cacheInfo.headers)
3393+
{
3394+
for (const auto& segment : header.segments)
3395+
{
3396+
const auto regionIt = cacheInfo.memoryRegions.find(segment.vmaddr);
3397+
assert(regionIt != cacheInfo.memoryRegions.end());
3398+
auto& region = regionIt->second;
3399+
assert(!region.imageStart || region.imageStart == start);
3400+
region.imageStart = start;
3401+
}
3402+
}
3403+
}
3404+
33903405
return cacheInfo;
33913406
}
33923407
void State::Store(SerializationContext& context, std::optional<DSCViewState> viewState) const

view/sharedcache/core/SharedCache.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ namespace SharedCacheCore {
4141
std::string prettyName;
4242
uint64_t start;
4343
uint64_t size;
44+
// Start address of the image this region belongs to.
45+
// 0 if the region does not belong to any image.
46+
uint64_t imageStart = 0;
4447
BNSegmentFlag flags;
4548
Type type;
4649

@@ -55,6 +58,7 @@ namespace SharedCacheCore {
5558
MSS(prettyName);
5659
MSS(start);
5760
MSS(size);
61+
MSS(imageStart);
5862
MSS_CAST(flags, uint64_t);
5963
MSS_CAST(type, uint8_t);
6064
}
@@ -67,6 +71,9 @@ namespace SharedCacheCore {
6771
region.MSL(size);
6872
region.MSL_CAST(flags, uint64_t, BNSegmentFlag);
6973
region.MSL_CAST(type, uint8_t, Type);
74+
if (context.doc.HasMember("imageStart"))
75+
region.MSL(imageStart);
76+
7077
return region;
7178
}
7279
};

0 commit comments

Comments
 (0)