X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FObject%2FMachOObjectFile.cpp;h=260e7557f433547c19f10fa4698fae19b16d7608;hb=8175be535acfffc3977231f58382a07e554d8d6b;hp=cd9c06ba24efe79ef2d0a36f0d5b205eda630559;hpb=58d03b3e08209bfda60d5575d3bdd91b8f325d85;p=oota-llvm.git diff --git a/lib/Object/MachOObjectFile.cpp b/lib/Object/MachOObjectFile.cpp index cd9c06ba24e..260e7557f43 100644 --- a/lib/Object/MachOObjectFile.cpp +++ b/lib/Object/MachOObjectFile.cpp @@ -14,10 +14,14 @@ #include "llvm/Object/MachO.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/Format.h" #include "llvm/Support/Host.h" +#include "llvm/Support/LEB128.h" +#include "llvm/Support/MachO.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include @@ -27,220 +31,19 @@ using namespace llvm; using namespace object; -namespace llvm { - -namespace object { - -struct nlist_base { - uint32_t n_strx; - uint8_t n_type; - uint8_t n_sect; - uint16_t n_desc; -}; - -struct section_base { - char sectname[16]; - char segname[16]; -}; - -template -static void SwapStruct(T &Value); - -template<> -void SwapStruct(MachO::any_relocation_info &H) { - sys::swapByteOrder(H.r_word0); - sys::swapByteOrder(H.r_word1); -} - -template<> -void SwapStruct(MachO::load_command &L) { - sys::swapByteOrder(L.cmd); - sys::swapByteOrder(L.cmdsize); -} - -template<> -void SwapStruct(nlist_base &S) { - sys::swapByteOrder(S.n_strx); - sys::swapByteOrder(S.n_desc); -} - -template<> -void SwapStruct(MachO::section &S) { - sys::swapByteOrder(S.addr); - sys::swapByteOrder(S.size); - sys::swapByteOrder(S.offset); - sys::swapByteOrder(S.align); - sys::swapByteOrder(S.reloff); - sys::swapByteOrder(S.nreloc); - sys::swapByteOrder(S.flags); - sys::swapByteOrder(S.reserved1); - sys::swapByteOrder(S.reserved2); -} - -template<> -void SwapStruct(MachO::section_64 &S) { - sys::swapByteOrder(S.addr); - sys::swapByteOrder(S.size); - sys::swapByteOrder(S.offset); - sys::swapByteOrder(S.align); - sys::swapByteOrder(S.reloff); - sys::swapByteOrder(S.nreloc); - sys::swapByteOrder(S.flags); - sys::swapByteOrder(S.reserved1); - sys::swapByteOrder(S.reserved2); - sys::swapByteOrder(S.reserved3); -} - -template<> -void SwapStruct(MachO::nlist &S) { - sys::swapByteOrder(S.n_strx); - sys::swapByteOrder(S.n_desc); - sys::swapByteOrder(S.n_value); -} - -template<> -void SwapStruct(MachO::nlist_64 &S) { - sys::swapByteOrder(S.n_strx); - sys::swapByteOrder(S.n_desc); - sys::swapByteOrder(S.n_value); -} - -template<> -void SwapStruct(MachO::mach_header &H) { - sys::swapByteOrder(H.magic); - sys::swapByteOrder(H.cputype); - sys::swapByteOrder(H.cpusubtype); - sys::swapByteOrder(H.filetype); - sys::swapByteOrder(H.ncmds); - sys::swapByteOrder(H.sizeofcmds); - sys::swapByteOrder(H.flags); -} - -template<> -void SwapStruct(MachO::mach_header_64 &H) { - sys::swapByteOrder(H.magic); - sys::swapByteOrder(H.cputype); - sys::swapByteOrder(H.cpusubtype); - sys::swapByteOrder(H.filetype); - sys::swapByteOrder(H.ncmds); - sys::swapByteOrder(H.sizeofcmds); - sys::swapByteOrder(H.flags); - sys::swapByteOrder(H.reserved); -} - -template<> -void SwapStruct(MachO::symtab_command &C) { - sys::swapByteOrder(C.cmd); - sys::swapByteOrder(C.cmdsize); - sys::swapByteOrder(C.symoff); - sys::swapByteOrder(C.nsyms); - sys::swapByteOrder(C.stroff); - sys::swapByteOrder(C.strsize); -} - -template<> -void SwapStruct(MachO::dysymtab_command &C) { - sys::swapByteOrder(C.cmd); - sys::swapByteOrder(C.cmdsize); - sys::swapByteOrder(C.ilocalsym); - sys::swapByteOrder(C.nlocalsym); - sys::swapByteOrder(C.iextdefsym); - sys::swapByteOrder(C.nextdefsym); - sys::swapByteOrder(C.iundefsym); - sys::swapByteOrder(C.nundefsym); - sys::swapByteOrder(C.tocoff); - sys::swapByteOrder(C.ntoc); - sys::swapByteOrder(C.modtaboff); - sys::swapByteOrder(C.nmodtab); - sys::swapByteOrder(C.extrefsymoff); - sys::swapByteOrder(C.nextrefsyms); - sys::swapByteOrder(C.indirectsymoff); - sys::swapByteOrder(C.nindirectsyms); - sys::swapByteOrder(C.extreloff); - sys::swapByteOrder(C.nextrel); - sys::swapByteOrder(C.locreloff); - sys::swapByteOrder(C.nlocrel); -} - -template<> -void SwapStruct(MachO::linkedit_data_command &C) { - sys::swapByteOrder(C.cmd); - sys::swapByteOrder(C.cmdsize); - sys::swapByteOrder(C.dataoff); - sys::swapByteOrder(C.datasize); -} - -template<> -void SwapStruct(MachO::segment_command &C) { - sys::swapByteOrder(C.cmd); - sys::swapByteOrder(C.cmdsize); - sys::swapByteOrder(C.vmaddr); - sys::swapByteOrder(C.vmsize); - sys::swapByteOrder(C.fileoff); - sys::swapByteOrder(C.filesize); - sys::swapByteOrder(C.maxprot); - sys::swapByteOrder(C.initprot); - sys::swapByteOrder(C.nsects); - sys::swapByteOrder(C.flags); -} - -template<> -void SwapStruct(MachO::segment_command_64 &C) { - sys::swapByteOrder(C.cmd); - sys::swapByteOrder(C.cmdsize); - sys::swapByteOrder(C.vmaddr); - sys::swapByteOrder(C.vmsize); - sys::swapByteOrder(C.fileoff); - sys::swapByteOrder(C.filesize); - sys::swapByteOrder(C.maxprot); - sys::swapByteOrder(C.initprot); - sys::swapByteOrder(C.nsects); - sys::swapByteOrder(C.flags); -} - -template<> -void SwapStruct(uint32_t &C) { - sys::swapByteOrder(C); -} - -template<> -void SwapStruct(MachO::linker_options_command &C) { - sys::swapByteOrder(C.cmd); - sys::swapByteOrder(C.cmdsize); - sys::swapByteOrder(C.count); -} - -template<> -void SwapStruct(MachO::version_min_command&C) { - sys::swapByteOrder(C.cmd); - sys::swapByteOrder(C.cmdsize); - sys::swapByteOrder(C.version); - sys::swapByteOrder(C.reserved); -} - -template<> -void SwapStruct(MachO::dylib_command&C) { - sys::swapByteOrder(C.cmd); - sys::swapByteOrder(C.cmdsize); - sys::swapByteOrder(C.dylib.name); - sys::swapByteOrder(C.dylib.timestamp); - sys::swapByteOrder(C.dylib.current_version); - sys::swapByteOrder(C.dylib.compatibility_version); -} - -template<> -void SwapStruct(MachO::data_in_code_entry &C) { - sys::swapByteOrder(C.offset); - sys::swapByteOrder(C.length); - sys::swapByteOrder(C.kind); +namespace { + struct section_base { + char sectname[16]; + char segname[16]; + }; } template -T getStruct(const MachOObjectFile *O, const char *P) { +static T getStruct(const MachOObjectFile *O, const char *P) { T Cmd; memcpy(&Cmd, P, sizeof(T)); if (O->isLittleEndian() != sys::IsLittleEndianHost) - SwapStruct(Cmd); + MachO::swapStruct(Cmd); return Cmd; } @@ -255,6 +58,17 @@ getSegmentLoadCommandNumSections(const MachOObjectFile *O, return S.nsects; } +static bool isPageZeroSegment(const MachOObjectFile *O, + const MachOObjectFile::LoadCommandInfo &L) { + if (O->is64Bit()) { + MachO::segment_command_64 S = O->getSegment64LoadCommand(L); + return StringRef("__PAGEZERO").equals(S.segname); + } + MachO::segment_command S = O->getSegmentLoadCommand(L); + return StringRef("__PAGEZERO").equals(S.segname); +} + + static const char * getSectionPtr(const MachOObjectFile *O, MachOObjectFile::LoadCommandInfo L, unsigned Sec) { @@ -274,10 +88,10 @@ static const char *getPtr(const MachOObjectFile *O, size_t Offset) { return O->getData().substr(Offset, 1).data(); } -static nlist_base +static MachO::nlist_base getSymbolTableEntryBase(const MachOObjectFile *O, DataRefImpl DRI) { const char *P = reinterpret_cast(DRI.p); - return getStruct(O, P); + return getStruct(O, P); } static StringRef parseSegmentOrSectionName(const char *P) { @@ -330,11 +144,9 @@ static void printRelocationTargetName(const MachOObjectFile *O, // to find a section beginning instead. for (const SectionRef &Section : O->sections()) { std::error_code ec; - uint64_t Addr; - StringRef Name; - if ((ec = Section.getAddress(Addr))) - report_fatal_error(ec.message()); + StringRef Name; + uint64_t Addr = Section.getAddress(); if (Addr != Val) continue; if ((ec = Section.getName(Name))) @@ -422,12 +234,12 @@ static uint32_t getSectionFlags(const MachOObjectFile *O, return Sect.flags; } -MachOObjectFile::MachOObjectFile(std::unique_ptr Object, - bool IsLittleEndian, bool Is64bits, - std::error_code &EC) - : ObjectFile(getMachOType(IsLittleEndian, Is64bits), std::move(Object)), +MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, + bool Is64bits, std::error_code &EC) + : ObjectFile(getMachOType(IsLittleEndian, Is64bits), Object), SymtabLoadCmd(nullptr), DysymtabLoadCmd(nullptr), - DataInCodeLoadCmd(nullptr) { + DataInCodeLoadCmd(nullptr), DyldInfoLoadCmd(nullptr), + HasPageZeroSegment(false) { uint32_t LoadCommandCount = this->getHeader().ncmds; MachO::LoadCommandType SegmentLoadType = is64Bit() ? MachO::LC_SEGMENT_64 : MachO::LC_SEGMENT; @@ -443,12 +255,18 @@ MachOObjectFile::MachOObjectFile(std::unique_ptr Object, } else if (Load.C.cmd == MachO::LC_DATA_IN_CODE) { assert(!DataInCodeLoadCmd && "Multiple data in code tables"); DataInCodeLoadCmd = Load.Ptr; + } else if (Load.C.cmd == MachO::LC_DYLD_INFO || + Load.C.cmd == MachO::LC_DYLD_INFO_ONLY) { + assert(!DyldInfoLoadCmd && "Multiple dyldinfo load commands"); + DyldInfoLoadCmd = Load.Ptr; } else if (Load.C.cmd == SegmentLoadType) { uint32_t NumSections = getSegmentLoadCommandNumSections(this, Load); for (unsigned J = 0; J < NumSections; ++J) { const char *Sec = getSectionPtr(this, Load, J); Sections.push_back(Sec); } + if (isPageZeroSegment(this, Load)) + HasPageZeroSegment = true; } else if (Load.C.cmd == MachO::LC_LOAD_DYLIB || Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB || Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB || @@ -474,7 +292,7 @@ void MachOObjectFile::moveSymbolNext(DataRefImpl &Symb) const { std::error_code MachOObjectFile::getSymbolName(DataRefImpl Symb, StringRef &Res) const { StringRef StringTable = getStringTableData(); - nlist_base Entry = getSymbolTableEntryBase(this, Symb); + MachO::nlist_base Entry = getSymbolTableEntryBase(this, Symb); const char *Start = &StringTable.data()[Entry.n_strx]; Res = StringRef(Start); return object_error::success; @@ -528,7 +346,7 @@ std::error_code MachOObjectFile::getSymbolAlignment(DataRefImpl DRI, uint32_t &Result) const { uint32_t flags = getSymbolFlags(DRI); if (flags & SymbolRef::SF_Common) { - nlist_base Entry = getSymbolTableEntryBase(this, DRI); + MachO::nlist_base Entry = getSymbolTableEntryBase(this, DRI); Result = 1 << MachO::GET_COMM_ALIGN(Entry.n_desc); } else { Result = 0; @@ -542,7 +360,7 @@ std::error_code MachOObjectFile::getSymbolSize(DataRefImpl DRI, uint64_t EndOffset = 0; uint8_t SectionIndex; - nlist_base Entry = getSymbolTableEntryBase(this, DRI); + MachO::nlist_base Entry = getSymbolTableEntryBase(this, DRI); uint64_t Value; getSymbolAddress(DRI, Value); if (Value == UnknownAddressOrSize) { @@ -574,11 +392,10 @@ std::error_code MachOObjectFile::getSymbolSize(DataRefImpl DRI, EndOffset = Value; } if (!EndOffset) { - uint64_t Size; DataRefImpl Sec; Sec.d.a = SectionIndex-1; - getSectionSize(Sec, Size); - getSectionAddress(Sec, EndOffset); + uint64_t Size = getSectionSize(Sec); + EndOffset = getSectionAddress(Sec); EndOffset += Size; } Result = EndOffset - BeginOffset; @@ -587,7 +404,7 @@ std::error_code MachOObjectFile::getSymbolSize(DataRefImpl DRI, std::error_code MachOObjectFile::getSymbolType(DataRefImpl Symb, SymbolRef::Type &Res) const { - nlist_base Entry = getSymbolTableEntryBase(this, Symb); + MachO::nlist_base Entry = getSymbolTableEntryBase(this, Symb); uint8_t n_type = Entry.n_type; Res = SymbolRef::ST_Other; @@ -610,7 +427,7 @@ std::error_code MachOObjectFile::getSymbolType(DataRefImpl Symb, } uint32_t MachOObjectFile::getSymbolFlags(DataRefImpl DRI) const { - nlist_base Entry = getSymbolTableEntryBase(this, DRI); + MachO::nlist_base Entry = getSymbolTableEntryBase(this, DRI); uint8_t MachOType = Entry.n_type; uint16_t MachOFlags = Entry.n_desc; @@ -639,6 +456,9 @@ uint32_t MachOObjectFile::getSymbolFlags(DataRefImpl DRI) const { if (MachOFlags & (MachO::N_WEAK_REF | MachO::N_WEAK_DEF)) Result |= SymbolRef::SF_Weak; + if (MachOFlags & (MachO::N_ARM_THUMB_DEF)) + Result |= SymbolRef::SF_Thumb; + if ((MachOType & MachO::N_TYPE) == MachO::N_ABS) Result |= SymbolRef::SF_Absolute; @@ -647,7 +467,7 @@ uint32_t MachOObjectFile::getSymbolFlags(DataRefImpl DRI) const { std::error_code MachOObjectFile::getSymbolSection(DataRefImpl Symb, section_iterator &Res) const { - nlist_base Entry = getSymbolTableEntryBase(this, Symb); + MachO::nlist_base Entry = getSymbolTableEntryBase(this, Symb); uint8_t index = Entry.n_sect; if (index == 0) { @@ -672,29 +492,16 @@ std::error_code MachOObjectFile::getSectionName(DataRefImpl Sec, return object_error::success; } -std::error_code MachOObjectFile::getSectionAddress(DataRefImpl Sec, - uint64_t &Res) const { - if (is64Bit()) { - MachO::section_64 Sect = getSection64(Sec); - Res = Sect.addr; - } else { - MachO::section Sect = getSection(Sec); - Res = Sect.addr; - } - return object_error::success; +uint64_t MachOObjectFile::getSectionAddress(DataRefImpl Sec) const { + if (is64Bit()) + return getSection64(Sec).addr; + return getSection(Sec).addr; } -std::error_code MachOObjectFile::getSectionSize(DataRefImpl Sec, - uint64_t &Res) const { - if (is64Bit()) { - MachO::section_64 Sect = getSection64(Sec); - Res = Sect.size; - } else { - MachO::section Sect = getSection(Sec); - Res = Sect.size; - } - - return object_error::success; +uint64_t MachOObjectFile::getSectionSize(DataRefImpl Sec) const { + if (is64Bit()) + return getSection64(Sec).size; + return getSection(Sec).size; } std::error_code MachOObjectFile::getSectionContents(DataRefImpl Sec, @@ -716,8 +523,7 @@ std::error_code MachOObjectFile::getSectionContents(DataRefImpl Sec, return object_error::success; } -std::error_code MachOObjectFile::getSectionAlignment(DataRefImpl Sec, - uint64_t &Res) const { +uint64_t MachOObjectFile::getSectionAlignment(DataRefImpl Sec) const { uint32_t Align; if (is64Bit()) { MachO::section_64 Sect = getSection64(Sec); @@ -727,92 +533,70 @@ std::error_code MachOObjectFile::getSectionAlignment(DataRefImpl Sec, Align = Sect.align; } - Res = uint64_t(1) << Align; - return object_error::success; + return uint64_t(1) << Align; } -std::error_code MachOObjectFile::isSectionText(DataRefImpl Sec, - bool &Res) const { +bool MachOObjectFile::isSectionText(DataRefImpl Sec) const { uint32_t Flags = getSectionFlags(this, Sec); - Res = Flags & MachO::S_ATTR_PURE_INSTRUCTIONS; - return object_error::success; + return Flags & MachO::S_ATTR_PURE_INSTRUCTIONS; } -std::error_code MachOObjectFile::isSectionData(DataRefImpl Sec, - bool &Result) const { +bool MachOObjectFile::isSectionData(DataRefImpl Sec) const { uint32_t Flags = getSectionFlags(this, Sec); unsigned SectionType = Flags & MachO::SECTION_TYPE; - Result = !(Flags & MachO::S_ATTR_PURE_INSTRUCTIONS) && - !(SectionType == MachO::S_ZEROFILL || - SectionType == MachO::S_GB_ZEROFILL); - return object_error::success; + return !(Flags & MachO::S_ATTR_PURE_INSTRUCTIONS) && + !(SectionType == MachO::S_ZEROFILL || + SectionType == MachO::S_GB_ZEROFILL); } -std::error_code MachOObjectFile::isSectionBSS(DataRefImpl Sec, - bool &Result) const { +bool MachOObjectFile::isSectionBSS(DataRefImpl Sec) const { uint32_t Flags = getSectionFlags(this, Sec); unsigned SectionType = Flags & MachO::SECTION_TYPE; - Result = !(Flags & MachO::S_ATTR_PURE_INSTRUCTIONS) && - (SectionType == MachO::S_ZEROFILL || - SectionType == MachO::S_GB_ZEROFILL); - return object_error::success; + return !(Flags & MachO::S_ATTR_PURE_INSTRUCTIONS) && + (SectionType == MachO::S_ZEROFILL || + SectionType == MachO::S_GB_ZEROFILL); } -std::error_code -MachOObjectFile::isSectionRequiredForExecution(DataRefImpl Sec, - bool &Result) const { +bool MachOObjectFile::isSectionRequiredForExecution(DataRefImpl Sect) const { // FIXME: Unimplemented. - Result = true; - return object_error::success; + return true; } -std::error_code MachOObjectFile::isSectionVirtual(DataRefImpl Sec, - bool &Result) const { +bool MachOObjectFile::isSectionVirtual(DataRefImpl Sec) const { // FIXME: Unimplemented. - Result = false; - return object_error::success; + return false; } -std::error_code MachOObjectFile::isSectionZeroInit(DataRefImpl Sec, - bool &Res) const { +bool MachOObjectFile::isSectionZeroInit(DataRefImpl Sec) const { uint32_t Flags = getSectionFlags(this, Sec); unsigned SectionType = Flags & MachO::SECTION_TYPE; - Res = SectionType == MachO::S_ZEROFILL || - SectionType == MachO::S_GB_ZEROFILL; - return object_error::success; + return SectionType == MachO::S_ZEROFILL || + SectionType == MachO::S_GB_ZEROFILL; } -std::error_code MachOObjectFile::isSectionReadOnlyData(DataRefImpl Sec, - bool &Result) const { +bool MachOObjectFile::isSectionReadOnlyData(DataRefImpl Sec) const { // Consider using the code from isSectionText to look for __const sections. // Alternately, emit S_ATTR_PURE_INSTRUCTIONS and/or S_ATTR_SOME_INSTRUCTIONS // to use section attributes to distinguish code from data. // FIXME: Unimplemented. - Result = false; - return object_error::success; + return false; } -std::error_code MachOObjectFile::sectionContainsSymbol(DataRefImpl Sec, - DataRefImpl Symb, - bool &Result) const { +bool MachOObjectFile::sectionContainsSymbol(DataRefImpl Sec, + DataRefImpl Symb) const { SymbolRef::Type ST; this->getSymbolType(Symb, ST); - if (ST == SymbolRef::ST_Unknown) { - Result = false; - return object_error::success; - } + if (ST == SymbolRef::ST_Unknown) + return false; - uint64_t SectBegin, SectEnd; - getSectionAddress(Sec, SectBegin); - getSectionSize(Sec, SectEnd); + uint64_t SectBegin = getSectionAddress(Sec); + uint64_t SectEnd = getSectionSize(Sec); SectEnd += SectBegin; uint64_t SymAddr; getSymbolAddress(Symb, SymAddr); - Result = (SymAddr >= SectBegin) && (SymAddr < SectEnd); - - return object_error::success; + return (SymAddr >= SectBegin) && (SymAddr < SectEnd); } relocation_iterator MachOObjectFile::section_rel_begin(DataRefImpl Sec) const { @@ -850,8 +634,7 @@ std::error_code MachOObjectFile::getRelocationAddress(DataRefImpl Rel, DataRefImpl Sec; Sec.d.a = Rel.d.a; - uint64_t SecAddress; - getSectionAddress(Sec, SecAddress); + uint64_t SecAddress = getSectionAddress(Sec); Res = SecAddress + Offset; return object_error::success; } @@ -956,7 +739,6 @@ MachOObjectFile::getRelocationTypeName(DataRefImpl Rel, res = Table[RType]; break; } - case Triple::arm64: case Triple::aarch64: { static const char *const Table[] = { "ARM64_RELOC_UNSIGNED", "ARM64_RELOC_SUBTRACTOR", @@ -1210,16 +992,6 @@ std::error_code MachOObjectFile::getRelocationHidden(DataRefImpl Rel, return object_error::success; } -std::error_code MachOObjectFile::getLibraryNext(DataRefImpl LibData, - LibraryRef &Res) const { - report_fatal_error("Needed libraries unimplemented in MachOObjectFile"); -} - -std::error_code MachOObjectFile::getLibraryPath(DataRefImpl LibData, - StringRef &Res) const { - report_fatal_error("Needed libraries unimplemented in MachOObjectFile"); -} - // // guessLibraryShortName() is passed a name of a dynamic library and returns a // guess on what the short name is. Then name is returned as a substring of the @@ -1368,31 +1140,26 @@ guess_qtx: // It is passed the index (0 - based) of the library as translated from // GET_LIBRARY_ORDINAL (1 - based). std::error_code MachOObjectFile::getLibraryShortNameByIndex(unsigned Index, - StringRef &Res) { + StringRef &Res) const { if (Index >= Libraries.size()) return object_error::parse_failed; - MachO::dylib_command D = - getStruct(this, Libraries[Index]); - if (D.dylib.name >= D.cmdsize) - return object_error::parse_failed; - // If the cache of LibrariesShortNames is not built up do that first for // all the Libraries. if (LibrariesShortNames.size() == 0) { for (unsigned i = 0; i < Libraries.size(); i++) { MachO::dylib_command D = getStruct(this, Libraries[i]); - if (D.dylib.name >= D.cmdsize) { - LibrariesShortNames.push_back(StringRef()); - continue; - } + if (D.dylib.name >= D.cmdsize) + return object_error::parse_failed; const char *P = (const char *)(Libraries[i]) + D.dylib.name; StringRef Name = StringRef(P); + if (D.dylib.name+Name.size() >= D.cmdsize) + return object_error::parse_failed; StringRef Suffix; bool isFramework; StringRef shortName = guessLibraryShortName(Name, isFramework, Suffix); - if (shortName == StringRef()) + if (shortName.empty()) LibrariesShortNames.push_back(Name); else LibrariesShortNames.push_back(shortName); @@ -1447,16 +1214,6 @@ section_iterator MachOObjectFile::section_end() const { return section_iterator(SectionRef(DRI, this)); } -library_iterator MachOObjectFile::needed_library_begin() const { - // TODO: implement - report_fatal_error("Needed libraries unimplemented in MachOObjectFile"); -} - -library_iterator MachOObjectFile::needed_library_end() const { - // TODO: implement - report_fatal_error("Needed libraries unimplemented in MachOObjectFile"); -} - uint8_t MachOObjectFile::getBytesInAddress() const { return is64Bit() ? 8 : 4; } @@ -1504,7 +1261,7 @@ Triple::ArchType MachOObjectFile::getArch(uint32_t CPUType) { case llvm::MachO::CPU_TYPE_ARM: return Triple::arm; case llvm::MachO::CPU_TYPE_ARM64: - return Triple::arm64; + return Triple::aarch64; case llvm::MachO::CPU_TYPE_POWERPC: return Triple::ppc; case llvm::MachO::CPU_TYPE_POWERPC64: @@ -1514,7 +1271,11 @@ Triple::ArchType MachOObjectFile::getArch(uint32_t CPUType) { } } -Triple MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType) { +Triple MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType, + const char **McpuDefault) { + if (McpuDefault) + *McpuDefault = nullptr; + switch (CPUType) { case MachO::CPU_TYPE_I386: switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { @@ -1538,15 +1299,25 @@ Triple MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType) { return Triple("armv4t-apple-darwin"); case MachO::CPU_SUBTYPE_ARM_V5TEJ: return Triple("armv5e-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_XSCALE: + return Triple("xscale-apple-darwin"); case MachO::CPU_SUBTYPE_ARM_V6: return Triple("armv6-apple-darwin"); case MachO::CPU_SUBTYPE_ARM_V6M: + if (McpuDefault) + *McpuDefault = "cortex-m0"; return Triple("armv6m-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V7: + return Triple("armv7-apple-darwin"); case MachO::CPU_SUBTYPE_ARM_V7EM: + if (McpuDefault) + *McpuDefault = "cortex-m4"; return Triple("armv7em-apple-darwin"); case MachO::CPU_SUBTYPE_ARM_V7K: return Triple("armv7k-apple-darwin"); case MachO::CPU_SUBTYPE_ARM_V7M: + if (McpuDefault) + *McpuDefault = "cortex-m3"; return Triple("armv7m-apple-darwin"); case MachO::CPU_SUBTYPE_ARM_V7S: return Triple("armv7s-apple-darwin"); @@ -1579,50 +1350,102 @@ Triple MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType) { } } +Triple MachOObjectFile::getThumbArch(uint32_t CPUType, uint32_t CPUSubType, + const char **McpuDefault) { + if (McpuDefault) + *McpuDefault = nullptr; + + switch (CPUType) { + case MachO::CPU_TYPE_ARM: + switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { + case MachO::CPU_SUBTYPE_ARM_V4T: + return Triple("thumbv4t-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V5TEJ: + return Triple("thumbv5e-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_XSCALE: + return Triple("xscale-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V6: + return Triple("thumbv6-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V6M: + if (McpuDefault) + *McpuDefault = "cortex-m0"; + return Triple("thumbv6m-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V7: + return Triple("thumbv7-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V7EM: + if (McpuDefault) + *McpuDefault = "cortex-m4"; + return Triple("thumbv7em-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V7K: + return Triple("thumbv7k-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V7M: + if (McpuDefault) + *McpuDefault = "cortex-m3"; + return Triple("thumbv7m-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V7S: + return Triple("thumbv7s-apple-darwin"); + default: + return Triple(); + } + default: + return Triple(); + } +} + +Triple MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType, + const char **McpuDefault, + Triple *ThumbTriple) { + Triple T = MachOObjectFile::getArch(CPUType, CPUSubType, McpuDefault); + *ThumbTriple = MachOObjectFile::getThumbArch(CPUType, CPUSubType, + McpuDefault); + return T; +} + Triple MachOObjectFile::getHostArch() { return Triple(sys::getDefaultTargetTriple()); } -Triple MachOObjectFile::getArch(StringRef ArchFlag) { - if (ArchFlag == "i386") - return Triple("i386-apple-darwin"); - else if (ArchFlag == "x86_64") - return Triple("x86_64-apple-darwin"); - else if (ArchFlag == "x86_64h") - return Triple("x86_64h-apple-darwin"); - else if (ArchFlag == "armv4t" || ArchFlag == "arm") - return Triple("armv4t-apple-darwin"); - else if (ArchFlag == "armv5e") - return Triple("armv5e-apple-darwin"); - else if (ArchFlag == "armv6") - return Triple("armv6-apple-darwin"); - else if (ArchFlag == "armv6m") - return Triple("armv6m-apple-darwin"); - else if (ArchFlag == "armv7em") - return Triple("armv7em-apple-darwin"); - else if (ArchFlag == "armv7k") - return Triple("armv7k-apple-darwin"); - else if (ArchFlag == "armv7k") - return Triple("armv7m-apple-darwin"); - else if (ArchFlag == "armv7s") - return Triple("armv7s-apple-darwin"); - else if (ArchFlag == "arm64") - return Triple("arm64-apple-darwin"); - else if (ArchFlag == "ppc") - return Triple("ppc-apple-darwin"); - else if (ArchFlag == "ppc64") - return Triple("ppc64-apple-darwin"); - else - return Triple(); +bool MachOObjectFile::isValidArch(StringRef ArchFlag) { + return StringSwitch(ArchFlag) + .Case("i386", true) + .Case("x86_64", true) + .Case("x86_64h", true) + .Case("armv4t", true) + .Case("arm", true) + .Case("armv5e", true) + .Case("armv6", true) + .Case("armv6m", true) + .Case("armv7em", true) + .Case("armv7k", true) + .Case("armv7m", true) + .Case("armv7s", true) + .Case("arm64", true) + .Case("ppc", true) + .Case("ppc64", true) + .Default(false); } unsigned MachOObjectFile::getArch() const { return getArch(getCPUType(this)); } -StringRef MachOObjectFile::getLoadName() const { - // TODO: Implement - report_fatal_error("get_load_name() unimplemented in MachOObjectFile"); +Triple MachOObjectFile::getArch(const char **McpuDefault, + Triple *ThumbTriple) const { + Triple T; + if (is64Bit()) { + MachO::mach_header_64 H_64; + H_64 = getHeader64(); + T = MachOObjectFile::getArch(H_64.cputype, H_64.cpusubtype, McpuDefault); + *ThumbTriple = MachOObjectFile::getThumbArch(H_64.cputype, H_64.cpusubtype, + McpuDefault); + } else { + MachO::mach_header H; + H = getHeader(); + T = MachOObjectFile::getArch(H.cputype, H.cpusubtype, McpuDefault); + *ThumbTriple = MachOObjectFile::getThumbArch(H.cputype, H.cpusubtype, + McpuDefault); + } + return T; } relocation_iterator MachOObjectFile::section_rel_begin(unsigned Index) const { @@ -1658,6 +1481,620 @@ dice_iterator MachOObjectFile::end_dices() const { return dice_iterator(DiceRef(DRI, this)); } +ExportEntry::ExportEntry(ArrayRef T) + : Trie(T), Malformed(false), Done(false) { } + +void ExportEntry::moveToFirst() { + pushNode(0); + pushDownUntilBottom(); +} + +void ExportEntry::moveToEnd() { + Stack.clear(); + Done = true; +} + +bool ExportEntry::operator==(const ExportEntry &Other) const { + // Common case, one at end, other iterating from begin. + if (Done || Other.Done) + return (Done == Other.Done); + // Not equal if different stack sizes. + if (Stack.size() != Other.Stack.size()) + return false; + // Not equal if different cumulative strings. + if (!CumulativeString.str().equals(Other.CumulativeString.str())) + return false; + // Equal if all nodes in both stacks match. + for (unsigned i=0; i < Stack.size(); ++i) { + if (Stack[i].Start != Other.Stack[i].Start) + return false; + } + return true; +} + +uint64_t ExportEntry::readULEB128(const uint8_t *&Ptr) { + unsigned Count; + uint64_t Result = decodeULEB128(Ptr, &Count); + Ptr += Count; + if (Ptr > Trie.end()) { + Ptr = Trie.end(); + Malformed = true; + } + return Result; +} + +StringRef ExportEntry::name() const { + return CumulativeString.str(); +} + +uint64_t ExportEntry::flags() const { + return Stack.back().Flags; +} + +uint64_t ExportEntry::address() const { + return Stack.back().Address; +} + +uint64_t ExportEntry::other() const { + return Stack.back().Other; +} + +StringRef ExportEntry::otherName() const { + const char* ImportName = Stack.back().ImportName; + if (ImportName) + return StringRef(ImportName); + return StringRef(); +} + +uint32_t ExportEntry::nodeOffset() const { + return Stack.back().Start - Trie.begin(); +} + +ExportEntry::NodeState::NodeState(const uint8_t *Ptr) + : Start(Ptr), Current(Ptr), Flags(0), Address(0), Other(0), + ImportName(nullptr), ChildCount(0), NextChildIndex(0), + ParentStringLength(0), IsExportNode(false) { +} + +void ExportEntry::pushNode(uint64_t offset) { + const uint8_t *Ptr = Trie.begin() + offset; + NodeState State(Ptr); + uint64_t ExportInfoSize = readULEB128(State.Current); + State.IsExportNode = (ExportInfoSize != 0); + const uint8_t* Children = State.Current + ExportInfoSize; + if (State.IsExportNode) { + State.Flags = readULEB128(State.Current); + if (State.Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT) { + State.Address = 0; + State.Other = readULEB128(State.Current); // dylib ordinal + State.ImportName = reinterpret_cast(State.Current); + } else { + State.Address = readULEB128(State.Current); + if (State.Flags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) + State.Other = readULEB128(State.Current); + } + } + State.ChildCount = *Children; + State.Current = Children + 1; + State.NextChildIndex = 0; + State.ParentStringLength = CumulativeString.size(); + Stack.push_back(State); +} + +void ExportEntry::pushDownUntilBottom() { + while (Stack.back().NextChildIndex < Stack.back().ChildCount) { + NodeState &Top = Stack.back(); + CumulativeString.resize(Top.ParentStringLength); + for (;*Top.Current != 0; Top.Current++) { + char C = *Top.Current; + CumulativeString.push_back(C); + } + Top.Current += 1; + uint64_t childNodeIndex = readULEB128(Top.Current); + Top.NextChildIndex += 1; + pushNode(childNodeIndex); + } + if (!Stack.back().IsExportNode) { + Malformed = true; + moveToEnd(); + } +} + +// We have a trie data structure and need a way to walk it that is compatible +// with the C++ iterator model. The solution is a non-recursive depth first +// traversal where the iterator contains a stack of parent nodes along with a +// string that is the accumulation of all edge strings along the parent chain +// to this point. +// +// There is one “export” node for each exported symbol. But because some +// symbols may be a prefix of another symbol (e.g. _dup and _dup2), an export +// node may have child nodes too. +// +// The algorithm for moveNext() is to keep moving down the leftmost unvisited +// child until hitting a node with no children (which is an export node or +// else the trie is malformed). On the way down, each node is pushed on the +// stack ivar. If there is no more ways down, it pops up one and tries to go +// down a sibling path until a childless node is reached. +void ExportEntry::moveNext() { + if (Stack.empty() || !Stack.back().IsExportNode) { + Malformed = true; + moveToEnd(); + return; + } + + Stack.pop_back(); + while (!Stack.empty()) { + NodeState &Top = Stack.back(); + if (Top.NextChildIndex < Top.ChildCount) { + pushDownUntilBottom(); + // Now at the next export node. + return; + } else { + if (Top.IsExportNode) { + // This node has no children but is itself an export node. + CumulativeString.resize(Top.ParentStringLength); + return; + } + Stack.pop_back(); + } + } + Done = true; +} + +iterator_range +MachOObjectFile::exports(ArrayRef Trie) { + ExportEntry Start(Trie); + Start.moveToFirst(); + + ExportEntry Finish(Trie); + Finish.moveToEnd(); + + return iterator_range(export_iterator(Start), + export_iterator(Finish)); +} + +iterator_range MachOObjectFile::exports() const { + return exports(getDyldInfoExportsTrie()); +} + + +MachORebaseEntry::MachORebaseEntry(ArrayRef Bytes, bool is64Bit) + : Opcodes(Bytes), Ptr(Bytes.begin()), SegmentOffset(0), SegmentIndex(0), + RemainingLoopCount(0), AdvanceAmount(0), RebaseType(0), + PointerSize(is64Bit ? 8 : 4), Malformed(false), Done(false) {} + +void MachORebaseEntry::moveToFirst() { + Ptr = Opcodes.begin(); + moveNext(); +} + +void MachORebaseEntry::moveToEnd() { + Ptr = Opcodes.end(); + RemainingLoopCount = 0; + Done = true; +} + +void MachORebaseEntry::moveNext() { + // If in the middle of some loop, move to next rebasing in loop. + SegmentOffset += AdvanceAmount; + if (RemainingLoopCount) { + --RemainingLoopCount; + return; + } + if (Ptr == Opcodes.end()) { + Done = true; + return; + } + bool More = true; + while (More && !Malformed) { + // Parse next opcode and set up next loop. + uint8_t Byte = *Ptr++; + uint8_t ImmValue = Byte & MachO::REBASE_IMMEDIATE_MASK; + uint8_t Opcode = Byte & MachO::REBASE_OPCODE_MASK; + switch (Opcode) { + case MachO::REBASE_OPCODE_DONE: + More = false; + Done = true; + moveToEnd(); + DEBUG_WITH_TYPE("mach-o-rebase", llvm::dbgs() << "REBASE_OPCODE_DONE\n"); + break; + case MachO::REBASE_OPCODE_SET_TYPE_IMM: + RebaseType = ImmValue; + DEBUG_WITH_TYPE( + "mach-o-rebase", + llvm::dbgs() << "REBASE_OPCODE_SET_TYPE_IMM: " + << "RebaseType=" << (int) RebaseType << "\n"); + break; + case MachO::REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: + SegmentIndex = ImmValue; + SegmentOffset = readULEB128(); + DEBUG_WITH_TYPE( + "mach-o-rebase", + llvm::dbgs() << "REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: " + << "SegmentIndex=" << SegmentIndex << ", " + << format("SegmentOffset=0x%06X", SegmentOffset) + << "\n"); + break; + case MachO::REBASE_OPCODE_ADD_ADDR_ULEB: + SegmentOffset += readULEB128(); + DEBUG_WITH_TYPE("mach-o-rebase", + llvm::dbgs() << "REBASE_OPCODE_ADD_ADDR_ULEB: " + << format("SegmentOffset=0x%06X", + SegmentOffset) << "\n"); + break; + case MachO::REBASE_OPCODE_ADD_ADDR_IMM_SCALED: + SegmentOffset += ImmValue * PointerSize; + DEBUG_WITH_TYPE("mach-o-rebase", + llvm::dbgs() << "REBASE_OPCODE_ADD_ADDR_IMM_SCALED: " + << format("SegmentOffset=0x%06X", + SegmentOffset) << "\n"); + break; + case MachO::REBASE_OPCODE_DO_REBASE_IMM_TIMES: + AdvanceAmount = PointerSize; + RemainingLoopCount = ImmValue - 1; + DEBUG_WITH_TYPE( + "mach-o-rebase", + llvm::dbgs() << "REBASE_OPCODE_DO_REBASE_IMM_TIMES: " + << format("SegmentOffset=0x%06X", SegmentOffset) + << ", AdvanceAmount=" << AdvanceAmount + << ", RemainingLoopCount=" << RemainingLoopCount + << "\n"); + return; + case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES: + AdvanceAmount = PointerSize; + RemainingLoopCount = readULEB128() - 1; + DEBUG_WITH_TYPE( + "mach-o-rebase", + llvm::dbgs() << "REBASE_OPCODE_DO_REBASE_ULEB_TIMES: " + << format("SegmentOffset=0x%06X", SegmentOffset) + << ", AdvanceAmount=" << AdvanceAmount + << ", RemainingLoopCount=" << RemainingLoopCount + << "\n"); + return; + case MachO::REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB: + AdvanceAmount = readULEB128() + PointerSize; + RemainingLoopCount = 0; + DEBUG_WITH_TYPE( + "mach-o-rebase", + llvm::dbgs() << "REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB: " + << format("SegmentOffset=0x%06X", SegmentOffset) + << ", AdvanceAmount=" << AdvanceAmount + << ", RemainingLoopCount=" << RemainingLoopCount + << "\n"); + return; + case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: + RemainingLoopCount = readULEB128() - 1; + AdvanceAmount = readULEB128() + PointerSize; + DEBUG_WITH_TYPE( + "mach-o-rebase", + llvm::dbgs() << "REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: " + << format("SegmentOffset=0x%06X", SegmentOffset) + << ", AdvanceAmount=" << AdvanceAmount + << ", RemainingLoopCount=" << RemainingLoopCount + << "\n"); + return; + default: + Malformed = true; + } + } +} + +uint64_t MachORebaseEntry::readULEB128() { + unsigned Count; + uint64_t Result = decodeULEB128(Ptr, &Count); + Ptr += Count; + if (Ptr > Opcodes.end()) { + Ptr = Opcodes.end(); + Malformed = true; + } + return Result; +} + +uint32_t MachORebaseEntry::segmentIndex() const { return SegmentIndex; } + +uint64_t MachORebaseEntry::segmentOffset() const { return SegmentOffset; } + +StringRef MachORebaseEntry::typeName() const { + switch (RebaseType) { + case MachO::REBASE_TYPE_POINTER: + return "pointer"; + case MachO::REBASE_TYPE_TEXT_ABSOLUTE32: + return "text abs32"; + case MachO::REBASE_TYPE_TEXT_PCREL32: + return "text rel32"; + } + return "unknown"; +} + +bool MachORebaseEntry::operator==(const MachORebaseEntry &Other) const { + assert(Opcodes == Other.Opcodes && "compare iterators of different files"); + return (Ptr == Other.Ptr) && + (RemainingLoopCount == Other.RemainingLoopCount) && + (Done == Other.Done); +} + +iterator_range +MachOObjectFile::rebaseTable(ArrayRef Opcodes, bool is64) { + MachORebaseEntry Start(Opcodes, is64); + Start.moveToFirst(); + + MachORebaseEntry Finish(Opcodes, is64); + Finish.moveToEnd(); + + return iterator_range(rebase_iterator(Start), + rebase_iterator(Finish)); +} + +iterator_range MachOObjectFile::rebaseTable() const { + return rebaseTable(getDyldInfoRebaseOpcodes(), is64Bit()); +} + + +MachOBindEntry::MachOBindEntry(ArrayRef Bytes, bool is64Bit, + Kind BK) + : Opcodes(Bytes), Ptr(Bytes.begin()), SegmentOffset(0), SegmentIndex(0), + Ordinal(0), Flags(0), Addend(0), RemainingLoopCount(0), AdvanceAmount(0), + BindType(0), PointerSize(is64Bit ? 8 : 4), + TableKind(BK), Malformed(false), Done(false) {} + +void MachOBindEntry::moveToFirst() { + Ptr = Opcodes.begin(); + moveNext(); +} + +void MachOBindEntry::moveToEnd() { + Ptr = Opcodes.end(); + RemainingLoopCount = 0; + Done = true; +} + +void MachOBindEntry::moveNext() { + // If in the middle of some loop, move to next binding in loop. + SegmentOffset += AdvanceAmount; + if (RemainingLoopCount) { + --RemainingLoopCount; + return; + } + if (Ptr == Opcodes.end()) { + Done = true; + return; + } + bool More = true; + while (More && !Malformed) { + // Parse next opcode and set up next loop. + uint8_t Byte = *Ptr++; + uint8_t ImmValue = Byte & MachO::BIND_IMMEDIATE_MASK; + uint8_t Opcode = Byte & MachO::BIND_OPCODE_MASK; + int8_t SignExtended; + const uint8_t *SymStart; + switch (Opcode) { + case MachO::BIND_OPCODE_DONE: + if (TableKind == Kind::Lazy) { + // Lazying bindings have a DONE opcode between entries. Need to ignore + // it to advance to next entry. But need not if this is last entry. + bool NotLastEntry = false; + for (const uint8_t *P = Ptr; P < Opcodes.end(); ++P) { + if (*P) { + NotLastEntry = true; + } + } + if (NotLastEntry) + break; + } + More = false; + Done = true; + moveToEnd(); + DEBUG_WITH_TYPE("mach-o-bind", llvm::dbgs() << "BIND_OPCODE_DONE\n"); + break; + case MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: + Ordinal = ImmValue; + DEBUG_WITH_TYPE( + "mach-o-bind", + llvm::dbgs() << "BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: " + << "Ordinal=" << Ordinal << "\n"); + break; + case MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: + Ordinal = readULEB128(); + DEBUG_WITH_TYPE( + "mach-o-bind", + llvm::dbgs() << "BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: " + << "Ordinal=" << Ordinal << "\n"); + break; + case MachO::BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: + if (ImmValue) { + SignExtended = MachO::BIND_OPCODE_MASK | ImmValue; + Ordinal = SignExtended; + } else + Ordinal = 0; + DEBUG_WITH_TYPE( + "mach-o-bind", + llvm::dbgs() << "BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: " + << "Ordinal=" << Ordinal << "\n"); + break; + case MachO::BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: + Flags = ImmValue; + SymStart = Ptr; + while (*Ptr) { + ++Ptr; + } + SymbolName = StringRef(reinterpret_cast(SymStart), + Ptr-SymStart); + ++Ptr; + DEBUG_WITH_TYPE( + "mach-o-bind", + llvm::dbgs() << "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: " + << "SymbolName=" << SymbolName << "\n"); + if (TableKind == Kind::Weak) { + if (ImmValue & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) + return; + } + break; + case MachO::BIND_OPCODE_SET_TYPE_IMM: + BindType = ImmValue; + DEBUG_WITH_TYPE( + "mach-o-bind", + llvm::dbgs() << "BIND_OPCODE_SET_TYPE_IMM: " + << "BindType=" << (int)BindType << "\n"); + break; + case MachO::BIND_OPCODE_SET_ADDEND_SLEB: + Addend = readSLEB128(); + if (TableKind == Kind::Lazy) + Malformed = true; + DEBUG_WITH_TYPE( + "mach-o-bind", + llvm::dbgs() << "BIND_OPCODE_SET_ADDEND_SLEB: " + << "Addend=" << Addend << "\n"); + break; + case MachO::BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: + SegmentIndex = ImmValue; + SegmentOffset = readULEB128(); + DEBUG_WITH_TYPE( + "mach-o-bind", + llvm::dbgs() << "BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: " + << "SegmentIndex=" << SegmentIndex << ", " + << format("SegmentOffset=0x%06X", SegmentOffset) + << "\n"); + break; + case MachO::BIND_OPCODE_ADD_ADDR_ULEB: + SegmentOffset += readULEB128(); + DEBUG_WITH_TYPE("mach-o-bind", + llvm::dbgs() << "BIND_OPCODE_ADD_ADDR_ULEB: " + << format("SegmentOffset=0x%06X", + SegmentOffset) << "\n"); + break; + case MachO::BIND_OPCODE_DO_BIND: + AdvanceAmount = PointerSize; + RemainingLoopCount = 0; + DEBUG_WITH_TYPE("mach-o-bind", + llvm::dbgs() << "BIND_OPCODE_DO_BIND: " + << format("SegmentOffset=0x%06X", + SegmentOffset) << "\n"); + return; + case MachO::BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: + AdvanceAmount = readULEB128(); + RemainingLoopCount = 0; + if (TableKind == Kind::Lazy) + Malformed = true; + DEBUG_WITH_TYPE( + "mach-o-bind", + llvm::dbgs() << "BIND_OPCODE_DO_BIND_IMM_TIMES: " + << format("SegmentOffset=0x%06X", SegmentOffset) + << ", AdvanceAmount=" << AdvanceAmount + << ", RemainingLoopCount=" << RemainingLoopCount + << "\n"); + return; + case MachO::BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: + AdvanceAmount = ImmValue * PointerSize; + RemainingLoopCount = 0; + if (TableKind == Kind::Lazy) + Malformed = true; + DEBUG_WITH_TYPE("mach-o-bind", + llvm::dbgs() + << "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: " + << format("SegmentOffset=0x%06X", + SegmentOffset) << "\n"); + return; + case MachO::BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: + RemainingLoopCount = readULEB128() - 1; + AdvanceAmount = readULEB128() + PointerSize; + if (TableKind == Kind::Lazy) + Malformed = true; + DEBUG_WITH_TYPE( + "mach-o-bind", + llvm::dbgs() << "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: " + << format("SegmentOffset=0x%06X", SegmentOffset) + << ", AdvanceAmount=" << AdvanceAmount + << ", RemainingLoopCount=" << RemainingLoopCount + << "\n"); + return; + default: + Malformed = true; + } + } +} + +uint64_t MachOBindEntry::readULEB128() { + unsigned Count; + uint64_t Result = decodeULEB128(Ptr, &Count); + Ptr += Count; + if (Ptr > Opcodes.end()) { + Ptr = Opcodes.end(); + Malformed = true; + } + return Result; +} + +int64_t MachOBindEntry::readSLEB128() { + unsigned Count; + int64_t Result = decodeSLEB128(Ptr, &Count); + Ptr += Count; + if (Ptr > Opcodes.end()) { + Ptr = Opcodes.end(); + Malformed = true; + } + return Result; +} + + +uint32_t MachOBindEntry::segmentIndex() const { return SegmentIndex; } + +uint64_t MachOBindEntry::segmentOffset() const { return SegmentOffset; } + +StringRef MachOBindEntry::typeName() const { + switch (BindType) { + case MachO::BIND_TYPE_POINTER: + return "pointer"; + case MachO::BIND_TYPE_TEXT_ABSOLUTE32: + return "text abs32"; + case MachO::BIND_TYPE_TEXT_PCREL32: + return "text rel32"; + } + return "unknown"; +} + +StringRef MachOBindEntry::symbolName() const { return SymbolName; } + +int64_t MachOBindEntry::addend() const { return Addend; } + +uint32_t MachOBindEntry::flags() const { return Flags; } + +int MachOBindEntry::ordinal() const { return Ordinal; } + +bool MachOBindEntry::operator==(const MachOBindEntry &Other) const { + assert(Opcodes == Other.Opcodes && "compare iterators of different files"); + return (Ptr == Other.Ptr) && + (RemainingLoopCount == Other.RemainingLoopCount) && + (Done == Other.Done); +} + +iterator_range +MachOObjectFile::bindTable(ArrayRef Opcodes, bool is64, + MachOBindEntry::Kind BKind) { + MachOBindEntry Start(Opcodes, is64, BKind); + Start.moveToFirst(); + + MachOBindEntry Finish(Opcodes, is64, BKind); + Finish.moveToEnd(); + + return iterator_range(bind_iterator(Start), + bind_iterator(Finish)); +} + +iterator_range MachOObjectFile::bindTable() const { + return bindTable(getDyldInfoBindOpcodes(), is64Bit(), + MachOBindEntry::Kind::Regular); +} + +iterator_range MachOObjectFile::lazyBindTable() const { + return bindTable(getDyldInfoLazyBindOpcodes(), is64Bit(), + MachOBindEntry::Kind::Lazy); +} + +iterator_range MachOObjectFile::weakBindTable() const { + return bindTable(getDyldInfoWeakBindOpcodes(), is64Bit(), + MachOBindEntry::Kind::Weak); +} + StringRef MachOObjectFile::getSectionFinalSegmentName(DataRefImpl Sec) const { ArrayRef Raw = getSectionRawFinalSegmentName(Sec); @@ -1668,14 +2105,14 @@ ArrayRef MachOObjectFile::getSectionRawName(DataRefImpl Sec) const { const section_base *Base = reinterpret_cast(Sections[Sec.d.a]); - return ArrayRef(Base->sectname); + return makeArrayRef(Base->sectname); } ArrayRef MachOObjectFile::getSectionRawFinalSegmentName(DataRefImpl Sec) const { const section_base *Base = reinterpret_cast(Sections[Sec.d.a]); - return ArrayRef(Base->segname); + return makeArrayRef(Base->segname); } bool @@ -1831,6 +2268,31 @@ MachOObjectFile::getDylibIDLoadCommand(const LoadCommandInfo &L) const { return getStruct(this, L.Ptr); } +MachO::dyld_info_command +MachOObjectFile::getDyldInfoLoadCommand(const LoadCommandInfo &L) const { + return getStruct(this, L.Ptr); +} + +MachO::dylinker_command +MachOObjectFile::getDylinkerCommand(const LoadCommandInfo &L) const { + return getStruct(this, L.Ptr); +} + +MachO::uuid_command +MachOObjectFile::getUuidCommand(const LoadCommandInfo &L) const { + return getStruct(this, L.Ptr); +} + +MachO::source_version_command +MachOObjectFile::getSourceVersionCommand(const LoadCommandInfo &L) const { + return getStruct(this, L.Ptr); +} + +MachO::entry_point_command +MachOObjectFile::getEntryPointCommand(const LoadCommandInfo &L) const { + return getStruct(this, L.Ptr); +} + MachO::any_relocation_info MachOObjectFile::getRelocation(DataRefImpl Rel) const { @@ -1901,6 +2363,62 @@ MachOObjectFile::getDataInCodeLoadCommand() const { return Cmd; } +ArrayRef MachOObjectFile::getDyldInfoRebaseOpcodes() const { + if (!DyldInfoLoadCmd) + return ArrayRef(); + + MachO::dyld_info_command DyldInfo + = getStruct(this, DyldInfoLoadCmd); + const uint8_t *Ptr = reinterpret_cast( + getPtr(this, DyldInfo.rebase_off)); + return ArrayRef(Ptr, DyldInfo.rebase_size); +} + +ArrayRef MachOObjectFile::getDyldInfoBindOpcodes() const { + if (!DyldInfoLoadCmd) + return ArrayRef(); + + MachO::dyld_info_command DyldInfo + = getStruct(this, DyldInfoLoadCmd); + const uint8_t *Ptr = reinterpret_cast( + getPtr(this, DyldInfo.bind_off)); + return ArrayRef(Ptr, DyldInfo.bind_size); +} + +ArrayRef MachOObjectFile::getDyldInfoWeakBindOpcodes() const { + if (!DyldInfoLoadCmd) + return ArrayRef(); + + MachO::dyld_info_command DyldInfo + = getStruct(this, DyldInfoLoadCmd); + const uint8_t *Ptr = reinterpret_cast( + getPtr(this, DyldInfo.weak_bind_off)); + return ArrayRef(Ptr, DyldInfo.weak_bind_size); +} + +ArrayRef MachOObjectFile::getDyldInfoLazyBindOpcodes() const { + if (!DyldInfoLoadCmd) + return ArrayRef(); + + MachO::dyld_info_command DyldInfo + = getStruct(this, DyldInfoLoadCmd); + const uint8_t *Ptr = reinterpret_cast( + getPtr(this, DyldInfo.lazy_bind_off)); + return ArrayRef(Ptr, DyldInfo.lazy_bind_size); +} + +ArrayRef MachOObjectFile::getDyldInfoExportsTrie() const { + if (!DyldInfoLoadCmd) + return ArrayRef(); + + MachO::dyld_info_command DyldInfo + = getStruct(this, DyldInfoLoadCmd); + const uint8_t *Ptr = reinterpret_cast( + getPtr(this, DyldInfo.export_off)); + return ArrayRef(Ptr, DyldInfo.export_size); +} + + StringRef MachOObjectFile::getStringTableData() const { MachO::symtab_command S = getSymtabLoadCommand(); return getData().substr(S.stroff, S.strsize); @@ -1923,26 +2441,28 @@ void MachOObjectFile::ReadULEB128s(uint64_t Index, } } -ErrorOr -ObjectFile::createMachOObjectFile(std::unique_ptr &Buffer) { - StringRef Magic = Buffer->getBuffer().slice(0, 4); +bool MachOObjectFile::isRelocatableObject() const { + return getHeader().filetype == MachO::MH_OBJECT; +} + +ErrorOr> +ObjectFile::createMachOObjectFile(MemoryBufferRef Buffer) { + StringRef Magic = Buffer.getBuffer().slice(0, 4); std::error_code EC; std::unique_ptr Ret; if (Magic == "\xFE\xED\xFA\xCE") - Ret.reset(new MachOObjectFile(std::move(Buffer), false, false, EC)); + Ret.reset(new MachOObjectFile(Buffer, false, false, EC)); else if (Magic == "\xCE\xFA\xED\xFE") - Ret.reset(new MachOObjectFile(std::move(Buffer), true, false, EC)); + Ret.reset(new MachOObjectFile(Buffer, true, false, EC)); else if (Magic == "\xFE\xED\xFA\xCF") - Ret.reset(new MachOObjectFile(std::move(Buffer), false, true, EC)); + Ret.reset(new MachOObjectFile(Buffer, false, true, EC)); else if (Magic == "\xCF\xFA\xED\xFE") - Ret.reset(new MachOObjectFile(std::move(Buffer), true, true, EC)); + Ret.reset(new MachOObjectFile(Buffer, true, true, EC)); else return object_error::parse_failed; if (EC) return EC; - return Ret.release(); + return std::move(Ret); } -} // end namespace object -} // end namespace llvm