X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FObject%2FMachOObjectFile.cpp;h=d1f79b225ee42d155e87c3922255f9b6bdf52277;hb=b508a338d9d922a1ec3fbef698bd9fc6b5217ae0;hp=bb973b41db2d80ed57ec6eb42e2d273483a1a744;hpb=367cf70f27e2e3261df2b27fc89fafe5b0a1dc22;p=oota-llvm.git diff --git a/lib/Object/MachOObjectFile.cpp b/lib/Object/MachOObjectFile.cpp index bb973b41db2..d1f79b225ee 100644 --- a/lib/Object/MachOObjectFile.cpp +++ b/lib/Object/MachOObjectFile.cpp @@ -38,8 +38,13 @@ namespace { }; } -template +// FIXME: Replace all uses of this function with getStructOrErr. +template static T getStruct(const MachOObjectFile *O, const char *P) { + // Don't read before the beginning or past the end of the file + if (P < O->getData().begin() || P + sizeof(T) > O->getData().end()) + report_fatal_error("Malformed MachO file."); + T Cmd; memcpy(&Cmd, P, sizeof(T)); if (O->isLittleEndian() != sys::IsLittleEndianHost) @@ -47,28 +52,19 @@ static T getStruct(const MachOObjectFile *O, const char *P) { return Cmd; } -static uint32_t -getSegmentLoadCommandNumSections(const MachOObjectFile *O, - const MachOObjectFile::LoadCommandInfo &L) { - if (O->is64Bit()) { - MachO::segment_command_64 S = O->getSegment64LoadCommand(L); - return S.nsects; - } - MachO::segment_command S = O->getSegmentLoadCommand(L); - return S.nsects; -} +template +static ErrorOr getStructOrErr(const MachOObjectFile *O, const char *P) { + // Don't read before the beginning or past the end of the file + if (P < O->getData().begin() || P + sizeof(T) > O->getData().end()) + return object_error::parse_failed; -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); + T Cmd; + memcpy(&Cmd, P, sizeof(T)); + if (O->isLittleEndian() != sys::IsLittleEndianHost) + MachO::swapStruct(Cmd); + return Cmd; } - static const char * getSectionPtr(const MachOObjectFile *O, MachOObjectFile::LoadCommandInfo L, unsigned Sec) { @@ -113,72 +109,6 @@ static unsigned getCPUType(const MachOObjectFile *O) { return O->getHeader().cputype; } -static void printRelocationTargetName(const MachOObjectFile *O, - const MachO::any_relocation_info &RE, - raw_string_ostream &fmt) { - bool IsScattered = O->isRelocationScattered(RE); - - // Target of a scattered relocation is an address. In the interest of - // generating pretty output, scan through the symbol table looking for a - // symbol that aligns with that address. If we find one, print it. - // Otherwise, we just print the hex address of the target. - if (IsScattered) { - uint32_t Val = O->getPlainRelocationSymbolNum(RE); - - for (const SymbolRef &Symbol : O->symbols()) { - std::error_code ec; - uint64_t Addr; - StringRef Name; - - if ((ec = Symbol.getAddress(Addr))) - report_fatal_error(ec.message()); - if (Addr != Val) - continue; - if ((ec = Symbol.getName(Name))) - report_fatal_error(ec.message()); - fmt << Name; - return; - } - - // If we couldn't find a symbol that this relocation refers to, try - // 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()); - if (Addr != Val) - continue; - if ((ec = Section.getName(Name))) - report_fatal_error(ec.message()); - fmt << Name; - return; - } - - fmt << format("0x%x", Val); - return; - } - - StringRef S; - bool isExtern = O->getPlainRelocationExternal(RE); - uint64_t Val = O->getPlainRelocationSymbolNum(RE); - - if (isExtern) { - symbol_iterator SI = O->symbol_begin(); - advance(SI, Val); - SI->getName(S); - } else { - section_iterator SI = O->section_begin(); - // Adjust for the fact that sections are 1-indexed. - advance(SI, Val - 1); - SI->getName(S); - } - - fmt << S; -} - static uint32_t getPlainRelocationAddress(const MachO::any_relocation_info &RE) { return RE.r_word0; @@ -221,11 +151,6 @@ static unsigned getPlainRelocationType(const MachOObjectFile *O, return RE.r_word1 & 0xf; } -static unsigned -getScatteredRelocationType(const MachO::any_relocation_info &RE) { - return (RE.r_word0 >> 24) & 0xf; -} - static uint32_t getSectionFlags(const MachOObjectFile *O, DataRefImpl Sec) { if (O->is64Bit()) { @@ -236,39 +161,146 @@ static uint32_t getSectionFlags(const MachOObjectFile *O, return Sect.flags; } +static ErrorOr +getLoadCommandInfo(const MachOObjectFile *Obj, const char *Ptr) { + auto CmdOrErr = getStructOrErr(Obj, Ptr); + if (!CmdOrErr) + return CmdOrErr.getError(); + if (CmdOrErr->cmdsize < 8) + return object_error::macho_small_load_command; + MachOObjectFile::LoadCommandInfo Load; + Load.Ptr = Ptr; + Load.C = CmdOrErr.get(); + return Load; +} + +static ErrorOr +getFirstLoadCommandInfo(const MachOObjectFile *Obj) { + unsigned HeaderSize = Obj->is64Bit() ? sizeof(MachO::mach_header_64) + : sizeof(MachO::mach_header); + return getLoadCommandInfo(Obj, getPtr(Obj, HeaderSize)); +} + +static ErrorOr +getNextLoadCommandInfo(const MachOObjectFile *Obj, + const MachOObjectFile::LoadCommandInfo &L) { + return getLoadCommandInfo(Obj, L.Ptr + L.C.cmdsize); +} + +template +static void parseHeader(const MachOObjectFile *Obj, T &Header, + std::error_code &EC) { + auto HeaderOrErr = getStructOrErr(Obj, getPtr(Obj, 0)); + if (HeaderOrErr) + Header = HeaderOrErr.get(); + else + EC = HeaderOrErr.getError(); +} + +// Parses LC_SEGMENT or LC_SEGMENT_64 load command, adds addresses of all +// sections to \param Sections, and optionally sets +// \param IsPageZeroSegment to true. +template +static std::error_code parseSegmentLoadCommand( + const MachOObjectFile *Obj, const MachOObjectFile::LoadCommandInfo &Load, + SmallVectorImpl &Sections, bool &IsPageZeroSegment) { + const unsigned SegmentLoadSize = sizeof(SegmentCmd); + if (Load.C.cmdsize < SegmentLoadSize) + return object_error::macho_load_segment_too_small; + auto SegOrErr = getStructOrErr(Obj, Load.Ptr); + if (!SegOrErr) + return SegOrErr.getError(); + SegmentCmd S = SegOrErr.get(); + const unsigned SectionSize = + Obj->is64Bit() ? sizeof(MachO::section_64) : sizeof(MachO::section); + if (S.nsects > std::numeric_limits::max() / SectionSize || + S.nsects * SectionSize > Load.C.cmdsize - SegmentLoadSize) + return object_error::macho_load_segment_too_many_sections; + for (unsigned J = 0; J < S.nsects; ++J) { + const char *Sec = getSectionPtr(Obj, Load, J); + Sections.push_back(Sec); + } + IsPageZeroSegment |= StringRef("__PAGEZERO").equals(S.segname); + return std::error_code(); +} + MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, bool Is64bits, std::error_code &EC) : ObjectFile(getMachOType(IsLittleEndian, Is64bits), Object), SymtabLoadCmd(nullptr), DysymtabLoadCmd(nullptr), - DataInCodeLoadCmd(nullptr), DyldInfoLoadCmd(nullptr), + DataInCodeLoadCmd(nullptr), LinkOptHintsLoadCmd(nullptr), + DyldInfoLoadCmd(nullptr), UuidLoadCmd(nullptr), HasPageZeroSegment(false) { - uint32_t LoadCommandCount = this->getHeader().ncmds; - MachO::LoadCommandType SegmentLoadType = is64Bit() ? - MachO::LC_SEGMENT_64 : MachO::LC_SEGMENT; + if (is64Bit()) + parseHeader(this, Header64, EC); + else + parseHeader(this, Header, EC); + if (EC) + return; - MachOObjectFile::LoadCommandInfo Load = getFirstLoadCommandInfo(); - for (unsigned I = 0; ; ++I) { + uint32_t LoadCommandCount = getHeader().ncmds; + if (LoadCommandCount == 0) + return; + + auto LoadOrErr = getFirstLoadCommandInfo(this); + if (!LoadOrErr) { + EC = LoadOrErr.getError(); + return; + } + LoadCommandInfo Load = LoadOrErr.get(); + for (unsigned I = 0; I < LoadCommandCount; ++I) { + LoadCommands.push_back(Load); if (Load.C.cmd == MachO::LC_SYMTAB) { - assert(!SymtabLoadCmd && "Multiple symbol tables"); + // Multiple symbol tables + if (SymtabLoadCmd) { + EC = object_error::parse_failed; + return; + } SymtabLoadCmd = Load.Ptr; } else if (Load.C.cmd == MachO::LC_DYSYMTAB) { - assert(!DysymtabLoadCmd && "Multiple dynamic symbol tables"); + // Multiple dynamic symbol tables + if (DysymtabLoadCmd) { + EC = object_error::parse_failed; + return; + } DysymtabLoadCmd = Load.Ptr; } else if (Load.C.cmd == MachO::LC_DATA_IN_CODE) { - assert(!DataInCodeLoadCmd && "Multiple data in code tables"); + // Multiple data in code tables + if (DataInCodeLoadCmd) { + EC = object_error::parse_failed; + return; + } DataInCodeLoadCmd = Load.Ptr; - } else if (Load.C.cmd == MachO::LC_DYLD_INFO || + } else if (Load.C.cmd == MachO::LC_LINKER_OPTIMIZATION_HINT) { + // Multiple linker optimization hint tables + if (LinkOptHintsLoadCmd) { + EC = object_error::parse_failed; + return; + } + LinkOptHintsLoadCmd = 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"); + // Multiple dyldinfo load commands + if (DyldInfoLoadCmd) { + EC = object_error::parse_failed; + return; + } 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); + } else if (Load.C.cmd == MachO::LC_UUID) { + // Multiple UUID load commands + if (UuidLoadCmd) { + EC = object_error::parse_failed; + return; } - if (isPageZeroSegment(this, Load)) - HasPageZeroSegment = true; + UuidLoadCmd = Load.Ptr; + } else if (Load.C.cmd == MachO::LC_SEGMENT_64) { + if ((EC = parseSegmentLoadCommand( + this, Load, Sections, HasPageZeroSegment))) + return; + } else if (Load.C.cmd == MachO::LC_SEGMENT) { + if ((EC = parseSegmentLoadCommand( + this, Load, Sections, HasPageZeroSegment))) + return; } 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 || @@ -276,12 +308,16 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB) { Libraries.push_back(Load.Ptr); } - - if (I == LoadCommandCount - 1) - break; - else - Load = getNextLoadCommandInfo(Load); + if (I < LoadCommandCount - 1) { + auto LoadOrErr = getNextLoadCommandInfo(this, Load); + if (!LoadOrErr) { + EC = LoadOrErr.getError(); + return; + } + Load = LoadOrErr.get(); + } } + assert(LoadCommands.size() == LoadCommandCount); } void MachOObjectFile::moveSymbolNext(DataRefImpl &Symb) const { @@ -291,13 +327,29 @@ void MachOObjectFile::moveSymbolNext(DataRefImpl &Symb) const { Symb.p += SymbolTableEntrySize; } -std::error_code MachOObjectFile::getSymbolName(DataRefImpl Symb, - StringRef &Res) const { +ErrorOr MachOObjectFile::getSymbolName(DataRefImpl Symb) const { StringRef StringTable = getStringTableData(); MachO::nlist_base Entry = getSymbolTableEntryBase(this, Symb); const char *Start = &StringTable.data()[Entry.n_strx]; - Res = StringRef(Start); - return object_error::success; + if (Start < getData().begin() || Start >= getData().end()) + report_fatal_error( + "Symbol name entry points before beginning or past end of file."); + return StringRef(Start); +} + +unsigned MachOObjectFile::getSectionType(SectionRef Sec) const { + DataRefImpl DRI = Sec.getRawDataRefImpl(); + uint32_t Flags = getSectionFlags(this, DRI); + return Flags & MachO::SECTION_TYPE; +} + +uint64_t MachOObjectFile::getNValue(DataRefImpl Sym) const { + if (is64Bit()) { + MachO::nlist_64 Entry = getSymbol64TableEntry(Sym); + return Entry.n_value; + } + MachO::nlist Entry = getSymbolTableEntry(Sym); + return Entry.n_value; } // getIndirectName() returns the name of the alias'ed symbol who's string table @@ -305,128 +357,56 @@ std::error_code MachOObjectFile::getSymbolName(DataRefImpl Symb, std::error_code MachOObjectFile::getIndirectName(DataRefImpl Symb, StringRef &Res) const { StringRef StringTable = getStringTableData(); - uint64_t NValue; - if (is64Bit()) { - MachO::nlist_64 Entry = getSymbol64TableEntry(Symb); - NValue = Entry.n_value; - if ((Entry.n_type & MachO::N_TYPE) != MachO::N_INDR) - return object_error::parse_failed; - } else { - MachO::nlist Entry = getSymbolTableEntry(Symb); - NValue = Entry.n_value; - if ((Entry.n_type & MachO::N_TYPE) != MachO::N_INDR) - return object_error::parse_failed; - } + MachO::nlist_base Entry = getSymbolTableEntryBase(this, Symb); + if ((Entry.n_type & MachO::N_TYPE) != MachO::N_INDR) + return object_error::parse_failed; + uint64_t NValue = getNValue(Symb); if (NValue >= StringTable.size()) return object_error::parse_failed; const char *Start = &StringTable.data()[NValue]; Res = StringRef(Start); - return object_error::success; + return std::error_code(); } -std::error_code MachOObjectFile::getSymbolAddress(DataRefImpl Symb, - uint64_t &Res) const { - if (is64Bit()) { - MachO::nlist_64 Entry = getSymbol64TableEntry(Symb); - if ((Entry.n_type & MachO::N_TYPE) == MachO::N_UNDF && - Entry.n_value == 0) - Res = UnknownAddressOrSize; - else - Res = Entry.n_value; - } else { - MachO::nlist Entry = getSymbolTableEntry(Symb); - if ((Entry.n_type & MachO::N_TYPE) == MachO::N_UNDF && - Entry.n_value == 0) - Res = UnknownAddressOrSize; - else - Res = Entry.n_value; - } - return object_error::success; +uint64_t MachOObjectFile::getSymbolValueImpl(DataRefImpl Sym) const { + return getNValue(Sym); +} + +ErrorOr MachOObjectFile::getSymbolAddress(DataRefImpl Sym) const { + return getSymbolValue(Sym); } -std::error_code MachOObjectFile::getSymbolAlignment(DataRefImpl DRI, - uint32_t &Result) const { +uint32_t MachOObjectFile::getSymbolAlignment(DataRefImpl DRI) const { uint32_t flags = getSymbolFlags(DRI); if (flags & SymbolRef::SF_Common) { MachO::nlist_base Entry = getSymbolTableEntryBase(this, DRI); - Result = 1 << MachO::GET_COMM_ALIGN(Entry.n_desc); - } else { - Result = 0; + return 1 << MachO::GET_COMM_ALIGN(Entry.n_desc); } - return object_error::success; + return 0; } -std::error_code MachOObjectFile::getSymbolSize(DataRefImpl DRI, - uint64_t &Result) const { - uint64_t BeginOffset; - uint64_t EndOffset = 0; - uint8_t SectionIndex; - - MachO::nlist_base Entry = getSymbolTableEntryBase(this, DRI); - uint64_t Value; - getSymbolAddress(DRI, Value); - if (Value == UnknownAddressOrSize) { - Result = UnknownAddressOrSize; - return object_error::success; - } - - BeginOffset = Value; - - SectionIndex = Entry.n_sect; - if (!SectionIndex) { - uint32_t flags = getSymbolFlags(DRI); - if (flags & SymbolRef::SF_Common) - Result = Value; - else - Result = UnknownAddressOrSize; - return object_error::success; - } - // Unfortunately symbols are unsorted so we need to touch all - // symbols from load command - for (const SymbolRef &Symbol : symbols()) { - DataRefImpl DRI = Symbol.getRawDataRefImpl(); - Entry = getSymbolTableEntryBase(this, DRI); - getSymbolAddress(DRI, Value); - if (Value == UnknownAddressOrSize) - continue; - if (Entry.n_sect == SectionIndex && Value > BeginOffset) - if (!EndOffset || Value < EndOffset) - EndOffset = Value; - } - if (!EndOffset) { - uint64_t Size; - DataRefImpl Sec; - Sec.d.a = SectionIndex-1; - getSectionSize(Sec, Size); - getSectionAddress(Sec, EndOffset); - EndOffset += Size; - } - Result = EndOffset - BeginOffset; - return object_error::success; +uint64_t MachOObjectFile::getCommonSymbolSizeImpl(DataRefImpl DRI) const { + return getNValue(DRI); } -std::error_code MachOObjectFile::getSymbolType(DataRefImpl Symb, - SymbolRef::Type &Res) const { +SymbolRef::Type MachOObjectFile::getSymbolType(DataRefImpl Symb) const { MachO::nlist_base Entry = getSymbolTableEntryBase(this, Symb); uint8_t n_type = Entry.n_type; - Res = SymbolRef::ST_Other; - // If this is a STAB debugging symbol, we can do nothing more. - if (n_type & MachO::N_STAB) { - Res = SymbolRef::ST_Debug; - return object_error::success; - } + if (n_type & MachO::N_STAB) + return SymbolRef::ST_Debug; switch (n_type & MachO::N_TYPE) { case MachO::N_UNDF : - Res = SymbolRef::ST_Unknown; - break; + return SymbolRef::ST_Unknown; case MachO::N_SECT : - Res = SymbolRef::ST_Function; - break; + section_iterator Sec = *getSymbolSection(Symb); + if (Sec->isData() || Sec->isBSS()) + return SymbolRef::ST_Data; + return SymbolRef::ST_Function; } - return object_error::success; + return SymbolRef::ST_Other; } uint32_t MachOObjectFile::getSymbolFlags(DataRefImpl DRI) const { @@ -437,9 +417,6 @@ uint32_t MachOObjectFile::getSymbolFlags(DataRefImpl DRI) const { uint32_t Result = SymbolRef::SF_None; - if ((MachOType & MachO::N_TYPE) == MachO::N_UNDF) - Result |= SymbolRef::SF_Undefined; - if ((MachOType & MachO::N_TYPE) == MachO::N_INDR) Result |= SymbolRef::SF_Indirect; @@ -449,11 +426,14 @@ uint32_t MachOObjectFile::getSymbolFlags(DataRefImpl DRI) const { if (MachOType & MachO::N_EXT) { Result |= SymbolRef::SF_Global; if ((MachOType & MachO::N_TYPE) == MachO::N_UNDF) { - uint64_t Value; - getSymbolAddress(DRI, Value); - if (Value && Value != UnknownAddressOrSize) + if (getNValue(DRI)) Result |= SymbolRef::SF_Common; + else + Result |= SymbolRef::SF_Undefined; } + + if (!(MachOType & MachO::N_PEXT)) + Result |= SymbolRef::SF_Exported; } if (MachOFlags & (MachO::N_WEAK_REF | MachO::N_WEAK_DEF)) @@ -468,20 +448,24 @@ uint32_t MachOObjectFile::getSymbolFlags(DataRefImpl DRI) const { return Result; } -std::error_code MachOObjectFile::getSymbolSection(DataRefImpl Symb, - section_iterator &Res) const { +ErrorOr +MachOObjectFile::getSymbolSection(DataRefImpl Symb) const { MachO::nlist_base Entry = getSymbolTableEntryBase(this, Symb); uint8_t index = Entry.n_sect; - if (index == 0) { - Res = section_end(); - } else { - DataRefImpl DRI; - DRI.d.a = index - 1; - Res = section_iterator(SectionRef(DRI, this)); - } + if (index == 0) + return section_end(); + DataRefImpl DRI; + DRI.d.a = index - 1; + if (DRI.d.a >= Sections.size()) + report_fatal_error("getSymbolSection: Invalid section index."); + return section_iterator(SectionRef(DRI, this)); +} - return object_error::success; +unsigned MachOObjectFile::getSymbolSectionID(SymbolRef Sym) const { + MachO::nlist_base Entry = + getSymbolTableEntryBase(this, Sym.getRawDataRefImpl()); + return Entry.n_sect - 1; } void MachOObjectFile::moveSectionNext(DataRefImpl &Sec) const { @@ -492,32 +476,42 @@ std::error_code MachOObjectFile::getSectionName(DataRefImpl Sec, StringRef &Result) const { ArrayRef Raw = getSectionRawName(Sec); Result = parseSegmentOrSectionName(Raw.data()); - return object_error::success; + return std::error_code(); } -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 { +uint64_t MachOObjectFile::getSectionSize(DataRefImpl Sec) const { + // In the case if a malformed Mach-O file where the section offset is past + // the end of the file or some part of the section size is past the end of + // the file return a size of zero or a size that covers the rest of the file + // but does not extend past the end of the file. + uint32_t SectOffset, SectType; + uint64_t SectSize; + if (is64Bit()) { MachO::section_64 Sect = getSection64(Sec); - Res = Sect.size; + SectOffset = Sect.offset; + SectSize = Sect.size; + SectType = Sect.flags & MachO::SECTION_TYPE; } else { MachO::section Sect = getSection(Sec); - Res = Sect.size; + SectOffset = Sect.offset; + SectSize = Sect.size; + SectType = Sect.flags & MachO::SECTION_TYPE; } - - return object_error::success; + if (SectType == MachO::S_ZEROFILL || SectType == MachO::S_GB_ZEROFILL) + return SectSize; + uint64_t FileSize = getData().size(); + if (SectOffset > FileSize) + return 0; + if (FileSize - SectOffset < SectSize) + return FileSize - SectOffset; + return SectSize; } std::error_code MachOObjectFile::getSectionContents(DataRefImpl Sec, @@ -536,11 +530,10 @@ std::error_code MachOObjectFile::getSectionContents(DataRefImpl Sec, } Res = this->getData().substr(Offset, Size); - return object_error::success; + return std::error_code(); } -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); @@ -550,92 +543,37 @@ 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 { - // FIXME: Unimplemented. - Result = true; - return object_error::success; +unsigned MachOObjectFile::getSectionID(SectionRef Sec) const { + return Sec.getRawDataRefImpl().d.a; } -std::error_code MachOObjectFile::isSectionVirtual(DataRefImpl Sec, - bool &Result) const { +bool MachOObjectFile::isSectionVirtual(DataRefImpl Sec) const { // FIXME: Unimplemented. - Result = false; - return object_error::success; -} - -std::error_code MachOObjectFile::isSectionZeroInit(DataRefImpl Sec, - bool &Res) 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; -} - -std::error_code MachOObjectFile::isSectionReadOnlyData(DataRefImpl Sec, - bool &Result) 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; -} - -std::error_code MachOObjectFile::sectionContainsSymbol(DataRefImpl Sec, - DataRefImpl Symb, - bool &Result) const { - SymbolRef::Type ST; - this->getSymbolType(Symb, ST); - if (ST == SymbolRef::ST_Unknown) { - Result = false; - return object_error::success; - } - - uint64_t SectBegin, SectEnd; - getSectionAddress(Sec, SectBegin); - getSectionSize(Sec, SectEnd); - SectEnd += SectBegin; - - uint64_t SymAddr; - getSymbolAddress(Symb, SymAddr); - Result = (SymAddr >= SectBegin) && (SymAddr < SectEnd); - - return object_error::success; + return false; } relocation_iterator MachOObjectFile::section_rel_begin(DataRefImpl Sec) const { @@ -666,26 +604,11 @@ void MachOObjectFile::moveRelocationNext(DataRefImpl &Rel) const { ++Rel.d.b; } -std::error_code MachOObjectFile::getRelocationAddress(DataRefImpl Rel, - uint64_t &Res) const { - uint64_t Offset; - getRelocationOffset(Rel, Offset); - - DataRefImpl Sec; - Sec.d.a = Rel.d.a; - uint64_t SecAddress; - getSectionAddress(Sec, SecAddress); - Res = SecAddress + Offset; - return object_error::success; -} - -std::error_code MachOObjectFile::getRelocationOffset(DataRefImpl Rel, - uint64_t &Res) const { +uint64_t MachOObjectFile::getRelocationOffset(DataRefImpl Rel) const { assert(getHeader().filetype == MachO::MH_OBJECT && "Only implemented for MH_OBJECT"); MachO::any_relocation_info RE = getRelocation(Rel); - Res = getAnyRelocationAddress(RE); - return object_error::success; + return getAnyRelocationAddress(RE); } symbol_iterator @@ -709,19 +632,20 @@ MachOObjectFile::getRelocationSymbol(DataRefImpl Rel) const { return symbol_iterator(SymbolRef(Sym, this)); } -std::error_code MachOObjectFile::getRelocationType(DataRefImpl Rel, - uint64_t &Res) const { +section_iterator +MachOObjectFile::getRelocationSection(DataRefImpl Rel) const { + return section_iterator(getAnyRelocationSection(getRelocation(Rel))); +} + +uint64_t MachOObjectFile::getRelocationType(DataRefImpl Rel) const { MachO::any_relocation_info RE = getRelocation(Rel); - Res = getAnyRelocationType(RE); - return object_error::success; + return getAnyRelocationType(RE); } -std::error_code -MachOObjectFile::getRelocationTypeName(DataRefImpl Rel, - SmallVectorImpl &Result) const { +void MachOObjectFile::getRelocationTypeName( + DataRefImpl Rel, SmallVectorImpl &Result) const { StringRef res; - uint64_t RType; - getRelocationType(Rel, RType); + uint64_t RType = getRelocationType(Rel); unsigned Arch = this->getArch(); @@ -825,211 +749,11 @@ MachOObjectFile::getRelocationTypeName(DataRefImpl Rel, break; } Result.append(res.begin(), res.end()); - return object_error::success; } -std::error_code -MachOObjectFile::getRelocationValueString(DataRefImpl Rel, - SmallVectorImpl &Result) const { +uint8_t MachOObjectFile::getRelocationLength(DataRefImpl Rel) const { MachO::any_relocation_info RE = getRelocation(Rel); - - unsigned Arch = this->getArch(); - - std::string fmtbuf; - raw_string_ostream fmt(fmtbuf); - unsigned Type = this->getAnyRelocationType(RE); - bool IsPCRel = this->getAnyRelocationPCRel(RE); - - // Determine any addends that should be displayed with the relocation. - // These require decoding the relocation type, which is triple-specific. - - // X86_64 has entirely custom relocation types. - if (Arch == Triple::x86_64) { - bool isPCRel = getAnyRelocationPCRel(RE); - - switch (Type) { - case MachO::X86_64_RELOC_GOT_LOAD: - case MachO::X86_64_RELOC_GOT: { - printRelocationTargetName(this, RE, fmt); - fmt << "@GOT"; - if (isPCRel) fmt << "PCREL"; - break; - } - case MachO::X86_64_RELOC_SUBTRACTOR: { - DataRefImpl RelNext = Rel; - moveRelocationNext(RelNext); - MachO::any_relocation_info RENext = getRelocation(RelNext); - - // X86_64_RELOC_SUBTRACTOR must be followed by a relocation of type - // X86_64_RELOC_UNSIGNED. - // NOTE: Scattered relocations don't exist on x86_64. - unsigned RType = getAnyRelocationType(RENext); - if (RType != MachO::X86_64_RELOC_UNSIGNED) - report_fatal_error("Expected X86_64_RELOC_UNSIGNED after " - "X86_64_RELOC_SUBTRACTOR."); - - // The X86_64_RELOC_UNSIGNED contains the minuend symbol; - // X86_64_RELOC_SUBTRACTOR contains the subtrahend. - printRelocationTargetName(this, RENext, fmt); - fmt << "-"; - printRelocationTargetName(this, RE, fmt); - break; - } - case MachO::X86_64_RELOC_TLV: - printRelocationTargetName(this, RE, fmt); - fmt << "@TLV"; - if (isPCRel) fmt << "P"; - break; - case MachO::X86_64_RELOC_SIGNED_1: - printRelocationTargetName(this, RE, fmt); - fmt << "-1"; - break; - case MachO::X86_64_RELOC_SIGNED_2: - printRelocationTargetName(this, RE, fmt); - fmt << "-2"; - break; - case MachO::X86_64_RELOC_SIGNED_4: - printRelocationTargetName(this, RE, fmt); - fmt << "-4"; - break; - default: - printRelocationTargetName(this, RE, fmt); - break; - } - // X86 and ARM share some relocation types in common. - } else if (Arch == Triple::x86 || Arch == Triple::arm || - Arch == Triple::ppc) { - // Generic relocation types... - switch (Type) { - case MachO::GENERIC_RELOC_PAIR: // prints no info - return object_error::success; - case MachO::GENERIC_RELOC_SECTDIFF: { - DataRefImpl RelNext = Rel; - moveRelocationNext(RelNext); - MachO::any_relocation_info RENext = getRelocation(RelNext); - - // X86 sect diff's must be followed by a relocation of type - // GENERIC_RELOC_PAIR. - unsigned RType = getAnyRelocationType(RENext); - - if (RType != MachO::GENERIC_RELOC_PAIR) - report_fatal_error("Expected GENERIC_RELOC_PAIR after " - "GENERIC_RELOC_SECTDIFF."); - - printRelocationTargetName(this, RE, fmt); - fmt << "-"; - printRelocationTargetName(this, RENext, fmt); - break; - } - } - - if (Arch == Triple::x86 || Arch == Triple::ppc) { - switch (Type) { - case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: { - DataRefImpl RelNext = Rel; - moveRelocationNext(RelNext); - MachO::any_relocation_info RENext = getRelocation(RelNext); - - // X86 sect diff's must be followed by a relocation of type - // GENERIC_RELOC_PAIR. - unsigned RType = getAnyRelocationType(RENext); - if (RType != MachO::GENERIC_RELOC_PAIR) - report_fatal_error("Expected GENERIC_RELOC_PAIR after " - "GENERIC_RELOC_LOCAL_SECTDIFF."); - - printRelocationTargetName(this, RE, fmt); - fmt << "-"; - printRelocationTargetName(this, RENext, fmt); - break; - } - case MachO::GENERIC_RELOC_TLV: { - printRelocationTargetName(this, RE, fmt); - fmt << "@TLV"; - if (IsPCRel) fmt << "P"; - break; - } - default: - printRelocationTargetName(this, RE, fmt); - } - } else { // ARM-specific relocations - switch (Type) { - case MachO::ARM_RELOC_HALF: - case MachO::ARM_RELOC_HALF_SECTDIFF: { - // Half relocations steal a bit from the length field to encode - // whether this is an upper16 or a lower16 relocation. - bool isUpper = getAnyRelocationLength(RE) >> 1; - - if (isUpper) - fmt << ":upper16:("; - else - fmt << ":lower16:("; - printRelocationTargetName(this, RE, fmt); - - DataRefImpl RelNext = Rel; - moveRelocationNext(RelNext); - MachO::any_relocation_info RENext = getRelocation(RelNext); - - // ARM half relocs must be followed by a relocation of type - // ARM_RELOC_PAIR. - unsigned RType = getAnyRelocationType(RENext); - if (RType != MachO::ARM_RELOC_PAIR) - report_fatal_error("Expected ARM_RELOC_PAIR after " - "ARM_RELOC_HALF"); - - // NOTE: The half of the target virtual address is stashed in the - // address field of the secondary relocation, but we can't reverse - // engineer the constant offset from it without decoding the movw/movt - // instruction to find the other half in its immediate field. - - // ARM_RELOC_HALF_SECTDIFF encodes the second section in the - // symbol/section pointer of the follow-on relocation. - if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) { - fmt << "-"; - printRelocationTargetName(this, RENext, fmt); - } - - fmt << ")"; - break; - } - default: { - printRelocationTargetName(this, RE, fmt); - } - } - } - } else - printRelocationTargetName(this, RE, fmt); - - fmt.flush(); - Result.append(fmtbuf.begin(), fmtbuf.end()); - return object_error::success; -} - -std::error_code MachOObjectFile::getRelocationHidden(DataRefImpl Rel, - bool &Result) const { - unsigned Arch = getArch(); - uint64_t Type; - getRelocationType(Rel, Type); - - Result = false; - - // On arches that use the generic relocations, GENERIC_RELOC_PAIR - // is always hidden. - if (Arch == Triple::x86 || Arch == Triple::arm || Arch == Triple::ppc) { - if (Type == MachO::GENERIC_RELOC_PAIR) Result = true; - } else if (Arch == Triple::x86_64) { - // On x86_64, X86_64_RELOC_UNSIGNED is hidden only when it follows - // an X86_64_RELOC_SUBTRACTOR. - if (Type == MachO::X86_64_RELOC_UNSIGNED && Rel.d.a > 0) { - DataRefImpl RelPrev = Rel; - RelPrev.d.a--; - uint64_t PrevType; - getRelocationType(RelPrev, PrevType); - if (PrevType == MachO::X86_64_RELOC_SUBTRACTOR) - Result = true; - } - } - - return object_error::success; + return getAnyRelocationLength(RE); } // @@ -1184,27 +908,22 @@ std::error_code MachOObjectFile::getLibraryShortNameByIndex(unsigned Index, 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); @@ -1212,7 +931,14 @@ std::error_code MachOObjectFile::getLibraryShortNameByIndex(unsigned Index, } Res = LibrariesShortNames[Index]; - return object_error::success; + return std::error_code(); +} + +section_iterator +MachOObjectFile::getRelocationRelocatedSection(relocation_iterator Rel) const { + DataRefImpl Sec; + Sec.d.a = Rel->getRawDataRefImpl().d.a; + return section_iterator(SectionRef(Sec, this)); } basic_symbol_iterator MachOObjectFile::symbol_begin_impl() const { @@ -1240,7 +966,8 @@ basic_symbol_iterator MachOObjectFile::getSymbolByIndex(unsigned Index) const { return basic_symbol_iterator(SymbolRef(DRI, this)); MachO::symtab_command Symtab = getSymtabLoadCommand(); - assert(Index < Symtab.nsyms && "Requested symbol index is out of range."); + if (Index >= Symtab.nsyms) + report_fatal_error("Requested symbol index is out of range."); unsigned SymbolTableEntrySize = is64Bit() ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist); DRI.p = reinterpret_cast(getPtr(this, Symtab.symoff)); @@ -1274,17 +1001,10 @@ StringRef MachOObjectFile::getFileFormatName() const { case llvm::MachO::CPU_TYPE_POWERPC: return "Mach-O 32-bit ppc"; default: - assert((CPUType & llvm::MachO::CPU_ARCH_ABI64) == 0 && - "64-bit object file when we're not 64-bit?"); return "Mach-O 32-bit unknown"; } } - // Make sure the cpu type has the correct mask. - assert((CPUType & llvm::MachO::CPU_ARCH_ABI64) - == llvm::MachO::CPU_ARCH_ABI64 && - "32-bit object file when we're 64-bit?"); - switch (CPUType) { case llvm::MachO::CPU_TYPE_X86_64: return "Mach-O 64-bit x86-64"; @@ -1438,8 +1158,7 @@ Triple MachOObjectFile::getThumbArch(uint32_t CPUType, uint32_t CPUSubType, } Triple MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType, - const char **McpuDefault, - Triple *ThumbTriple) { + const char **McpuDefault, Triple *ThumbTriple) { Triple T = MachOObjectFile::getArch(CPUType, CPUSubType, McpuDefault); *ThumbTriple = MachOObjectFile::getThumbArch(CPUType, CPUSubType, McpuDefault); @@ -1460,6 +1179,7 @@ bool MachOObjectFile::isValidArch(StringRef ArchFlag) { .Case("armv5e", true) .Case("armv6", true) .Case("armv6m", true) + .Case("armv7", true) .Case("armv7em", true) .Case("armv7k", true) .Case("armv7m", true) @@ -1476,21 +1196,8 @@ unsigned MachOObjectFile::getArch() const { 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; + *ThumbTriple = getThumbArch(Header.cputype, Header.cpusubtype, McpuDefault); + return getArch(Header.cputype, Header.cpusubtype, McpuDefault); } relocation_iterator MachOObjectFile::section_rel_begin(unsigned Index) const { @@ -1526,8 +1233,8 @@ dice_iterator MachOObjectFile::end_dices() const { return dice_iterator(DiceRef(DRI, this)); } -ExportEntry::ExportEntry(ArrayRef T) - : Trie(T), Malformed(false), Done(false) { } +ExportEntry::ExportEntry(ArrayRef T) + : Trie(T), Malformed(false), Done(false) {} void ExportEntry::moveToFirst() { pushNode(0); @@ -1540,21 +1247,21 @@ void ExportEntry::moveToEnd() { } bool ExportEntry::operator==(const ExportEntry &Other) const { - // Common case, one at end, other iterating from begin. + // 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())) + if (!CumulativeString.equals(Other.CumulativeString)) 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; + return true; } uint64_t ExportEntry::readULEB128(const uint8_t *&Ptr) { @@ -1569,7 +1276,7 @@ uint64_t ExportEntry::readULEB128(const uint8_t *&Ptr) { } StringRef ExportEntry::name() const { - return CumulativeString.str(); + return CumulativeString; } uint64_t ExportEntry::flags() const { @@ -1595,11 +1302,10 @@ 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) { -} +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; @@ -1616,7 +1322,7 @@ void ExportEntry::pushNode(uint64_t offset) { } else { State.Address = readULEB128(State.Current); if (State.Flags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) - State.Other = readULEB128(State.Current); + State.Other = readULEB128(State.Current); } } State.ChildCount = *Children; @@ -1651,9 +1357,9 @@ void ExportEntry::pushDownUntilBottom() { // 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 +// 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. +// 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 @@ -1686,23 +1392,24 @@ void ExportEntry::moveNext() { Done = true; } -iterator_range +iterator_range MachOObjectFile::exports(ArrayRef Trie) { ExportEntry Start(Trie); - Start.moveToFirst(); + if (Trie.size() == 0) + Start.moveToEnd(); + else + Start.moveToFirst(); ExportEntry Finish(Trie); Finish.moveToEnd(); - return iterator_range(export_iterator(Start), - export_iterator(Finish)); + return make_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), @@ -1866,17 +1573,14 @@ MachOObjectFile::rebaseTable(ArrayRef Opcodes, bool is64) { MachORebaseEntry Finish(Opcodes, is64); Finish.moveToEnd(); - return iterator_range(rebase_iterator(Start), - rebase_iterator(Finish)); + return make_range(rebase_iterator(Start), rebase_iterator(Finish)); } iterator_range MachOObjectFile::rebaseTable() const { return rebaseTable(getDyldInfoRebaseOpcodes(), is64Bit()); } - -MachOBindEntry::MachOBindEntry(ArrayRef Bytes, bool is64Bit, - Kind BK) +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), @@ -1962,9 +1666,9 @@ void MachOBindEntry::moveNext() { while (*Ptr) { ++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: " @@ -2016,20 +1720,20 @@ void MachOBindEntry::moveNext() { SegmentOffset) << "\n"); return; case MachO::BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: - AdvanceAmount = readULEB128(); + AdvanceAmount = readULEB128() + PointerSize; RemainingLoopCount = 0; if (TableKind == Kind::Lazy) Malformed = true; DEBUG_WITH_TYPE( "mach-o-bind", - llvm::dbgs() << "BIND_OPCODE_DO_BIND_IMM_TIMES: " + llvm::dbgs() << "BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: " << format("SegmentOffset=0x%06X", SegmentOffset) << ", AdvanceAmount=" << AdvanceAmount << ", RemainingLoopCount=" << RemainingLoopCount << "\n"); return; case MachO::BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: - AdvanceAmount = ImmValue * PointerSize; + AdvanceAmount = ImmValue * PointerSize + PointerSize; RemainingLoopCount = 0; if (TableKind == Kind::Lazy) Malformed = true; @@ -2080,7 +1784,6 @@ int64_t MachOBindEntry::readSLEB128() { return Result; } - uint32_t MachOBindEntry::segmentIndex() const { return SegmentIndex; } uint64_t MachOBindEntry::segmentOffset() const { return SegmentOffset; } @@ -2121,8 +1824,7 @@ MachOObjectFile::bindTable(ArrayRef Opcodes, bool is64, MachOBindEntry Finish(Opcodes, is64, BKind); Finish.moveToEnd(); - return iterator_range(bind_iterator(Start), - bind_iterator(Finish)); + return make_range(bind_iterator(Start), bind_iterator(Finish)); } iterator_range MachOObjectFile::bindTable() const { @@ -2140,6 +1842,21 @@ iterator_range MachOObjectFile::weakBindTable() const { MachOBindEntry::Kind::Weak); } +MachOObjectFile::load_command_iterator +MachOObjectFile::begin_load_commands() const { + return LoadCommands.begin(); +} + +MachOObjectFile::load_command_iterator +MachOObjectFile::end_load_commands() const { + return LoadCommands.end(); +} + +iterator_range +MachOObjectFile::load_commands() const { + return make_range(begin_load_commands(), end_load_commands()); +} + StringRef MachOObjectFile::getSectionFinalSegmentName(DataRefImpl Sec) const { ArrayRef Raw = getSectionRawFinalSegmentName(Sec); @@ -2148,6 +1865,7 @@ MachOObjectFile::getSectionFinalSegmentName(DataRefImpl Sec) const { ArrayRef MachOObjectFile::getSectionRawName(DataRefImpl Sec) const { + assert(Sec.d.a < Sections.size() && "Should have detected this earlier"); const section_base *Base = reinterpret_cast(Sections[Sec.d.a]); return makeArrayRef(Base->sectname); @@ -2155,6 +1873,7 @@ MachOObjectFile::getSectionRawName(DataRefImpl Sec) const { ArrayRef MachOObjectFile::getSectionRawFinalSegmentName(DataRefImpl Sec) const { + assert(Sec.d.a < Sections.size() && "Should have detected this earlier"); const section_base *Base = reinterpret_cast(Sections[Sec.d.a]); return makeArrayRef(Base->segname); @@ -2192,6 +1911,11 @@ uint32_t MachOObjectFile::getScatteredRelocationValue( return RE.r_word1; } +uint32_t MachOObjectFile::getScatteredRelocationType( + const MachO::any_relocation_info &RE) const { + return (RE.r_word0 >> 24) & 0xf; +} + unsigned MachOObjectFile::getAnyRelocationAddress( const MachO::any_relocation_info &RE) const { if (isRelocationScattered(RE)) @@ -2222,40 +1946,25 @@ MachOObjectFile::getAnyRelocationType( } SectionRef -MachOObjectFile::getRelocationSection( +MachOObjectFile::getAnyRelocationSection( const MachO::any_relocation_info &RE) const { if (isRelocationScattered(RE) || getPlainRelocationExternal(RE)) return *section_end(); - unsigned SecNum = getPlainRelocationSymbolNum(RE) - 1; + unsigned SecNum = getPlainRelocationSymbolNum(RE); + if (SecNum == MachO::R_ABS || SecNum > Sections.size()) + return *section_end(); DataRefImpl DRI; - DRI.d.a = SecNum; + DRI.d.a = SecNum - 1; return SectionRef(DRI, this); } -MachOObjectFile::LoadCommandInfo -MachOObjectFile::getFirstLoadCommandInfo() const { - MachOObjectFile::LoadCommandInfo Load; - - unsigned HeaderSize = is64Bit() ? sizeof(MachO::mach_header_64) : - sizeof(MachO::mach_header); - Load.Ptr = getPtr(this, HeaderSize); - Load.C = getStruct(this, Load.Ptr); - return Load; -} - -MachOObjectFile::LoadCommandInfo -MachOObjectFile::getNextLoadCommandInfo(const LoadCommandInfo &L) const { - MachOObjectFile::LoadCommandInfo Next; - Next.Ptr = L.Ptr + L.C.cmdsize; - Next.C = getStruct(this, Next.Ptr); - return Next; -} - MachO::section MachOObjectFile::getSection(DataRefImpl DRI) const { + assert(DRI.d.a < Sections.size() && "Should have detected this earlier"); return getStruct(this, Sections[DRI.d.a]); } MachO::section_64 MachOObjectFile::getSection64(DataRefImpl DRI) const { + assert(DRI.d.a < Sections.size() && "Should have detected this earlier"); return getStruct(this, Sections[DRI.d.a]); } @@ -2298,9 +2007,9 @@ MachOObjectFile::getSegment64LoadCommand(const LoadCommandInfo &L) const { return getStruct(this, L.Ptr); } -MachO::linker_options_command -MachOObjectFile::getLinkerOptionsLoadCommand(const LoadCommandInfo &L) const { - return getStruct(this, L.Ptr); +MachO::linker_option_command +MachOObjectFile::getLinkerOptionLoadCommand(const LoadCommandInfo &L) const { + return getStruct(this, L.Ptr); } MachO::version_min_command @@ -2328,6 +2037,11 @@ MachOObjectFile::getUuidCommand(const LoadCommandInfo &L) const { return getStruct(this, L.Ptr); } +MachO::rpath_command +MachOObjectFile::getRpathCommand(const LoadCommandInfo &L) const { + return getStruct(this, L.Ptr); +} + MachO::source_version_command MachOObjectFile::getSourceVersionCommand(const LoadCommandInfo &L) const { return getStruct(this, L.Ptr); @@ -2338,6 +2052,50 @@ MachOObjectFile::getEntryPointCommand(const LoadCommandInfo &L) const { return getStruct(this, L.Ptr); } +MachO::encryption_info_command +MachOObjectFile::getEncryptionInfoCommand(const LoadCommandInfo &L) const { + return getStruct(this, L.Ptr); +} + +MachO::encryption_info_command_64 +MachOObjectFile::getEncryptionInfoCommand64(const LoadCommandInfo &L) const { + return getStruct(this, L.Ptr); +} + +MachO::sub_framework_command +MachOObjectFile::getSubFrameworkCommand(const LoadCommandInfo &L) const { + return getStruct(this, L.Ptr); +} + +MachO::sub_umbrella_command +MachOObjectFile::getSubUmbrellaCommand(const LoadCommandInfo &L) const { + return getStruct(this, L.Ptr); +} + +MachO::sub_library_command +MachOObjectFile::getSubLibraryCommand(const LoadCommandInfo &L) const { + return getStruct(this, L.Ptr); +} + +MachO::sub_client_command +MachOObjectFile::getSubClientCommand(const LoadCommandInfo &L) const { + return getStruct(this, L.Ptr); +} + +MachO::routines_command +MachOObjectFile::getRoutinesCommand(const LoadCommandInfo &L) const { + return getStruct(this, L.Ptr); +} + +MachO::routines_command_64 +MachOObjectFile::getRoutinesCommand64(const LoadCommandInfo &L) const { + return getStruct(this, L.Ptr); +} + +MachO::thread_command +MachOObjectFile::getThreadCommand(const LoadCommandInfo &L) const { + return getStruct(this, L.Ptr); +} MachO::any_relocation_info MachOObjectFile::getRelocation(DataRefImpl Rel) const { @@ -2364,12 +2122,13 @@ MachOObjectFile::getDice(DataRefImpl Rel) const { return getStruct(this, P); } -MachO::mach_header MachOObjectFile::getHeader() const { - return getStruct(this, getPtr(this, 0)); +const MachO::mach_header &MachOObjectFile::getHeader() const { + return Header; } -MachO::mach_header_64 MachOObjectFile::getHeader64() const { - return getStruct(this, getPtr(this, 0)); +const MachO::mach_header_64 &MachOObjectFile::getHeader64() const { + assert(is64Bit()); + return Header64; } uint32_t MachOObjectFile::getIndirectSymbolTableEntry( @@ -2387,11 +2146,47 @@ MachOObjectFile::getDataInCodeTableEntry(uint32_t DataOffset, } MachO::symtab_command MachOObjectFile::getSymtabLoadCommand() const { - return getStruct(this, SymtabLoadCmd); + if (SymtabLoadCmd) + return getStruct(this, SymtabLoadCmd); + + // If there is no SymtabLoadCmd return a load command with zero'ed fields. + MachO::symtab_command Cmd; + Cmd.cmd = MachO::LC_SYMTAB; + Cmd.cmdsize = sizeof(MachO::symtab_command); + Cmd.symoff = 0; + Cmd.nsyms = 0; + Cmd.stroff = 0; + Cmd.strsize = 0; + return Cmd; } MachO::dysymtab_command MachOObjectFile::getDysymtabLoadCommand() const { - return getStruct(this, DysymtabLoadCmd); + if (DysymtabLoadCmd) + return getStruct(this, DysymtabLoadCmd); + + // If there is no DysymtabLoadCmd return a load command with zero'ed fields. + MachO::dysymtab_command Cmd; + Cmd.cmd = MachO::LC_DYSYMTAB; + Cmd.cmdsize = sizeof(MachO::dysymtab_command); + Cmd.ilocalsym = 0; + Cmd.nlocalsym = 0; + Cmd.iextdefsym = 0; + Cmd.nextdefsym = 0; + Cmd.iundefsym = 0; + Cmd.nundefsym = 0; + Cmd.tocoff = 0; + Cmd.ntoc = 0; + Cmd.modtaboff = 0; + Cmd.nmodtab = 0; + Cmd.extrefsymoff = 0; + Cmd.nextrefsyms = 0; + Cmd.indirectsymoff = 0; + Cmd.nindirectsyms = 0; + Cmd.extreloff = 0; + Cmd.nextrel = 0; + Cmd.locreloff = 0; + Cmd.nlocrel = 0; + return Cmd; } MachO::linkedit_data_command @@ -2408,61 +2203,83 @@ MachOObjectFile::getDataInCodeLoadCommand() const { return Cmd; } +MachO::linkedit_data_command +MachOObjectFile::getLinkOptHintsLoadCommand() const { + if (LinkOptHintsLoadCmd) + return getStruct(this, LinkOptHintsLoadCmd); + + // If there is no LinkOptHintsLoadCmd return a load command with zero'ed + // fields. + MachO::linkedit_data_command Cmd; + Cmd.cmd = MachO::LC_LINKER_OPTIMIZATION_HINT; + Cmd.cmdsize = sizeof(MachO::linkedit_data_command); + Cmd.dataoff = 0; + Cmd.datasize = 0; + return Cmd; +} + ArrayRef MachOObjectFile::getDyldInfoRebaseOpcodes() const { - if (!DyldInfoLoadCmd) - return ArrayRef(); + if (!DyldInfoLoadCmd) + return None; - 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); + MachO::dyld_info_command DyldInfo = + getStruct(this, DyldInfoLoadCmd); + const uint8_t *Ptr = + reinterpret_cast(getPtr(this, DyldInfo.rebase_off)); + return makeArrayRef(Ptr, DyldInfo.rebase_size); } ArrayRef MachOObjectFile::getDyldInfoBindOpcodes() const { - if (!DyldInfoLoadCmd) - return ArrayRef(); + if (!DyldInfoLoadCmd) + return None; - 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); + MachO::dyld_info_command DyldInfo = + getStruct(this, DyldInfoLoadCmd); + const uint8_t *Ptr = + reinterpret_cast(getPtr(this, DyldInfo.bind_off)); + return makeArrayRef(Ptr, DyldInfo.bind_size); } ArrayRef MachOObjectFile::getDyldInfoWeakBindOpcodes() const { - if (!DyldInfoLoadCmd) - return ArrayRef(); + if (!DyldInfoLoadCmd) + return None; - 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); + MachO::dyld_info_command DyldInfo = + getStruct(this, DyldInfoLoadCmd); + const uint8_t *Ptr = + reinterpret_cast(getPtr(this, DyldInfo.weak_bind_off)); + return makeArrayRef(Ptr, DyldInfo.weak_bind_size); } ArrayRef MachOObjectFile::getDyldInfoLazyBindOpcodes() const { - if (!DyldInfoLoadCmd) - return ArrayRef(); + if (!DyldInfoLoadCmd) + return None; - 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); + MachO::dyld_info_command DyldInfo = + getStruct(this, DyldInfoLoadCmd); + const uint8_t *Ptr = + reinterpret_cast(getPtr(this, DyldInfo.lazy_bind_off)); + return makeArrayRef(Ptr, DyldInfo.lazy_bind_size); } ArrayRef MachOObjectFile::getDyldInfoExportsTrie() const { - if (!DyldInfoLoadCmd) - return ArrayRef(); + if (!DyldInfoLoadCmd) + return None; - 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); + MachO::dyld_info_command DyldInfo = + getStruct(this, DyldInfoLoadCmd); + const uint8_t *Ptr = + reinterpret_cast(getPtr(this, DyldInfo.export_off)); + return makeArrayRef(Ptr, DyldInfo.export_size); } +ArrayRef MachOObjectFile::getUuid() const { + if (!UuidLoadCmd) + return None; + // Returning a pointer is fine as uuid doesn't need endian swapping. + const char *Ptr = UuidLoadCmd + offsetof(MachO::uuid_command, uuid); + return makeArrayRef(reinterpret_cast(Ptr), 16); +} StringRef MachOObjectFile::getStringTableData() const { MachO::symtab_command S = getSymtabLoadCommand(); @@ -2510,4 +2327,3 @@ ObjectFile::createMachOObjectFile(MemoryBufferRef Buffer) { return EC; return std::move(Ret); } -