X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FObject%2FMachOObjectFile.cpp;h=6955ef090ae73c0fe227b19c9a3d5c5e0d0dc919;hb=7b837d8c75f78fe55c9b348b9ec2281169a48d2a;hp=d229671954f8b0dbcfd7c636a31f493aae696e3b;hpb=e32981048244ecfa67d0bdc211af1bac2020a555;p=oota-llvm.git diff --git a/lib/Object/MachOObjectFile.cpp b/lib/Object/MachOObjectFile.cpp index d229671954f..6955ef090ae 100644 --- a/lib/Object/MachOObjectFile.cpp +++ b/lib/Object/MachOObjectFile.cpp @@ -12,12 +12,14 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/Triple.h" #include "llvm/Object/MachO.h" -#include "llvm/Object/MachOFormat.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/DataExtractor.h" #include "llvm/Support/Format.h" +#include "llvm/Support/Host.h" #include "llvm/Support/MemoryBuffer.h" - +#include "llvm/Support/raw_ostream.h" #include #include #include @@ -28,595 +30,741 @@ using namespace object; namespace llvm { namespace object { -MachOObjectFile::MachOObjectFile(MemoryBuffer *Object, MachOObject *MOO, - error_code &ec) - : ObjectFile(Binary::ID_MachO, Object, ec), - MachOObj(MOO), - RegisteredStringTable(std::numeric_limits::max()) { - DataRefImpl DRI; - moveToNextSection(DRI); - uint32_t LoadCommandCount = MachOObj->getHeader().NumLoadCommands; - while (DRI.d.a < LoadCommandCount) { - Sections.push_back(DRI); - DRI.d.b++; - moveToNextSection(DRI); - } +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 SwapValue(T &Value) { + Value = sys::SwapByteOrder(Value); } +template +static void SwapStruct(T &Value); -ObjectFile *ObjectFile::createMachOObjectFile(MemoryBuffer *Buffer) { - error_code ec; - std::string Err; - MachOObject *MachOObj = MachOObject::LoadFromBuffer(Buffer, &Err); - if (!MachOObj) - return NULL; - return new MachOObjectFile(Buffer, MachOObj, ec); +template<> +void SwapStruct(MachO::any_relocation_info &H) { + SwapValue(H.r_word0); + SwapValue(H.r_word1); } -/*===-- Symbols -----------------------------------------------------------===*/ +template<> +void SwapStruct(MachO::load_command &L) { + SwapValue(L.cmd); + SwapValue(L.cmdsize); +} -void MachOObjectFile::moveToNextSymbol(DataRefImpl &DRI) const { - uint32_t LoadCommandCount = MachOObj->getHeader().NumLoadCommands; - while (DRI.d.a < LoadCommandCount) { - LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); - if (LCI.Command.Type == macho::LCT_Symtab) { - InMemoryStruct SymtabLoadCmd; - MachOObj->ReadSymtabLoadCommand(LCI, SymtabLoadCmd); - if (DRI.d.b < SymtabLoadCmd->NumSymbolTableEntries) - return; - } +template<> +void SwapStruct(nlist_base &S) { + SwapValue(S.n_strx); + SwapValue(S.n_desc); +} - DRI.d.a++; - DRI.d.b = 0; - } +template<> +void SwapStruct(MachO::section &S) { + SwapValue(S.addr); + SwapValue(S.size); + SwapValue(S.offset); + SwapValue(S.align); + SwapValue(S.reloff); + SwapValue(S.nreloc); + SwapValue(S.flags); + SwapValue(S.reserved1); + SwapValue(S.reserved2); } -void MachOObjectFile::getSymbolTableEntry(DataRefImpl DRI, - InMemoryStruct &Res) const { - InMemoryStruct SymtabLoadCmd; - LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); - MachOObj->ReadSymtabLoadCommand(LCI, SymtabLoadCmd); +template<> +void SwapStruct(MachO::section_64 &S) { + SwapValue(S.addr); + SwapValue(S.size); + SwapValue(S.offset); + SwapValue(S.align); + SwapValue(S.reloff); + SwapValue(S.nreloc); + SwapValue(S.flags); + SwapValue(S.reserved1); + SwapValue(S.reserved2); + SwapValue(S.reserved3); +} - if (RegisteredStringTable != DRI.d.a) { - MachOObj->RegisterStringTable(*SymtabLoadCmd); - RegisteredStringTable = DRI.d.a; - } +template<> +void SwapStruct(MachO::nlist &S) { + SwapValue(S.n_strx); + SwapValue(S.n_desc); + SwapValue(S.n_value); +} - MachOObj->ReadSymbolTableEntry(SymtabLoadCmd->SymbolTableOffset, DRI.d.b, - Res); +template<> +void SwapStruct(MachO::nlist_64 &S) { + SwapValue(S.n_strx); + SwapValue(S.n_desc); + SwapValue(S.n_value); } -void MachOObjectFile::getSymbol64TableEntry(DataRefImpl DRI, - InMemoryStruct &Res) const { - InMemoryStruct SymtabLoadCmd; - LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); - MachOObj->ReadSymtabLoadCommand(LCI, SymtabLoadCmd); +template<> +void SwapStruct(MachO::mach_header &H) { + SwapValue(H.magic); + SwapValue(H.cputype); + SwapValue(H.cpusubtype); + SwapValue(H.filetype); + SwapValue(H.ncmds); + SwapValue(H.sizeofcmds); + SwapValue(H.flags); +} - if (RegisteredStringTable != DRI.d.a) { - MachOObj->RegisterStringTable(*SymtabLoadCmd); - RegisteredStringTable = DRI.d.a; - } +template<> +void SwapStruct(MachO::mach_header_64 &H) { + SwapValue(H.magic); + SwapValue(H.cputype); + SwapValue(H.cpusubtype); + SwapValue(H.filetype); + SwapValue(H.ncmds); + SwapValue(H.sizeofcmds); + SwapValue(H.flags); + SwapValue(H.reserved); +} - MachOObj->ReadSymbol64TableEntry(SymtabLoadCmd->SymbolTableOffset, DRI.d.b, - Res); +template<> +void SwapStruct(MachO::symtab_command &C) { + SwapValue(C.cmd); + SwapValue(C.cmdsize); + SwapValue(C.symoff); + SwapValue(C.nsyms); + SwapValue(C.stroff); + SwapValue(C.strsize); } +template<> +void SwapStruct(MachO::dysymtab_command &C) { + SwapValue(C.cmd); + SwapValue(C.cmdsize); + SwapValue(C.ilocalsym); + SwapValue(C.nlocalsym); + SwapValue(C.iextdefsym); + SwapValue(C.nextdefsym); + SwapValue(C.iundefsym); + SwapValue(C.nundefsym); + SwapValue(C.tocoff); + SwapValue(C.ntoc); + SwapValue(C.modtaboff); + SwapValue(C.nmodtab); + SwapValue(C.extrefsymoff); + SwapValue(C.nextrefsyms); + SwapValue(C.indirectsymoff); + SwapValue(C.nindirectsyms); + SwapValue(C.extreloff); + SwapValue(C.nextrel); + SwapValue(C.locreloff); + SwapValue(C.nlocrel); +} -error_code MachOObjectFile::getSymbolNext(DataRefImpl DRI, - SymbolRef &Result) const { - DRI.d.b++; - moveToNextSymbol(DRI); - Result = SymbolRef(DRI, this); - return object_error::success; +template<> +void SwapStruct(MachO::linkedit_data_command &C) { + SwapValue(C.cmd); + SwapValue(C.cmdsize); + SwapValue(C.dataoff); + SwapValue(C.datasize); } -error_code MachOObjectFile::getSymbolName(DataRefImpl DRI, - StringRef &Result) const { - if (MachOObj->is64Bit()) { - InMemoryStruct Entry; - getSymbol64TableEntry(DRI, Entry); - Result = MachOObj->getStringAtIndex(Entry->StringIndex); - } else { - InMemoryStruct Entry; - getSymbolTableEntry(DRI, Entry); - Result = MachOObj->getStringAtIndex(Entry->StringIndex); - } - return object_error::success; +template<> +void SwapStruct(MachO::segment_command &C) { + SwapValue(C.cmd); + SwapValue(C.cmdsize); + SwapValue(C.vmaddr); + SwapValue(C.vmsize); + SwapValue(C.fileoff); + SwapValue(C.filesize); + SwapValue(C.maxprot); + SwapValue(C.initprot); + SwapValue(C.nsects); + SwapValue(C.flags); } -error_code MachOObjectFile::getSymbolFileOffset(DataRefImpl DRI, - uint64_t &Result) const { - if (MachOObj->is64Bit()) { - InMemoryStruct Entry; - getSymbol64TableEntry(DRI, Entry); - Result = Entry->Value; - if (Entry->SectionIndex) { - InMemoryStruct Section; - getSection64(Sections[Entry->SectionIndex-1], Section); - Result += Section->Offset - Section->Address; - } - } else { - InMemoryStruct Entry; - getSymbolTableEntry(DRI, Entry); - Result = Entry->Value; - if (Entry->SectionIndex) { - InMemoryStruct Section; - getSection(Sections[Entry->SectionIndex-1], Section); - Result += Section->Offset - Section->Address; - } - } +template<> +void SwapStruct(MachO::segment_command_64 &C) { + SwapValue(C.cmd); + SwapValue(C.cmdsize); + SwapValue(C.vmaddr); + SwapValue(C.vmsize); + SwapValue(C.fileoff); + SwapValue(C.filesize); + SwapValue(C.maxprot); + SwapValue(C.initprot); + SwapValue(C.nsects); + SwapValue(C.flags); +} - return object_error::success; +template<> +void SwapStruct(uint32_t &C) { + SwapValue(C); } -error_code MachOObjectFile::getSymbolAddress(DataRefImpl DRI, - uint64_t &Result) const { - if (MachOObj->is64Bit()) { - InMemoryStruct Entry; - getSymbol64TableEntry(DRI, Entry); - Result = Entry->Value; - } else { - InMemoryStruct Entry; - getSymbolTableEntry(DRI, Entry); - Result = Entry->Value; +template<> +void SwapStruct(MachO::linker_options_command &C) { + SwapValue(C.cmd); + SwapValue(C.cmdsize); + SwapValue(C.count); +} + +template<> +void SwapStruct(MachO::version_min_command&C) { + SwapValue(C.cmd); + SwapValue(C.cmdsize); + SwapValue(C.version); + SwapValue(C.reserved); +} + +template<> +void SwapStruct(MachO::data_in_code_entry &C) { + SwapValue(C.offset); + SwapValue(C.length); + SwapValue(C.kind); +} + +template +T getStruct(const MachOObjectFile *O, const char *P) { + T Cmd; + memcpy(&Cmd, P, sizeof(T)); + if (O->isLittleEndian() != sys::IsLittleEndianHost) + SwapStruct(Cmd); + 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; } - return object_error::success; + MachO::segment_command S = O->getSegmentLoadCommand(L); + return S.nsects; } -error_code MachOObjectFile::getSymbolSize(DataRefImpl DRI, - uint64_t &Result) const { - uint32_t LoadCommandCount = MachOObj->getHeader().NumLoadCommands; - uint64_t BeginOffset; - uint64_t EndOffset = 0; - uint8_t SectionIndex; - if (MachOObj->is64Bit()) { - InMemoryStruct Entry; - getSymbol64TableEntry(DRI, Entry); - BeginOffset = Entry->Value; - SectionIndex = Entry->SectionIndex; - if (!SectionIndex) { - uint32_t flags = SymbolRef::SF_None; - getSymbolFlags(DRI, flags); - if (flags & SymbolRef::SF_Common) - Result = Entry->Value; - else - Result = UnknownAddressOrSize; - return object_error::success; - } - // Unfortunately symbols are unsorted so we need to touch all - // symbols from load command - DRI.d.b = 0; - uint32_t Command = DRI.d.a; - while (Command == DRI.d.a) { - moveToNextSymbol(DRI); - if (DRI.d.a < LoadCommandCount) { - getSymbol64TableEntry(DRI, Entry); - if (Entry->SectionIndex == SectionIndex && Entry->Value > BeginOffset) - if (!EndOffset || Entry->Value < EndOffset) - EndOffset = Entry->Value; - } - DRI.d.b++; - } - } else { - InMemoryStruct Entry; - getSymbolTableEntry(DRI, Entry); - BeginOffset = Entry->Value; - SectionIndex = Entry->SectionIndex; - if (!SectionIndex) { - uint32_t flags = SymbolRef::SF_None; - getSymbolFlags(DRI, flags); - if (flags & SymbolRef::SF_Common) - Result = Entry->Value; - else - Result = UnknownAddressOrSize; - return object_error::success; +static const char * +getSectionPtr(const MachOObjectFile *O, MachOObjectFile::LoadCommandInfo L, + unsigned Sec) { + uintptr_t CommandAddr = reinterpret_cast(L.Ptr); + + bool Is64 = O->is64Bit(); + unsigned SegmentLoadSize = Is64 ? sizeof(MachO::segment_command_64) : + sizeof(MachO::segment_command); + unsigned SectionSize = Is64 ? sizeof(MachO::section_64) : + sizeof(MachO::section); + + uintptr_t SectionAddr = CommandAddr + SegmentLoadSize + Sec * SectionSize; + return reinterpret_cast(SectionAddr); +} + +static const char *getPtr(const MachOObjectFile *O, size_t Offset) { + return O->getData().substr(Offset, 1).data(); +} + +static nlist_base +getSymbolTableEntryBase(const MachOObjectFile *O, DataRefImpl DRI) { + const char *P = reinterpret_cast(DRI.p); + return getStruct(O, P); +} + +static StringRef parseSegmentOrSectionName(const char *P) { + if (P[15] == 0) + // Null terminated. + return P; + // Not null terminated, so this is a 16 char string. + return StringRef(P, 16); +} + +// Helper to advance a section or symbol iterator multiple increments at a time. +template +static void advance(T &it, size_t Val) { + while (Val--) + ++it; +} + +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()) { + 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; } - // Unfortunately symbols are unsorted so we need to touch all - // symbols from load command - DRI.d.b = 0; - uint32_t Command = DRI.d.a; - while (Command == DRI.d.a) { - moveToNextSymbol(DRI); - if (DRI.d.a < LoadCommandCount) { - getSymbolTableEntry(DRI, Entry); - if (Entry->SectionIndex == SectionIndex && Entry->Value > BeginOffset) - if (!EndOffset || Entry->Value < EndOffset) - EndOffset = Entry->Value; - } - DRI.d.b++; + + // 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()) { + 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; } - if (!EndOffset) { - uint64_t Size; - getSectionSize(Sections[SectionIndex-1], Size); - getSectionAddress(Sections[SectionIndex-1], EndOffset); - EndOffset += Size; + + 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); } - Result = EndOffset - BeginOffset; - return object_error::success; + + fmt << S; } -error_code MachOObjectFile::getSymbolNMTypeChar(DataRefImpl DRI, - char &Result) const { - uint8_t Type, Flags; - if (MachOObj->is64Bit()) { - InMemoryStruct Entry; - getSymbol64TableEntry(DRI, Entry); - Type = Entry->Type; - Flags = Entry->Flags; - } else { - InMemoryStruct Entry; - getSymbolTableEntry(DRI, Entry); - Type = Entry->Type; - Flags = Entry->Flags; +static uint32_t +getPlainRelocationAddress(const MachO::any_relocation_info &RE) { + return RE.r_word0; +} + +static unsigned +getScatteredRelocationAddress(const MachO::any_relocation_info &RE) { + return RE.r_word0 & 0xffffff; +} + +static bool getPlainRelocationPCRel(const MachOObjectFile *O, + const MachO::any_relocation_info &RE) { + if (O->isLittleEndian()) + return (RE.r_word1 >> 24) & 1; + return (RE.r_word1 >> 7) & 1; +} + +static bool +getScatteredRelocationPCRel(const MachOObjectFile *O, + const MachO::any_relocation_info &RE) { + return (RE.r_word0 >> 30) & 1; +} + +static unsigned getPlainRelocationLength(const MachOObjectFile *O, + const MachO::any_relocation_info &RE) { + if (O->isLittleEndian()) + return (RE.r_word1 >> 25) & 3; + return (RE.r_word1 >> 5) & 3; +} + +static unsigned +getScatteredRelocationLength(const MachO::any_relocation_info &RE) { + return (RE.r_word0 >> 28) & 3; +} + +static unsigned getPlainRelocationType(const MachOObjectFile *O, + const MachO::any_relocation_info &RE) { + if (O->isLittleEndian()) + return RE.r_word1 >> 28; + 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()) { + MachO::section_64 Sect = O->getSection64(Sec); + return Sect.flags; } + MachO::section Sect = O->getSection(Sec); + return Sect.flags; +} - char Char; - switch (Type & macho::STF_TypeMask) { - case macho::STT_Undefined: - Char = 'u'; - break; - case macho::STT_Absolute: - case macho::STT_Section: - Char = 's'; - break; - default: - Char = '?'; +MachOObjectFile::MachOObjectFile(MemoryBuffer *Object, bool IsLittleEndian, + bool Is64bits, error_code &EC, + bool BufferOwned) + : ObjectFile(getMachOType(IsLittleEndian, Is64bits), Object, BufferOwned), + SymtabLoadCmd(NULL), DysymtabLoadCmd(NULL), DataInCodeLoadCmd(NULL) { + uint32_t LoadCommandCount = this->getHeader().ncmds; + MachO::LoadCommandType SegmentLoadType = is64Bit() ? + MachO::LC_SEGMENT_64 : MachO::LC_SEGMENT; + + MachOObjectFile::LoadCommandInfo Load = getFirstLoadCommandInfo(); + for (unsigned I = 0; ; ++I) { + if (Load.C.cmd == MachO::LC_SYMTAB) { + assert(!SymtabLoadCmd && "Multiple symbol tables"); + SymtabLoadCmd = Load.Ptr; + } else if (Load.C.cmd == MachO::LC_DYSYMTAB) { + assert(!DysymtabLoadCmd && "Multiple dynamic symbol tables"); + DysymtabLoadCmd = Load.Ptr; + } 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 == 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 (I == LoadCommandCount - 1) break; + else + Load = getNextLoadCommandInfo(Load); } +} + +void MachOObjectFile::moveSymbolNext(DataRefImpl &Symb) const { + unsigned SymbolTableEntrySize = is64Bit() ? + sizeof(MachO::nlist_64) : + sizeof(MachO::nlist); + Symb.p += SymbolTableEntrySize; +} - if (Flags & (macho::STF_External | macho::STF_PrivateExtern)) - Char = toupper(Char); - Result = Char; +error_code MachOObjectFile::getSymbolName(DataRefImpl Symb, + StringRef &Res) const { + StringRef StringTable = getStringTableData(); + nlist_base Entry = getSymbolTableEntryBase(this, Symb); + const char *Start = &StringTable.data()[Entry.n_strx]; + Res = StringRef(Start); return object_error::success; } -error_code MachOObjectFile::getSymbolFlags(DataRefImpl DRI, - uint32_t &Result) const { - uint16_t MachOFlags; - uint8_t MachOType; - if (MachOObj->is64Bit()) { - InMemoryStruct Entry; - getSymbol64TableEntry(DRI, Entry); - MachOFlags = Entry->Flags; - MachOType = Entry->Type; +error_code MachOObjectFile::getSymbolAddress(DataRefImpl Symb, + uint64_t &Res) const { + if (is64Bit()) { + MachO::nlist_64 Entry = getSymbol64TableEntry(Symb); + Res = Entry.n_value; } else { - InMemoryStruct Entry; - getSymbolTableEntry(DRI, Entry); - MachOFlags = Entry->Flags; - MachOType = Entry->Type; + MachO::nlist Entry = getSymbolTableEntry(Symb); + Res = Entry.n_value; } + return object_error::success; +} - // TODO: Correctly set SF_ThreadLocal - Result = SymbolRef::SF_None; - - if ((MachOType & MachO::NlistMaskType) == MachO::NListTypeUndefined) - Result |= SymbolRef::SF_Undefined; - - if (MachOFlags & macho::STF_StabsEntryMask) - Result |= SymbolRef::SF_FormatSpecific; +error_code +MachOObjectFile::getSymbolFileOffset(DataRefImpl Symb, + uint64_t &Res) const { + nlist_base Entry = getSymbolTableEntryBase(this, Symb); + getSymbolAddress(Symb, Res); + if (Entry.n_sect) { + uint64_t Delta; + DataRefImpl SecRel; + SecRel.d.a = Entry.n_sect-1; + if (is64Bit()) { + MachO::section_64 Sec = getSection64(SecRel); + Delta = Sec.offset - Sec.addr; + } else { + MachO::section Sec = getSection(SecRel); + Delta = Sec.offset - Sec.addr; + } - if (MachOType & MachO::NlistMaskExternal) { - Result |= SymbolRef::SF_Global; - if ((MachOType & MachO::NlistMaskType) == MachO::NListTypeUndefined) - Result |= SymbolRef::SF_Common; + Res += Delta; } - if (MachOFlags & (MachO::NListDescWeakRef | MachO::NListDescWeakDef)) - Result |= SymbolRef::SF_Weak; - - if ((MachOType & MachO::NlistMaskType) == MachO::NListTypeAbsolute) - Result |= SymbolRef::SF_Absolute; - return object_error::success; } -error_code MachOObjectFile::getSymbolSection(DataRefImpl Symb, - section_iterator &Res) const { - uint8_t index; - if (MachOObj->is64Bit()) { - InMemoryStruct Entry; - getSymbol64TableEntry(Symb, Entry); - index = Entry->SectionIndex; +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); + Result = 1 << MachO::GET_COMM_ALIGN(Entry.n_desc); } else { - InMemoryStruct Entry; - getSymbolTableEntry(Symb, Entry); - index = Entry->SectionIndex; + Result = 0; } + return object_error::success; +} + +error_code MachOObjectFile::getSymbolSize(DataRefImpl DRI, + uint64_t &Result) const { + uint64_t BeginOffset; + uint64_t EndOffset = 0; + uint8_t SectionIndex; - if (index == 0) - Res = end_sections(); - else - Res = section_iterator(SectionRef(Sections[index-1], this)); + nlist_base Entry = getSymbolTableEntryBase(this, DRI); + uint64_t Value; + getSymbolAddress(DRI, Value); + 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 (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; } error_code MachOObjectFile::getSymbolType(DataRefImpl Symb, SymbolRef::Type &Res) const { - uint8_t n_type; - if (MachOObj->is64Bit()) { - InMemoryStruct Entry; - getSymbol64TableEntry(Symb, Entry); - n_type = Entry->Type; - } else { - InMemoryStruct Entry; - getSymbolTableEntry(Symb, Entry); - n_type = Entry->Type; - } + 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::NlistMaskStab) { + if (n_type & MachO::N_STAB) { Res = SymbolRef::ST_Debug; return object_error::success; } - switch (n_type & MachO::NlistMaskType) { - case MachO::NListTypeUndefined : + switch (n_type & MachO::N_TYPE) { + case MachO::N_UNDF : Res = SymbolRef::ST_Unknown; break; - case MachO::NListTypeSection : + case MachO::N_SECT : Res = SymbolRef::ST_Function; break; } return object_error::success; } +uint32_t MachOObjectFile::getSymbolFlags(DataRefImpl DRI) const { + nlist_base Entry = getSymbolTableEntryBase(this, DRI); -symbol_iterator MachOObjectFile::begin_symbols() const { - // DRI.d.a = segment number; DRI.d.b = symbol index. - DataRefImpl DRI; - moveToNextSymbol(DRI); - return symbol_iterator(SymbolRef(DRI, this)); -} + uint8_t MachOType = Entry.n_type; + uint16_t MachOFlags = Entry.n_desc; -symbol_iterator MachOObjectFile::end_symbols() const { - DataRefImpl DRI; - DRI.d.a = MachOObj->getHeader().NumLoadCommands; - return symbol_iterator(SymbolRef(DRI, this)); -} + uint32_t Result = SymbolRef::SF_None; -symbol_iterator MachOObjectFile::begin_dynamic_symbols() const { - // TODO: implement - report_fatal_error("Dynamic symbols unimplemented in MachOObjectFile"); -} + if ((MachOType & MachO::N_TYPE) == MachO::N_UNDF) + Result |= SymbolRef::SF_Undefined; -symbol_iterator MachOObjectFile::end_dynamic_symbols() const { - // TODO: implement - report_fatal_error("Dynamic symbols unimplemented in MachOObjectFile"); -} + if (MachOType & MachO::N_STAB) + Result |= SymbolRef::SF_FormatSpecific; -library_iterator MachOObjectFile::begin_libraries_needed() const { - // TODO: implement - report_fatal_error("Needed libraries unimplemented in MachOObjectFile"); -} + 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) + Result |= SymbolRef::SF_Common; + } + } -library_iterator MachOObjectFile::end_libraries_needed() const { - // TODO: implement - report_fatal_error("Needed libraries unimplemented in MachOObjectFile"); -} + if (MachOFlags & (MachO::N_WEAK_REF | MachO::N_WEAK_DEF)) + Result |= SymbolRef::SF_Weak; -StringRef MachOObjectFile::getLoadName() const { - // TODO: Implement - report_fatal_error("get_load_name() unimplemented in MachOObjectFile"); + if ((MachOType & MachO::N_TYPE) == MachO::N_ABS) + Result |= SymbolRef::SF_Absolute; + + return Result; } -/*===-- Sections ----------------------------------------------------------===*/ - -void MachOObjectFile::moveToNextSection(DataRefImpl &DRI) const { - uint32_t LoadCommandCount = MachOObj->getHeader().NumLoadCommands; - while (DRI.d.a < LoadCommandCount) { - LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); - if (LCI.Command.Type == macho::LCT_Segment) { - InMemoryStruct SegmentLoadCmd; - MachOObj->ReadSegmentLoadCommand(LCI, SegmentLoadCmd); - if (DRI.d.b < SegmentLoadCmd->NumSections) - return; - } else if (LCI.Command.Type == macho::LCT_Segment64) { - InMemoryStruct Segment64LoadCmd; - MachOObj->ReadSegment64LoadCommand(LCI, Segment64LoadCmd); - if (DRI.d.b < Segment64LoadCmd->NumSections) - return; - } +error_code +MachOObjectFile::getSymbolSection(DataRefImpl Symb, + section_iterator &Res) const { + nlist_base Entry = getSymbolTableEntryBase(this, Symb); + uint8_t index = Entry.n_sect; - DRI.d.a++; - DRI.d.b = 0; + if (index == 0) { + Res = section_end(); + } else { + DataRefImpl DRI; + DRI.d.a = index - 1; + Res = section_iterator(SectionRef(DRI, this)); } -} -error_code MachOObjectFile::getSectionNext(DataRefImpl DRI, - SectionRef &Result) const { - DRI.d.b++; - moveToNextSection(DRI); - Result = SectionRef(DRI, this); return object_error::success; } -void -MachOObjectFile::getSection(DataRefImpl DRI, - InMemoryStruct &Res) const { - InMemoryStruct SLC; - LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); - MachOObj->ReadSegmentLoadCommand(LCI, SLC); - MachOObj->ReadSection(LCI, DRI.d.b, Res); -} - -std::size_t MachOObjectFile::getSectionIndex(DataRefImpl Sec) const { - SectionList::const_iterator loc = - std::find(Sections.begin(), Sections.end(), Sec); - assert(loc != Sections.end() && "Sec is not a valid section!"); - return std::distance(Sections.begin(), loc); -} - -void -MachOObjectFile::getSection64(DataRefImpl DRI, - InMemoryStruct &Res) const { - InMemoryStruct SLC; - LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); - MachOObj->ReadSegment64LoadCommand(LCI, SLC); - MachOObj->ReadSection64(LCI, DRI.d.b, Res); -} - -static bool is64BitLoadCommand(const MachOObject *MachOObj, DataRefImpl DRI) { - LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); - if (LCI.Command.Type == macho::LCT_Segment64) - return true; - assert(LCI.Command.Type == macho::LCT_Segment && "Unexpected Type."); - return false; -} - -error_code MachOObjectFile::getSectionName(DataRefImpl DRI, - StringRef &Result) const { - // FIXME: thread safety. - static char result[34]; - if (is64BitLoadCommand(MachOObj, DRI)) { - InMemoryStruct SLC; - LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); - MachOObj->ReadSegment64LoadCommand(LCI, SLC); - InMemoryStruct Sect; - MachOObj->ReadSection64(LCI, DRI.d.b, Sect); - - strcpy(result, Sect->SegmentName); - strcat(result, ","); - strcat(result, Sect->Name); - } else { - InMemoryStruct SLC; - LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); - MachOObj->ReadSegmentLoadCommand(LCI, SLC); - InMemoryStruct Sect; - MachOObj->ReadSection(LCI, DRI.d.b, Sect); - - strcpy(result, Sect->SegmentName); - strcat(result, ","); - strcat(result, Sect->Name); - } - Result = StringRef(result); +error_code MachOObjectFile::getSymbolValue(DataRefImpl Symb, + uint64_t &Val) const { + report_fatal_error("getSymbolValue unimplemented in MachOObjectFile"); +} + +void MachOObjectFile::moveSectionNext(DataRefImpl &Sec) const { + Sec.d.a++; +} + +error_code +MachOObjectFile::getSectionName(DataRefImpl Sec, StringRef &Result) const { + ArrayRef Raw = getSectionRawName(Sec); + Result = parseSegmentOrSectionName(Raw.data()); return object_error::success; } -error_code MachOObjectFile::getSectionAddress(DataRefImpl DRI, - uint64_t &Result) const { - if (is64BitLoadCommand(MachOObj, DRI)) { - InMemoryStruct Sect; - getSection64(DRI, Sect); - Result = Sect->Address; +error_code +MachOObjectFile::getSectionAddress(DataRefImpl Sec, uint64_t &Res) const { + if (is64Bit()) { + MachO::section_64 Sect = getSection64(Sec); + Res = Sect.addr; } else { - InMemoryStruct Sect; - getSection(DRI, Sect); - Result = Sect->Address; + MachO::section Sect = getSection(Sec); + Res = Sect.addr; } return object_error::success; } -error_code MachOObjectFile::getSectionSize(DataRefImpl DRI, - uint64_t &Result) const { - if (is64BitLoadCommand(MachOObj, DRI)) { - InMemoryStruct Sect; - getSection64(DRI, Sect); - Result = Sect->Size; +error_code +MachOObjectFile::getSectionSize(DataRefImpl Sec, uint64_t &Res) const { + if (is64Bit()) { + MachO::section_64 Sect = getSection64(Sec); + Res = Sect.size; } else { - InMemoryStruct Sect; - getSection(DRI, Sect); - Result = Sect->Size; + MachO::section Sect = getSection(Sec); + Res = Sect.size; } + return object_error::success; } -error_code MachOObjectFile::getSectionContents(DataRefImpl DRI, - StringRef &Result) const { - if (is64BitLoadCommand(MachOObj, DRI)) { - InMemoryStruct Sect; - getSection64(DRI, Sect); - Result = MachOObj->getData(Sect->Offset, Sect->Size); +error_code +MachOObjectFile::getSectionContents(DataRefImpl Sec, StringRef &Res) const { + uint32_t Offset; + uint64_t Size; + + if (is64Bit()) { + MachO::section_64 Sect = getSection64(Sec); + Offset = Sect.offset; + Size = Sect.size; } else { - InMemoryStruct Sect; - getSection(DRI, Sect); - Result = MachOObj->getData(Sect->Offset, Sect->Size); + MachO::section Sect = getSection(Sec); + Offset = Sect.offset; + Size = Sect.size; } + + Res = this->getData().substr(Offset, Size); return object_error::success; } -error_code MachOObjectFile::getSectionAlignment(DataRefImpl DRI, - uint64_t &Result) const { - if (is64BitLoadCommand(MachOObj, DRI)) { - InMemoryStruct Sect; - getSection64(DRI, Sect); - Result = uint64_t(1) << Sect->Align; +error_code +MachOObjectFile::getSectionAlignment(DataRefImpl Sec, uint64_t &Res) const { + uint32_t Align; + if (is64Bit()) { + MachO::section_64 Sect = getSection64(Sec); + Align = Sect.align; } else { - InMemoryStruct Sect; - getSection(DRI, Sect); - Result = uint64_t(1) << Sect->Align; + MachO::section Sect = getSection(Sec); + Align = Sect.align; } + + Res = uint64_t(1) << Align; return object_error::success; } -error_code MachOObjectFile::isSectionText(DataRefImpl DRI, - bool &Result) const { - if (is64BitLoadCommand(MachOObj, DRI)) { - InMemoryStruct Sect; - getSection64(DRI, Sect); - Result = !strcmp(Sect->Name, "__text"); - } else { - InMemoryStruct Sect; - getSection(DRI, Sect); - Result = !strcmp(Sect->Name, "__text"); - } +error_code +MachOObjectFile::isSectionText(DataRefImpl Sec, bool &Res) const { + uint32_t Flags = getSectionFlags(this, Sec); + Res = Flags & MachO::S_ATTR_PURE_INSTRUCTIONS; return object_error::success; } -error_code MachOObjectFile::isSectionData(DataRefImpl DRI, - bool &Result) const { +error_code MachOObjectFile::isSectionData(DataRefImpl DRI, bool &Result) const { // FIXME: Unimplemented. Result = false; return object_error::success; } -error_code MachOObjectFile::isSectionBSS(DataRefImpl DRI, - bool &Result) const { +error_code MachOObjectFile::isSectionBSS(DataRefImpl DRI, bool &Result) const { // FIXME: Unimplemented. Result = false; return object_error::success; } -error_code MachOObjectFile::isSectionRequiredForExecution(DataRefImpl Sec, - bool &Result) const { - // FIXME: Unimplemented +error_code +MachOObjectFile::isSectionRequiredForExecution(DataRefImpl Sec, + bool &Result) const { + // FIXME: Unimplemented. Result = true; return object_error::success; } error_code MachOObjectFile::isSectionVirtual(DataRefImpl Sec, - bool &Result) const { - // FIXME: Unimplemented + bool &Result) const { + // FIXME: Unimplemented. Result = false; return object_error::success; } -error_code MachOObjectFile::isSectionZeroInit(DataRefImpl DRI, - bool &Result) const { - if (MachOObj->is64Bit()) { - InMemoryStruct Sect; - getSection64(DRI, Sect); - unsigned SectionType = Sect->Flags & MachO::SectionFlagMaskSectionType; - Result = (SectionType == MachO::SectionTypeZeroFill || - SectionType == MachO::SectionTypeZeroFillLarge); - } else { - InMemoryStruct Sect; - getSection(DRI, Sect); - unsigned SectionType = Sect->Flags & MachO::SectionFlagMaskSectionType; - Result = (SectionType == MachO::SectionTypeZeroFill || - SectionType == MachO::SectionTypeZeroFillLarge); - } - +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; } -error_code MachOObjectFile::sectionContainsSymbol(DataRefImpl Sec, - DataRefImpl Symb, +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; +} + +error_code +MachOObjectFile::sectionContainsSymbol(DataRefImpl Sec, DataRefImpl Symb, + bool &Result) const { SymbolRef::Type ST; - getSymbolType(Symb, ST); + this->getSymbolType(Symb, ST); if (ST == SymbolRef::ST_Unknown) { Result = false; return object_error::success; @@ -627,164 +775,111 @@ error_code MachOObjectFile::sectionContainsSymbol(DataRefImpl Sec, getSectionSize(Sec, SectEnd); SectEnd += SectBegin; - if (MachOObj->is64Bit()) { - InMemoryStruct Entry; - getSymbol64TableEntry(Symb, Entry); - uint64_t SymAddr= Entry->Value; - Result = (SymAddr >= SectBegin) && (SymAddr < SectEnd); - } else { - InMemoryStruct Entry; - getSymbolTableEntry(Symb, Entry); - uint64_t SymAddr= Entry->Value; - Result = (SymAddr >= SectBegin) && (SymAddr < SectEnd); - } + uint64_t SymAddr; + getSymbolAddress(Symb, SymAddr); + Result = (SymAddr >= SectBegin) && (SymAddr < SectEnd); return object_error::success; } -relocation_iterator MachOObjectFile::getSectionRelBegin(DataRefImpl Sec) const { - DataRefImpl ret; - ret.d.b = getSectionIndex(Sec); - return relocation_iterator(RelocationRef(ret, this)); -} -relocation_iterator MachOObjectFile::getSectionRelEnd(DataRefImpl Sec) const { - uint32_t last_reloc; - if (is64BitLoadCommand(MachOObj, Sec)) { - InMemoryStruct Sect; - getSection64(Sec, Sect); - last_reloc = Sect->NumRelocationTableEntries; +relocation_iterator MachOObjectFile::section_rel_begin(DataRefImpl Sec) const { + uint32_t Offset; + if (is64Bit()) { + MachO::section_64 Sect = getSection64(Sec); + Offset = Sect.reloff; } else { - InMemoryStruct Sect; - getSection(Sec, Sect); - last_reloc = Sect->NumRelocationTableEntries; + MachO::section Sect = getSection(Sec); + Offset = Sect.reloff; } - DataRefImpl ret; - ret.d.a = last_reloc; - ret.d.b = getSectionIndex(Sec); - return relocation_iterator(RelocationRef(ret, this)); -} -section_iterator MachOObjectFile::begin_sections() const { - DataRefImpl DRI; - moveToNextSection(DRI); - return section_iterator(SectionRef(DRI, this)); + DataRefImpl Ret; + Ret.p = reinterpret_cast(getPtr(this, Offset)); + return relocation_iterator(RelocationRef(Ret, this)); } -section_iterator MachOObjectFile::end_sections() const { - DataRefImpl DRI; - DRI.d.a = MachOObj->getHeader().NumLoadCommands; - return section_iterator(SectionRef(DRI, this)); -} +relocation_iterator +MachOObjectFile::section_rel_end(DataRefImpl Sec) const { + uint32_t Offset; + uint32_t Num; + if (is64Bit()) { + MachO::section_64 Sect = getSection64(Sec); + Offset = Sect.reloff; + Num = Sect.nreloc; + } else { + MachO::section Sect = getSection(Sec); + Offset = Sect.reloff; + Num = Sect.nreloc; + } -/*===-- Relocations -------------------------------------------------------===*/ + const MachO::any_relocation_info *P = + reinterpret_cast(getPtr(this, Offset)); + + DataRefImpl Ret; + Ret.p = reinterpret_cast(P + Num); + return relocation_iterator(RelocationRef(Ret, this)); +} -void MachOObjectFile:: -getRelocation(DataRefImpl Rel, - InMemoryStruct &Res) const { - uint32_t relOffset; - if (MachOObj->is64Bit()) { - InMemoryStruct Sect; - getSection64(Sections[Rel.d.b], Sect); - relOffset = Sect->RelocationTableOffset; +bool MachOObjectFile::section_rel_empty(DataRefImpl Sec) const { + if (is64Bit()) { + MachO::section_64 Sect = getSection64(Sec); + return Sect.nreloc == 0; } else { - InMemoryStruct Sect; - getSection(Sections[Rel.d.b], Sect); - relOffset = Sect->RelocationTableOffset; + MachO::section Sect = getSection(Sec); + return Sect.nreloc == 0; } - MachOObj->ReadRelocationEntry(relOffset, Rel.d.a, Res); } -error_code MachOObjectFile::getRelocationNext(DataRefImpl Rel, - RelocationRef &Res) const { - ++Rel.d.a; - Res = RelocationRef(Rel, this); - return object_error::success; + +void MachOObjectFile::moveRelocationNext(DataRefImpl &Rel) const { + const MachO::any_relocation_info *P = + reinterpret_cast(Rel.p); + Rel.p = reinterpret_cast(P + 1); } -error_code MachOObjectFile::getRelocationAddress(DataRefImpl Rel, - uint64_t &Res) const { - const uint8_t* sectAddress = 0; - if (MachOObj->is64Bit()) { - InMemoryStruct Sect; - getSection64(Sections[Rel.d.b], Sect); - sectAddress += Sect->Address; - } else { - InMemoryStruct Sect; - getSection(Sections[Rel.d.b], Sect); - sectAddress += Sect->Address; - } - InMemoryStruct RE; - getRelocation(Rel, RE); - unsigned Arch = getArch(); - bool isScattered = (Arch != Triple::x86_64) && - (RE->Word0 & macho::RF_Scattered); - uint64_t RelAddr = 0; - if (isScattered) - RelAddr = RE->Word0 & 0xFFFFFF; - else - RelAddr = RE->Word0; - - Res = reinterpret_cast(sectAddress + RelAddr); - return object_error::success; +error_code +MachOObjectFile::getRelocationAddress(DataRefImpl Rel, uint64_t &Res) const { + report_fatal_error("getRelocationAddress not implemented in MachOObjectFile"); } + error_code MachOObjectFile::getRelocationOffset(DataRefImpl Rel, uint64_t &Res) const { - InMemoryStruct RE; - getRelocation(Rel, RE); - - unsigned Arch = getArch(); - bool isScattered = (Arch != Triple::x86_64) && - (RE->Word0 & macho::RF_Scattered); - if (isScattered) - Res = RE->Word0 & 0xFFFFFF; - else - Res = RE->Word0; + MachO::any_relocation_info RE = getRelocation(Rel); + Res = getAnyRelocationAddress(RE); return object_error::success; } -error_code MachOObjectFile::getRelocationSymbol(DataRefImpl Rel, - SymbolRef &Res) const { - InMemoryStruct RE; - getRelocation(Rel, RE); - uint32_t SymbolIdx = RE->Word1 & 0xffffff; - bool isExtern = (RE->Word1 >> 27) & 1; +symbol_iterator +MachOObjectFile::getRelocationSymbol(DataRefImpl Rel) const { + MachO::any_relocation_info RE = getRelocation(Rel); + uint32_t SymbolIdx = getPlainRelocationSymbolNum(RE); + bool isExtern = getPlainRelocationExternal(RE); + if (!isExtern) + return symbol_end(); + + MachO::symtab_command S = getSymtabLoadCommand(); + unsigned SymbolTableEntrySize = is64Bit() ? + sizeof(MachO::nlist_64) : + sizeof(MachO::nlist); + uint64_t Offset = S.symoff + SymbolIdx * SymbolTableEntrySize; DataRefImpl Sym; - moveToNextSymbol(Sym); - if (isExtern) { - for (unsigned i = 0; i < SymbolIdx; i++) { - Sym.d.b++; - moveToNextSymbol(Sym); - assert(Sym.d.a < MachOObj->getHeader().NumLoadCommands && - "Relocation symbol index out of range!"); - } - } - Res = SymbolRef(Sym, this); - return object_error::success; + Sym.p = reinterpret_cast(getPtr(this, Offset)); + return symbol_iterator(SymbolRef(Sym, this)); } + error_code MachOObjectFile::getRelocationType(DataRefImpl Rel, uint64_t &Res) const { - InMemoryStruct RE; - getRelocation(Rel, RE); - Res = RE->Word0; - Res <<= 32; - Res |= RE->Word1; + MachO::any_relocation_info RE = getRelocation(Rel); + Res = getAnyRelocationType(RE); return object_error::success; } -error_code MachOObjectFile::getRelocationTypeName(DataRefImpl Rel, - SmallVectorImpl &Result) const { - // TODO: Support scattered relocations. - StringRef res; - InMemoryStruct RE; - getRelocation(Rel, RE); - unsigned Arch = getArch(); - bool isScattered = (Arch != Triple::x86_64) && - (RE->Word0 & macho::RF_Scattered); +error_code +MachOObjectFile::getRelocationTypeName(DataRefImpl Rel, + SmallVectorImpl &Result) const { + StringRef res; + uint64_t RType; + getRelocationType(Rel, RType); - unsigned r_type; - if (isScattered) - r_type = (RE->Word0 >> 24) & 0xF; - else - r_type = (RE->Word1 >> 28) & 0xF; + unsigned Arch = this->getArch(); switch (Arch) { case Triple::x86: { @@ -796,10 +891,10 @@ error_code MachOObjectFile::getRelocationTypeName(DataRefImpl Rel, "GENERIC_RELOC_LOCAL_SECTDIFF", "GENERIC_RELOC_TLV" }; - if (r_type > 6) + if (RType > 5) res = "Unknown"; else - res = Table[r_type]; + res = Table[RType]; break; } case Triple::x86_64: { @@ -815,10 +910,10 @@ error_code MachOObjectFile::getRelocationTypeName(DataRefImpl Rel, "X86_64_RELOC_SIGNED_4", "X86_64_RELOC_TLV" }; - if (r_type > 9) + if (RType > 9) res = "Unknown"; else - res = Table[r_type]; + res = Table[RType]; break; } case Triple::arm: { @@ -834,10 +929,27 @@ error_code MachOObjectFile::getRelocationTypeName(DataRefImpl Rel, "ARM_RELOC_HALF", "ARM_RELOC_HALF_SECTDIFF" }; - if (r_type > 9) + if (RType > 9) res = "Unknown"; else - res = Table[r_type]; + res = Table[RType]; + break; + } + case Triple::arm64: + case Triple::aarch64: { + static const char *const Table[] = { + "ARM64_RELOC_UNSIGNED", "ARM64_RELOC_SUBTRACTOR", + "ARM64_RELOC_BRANCH26", "ARM64_RELOC_PAGE21", + "ARM64_RELOC_PAGEOFF12", "ARM64_RELOC_GOT_LOAD_PAGE21", + "ARM64_RELOC_GOT_LOAD_PAGEOFF12", "ARM64_RELOC_POINTER_TO_GOT", + "ARM64_RELOC_TLVP_LOAD_PAGE21", "ARM64_RELOC_TLVP_LOAD_PAGEOFF12", + "ARM64_RELOC_ADDEND" + }; + + if (RType >= array_lengthof(Table)) + res = "Unknown"; + else + res = Table[RType]; break; } case Triple::ppc: { @@ -859,7 +971,10 @@ error_code MachOObjectFile::getRelocationTypeName(DataRefImpl Rel, "PPC_RELOC_LO14_SECTDIFF", "PPC_RELOC_LOCAL_SECTDIFF" }; - res = Table[r_type]; + if (RType > 15) + res = "Unknown"; + else + res = Table[RType]; break; } case Triple::UnknownArch: @@ -869,299 +984,154 @@ error_code MachOObjectFile::getRelocationTypeName(DataRefImpl Rel, Result.append(res.begin(), res.end()); return object_error::success; } -error_code MachOObjectFile::getRelocationAdditionalInfo(DataRefImpl Rel, - int64_t &Res) const { - InMemoryStruct RE; - getRelocation(Rel, RE); - bool isExtern = (RE->Word1 >> 27) & 1; - Res = 0; - if (!isExtern) { - const uint8_t* sectAddress = base(); - if (MachOObj->is64Bit()) { - InMemoryStruct Sect; - getSection64(Sections[Rel.d.b], Sect); - sectAddress += Sect->Offset; - } else { - InMemoryStruct Sect; - getSection(Sections[Rel.d.b], Sect); - sectAddress += Sect->Offset; - } - Res = reinterpret_cast(sectAddress); - } - return object_error::success; -} - -// Helper to advance a section or symbol iterator multiple increments at a time. -template -error_code advance(T &it, size_t Val) { - error_code ec; - while (Val--) { - it.increment(ec); - } - return ec; -} - -template -void advanceTo(T &it, size_t Val) { - if (error_code ec = advance(it, Val)) - report_fatal_error(ec.message()); -} - -void MachOObjectFile::printRelocationTargetName( - InMemoryStruct& RE, - raw_string_ostream &fmt) const { - unsigned Arch = getArch(); - bool isScattered = (Arch != Triple::x86_64) && - (RE->Word0 & macho::RF_Scattered); - // 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 = RE->Word1; - - error_code ec; - for (symbol_iterator SI = begin_symbols(), SE = end_symbols(); SI != SE; - SI.increment(ec)) { - if (ec) report_fatal_error(ec.message()); - - uint64_t Addr; - StringRef Name; - - if ((ec = SI->getAddress(Addr))) - report_fatal_error(ec.message()); - if (Addr != Val) continue; - if ((ec = SI->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 (section_iterator SI = begin_sections(), SE = end_sections(); SI != SE; - SI.increment(ec)) { - if (ec) report_fatal_error(ec.message()); - - uint64_t Addr; - StringRef Name; - - if ((ec = SI->getAddress(Addr))) - report_fatal_error(ec.message()); - if (Addr != Val) continue; - if ((ec = SI->getName(Name))) - report_fatal_error(ec.message()); - fmt << Name; - return; - } - - fmt << format("0x%x", Val); - return; - } - - StringRef S; - bool isExtern = (RE->Word1 >> 27) & 1; - uint32_t Val = RE->Word1 & 0xFFFFFF; - - if (isExtern) { - symbol_iterator SI = begin_symbols(); - advanceTo(SI, Val); - SI->getName(S); - } else { - section_iterator SI = begin_sections(); - advanceTo(SI, Val); - SI->getName(S); - } - - fmt << S; -} - -error_code MachOObjectFile::getRelocationValueString(DataRefImpl Rel, +error_code +MachOObjectFile::getRelocationValueString(DataRefImpl Rel, SmallVectorImpl &Result) const { - InMemoryStruct RE; - getRelocation(Rel, RE); + MachO::any_relocation_info RE = getRelocation(Rel); - unsigned Arch = getArch(); - bool isScattered = (Arch != Triple::x86_64) && - (RE->Word0 & macho::RF_Scattered); + unsigned Arch = this->getArch(); std::string fmtbuf; raw_string_ostream fmt(fmtbuf); - - unsigned Type; - if (isScattered) - Type = (RE->Word0 >> 24) & 0xF; - else - Type = (RE->Word1 >> 28) & 0xF; - - bool isPCRel; - if (isScattered) - isPCRel = ((RE->Word0 >> 30) & 1); - else - isPCRel = ((RE->Word1 >> 24) & 1); + 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 = ((RE->Word1 >> 24) & 1); + bool isPCRel = getAnyRelocationPCRel(RE); switch (Type) { - case macho::RIT_X86_64_GOTLoad: // X86_64_RELOC_GOT_LOAD - case macho::RIT_X86_64_GOT: { // X86_64_RELOC_GOT - printRelocationTargetName(RE, fmt); + 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::RIT_X86_64_Subtractor: { // X86_64_RELOC_SUBTRACTOR - InMemoryStruct RENext; + case MachO::X86_64_RELOC_SUBTRACTOR: { DataRefImpl RelNext = Rel; RelNext.d.a++; - getRelocation(RelNext, RENext); + MachO::any_relocation_info RENext = getRelocation(RelNext); - // X86_64_SUBTRACTOR must be followed by a relocation of type + // 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 = (RENext->Word1 >> 28) & 0xF; - if (RType != 0) + 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_SUBTRACTOR contains to the subtrahend. - printRelocationTargetName(RENext, fmt); + // The X86_64_RELOC_UNSIGNED contains the minuend symbol; + // X86_64_RELOC_SUBTRACTOR contains the subtrahend. + printRelocationTargetName(this, RENext, fmt); fmt << "-"; - printRelocationTargetName(RE, fmt); + printRelocationTargetName(this, RE, fmt); + break; } - case macho::RIT_X86_64_TLV: - printRelocationTargetName(RE, fmt); + case MachO::X86_64_RELOC_TLV: + printRelocationTargetName(this, RE, fmt); fmt << "@TLV"; if (isPCRel) fmt << "P"; break; - case macho::RIT_X86_64_Signed1: // X86_64_RELOC_SIGNED1 - printRelocationTargetName(RE, fmt); + case MachO::X86_64_RELOC_SIGNED_1: + printRelocationTargetName(this, RE, fmt); fmt << "-1"; break; - case macho::RIT_X86_64_Signed2: // X86_64_RELOC_SIGNED2 - printRelocationTargetName(RE, fmt); + case MachO::X86_64_RELOC_SIGNED_2: + printRelocationTargetName(this, RE, fmt); fmt << "-2"; break; - case macho::RIT_X86_64_Signed4: // X86_64_RELOC_SIGNED4 - printRelocationTargetName(RE, fmt); + case MachO::X86_64_RELOC_SIGNED_4: + printRelocationTargetName(this, RE, fmt); fmt << "-4"; break; default: - printRelocationTargetName(RE, fmt); + printRelocationTargetName(this, RE, fmt); break; } // X86 and ARM share some relocation types in common. - } else if (Arch == Triple::x86 || Arch == Triple::arm) { + } else if (Arch == Triple::x86 || Arch == Triple::arm || + Arch == Triple::ppc) { // Generic relocation types... switch (Type) { - case macho::RIT_Pair: // GENERIC_RELOC_PAIR - prints no info + case MachO::GENERIC_RELOC_PAIR: // prints no info return object_error::success; - case macho::RIT_Difference: { // GENERIC_RELOC_SECTDIFF - InMemoryStruct RENext; + case MachO::GENERIC_RELOC_SECTDIFF: { DataRefImpl RelNext = Rel; RelNext.d.a++; - getRelocation(RelNext, RENext); + MachO::any_relocation_info RENext = getRelocation(RelNext); // X86 sect diff's must be followed by a relocation of type // GENERIC_RELOC_PAIR. - bool isNextScattered = (Arch != Triple::x86_64) && - (RENext->Word0 & macho::RF_Scattered); - unsigned RType; - if (isNextScattered) - RType = (RENext->Word0 >> 24) & 0xF; - else - RType = (RENext->Word1 >> 28) & 0xF; - if (RType != 1) + unsigned RType = getAnyRelocationType(RENext); + + if (RType != MachO::GENERIC_RELOC_PAIR) report_fatal_error("Expected GENERIC_RELOC_PAIR after " "GENERIC_RELOC_SECTDIFF."); - printRelocationTargetName(RE, fmt); + printRelocationTargetName(this, RE, fmt); fmt << "-"; - printRelocationTargetName(RENext, fmt); + printRelocationTargetName(this, RENext, fmt); break; } } - if (Arch == Triple::x86) { - // All X86 relocations that need special printing were already - // handled in the generic code. + if (Arch == Triple::x86 || Arch == Triple::ppc) { switch (Type) { - case macho::RIT_Generic_LocalDifference:{// GENERIC_RELOC_LOCAL_SECTDIFF - InMemoryStruct RENext; + case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: { DataRefImpl RelNext = Rel; RelNext.d.a++; - getRelocation(RelNext, RENext); + MachO::any_relocation_info RENext = getRelocation(RelNext); // X86 sect diff's must be followed by a relocation of type // GENERIC_RELOC_PAIR. - bool isNextScattered = (Arch != Triple::x86_64) && - (RENext->Word0 & macho::RF_Scattered); - unsigned RType; - if (isNextScattered) - RType = (RENext->Word0 >> 24) & 0xF; - else - RType = (RENext->Word1 >> 28) & 0xF; - if (RType != 1) + unsigned RType = getAnyRelocationType(RENext); + if (RType != MachO::GENERIC_RELOC_PAIR) report_fatal_error("Expected GENERIC_RELOC_PAIR after " "GENERIC_RELOC_LOCAL_SECTDIFF."); - printRelocationTargetName(RE, fmt); + printRelocationTargetName(this, RE, fmt); fmt << "-"; - printRelocationTargetName(RENext, fmt); + printRelocationTargetName(this, RENext, fmt); break; } - case macho::RIT_Generic_TLV: { - printRelocationTargetName(RE, fmt); + case MachO::GENERIC_RELOC_TLV: { + printRelocationTargetName(this, RE, fmt); fmt << "@TLV"; - if (isPCRel) fmt << "P"; + if (IsPCRel) fmt << "P"; break; } default: - printRelocationTargetName(RE, fmt); + printRelocationTargetName(this, RE, fmt); } } else { // ARM-specific relocations switch (Type) { - case macho::RIT_ARM_Half: // ARM_RELOC_HALF - case macho::RIT_ARM_HalfDifference: { // ARM_RELOC_HALF_SECTDIFF + 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; - if (isScattered) - isUpper = (RE->Word0 >> 28) & 1; - else - isUpper = (RE->Word1 >> 25) & 1; + bool isUpper = getAnyRelocationLength(RE) >> 1; if (isUpper) fmt << ":upper16:("; else fmt << ":lower16:("; - printRelocationTargetName(RE, fmt); + printRelocationTargetName(this, RE, fmt); - InMemoryStruct RENext; DataRefImpl RelNext = Rel; RelNext.d.a++; - getRelocation(RelNext, RENext); + MachO::any_relocation_info RENext = getRelocation(RelNext); // ARM half relocs must be followed by a relocation of type // ARM_RELOC_PAIR. - bool isNextScattered = (Arch != Triple::x86_64) && - (RENext->Word0 & macho::RF_Scattered); - unsigned RType; - if (isNextScattered) - RType = (RENext->Word0 >> 24) & 0xF; - else - RType = (RENext->Word1 >> 28) & 0xF; - - if (RType != 1) + unsigned RType = getAnyRelocationType(RENext); + if (RType != MachO::ARM_RELOC_PAIR) report_fatal_error("Expected ARM_RELOC_PAIR after " - "GENERIC_RELOC_HALF"); + "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 @@ -1170,59 +1140,49 @@ error_code MachOObjectFile::getRelocationValueString(DataRefImpl Rel, // ARM_RELOC_HALF_SECTDIFF encodes the second section in the // symbol/section pointer of the follow-on relocation. - if (Type == macho::RIT_ARM_HalfDifference) { + if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) { fmt << "-"; - printRelocationTargetName(RENext, fmt); + printRelocationTargetName(this, RENext, fmt); } fmt << ")"; break; } default: { - printRelocationTargetName(RE, fmt); + printRelocationTargetName(this, RE, fmt); } } } } else - printRelocationTargetName(RE, fmt); + printRelocationTargetName(this, RE, fmt); fmt.flush(); Result.append(fmtbuf.begin(), fmtbuf.end()); return object_error::success; } -error_code MachOObjectFile::getRelocationHidden(DataRefImpl Rel, - bool &Result) const { - InMemoryStruct RE; - getRelocation(Rel, RE); - +error_code +MachOObjectFile::getRelocationHidden(DataRefImpl Rel, bool &Result) const { unsigned Arch = getArch(); - bool isScattered = (Arch != Triple::x86_64) && - (RE->Word0 & macho::RF_Scattered); - unsigned Type; - if (isScattered) - Type = (RE->Word0 >> 24) & 0xF; - else - Type = (RE->Word1 >> 28) & 0xF; + 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) { - if (Type == macho::RIT_Pair) Result = true; + 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 X864_64_RELOC_SUBTRACTOR. - if (Type == macho::RIT_X86_64_Unsigned && Rel.d.a > 0) { + // an X86_64_RELOC_SUBTRACTOR. + if (Type == MachO::X86_64_RELOC_UNSIGNED && Rel.d.a > 0) { DataRefImpl RelPrev = Rel; RelPrev.d.a--; - InMemoryStruct REPrev; - getRelocation(RelPrev, REPrev); - - unsigned PrevType = (REPrev->Word1 >> 28) & 0xF; - - if (PrevType == macho::RIT_X86_64_Subtractor) Result = true; + uint64_t PrevType; + getRelocationType(RelPrev, PrevType); + if (PrevType == MachO::X86_64_RELOC_SUBTRACTOR) + Result = true; } } @@ -1239,57 +1199,419 @@ error_code MachOObjectFile::getLibraryPath(DataRefImpl LibData, report_fatal_error("Needed libraries unimplemented in MachOObjectFile"); } +basic_symbol_iterator MachOObjectFile::symbol_begin_impl() const { + DataRefImpl DRI; + if (!SymtabLoadCmd) + return basic_symbol_iterator(SymbolRef(DRI, this)); + + MachO::symtab_command Symtab = getSymtabLoadCommand(); + DRI.p = reinterpret_cast(getPtr(this, Symtab.symoff)); + return basic_symbol_iterator(SymbolRef(DRI, this)); +} + +basic_symbol_iterator MachOObjectFile::symbol_end_impl() const { + DataRefImpl DRI; + if (!SymtabLoadCmd) + return basic_symbol_iterator(SymbolRef(DRI, this)); + + MachO::symtab_command Symtab = getSymtabLoadCommand(); + unsigned SymbolTableEntrySize = is64Bit() ? + sizeof(MachO::nlist_64) : + sizeof(MachO::nlist); + unsigned Offset = Symtab.symoff + + Symtab.nsyms * SymbolTableEntrySize; + DRI.p = reinterpret_cast(getPtr(this, Offset)); + return basic_symbol_iterator(SymbolRef(DRI, this)); +} + +section_iterator MachOObjectFile::section_begin() const { + DataRefImpl DRI; + return section_iterator(SectionRef(DRI, this)); +} + +section_iterator MachOObjectFile::section_end() const { + DataRefImpl DRI; + DRI.d.a = Sections.size(); + return section_iterator(SectionRef(DRI, this)); +} + +library_iterator MachOObjectFile::needed_library_begin() const { + // TODO: implement + report_fatal_error("Needed libraries unimplemented in MachOObjectFile"); +} -/*===-- Miscellaneous -----------------------------------------------------===*/ +library_iterator MachOObjectFile::needed_library_end() const { + // TODO: implement + report_fatal_error("Needed libraries unimplemented in MachOObjectFile"); +} uint8_t MachOObjectFile::getBytesInAddress() const { - return MachOObj->is64Bit() ? 8 : 4; + return is64Bit() ? 8 : 4; } StringRef MachOObjectFile::getFileFormatName() const { - if (!MachOObj->is64Bit()) { - switch (MachOObj->getHeader().CPUType) { - case llvm::MachO::CPUTypeI386: + unsigned CPUType = getCPUType(this); + if (!is64Bit()) { + switch (CPUType) { + case llvm::MachO::CPU_TYPE_I386: return "Mach-O 32-bit i386"; - case llvm::MachO::CPUTypeARM: + case llvm::MachO::CPU_TYPE_ARM: return "Mach-O arm"; - case llvm::MachO::CPUTypePowerPC: + case llvm::MachO::CPU_TYPE_POWERPC: return "Mach-O 32-bit ppc"; default: - assert((MachOObj->getHeader().CPUType & llvm::MachO::CPUArchABI64) == 0 && + assert((CPUType & llvm::MachO::CPU_ARCH_ABI64) == 0 && "64-bit object file when we're not 64-bit?"); return "Mach-O 32-bit unknown"; } } - switch (MachOObj->getHeader().CPUType) { - case llvm::MachO::CPUTypeX86_64: + // 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"; - case llvm::MachO::CPUTypePowerPC64: + case llvm::MachO::CPU_TYPE_ARM64: + return "Mach-O arm64"; + case llvm::MachO::CPU_TYPE_POWERPC64: return "Mach-O 64-bit ppc64"; default: - assert((MachOObj->getHeader().CPUType & llvm::MachO::CPUArchABI64) == 1 && - "32-bit object file when we're 64-bit?"); return "Mach-O 64-bit unknown"; } } -unsigned MachOObjectFile::getArch() const { - switch (MachOObj->getHeader().CPUType) { - case llvm::MachO::CPUTypeI386: +Triple::ArchType MachOObjectFile::getArch(uint32_t CPUType) { + switch (CPUType) { + case llvm::MachO::CPU_TYPE_I386: return Triple::x86; - case llvm::MachO::CPUTypeX86_64: + case llvm::MachO::CPU_TYPE_X86_64: return Triple::x86_64; - case llvm::MachO::CPUTypeARM: + case llvm::MachO::CPU_TYPE_ARM: return Triple::arm; - case llvm::MachO::CPUTypePowerPC: + case llvm::MachO::CPU_TYPE_ARM64: + return Triple::arm64; + case llvm::MachO::CPU_TYPE_POWERPC: return Triple::ppc; - case llvm::MachO::CPUTypePowerPC64: + case llvm::MachO::CPU_TYPE_POWERPC64: return Triple::ppc64; default: return Triple::UnknownArch; } } +unsigned MachOObjectFile::getArch() const { + return getArch(getCPUType(this)); +} + +StringRef MachOObjectFile::getLoadName() const { + // TODO: Implement + report_fatal_error("get_load_name() unimplemented in MachOObjectFile"); +} + +relocation_iterator MachOObjectFile::section_rel_begin(unsigned Index) const { + DataRefImpl DRI; + DRI.d.a = Index; + return section_rel_begin(DRI); +} + +relocation_iterator MachOObjectFile::section_rel_end(unsigned Index) const { + DataRefImpl DRI; + DRI.d.a = Index; + return section_rel_end(DRI); +} + +dice_iterator MachOObjectFile::begin_dices() const { + DataRefImpl DRI; + if (!DataInCodeLoadCmd) + return dice_iterator(DiceRef(DRI, this)); + + MachO::linkedit_data_command DicLC = getDataInCodeLoadCommand(); + DRI.p = reinterpret_cast(getPtr(this, DicLC.dataoff)); + return dice_iterator(DiceRef(DRI, this)); +} + +dice_iterator MachOObjectFile::end_dices() const { + DataRefImpl DRI; + if (!DataInCodeLoadCmd) + return dice_iterator(DiceRef(DRI, this)); + + MachO::linkedit_data_command DicLC = getDataInCodeLoadCommand(); + unsigned Offset = DicLC.dataoff + DicLC.datasize; + DRI.p = reinterpret_cast(getPtr(this, Offset)); + return dice_iterator(DiceRef(DRI, this)); +} + +StringRef +MachOObjectFile::getSectionFinalSegmentName(DataRefImpl Sec) const { + ArrayRef Raw = getSectionRawFinalSegmentName(Sec); + return parseSegmentOrSectionName(Raw.data()); +} + +ArrayRef +MachOObjectFile::getSectionRawName(DataRefImpl Sec) const { + const section_base *Base = + reinterpret_cast(Sections[Sec.d.a]); + return ArrayRef(Base->sectname); +} + +ArrayRef +MachOObjectFile::getSectionRawFinalSegmentName(DataRefImpl Sec) const { + const section_base *Base = + reinterpret_cast(Sections[Sec.d.a]); + return ArrayRef(Base->segname); +} + +bool +MachOObjectFile::isRelocationScattered(const MachO::any_relocation_info &RE) + const { + if (getCPUType(this) == MachO::CPU_TYPE_X86_64) + return false; + return getPlainRelocationAddress(RE) & MachO::R_SCATTERED; +} + +unsigned MachOObjectFile::getPlainRelocationSymbolNum( + const MachO::any_relocation_info &RE) const { + if (isLittleEndian()) + return RE.r_word1 & 0xffffff; + return RE.r_word1 >> 8; +} + +bool MachOObjectFile::getPlainRelocationExternal( + const MachO::any_relocation_info &RE) const { + if (isLittleEndian()) + return (RE.r_word1 >> 27) & 1; + return (RE.r_word1 >> 4) & 1; +} + +bool MachOObjectFile::getScatteredRelocationScattered( + const MachO::any_relocation_info &RE) const { + return RE.r_word0 >> 31; +} + +uint32_t MachOObjectFile::getScatteredRelocationValue( + const MachO::any_relocation_info &RE) const { + return RE.r_word1; +} + +unsigned MachOObjectFile::getAnyRelocationAddress( + const MachO::any_relocation_info &RE) const { + if (isRelocationScattered(RE)) + return getScatteredRelocationAddress(RE); + return getPlainRelocationAddress(RE); +} + +unsigned MachOObjectFile::getAnyRelocationPCRel( + const MachO::any_relocation_info &RE) const { + if (isRelocationScattered(RE)) + return getScatteredRelocationPCRel(this, RE); + return getPlainRelocationPCRel(this, RE); +} + +unsigned MachOObjectFile::getAnyRelocationLength( + const MachO::any_relocation_info &RE) const { + if (isRelocationScattered(RE)) + return getScatteredRelocationLength(RE); + return getPlainRelocationLength(this, RE); +} + +unsigned +MachOObjectFile::getAnyRelocationType( + const MachO::any_relocation_info &RE) const { + if (isRelocationScattered(RE)) + return getScatteredRelocationType(RE); + return getPlainRelocationType(this, RE); +} + +SectionRef +MachOObjectFile::getRelocationSection( + const MachO::any_relocation_info &RE) const { + if (isRelocationScattered(RE) || getPlainRelocationExternal(RE)) + return *section_end(); + unsigned SecNum = getPlainRelocationSymbolNum(RE) - 1; + DataRefImpl DRI; + DRI.d.a = SecNum; + 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 { + return getStruct(this, Sections[DRI.d.a]); +} + +MachO::section_64 MachOObjectFile::getSection64(DataRefImpl DRI) const { + return getStruct(this, Sections[DRI.d.a]); +} + +MachO::section MachOObjectFile::getSection(const LoadCommandInfo &L, + unsigned Index) const { + const char *Sec = getSectionPtr(this, L, Index); + return getStruct(this, Sec); +} + +MachO::section_64 MachOObjectFile::getSection64(const LoadCommandInfo &L, + unsigned Index) const { + const char *Sec = getSectionPtr(this, L, Index); + return getStruct(this, Sec); +} + +MachO::nlist +MachOObjectFile::getSymbolTableEntry(DataRefImpl DRI) const { + const char *P = reinterpret_cast(DRI.p); + return getStruct(this, P); +} + +MachO::nlist_64 +MachOObjectFile::getSymbol64TableEntry(DataRefImpl DRI) const { + const char *P = reinterpret_cast(DRI.p); + return getStruct(this, P); +} + +MachO::linkedit_data_command +MachOObjectFile::getLinkeditDataLoadCommand(const LoadCommandInfo &L) const { + return getStruct(this, L.Ptr); +} + +MachO::segment_command +MachOObjectFile::getSegmentLoadCommand(const LoadCommandInfo &L) const { + return getStruct(this, L.Ptr); +} + +MachO::segment_command_64 +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::version_min_command +MachOObjectFile::getVersionMinLoadCommand(const LoadCommandInfo &L) const { + return getStruct(this, L.Ptr); +} + +MachO::any_relocation_info +MachOObjectFile::getRelocation(DataRefImpl Rel) const { + const char *P = reinterpret_cast(Rel.p); + return getStruct(this, P); +} + +MachO::data_in_code_entry +MachOObjectFile::getDice(DataRefImpl Rel) const { + const char *P = reinterpret_cast(Rel.p); + return getStruct(this, P); +} + +MachO::mach_header MachOObjectFile::getHeader() const { + return getStruct(this, getPtr(this, 0)); +} + +MachO::mach_header_64 MachOObjectFile::getHeader64() const { + return getStruct(this, getPtr(this, 0)); +} + +uint32_t MachOObjectFile::getIndirectSymbolTableEntry( + const MachO::dysymtab_command &DLC, + unsigned Index) const { + uint64_t Offset = DLC.indirectsymoff + Index * sizeof(uint32_t); + return getStruct(this, getPtr(this, Offset)); +} + +MachO::data_in_code_entry +MachOObjectFile::getDataInCodeTableEntry(uint32_t DataOffset, + unsigned Index) const { + uint64_t Offset = DataOffset + Index * sizeof(MachO::data_in_code_entry); + return getStruct(this, getPtr(this, Offset)); +} + +MachO::symtab_command MachOObjectFile::getSymtabLoadCommand() const { + return getStruct(this, SymtabLoadCmd); +} + +MachO::dysymtab_command MachOObjectFile::getDysymtabLoadCommand() const { + return getStruct(this, DysymtabLoadCmd); +} + +MachO::linkedit_data_command +MachOObjectFile::getDataInCodeLoadCommand() const { + if (DataInCodeLoadCmd) + return getStruct(this, DataInCodeLoadCmd); + + // If there is no DataInCodeLoadCmd return a load command with zero'ed fields. + MachO::linkedit_data_command Cmd; + Cmd.cmd = MachO::LC_DATA_IN_CODE; + Cmd.cmdsize = sizeof(MachO::linkedit_data_command); + Cmd.dataoff = 0; + Cmd.datasize = 0; + return Cmd; +} + +StringRef MachOObjectFile::getStringTableData() const { + MachO::symtab_command S = getSymtabLoadCommand(); + return getData().substr(S.stroff, S.strsize); +} + +bool MachOObjectFile::is64Bit() const { + return getType() == getMachOType(false, true) || + getType() == getMachOType(true, true); +} + +void MachOObjectFile::ReadULEB128s(uint64_t Index, + SmallVectorImpl &Out) const { + DataExtractor extractor(ObjectFile::getData(), true, 0); + + uint32_t offset = Index; + uint64_t data = 0; + while (uint64_t delta = extractor.getULEB128(&offset)) { + data += delta; + Out.push_back(data); + } +} + +ErrorOr ObjectFile::createMachOObjectFile(MemoryBuffer *Buffer, + bool BufferOwned) { + StringRef Magic = Buffer->getBuffer().slice(0, 4); + error_code EC; + std::unique_ptr Ret; + if (Magic == "\xFE\xED\xFA\xCE") + Ret.reset(new MachOObjectFile(Buffer, false, false, EC, BufferOwned)); + else if (Magic == "\xCE\xFA\xED\xFE") + Ret.reset(new MachOObjectFile(Buffer, true, false, EC, BufferOwned)); + else if (Magic == "\xFE\xED\xFA\xCF") + Ret.reset(new MachOObjectFile(Buffer, false, true, EC, BufferOwned)); + else if (Magic == "\xCF\xFA\xED\xFE") + Ret.reset(new MachOObjectFile(Buffer, true, true, EC, BufferOwned)); + else { + delete Buffer; + return object_error::parse_failed; + } + + if (EC) + return EC; + return Ret.release(); +} + } // end namespace object } // end namespace llvm