#include <stdlib.h>
#include "dsc_iterator.h"
#include "dyld_cache_format.h"
#define NO_ULEB
#include "Architectures.hpp"
#include "MachOFileAbstraction.hpp"
#include "CacheFileAbstraction.hpp"
namespace dyld {
template <typename E>
const uint8_t* mappedAddress(const uint8_t* cache, uint64_t addr)
{
const dyldCacheHeader<E>* header = (dyldCacheHeader<E>*)cache;
const dyldCacheFileMapping<E>* mappings = (dyldCacheFileMapping<E>*)&cache[header->mappingOffset()];
for (uint32_t i=0; i < header->mappingCount(); ++i) {
if ( (mappings[i].address() <= addr) && (addr < (mappings[i].address() + mappings[i].size())) ) {
return &cache[mappings[i].file_offset() + addr - mappings[i].address()];
}
}
return NULL;
}
template <typename A>
void walkSegments(const uint8_t* cache, const char* dylibPath, const uint8_t* machHeader, dyld_shared_cache_iterator_t callback)
{
typedef typename A::P P;
typedef typename A::P::E E;
const macho_header<P>* mh = (const macho_header<P>*)machHeader;
const macho_load_command<P>* const cmds = (macho_load_command<P>*)(machHeader + sizeof(macho_header<P>));
const uint32_t cmd_count = mh->ncmds();
const macho_load_command<P>* cmd = cmds;
for (uint32_t i = 0; i < cmd_count; ++i) {
if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
macho_segment_command<P>* segCmd = (macho_segment_command<P>*)cmd;
const uint8_t* segStartInCache = mappedAddress<E>(cache, segCmd->vmaddr());
uint64_t fileOffset = segStartInCache - cache;
callback(dylibPath, segCmd->segname(), fileOffset, segCmd->vmsize());
}
cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
}
}
template <typename A>
int walkImages(const uint8_t* cache, dyld_shared_cache_iterator_t callback)
{
typedef typename A::P::E E;
const dyldCacheHeader<E>* header = (dyldCacheHeader<E>*)cache;
const dyldCacheImageInfo<E>* dylibs = (dyldCacheImageInfo<E>*)&cache[header->imagesOffset()];
for (uint32_t i=0; i < header->imagesCount(); ++i) {
const char* dylibPath = (char*)cache + dylibs[i].pathFileOffset();
const uint8_t* machHeader = mappedAddress<E>(cache, dylibs[i].address());
walkSegments<A>(cache, dylibPath, machHeader, callback);
}
return 0;
}
}
int dyld_shared_cache_iterate_segments(const void* shared_cache_file, dyld_shared_cache_iterator_t callback)
{
const uint8_t* cache = (uint8_t*)shared_cache_file;
if ( strcmp((char*)cache, "dyld_v1 i386") == 0 )
return dyld::walkImages<x86>(cache, callback);
else if ( strcmp((char*)cache, "dyld_v1 x86_64") == 0 )
return dyld::walkImages<x86_64>(cache, callback);
else if ( strcmp((char*)cache, "dyld_v1 ppc") == 0 )
return dyld::walkImages<ppc>(cache, callback);
else
return -1;
}