void MachOLoader::loadDylibs(const MachO& mach, bool nobind, bool bindLazy) { for (std::string dylib : mach.dylibs()) { // __darwin_dlopen checks if already loaded // automatically adds a reference if so int flags = DARWIN_RTLD_GLOBAL; if (nobind) flags |= __DARLING_RTLD_NOBIND; if (bindLazy) flags |= DARWIN_RTLD_LAZY; else flags |= DARWIN_RTLD_NOW; if (!Darling::DlopenWithContext(dylib.c_str(), flags, m_rpathContext)) { LOG << "Failed to dlopen " << dylib << ", throwing an exception\n"; std::stringstream ss; ss << "Cannot load " << dylib << ": " << __darwin_dlerror(); throw std::runtime_error(ss.str()); } } }
void printBinInfo(const char* path, const char* arch, const char* opt) { MachO* macho = MachO::readFile(path, arch, true); if (!macho) throw std::runtime_error("Load failed"); OpMode opmode = getOpMode(opt); std::cout << "Platform: " << macho->platform() << std::endl; switch (opmode) { case ModeDylibs: { std::cout << "Dylibs:\n"; for (const char* name : macho->dylibs()) { std::cout << "\t" << name << std::endl; } break; } case ModeSymbols: { std::cout << "Symbols:\n"; for (const MachO::Symbol& s : macho->symbols()) { if (!s.addr) continue; std::cout << '\t' << s.name << " at " << "[0x" << std::hex << std::setfill('0'); if (macho->is64()) std::cout << std::setw(16); else std::cout << std::setw(8); std::cout << s.addr << std::setw(0) << std::dec << ']' << std::endl; } break; } case ModeExports: { std::cout << "Exports:\n"; for (const MachO::Export* e : macho->exports()) { std::cout << '\t' << e->name << " at " << "[0x" << std::hex << std::setfill('0'); if (macho->is64()) std::cout << std::setw(16); else std::cout << std::setw(8); std::cout << e->addr << std::setw(0) << "] (flag: " << e->flag << ")" << std::dec << std::endl; } break; } case ModeBinds: { std::cout << "Binds:\n"; for (const MachO::Bind* b : macho->binds()) { std::cout << '\t' << b->name << " at " << "[0x" << std::hex << std::setfill('0'); if (macho->is64()) std::cout << std::setw(16); else std::cout << std::setw(8); std::cout << b->vmaddr << std::setw(0) << "] "; if (!b->is_classic) std::cout << "(addend: " << b->addend; else std::cout << "(value: " << b->value; std::cout << ", type: " << int(b->type) << ", ordinal: " << int(b->ordinal) << ")"; if (b->is_weak) std::cout << 'W'; if (b->is_classic) std::cout << 'C'; if (b->is_lazy) std::cout << 'L'; std::cout << std::dec << std::endl; } break; } case ModeSegments: { std::cout << "Segments:\n" << std::hex; printSegments(macho->segments64()); printSegments(macho->segments()); break; } case ModeRebases: { std::cout << "Rebases:\n"; for (MachO::Rebase* r : macho->rebases()) { std::cout << "\t at [0x" << std::hex << std::setfill('0'); if (macho->is64()) std::cout << std::setw(16); else std::cout << std::setw(8); std::cout << r->vmaddr << std::dec << std::setw(0) << "]\n"; } break; } case ModeRelocations: { std::cout << "External relocations:\n"; for (MachO::Relocation* r : macho->relocations()) { std::cout << '\t' << r->name << " at " << "[0x" << std::hex << std::setfill('0'); if (macho->is64()) std::cout << std::setw(16); else std::cout << std::setw(8); std::cout << r->addr << std::setw(0) << "] "; if (r->pcrel) std::cout << "PC-REL"; std::cout << std::endl; } break; } } delete macho; }
void MachOLoader::loadSegments(const MachO& mach, intptr* slide, intptr* base, ELFBlock* elf) { *base = 0; --*base; if (m_pTrampolineMgr) m_pTrampolineMgr->invalidateMemoryMap(); const std::vector<Segment*>& segments = getSegments(mach); for (Segment* seg : segments) { const char* name = seg->segname; if (!strcmp(name, SEG_PAGEZERO)) continue; LOG << seg->segname << ": " << "fileoff=" << seg->fileoff << ", vmaddr=" << seg->vmaddr <<std::endl; int prot = 0, maxprot = 0; if (seg->initprot & VM_PROT_READ) prot |= PROT_READ; if (seg->initprot & VM_PROT_WRITE) prot |= PROT_WRITE; if (seg->initprot & VM_PROT_EXECUTE) prot |= PROT_EXEC; if (seg->maxprot & VM_PROT_READ) maxprot |= PROT_READ; if (seg->maxprot & VM_PROT_WRITE) maxprot |= PROT_WRITE; if (seg->maxprot & VM_PROT_EXECUTE) maxprot |= PROT_EXEC; intptr filesize = alignMem(seg->filesize, 0x1000); intptr vmaddr = seg->vmaddr + *slide; if (vmaddr < m_last_addr) { LOG << "will rebase: filename=" << mach.filename() << ", vmaddr=" << (void*)vmaddr << ", last_addr=" << (void*)m_last_addr <<std::endl; assert(seg == segments[0]); vmaddr = m_last_addr; *slide = vmaddr - seg->vmaddr; } *base = std::min(*base, vmaddr); intptr vmsize = alignMem(seg->vmsize, 0x1000); LOG << "mmap(file) " << mach.filename() << ' ' << name << ": " << (void*)vmaddr << "-" << (void*)(vmaddr + filesize) << " offset=" << mach.offset() + seg->fileoff <<std::endl; if (filesize == 0) continue; checkMmapMinAddr(vmaddr); void* mapped = ::mmap((void*)vmaddr, filesize, maxprot, MAP_PRIVATE | MAP_FIXED, mach.fd(), mach.offset() + seg->fileoff); m_mprotects.push_back(MProtect{(void*) vmaddr, filesize, prot}); if (mapped == MAP_FAILED) { std::stringstream ss; ss << "Failed to mmap '" << mach.filename() << "': " << strerror(errno); throw std::runtime_error(ss.str()); } assert(vmsize >= filesize); if (vmsize > filesize) { LOG << "mmap(anon) " << mach.filename() << ' ' << name << ": " << (void*)(vmaddr + filesize) << "-" << (void*)(vmaddr + vmsize) <<std::endl; void* mapped = ::mmap(reinterpret_cast<char*>(vmaddr) + filesize, vmsize - filesize, prot, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, 0, 0); if (mapped == MAP_FAILED) { std::stringstream ss; ss << "mmap(anon) failed on '" << mach.filename() << "': " << strerror(errno); throw std::runtime_error(ss.str()); } } m_last_addr = std::max(m_last_addr, (intptr)vmaddr + vmsize); if (elf) elf->addSection(name, (void*)vmaddr, vmsize, 0); } }