| 248 | } |
| 249 | |
| 250 | bool SharedCache::ProcessEntryImage(const std::string& path, const dyld_cache_image_info& info) |
| 251 | { |
| 252 | auto imageHeader = SharedCacheMachOHeader::ParseHeaderForAddress(m_vm, info.address, path); |
| 253 | if (!imageHeader.has_value()) |
| 254 | return false; |
| 255 | |
| 256 | // Add the image to the cache. |
| 257 | CacheImage image; |
| 258 | image.headerAddress = info.address; |
| 259 | image.path = path; |
| 260 | |
| 261 | // Add all image regions. |
| 262 | for (const auto& segment : imageHeader->segments) |
| 263 | { |
| 264 | char segName[17]; |
| 265 | memcpy(segName, segment.segname, 16); |
| 266 | segName[16] = 0; |
| 267 | |
| 268 | // Many images include a __LINKEDIT segment that share a single region in the shared cache. |
| 269 | // Reuse the same `MemoryRegion` to represent all of these link edit regions. |
| 270 | // Check to see if we have a shared region, if so skip it. |
| 271 | if (std::string(segName) == "__LINKEDIT") |
| 272 | { |
| 273 | // TODO: Loosen this to any shared region? |
| 274 | if (const auto linkEditRegion = GetRegionAt(segment.vmaddr)) |
| 275 | { |
| 276 | image.regionStarts.push_back(linkEditRegion->start); |
| 277 | continue; |
| 278 | } |
| 279 | } |
| 280 | |
| 281 | CacheRegion sectionRegion; |
| 282 | sectionRegion.type = CacheRegionType::Image; |
| 283 | sectionRegion.name = imageHeader->identifierPrefix + "::" + std::string(segName); |
| 284 | sectionRegion.start = segment.vmaddr; |
| 285 | sectionRegion.size = segment.vmsize; |
| 286 | // Associate this region with this image, this makes it easier to identify what image owns this region. |
| 287 | sectionRegion.imageStart = image.headerAddress; |
| 288 | |
| 289 | uint32_t flags = SegmentFlagsFromMachOProtections(segment.initprot, segment.maxprot); |
| 290 | // if we're positive we have an entry point for some reason, force the segment |
| 291 | // executable. this helps with kernel images. |
| 292 | for (const auto& entryPoint : imageHeader->m_entryPoints) |
| 293 | if (segment.vmaddr <= entryPoint && (entryPoint < (segment.vmaddr + segment.filesize))) |
| 294 | flags |= SegmentExecutable; |
| 295 | sectionRegion.flags = static_cast<BNSegmentFlag>(flags); |
| 296 | |
| 297 | image.regionStarts.push_back(sectionRegion.start); |
| 298 | // Add the image section to the cache and also to the image region starts |
| 299 | AddRegion(std::move(sectionRegion)); |
| 300 | } |
| 301 | |
| 302 | // Add the exported symbols to the available symbols. |
| 303 | std::vector<CacheSymbol> exportSymbols = imageHeader->ReadExportSymbolTrie(*m_vm); |
| 304 | AddSymbols(std::move(exportSymbols)); |
| 305 | |
| 306 | // This is behind a shared pointer as the header itself is very large. |
| 307 | image.header = std::make_shared<SharedCacheMachOHeader>(std::move(*imageHeader)); |
nothing calls this directly
no test coverage detected