diff options
-rw-r--r-- | include/llvm/Object/Binary.h | 3 | ||||
-rw-r--r-- | include/llvm/Object/MachO.h | 1645 | ||||
-rw-r--r-- | lib/Object/MachOObjectFile.cpp | 1461 | ||||
-rw-r--r-- | test/tools/llvm-readobj/Inputs/trivial.obj.macho-arm | bin | 0 -> 908 bytes | |||
-rw-r--r-- | test/tools/llvm-readobj/relocations.test | 89 | ||||
-rw-r--r-- | test/tools/llvm-readobj/sections-ext.test | 277 | ||||
-rw-r--r-- | test/tools/llvm-readobj/sections.test | 121 | ||||
-rw-r--r-- | tools/llvm-objdump/MachODump.cpp | 43 | ||||
-rw-r--r-- | tools/llvm-objdump/llvm-objdump.cpp | 20 | ||||
-rw-r--r-- | tools/llvm-readobj/MachODumper.cpp | 133 | ||||
-rw-r--r-- | tools/llvm-symbolizer/LLVMSymbolize.cpp | 2 |
11 files changed, 2039 insertions, 1755 deletions
diff --git a/include/llvm/Object/Binary.h b/include/llvm/Object/Binary.h index ac5bfed..78fcf6f 100644 --- a/include/llvm/Object/Binary.h +++ b/include/llvm/Object/Binary.h @@ -100,7 +100,8 @@ public: } bool isLittleEndian() const { - return !(TypeID == ID_ELF32B || TypeID == ID_ELF64B); + return !(TypeID == ID_ELF32B || TypeID == ID_ELF64B || + TypeID == ID_MachO32B || TypeID == ID_MachO64B); } }; diff --git a/include/llvm/Object/MachO.h b/include/llvm/Object/MachO.h index 8867068..cec649e 100644 --- a/include/llvm/Object/MachO.h +++ b/include/llvm/Object/MachO.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// // -// This file declares the MachOObjectFile class, which binds the MachOObject -// class to the generic ObjectFile wrapper. +// This file declares the MachOObjectFile class, which implement the ObjectFile +// interface for MachO files. // //===----------------------------------------------------------------------===// @@ -17,1607 +17,140 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/Triple.h" #include "llvm/Object/MachOFormat.h" #include "llvm/Object/ObjectFile.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Format.h" #include "llvm/Support/MachO.h" #include "llvm/Support/raw_ostream.h" namespace llvm { namespace object { -using support::endianness; - -template<endianness E, bool B> -struct MachOType { - static const endianness TargetEndianness = E; - static const bool Is64Bits = B; -}; - -template<endianness TargetEndianness> -struct MachOInt24Impl; - -template<> -struct MachOInt24Impl<support::little> { - uint8_t bytes[3]; - operator uint32_t() const { - return (bytes[2] << 24) | (bytes[1] << 16) | bytes[0]; - } -}; - -template<> -struct MachOInt24Impl<support::big> { - uint8_t bytes[3]; - operator uint32_t() const { - return (bytes[0] << 24) | (bytes[1] << 16) | bytes[2]; - } -}; - -template<endianness TargetEndianness> -struct MachODataTypeTypedefHelperCommon { - typedef support::detail::packed_endian_specific_integral - <uint16_t, TargetEndianness, support::unaligned> MachOInt16; - typedef support::detail::packed_endian_specific_integral - <uint32_t, TargetEndianness, support::unaligned> MachOInt32; - typedef support::detail::packed_endian_specific_integral - <uint64_t, TargetEndianness, support::unaligned> MachOInt64; - typedef MachOInt24Impl<TargetEndianness> MachOInt24; -}; - -#define LLVM_MACHOB_IMPORT_TYPES_TYPENAME(E) \ -typedef typename MachODataTypeTypedefHelperCommon<E>::MachOInt16 MachOInt16; \ -typedef typename MachODataTypeTypedefHelperCommon<E>::MachOInt32 MachOInt32; \ -typedef typename MachODataTypeTypedefHelperCommon<E>::MachOInt64 MachOInt64; \ -typedef typename MachODataTypeTypedefHelperCommon<E>::MachOInt24 MachOInt24; - -#define LLVM_MACHOB_IMPORT_TYPES(E) \ -typedef MachODataTypeTypedefHelperCommon<E>::MachOInt16 MachOInt16; \ -typedef MachODataTypeTypedefHelperCommon<E>::MachOInt32 MachOInt32; \ -typedef MachODataTypeTypedefHelperCommon<E>::MachOInt64 MachOInt64; \ -typedef MachODataTypeTypedefHelperCommon<E>::MachOInt24 MachOInt24; - -template<class MachOT> -struct MachODataTypeTypedefHelper; - -template<endianness TargetEndianness> -struct MachODataTypeTypedefHelper<MachOType<TargetEndianness, false> > { - typedef MachODataTypeTypedefHelperCommon<TargetEndianness> Base; - typedef typename Base::MachOInt32 MachOIntPtr; -}; - -template<endianness TargetEndianness> -struct MachODataTypeTypedefHelper<MachOType<TargetEndianness, true> > { - typedef MachODataTypeTypedefHelperCommon<TargetEndianness> Base; - typedef typename Base::MachOInt64 MachOIntPtr; -}; - -#define LLVM_MACHO_IMPORT_TYPES(MachOT, E, B) \ -LLVM_MACHOB_IMPORT_TYPES_TYPENAME(E) \ -typedef typename \ - MachODataTypeTypedefHelper <MachOT<E, B> >::MachOIntPtr MachOIntPtr; - -namespace MachOFormat { - struct SectionBase { - char Name[16]; - char SegmentName[16]; - }; - - template<class MachOT> - struct Section; - - template<endianness TargetEndianness> - struct Section<MachOType<TargetEndianness, false> > { - LLVM_MACHOB_IMPORT_TYPES_TYPENAME(TargetEndianness) - char Name[16]; - char SegmentName[16]; - MachOInt32 Address; - MachOInt32 Size; - MachOInt32 Offset; - MachOInt32 Align; - MachOInt32 RelocationTableOffset; - MachOInt32 NumRelocationTableEntries; - MachOInt32 Flags; - MachOInt32 Reserved1; - MachOInt32 Reserved2; - }; - - template<endianness TargetEndianness> - struct Section<MachOType<TargetEndianness, true> > { - LLVM_MACHOB_IMPORT_TYPES_TYPENAME(TargetEndianness) - char Name[16]; - char SegmentName[16]; - MachOInt64 Address; - MachOInt64 Size; - MachOInt32 Offset; - MachOInt32 Align; - MachOInt32 RelocationTableOffset; - MachOInt32 NumRelocationTableEntries; - MachOInt32 Flags; - MachOInt32 Reserved1; - MachOInt32 Reserved2; - MachOInt32 Reserved3; - }; - - struct MachOInt24 { - uint8_t bytes[3]; - operator uint32_t() const { - return (bytes[2] << 24) | (bytes[1] << 16) | bytes[0]; - } - }; - - template<bool HostIsLittleEndian, endianness TargetEndianness> - struct RelocationEntry; - - template<> - struct RelocationEntry<true, support::little> { - LLVM_MACHOB_IMPORT_TYPES(support::little) - MachOInt32 Address; - MachOInt24 SymbolNum; - unsigned PCRel : 1; - unsigned Length : 2; - unsigned External : 1; - unsigned Type : 4; - }; - - template<> - struct RelocationEntry<false, support::little> { - LLVM_MACHOB_IMPORT_TYPES(support::little) - MachOInt32 Address; - MachOInt24 SymbolNum; - unsigned Type : 4; - unsigned External : 1; - unsigned Length : 2; - unsigned PCRel : 1; - }; - - template<> - struct RelocationEntry<true, support::big> { - LLVM_MACHOB_IMPORT_TYPES(support::big) - MachOInt32 Address; - MachOInt24 SymbolNum; - unsigned Type : 4; - unsigned External : 1; - unsigned Length : 2; - unsigned PCRel : 1; - }; - - template<> - struct RelocationEntry<false, support::big> { - LLVM_MACHOB_IMPORT_TYPES(support::big) - MachOInt32 Address; - MachOInt24 SymbolNum; - unsigned PCRel : 1; - unsigned Length : 2; - unsigned External : 1; - unsigned Type : 4; - }; - - template<bool HostIsLittleEndian, endianness TargetEndianness> - struct ScatteredRelocationEntry; - - template<> - struct ScatteredRelocationEntry<true, support::little> { - LLVM_MACHOB_IMPORT_TYPES(support::little) - MachOInt24 Address; - unsigned Type : 4; - unsigned Length : 2; - unsigned PCRel : 1; - unsigned Scattered : 1; - MachOInt32 Value; - }; - - template<> - struct ScatteredRelocationEntry<false, support::little> { - LLVM_MACHOB_IMPORT_TYPES(support::little) - MachOInt24 Address; - unsigned Scattered : 1; - unsigned PCRel : 1; - unsigned Length : 2; - unsigned Type : 4; - MachOInt32 Value; - }; - - template<> - struct ScatteredRelocationEntry<true, support::big> { - LLVM_MACHOB_IMPORT_TYPES(support::big) - unsigned Type : 4; - unsigned Length : 2; - unsigned PCRel : 1; - unsigned Scattered : 1; - MachOInt24 Address; - MachOInt32 Value; - }; - - template<> - struct ScatteredRelocationEntry<false, support::big> { - LLVM_MACHOB_IMPORT_TYPES(support::big) - unsigned Scattered : 1; - unsigned PCRel : 1; - unsigned Length : 2; - unsigned Type : 4; - MachOInt24 Address; - MachOInt32 Value; - }; - - template<endianness TargetEndianness> - struct SymbolTableEntryBase { - LLVM_MACHOB_IMPORT_TYPES_TYPENAME(TargetEndianness) - MachOInt32 StringIndex; - uint8_t Type; - uint8_t SectionIndex; - MachOInt16 Flags; - }; - - template<class MachOT> - struct SymbolTableEntry; - - template<endianness TargetEndianness, bool Is64Bits> - struct SymbolTableEntry<MachOType<TargetEndianness, Is64Bits> > { - LLVM_MACHO_IMPORT_TYPES(MachOType, TargetEndianness, Is64Bits) - MachOInt32 StringIndex; - uint8_t Type; - uint8_t SectionIndex; - MachOInt16 Flags; - MachOIntPtr Value; - }; - - template<endianness TargetEndianness> - struct LoadCommand { - LLVM_MACHOB_IMPORT_TYPES_TYPENAME(TargetEndianness) - MachOInt32 Type; - MachOInt32 Size; - }; - - template<endianness TargetEndianness> - struct SymtabLoadCommand { - LLVM_MACHOB_IMPORT_TYPES_TYPENAME(TargetEndianness) - MachOInt32 Type; - MachOInt32 Size; - MachOInt32 SymbolTableOffset; - MachOInt32 NumSymbolTableEntries; - MachOInt32 StringTableOffset; - MachOInt32 StringTableSize; - }; - - template<class MachOT> - struct SegmentLoadCommand; - - template<endianness TargetEndianness, bool Is64Bits> - struct SegmentLoadCommand<MachOType<TargetEndianness, Is64Bits> > { - LLVM_MACHO_IMPORT_TYPES(MachOType, TargetEndianness, Is64Bits) - MachOInt32 Type; - MachOInt32 Size; - char Name[16]; - MachOIntPtr VMAddress; - MachOIntPtr VMSize; - MachOIntPtr FileOffset; - MachOIntPtr FileSize; - MachOInt32 MaxVMProtection; - MachOInt32 InitialVMProtection; - MachOInt32 NumSections; - MachOInt32 Flags; - }; - - template<endianness TargetEndianness> - struct LinkeditDataLoadCommand { - LLVM_MACHOB_IMPORT_TYPES_TYPENAME(TargetEndianness) - MachOInt32 Type; - MachOInt32 Size; - MachOInt32 DataOffset; - MachOInt32 DataSize; - }; - - template<endianness TargetEndianness> - struct Header { - LLVM_MACHOB_IMPORT_TYPES_TYPENAME(TargetEndianness) - MachOInt32 Magic; - MachOInt32 CPUType; - MachOInt32 CPUSubtype; - MachOInt32 FileType; - MachOInt32 NumLoadCommands; - MachOInt32 SizeOfLoadCommands; - MachOInt32 Flags; - }; -} - -class MachOObjectFileBase : public ObjectFile { -public: - typedef MachOFormat::SectionBase SectionBase; - - MachOObjectFileBase(MemoryBuffer *Object, bool IsLittleEndian, bool Is64Bits, - error_code &ec); - - virtual symbol_iterator begin_dynamic_symbols() const; - virtual symbol_iterator end_dynamic_symbols() const; - virtual library_iterator begin_libraries_needed() const; - virtual library_iterator end_libraries_needed() const; - - virtual uint8_t getBytesInAddress() const; - virtual StringRef getLoadName() const; - - bool is64Bit() const; - void ReadULEB128s(uint64_t Index, SmallVectorImpl<uint64_t> &Out) const; - unsigned getHeaderSize() const; - StringRef getData(size_t Offset, size_t Size) const; - - static inline bool classof(const Binary *v) { - return v->isMachO(); - } - -protected: - StringRef parseSegmentOrSectionName(const char *P) const; - - virtual error_code getSymbolValue(DataRefImpl Symb, uint64_t &Val) const; - virtual error_code isSectionData(DataRefImpl Sec, bool &Res) const; - virtual error_code isSectionBSS(DataRefImpl Sec, bool &Res) const; - virtual error_code isSectionRequiredForExecution(DataRefImpl Sec, - bool &Res) const; - virtual error_code isSectionVirtual(DataRefImpl Sec, bool &Res) const; - virtual error_code isSectionReadOnlyData(DataRefImpl Sec, bool &Res) const; - virtual relocation_iterator getSectionRelBegin(DataRefImpl Sec) const; - - virtual error_code getRelocationNext(DataRefImpl Rel, - RelocationRef &Res) const; - - virtual error_code getLibraryNext(DataRefImpl LibData, LibraryRef &Res) const; - virtual error_code getLibraryPath(DataRefImpl LibData, StringRef &Res) const; - virtual error_code getRelocationAdditionalInfo(DataRefImpl Rel, - int64_t &Res) const; - - std::size_t getSectionIndex(DataRefImpl Sec) const; - - typedef SmallVector<DataRefImpl, 1> SectionList; - SectionList Sections; -}; - -template<endianness TargetEndianness> -class MachOObjectFileMiddle : public MachOObjectFileBase { +class MachOObjectFile : public ObjectFile { public: + struct LoadCommandInfo { + const char *Ptr; // Where in memory the load command is. + macho::LoadCommand C; // The command itself. + }; - typedef MachOFormat::SymbolTableEntryBase<TargetEndianness> - SymbolTableEntryBase; - typedef MachOFormat::LinkeditDataLoadCommand<TargetEndianness> - LinkeditDataLoadCommand; - typedef MachOFormat::Header<TargetEndianness> Header; - typedef MachOFormat::SymtabLoadCommand<TargetEndianness> SymtabLoadCommand; - typedef MachOFormat::RelocationEntry<sys::IsLittleEndianHost, TargetEndianness> RelocationEntry; - typedef MachOFormat::ScatteredRelocationEntry<sys::IsLittleEndianHost, TargetEndianness> - ScatteredRelocationEntry; - typedef MachOFormat::LoadCommand<TargetEndianness> LoadCommand; - - MachOObjectFileMiddle(MemoryBuffer *Object, bool Is64Bits, error_code &ec); - - const Header *getHeader() const; - const LoadCommand *getLoadCommandInfo(unsigned Index) const; - const RelocationEntry *getRelocation(DataRefImpl Rel) const; - bool isRelocationScattered(const RelocationEntry *RE) const; - bool isRelocationPCRel(const RelocationEntry *RE) const; - unsigned getRelocationLength(const RelocationEntry *RE) const; - unsigned getRelocationTypeImpl(const RelocationEntry *RE) const; - - void moveToNextSymbol(DataRefImpl &DRI) const; - void printRelocationTargetName(const RelocationEntry *RE, - raw_string_ostream &fmt) const; - const SectionBase *getSectionBase(DataRefImpl DRI) const; - const SymbolTableEntryBase *getSymbolTableEntryBase(DataRefImpl DRI) const; - unsigned getCPUType() const; - - // In a MachO file, sections have a segment name. This is used in the .o - // files. They have a single segment, but this field specifies which segment - // a section should be put in in the final object. - StringRef getSectionFinalSegmentName(DataRefImpl Sec) const; - - // Names are stored as 16 bytes. These returns the raw 16 bytes without - // interpreting them as a C string. - ArrayRef<char> getSectionRawName(DataRefImpl Sec) const; - ArrayRef<char> getSectionRawFinalSegmentName(DataRefImpl Sec) const; + MachOObjectFile(MemoryBuffer *Object, bool IsLittleEndian, bool Is64Bits, + error_code &ec); - virtual error_code getSymbolFlags(DataRefImpl Symb, uint32_t &Res) const; - virtual error_code getSymbolNMTypeChar(DataRefImpl Symb, char &Res) const; + virtual error_code getSymbolNext(DataRefImpl Symb, SymbolRef &Res) const; + virtual error_code getSymbolName(DataRefImpl Symb, StringRef &Res) const; + virtual error_code getSymbolAddress(DataRefImpl Symb, uint64_t &Res) const; + virtual error_code getSymbolFileOffset(DataRefImpl Symb, uint64_t &Res) const; + virtual error_code getSymbolSize(DataRefImpl Symb, uint64_t &Res) const; virtual error_code getSymbolType(DataRefImpl Symb, SymbolRef::Type &Res) const; - virtual error_code getSymbolName(DataRefImpl Symb, StringRef &Res) const; + virtual error_code getSymbolNMTypeChar(DataRefImpl Symb, char &Res) const; + virtual error_code getSymbolFlags(DataRefImpl Symb, uint32_t &Res) const; virtual error_code getSymbolSection(DataRefImpl Symb, section_iterator &Res) const; - virtual error_code getSectionName(DataRefImpl Sec, StringRef &Res) const; - virtual error_code getSymbolNext(DataRefImpl Symb, SymbolRef &Res) const; - virtual symbol_iterator begin_symbols() const; - virtual unsigned getArch() const; - virtual StringRef getFileFormatName() const; - virtual symbol_iterator end_symbols() const; - virtual section_iterator end_sections() const; - - static bool classof(const Binary *v); - -private: - // Helper to advance a section or symbol iterator multiple increments at a - // time. - template<class T> - static error_code advance(T &it, size_t Val); - - template<class T> - static void advanceTo(T &it, size_t Val); -}; - -template<class MachOT> -struct MachOObjectFileHelperCommon; - -template<endianness TargetEndianness, bool Is64Bits> -struct MachOObjectFileHelperCommon<MachOType<TargetEndianness, Is64Bits> > { - typedef - MachOFormat::SegmentLoadCommand<MachOType<TargetEndianness, Is64Bits> > - SegmentLoadCommand; - typedef MachOFormat::SymbolTableEntry<MachOType<TargetEndianness, Is64Bits> > - SymbolTableEntry; - typedef MachOFormat::Section<MachOType<TargetEndianness, Is64Bits> > Section; -}; - -template<class MachOT> -struct MachOObjectFileHelper; - -template<endianness TargetEndianness> -struct MachOObjectFileHelper<MachOType<TargetEndianness, false> > : - public MachOObjectFileHelperCommon<MachOType<TargetEndianness, false> > { - static const macho::LoadCommandType SegmentLoadType = macho::LCT_Segment; -}; - -template<endianness TargetEndianness> -struct MachOObjectFileHelper<MachOType<TargetEndianness, true> > : - public MachOObjectFileHelperCommon<MachOType<TargetEndianness, true> > { - static const macho::LoadCommandType SegmentLoadType = macho::LCT_Segment64; -}; - -template<class MachOT> -class MachOObjectFile : public MachOObjectFileMiddle<MachOT::TargetEndianness> { -public: - static const endianness TargetEndianness = MachOT::TargetEndianness; - static const bool Is64Bits = MachOT::Is64Bits; - - typedef MachOObjectFileMiddle<MachOT::TargetEndianness> Base; - typedef typename Base::RelocationEntry RelocationEntry; - typedef typename Base::SectionBase SectionBase; - typedef typename Base::SymbolTableEntryBase SymbolTableEntryBase; - typedef typename Base::LoadCommand LoadCommand; - - typedef MachOObjectFileHelper<MachOT> Helper; - static const macho::LoadCommandType SegmentLoadType = Helper::SegmentLoadType; - typedef typename Helper::SegmentLoadCommand SegmentLoadCommand; - typedef typename Helper::SymbolTableEntry SymbolTableEntry; - typedef typename Helper::Section Section; - - MachOObjectFile(MemoryBuffer *Object, error_code &ec); - static bool classof(const Binary *v); - - const Section *getSection(DataRefImpl DRI) const; - const SymbolTableEntry *getSymbolTableEntry(DataRefImpl DRI) const; - const RelocationEntry *getRelocation(DataRefImpl Rel) const; + virtual error_code getSymbolValue(DataRefImpl Symb, uint64_t &Val) const; + virtual error_code getSectionNext(DataRefImpl Sec, SectionRef &Res) const; + virtual error_code getSectionName(DataRefImpl Sec, StringRef &Res) const; virtual error_code getSectionAddress(DataRefImpl Sec, uint64_t &Res) const; virtual error_code getSectionSize(DataRefImpl Sec, uint64_t &Res) const; virtual error_code getSectionContents(DataRefImpl Sec, StringRef &Res) const; virtual error_code getSectionAlignment(DataRefImpl Sec, uint64_t &Res) const; virtual error_code isSectionText(DataRefImpl Sec, bool &Res) const; + virtual error_code isSectionData(DataRefImpl Sec, bool &Res) const; + virtual error_code isSectionBSS(DataRefImpl Sec, bool &Res) const; + virtual error_code isSectionRequiredForExecution(DataRefImpl Sec, + bool &Res) const; + virtual error_code isSectionVirtual(DataRefImpl Sec, bool &Res) const; virtual error_code isSectionZeroInit(DataRefImpl Sec, bool &Res) const; + virtual error_code isSectionReadOnlyData(DataRefImpl Sec, bool &Res) const; + virtual error_code sectionContainsSymbol(DataRefImpl Sec, DataRefImpl Symb, + bool &Result) const; + virtual relocation_iterator getSectionRelBegin(DataRefImpl Sec) const; virtual relocation_iterator getSectionRelEnd(DataRefImpl Sec) const; + + virtual error_code getRelocationNext(DataRefImpl Rel, + RelocationRef &Res) const; virtual error_code getRelocationAddress(DataRefImpl Rel, uint64_t &Res) const; virtual error_code getRelocationOffset(DataRefImpl Rel, uint64_t &Res) const; virtual error_code getRelocationSymbol(DataRefImpl Rel, SymbolRef &Res) const; virtual error_code getRelocationType(DataRefImpl Rel, uint64_t &Res) const; virtual error_code getRelocationTypeName(DataRefImpl Rel, SmallVectorImpl<char> &Result) const; + virtual error_code getRelocationAdditionalInfo(DataRefImpl Rel, + int64_t &Res) const; virtual error_code getRelocationValueString(DataRefImpl Rel, SmallVectorImpl<char> &Result) const; virtual error_code getRelocationHidden(DataRefImpl Rel, bool &Result) const; - virtual error_code getSymbolFileOffset(DataRefImpl Symb, uint64_t &Res) const; - virtual error_code sectionContainsSymbol(DataRefImpl Sec, DataRefImpl Symb, - bool &Result) const; - virtual error_code getSymbolAddress(DataRefImpl Symb, uint64_t &Res) const; - virtual error_code getSymbolSize(DataRefImpl Symb, uint64_t &Res) const; - virtual error_code getSectionNext(DataRefImpl Sec, SectionRef &Res) const; - virtual section_iterator begin_sections() const; - void moveToNextSection(DataRefImpl &DRI) const; -}; - -typedef MachOObjectFileMiddle<support::little> MachOObjectFileLE; -typedef MachOObjectFileMiddle<support::big> MachOObjectFileBE; - -typedef MachOObjectFile<MachOType<support::little, false> > - MachOObjectFileLE32; -typedef MachOObjectFile<MachOType<support::big, false> > - MachOObjectFileBE32; -typedef MachOObjectFile<MachOType<support::little, true> > - MachOObjectFileLE64; -typedef MachOObjectFile<MachOType<support::big, true> > - MachOObjectFileBE64; - -template<endianness TargetEndianness> -MachOObjectFileMiddle<TargetEndianness>::MachOObjectFileMiddle(MemoryBuffer *O, - bool Is64Bits, - error_code &ec) : - MachOObjectFileBase(O, TargetEndianness == support::little, Is64Bits, ec) { -} - -template<endianness E> -const typename MachOObjectFileMiddle<E>::SymbolTableEntryBase * -MachOObjectFileMiddle<E>::getSymbolTableEntryBase(DataRefImpl DRI) const { - const LoadCommand *L = getLoadCommandInfo(DRI.d.a); - const SymtabLoadCommand *S = reinterpret_cast<const SymtabLoadCommand *>(L); - - unsigned Index = DRI.d.b; - - unsigned SymbolTableEntrySize = is64Bit() ? - sizeof(MachOObjectFileLE64::SymbolTableEntry) : - sizeof(MachOObjectFileLE32::SymbolTableEntry); - - uint64_t Offset = S->SymbolTableOffset + Index * SymbolTableEntrySize; - StringRef Data = getData(Offset, SymbolTableEntrySize); - return reinterpret_cast<const SymbolTableEntryBase*>(Data.data()); -} - -template<endianness E> -const typename MachOObjectFileMiddle<E>::Header * -MachOObjectFileMiddle<E>::getHeader() const { - StringRef Data = getData(0, sizeof(Header)); - return reinterpret_cast<const Header*>(Data.data()); -} - -template<endianness E> -const typename MachOObjectFileMiddle<E>::LoadCommand * -MachOObjectFileMiddle<E>::getLoadCommandInfo(unsigned Index) const { - assert(Index < getHeader()->NumLoadCommands); - uint64_t Offset; - uint64_t NewOffset = getHeaderSize(); - const LoadCommand *Load; - unsigned I = 0; - do { - Offset = NewOffset; - StringRef Data = getData(Offset, sizeof(MachOObjectFileLE::LoadCommand)); - Load = reinterpret_cast<const LoadCommand*>(Data.data()); - NewOffset = Offset + Load->Size; - ++I; - } while (I != Index + 1); - - return reinterpret_cast<const LoadCommand*>(Load); -} - -template<endianness E> -const typename MachOObjectFileMiddle<E>::RelocationEntry * -MachOObjectFileMiddle<E>::getRelocation(DataRefImpl Rel) const { - if (const MachOObjectFile<MachOType<E, true> > *O = - dyn_cast<MachOObjectFile<MachOType<E, true> > >(this)) - return O->getRelocation(Rel); - - const MachOObjectFile<MachOType<E, false> > *O = - cast<MachOObjectFile<MachOType<E, false> > >(this); - return O->getRelocation(Rel); -} - -template<endianness E> -bool -MachOObjectFileMiddle<E>::isRelocationScattered(const RelocationEntry *RE) - const { - if (this->getCPUType() == llvm::MachO::CPUTypeX86_64) - return false; - return RE->Address & macho::RF_Scattered; -} - -template<endianness E> -bool -MachOObjectFileMiddle<E>::isRelocationPCRel(const RelocationEntry *RE) const { - typedef MachOObjectFileMiddle<E> ObjType; - if (isRelocationScattered(RE)) { - const typename MachOObjectFileMiddle<E>::ScatteredRelocationEntry *SRE = - reinterpret_cast<const typename ObjType::ScatteredRelocationEntry *>(RE); - return SRE->PCRel; - } - return RE->PCRel; -} - -template<endianness E> -unsigned -MachOObjectFileMiddle<E>::getRelocationLength(const RelocationEntry *RE) const { - typedef MachOObjectFileMiddle<E> ObjType; - if (isRelocationScattered(RE)) { - const typename ObjType::ScatteredRelocationEntry *SRE = - reinterpret_cast<const typename ObjType::ScatteredRelocationEntry *>(RE); - return SRE->Length; - } - return RE->Length; -} - -template<endianness E> -unsigned -MachOObjectFileMiddle<E>::getRelocationTypeImpl(const RelocationEntry *RE) - const { - typedef MachOObjectFileMiddle<E> ObjType; - if (isRelocationScattered(RE)) { - const typename ObjType::ScatteredRelocationEntry *SRE = - reinterpret_cast<const typename ObjType::ScatteredRelocationEntry *>(RE); - return SRE->Type; - } - return RE->Type; -} - -// Helper to advance a section or symbol iterator multiple increments at a time. -template<endianness E> -template<class T> -error_code MachOObjectFileMiddle<E>::advance(T &it, size_t Val) { - error_code ec; - while (Val--) { - it.increment(ec); - } - return ec; -} - -template<endianness E> -template<class T> -void MachOObjectFileMiddle<E>::advanceTo(T &it, size_t Val) { - if (error_code ec = advance(it, Val)) - report_fatal_error(ec.message()); -} - -template<endianness E> -void -MachOObjectFileMiddle<E>::printRelocationTargetName(const RelocationEntry *RE, - raw_string_ostream &fmt) const { - bool IsScattered = 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 = RE->SymbolNum; - - 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->External; - uint64_t Val = RE->Address; - - 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; -} - -template<endianness E> -const typename MachOObjectFileMiddle<E>::SectionBase * -MachOObjectFileMiddle<E>::getSectionBase(DataRefImpl DRI) const { - uintptr_t CommandAddr = - reinterpret_cast<uintptr_t>(getLoadCommandInfo(DRI.d.a)); - - bool Is64 = is64Bit(); - unsigned SegmentLoadSize = - Is64 ? sizeof(MachOObjectFileLE64::SegmentLoadCommand) : - sizeof(MachOObjectFileLE32::SegmentLoadCommand); - unsigned SectionSize = Is64 ? sizeof(MachOObjectFileLE64::Section) : - sizeof(MachOObjectFileLE32::Section); - - uintptr_t SectionAddr = CommandAddr + SegmentLoadSize + DRI.d.b * SectionSize; - return reinterpret_cast<const SectionBase*>(SectionAddr); -} - -template<endianness E> -unsigned MachOObjectFileMiddle<E>::getCPUType() const { - return getHeader()->CPUType; -} - -template<endianness E> -void MachOObjectFileMiddle<E>::moveToNextSymbol(DataRefImpl &DRI) const { - uint32_t LoadCommandCount = getHeader()->NumLoadCommands; - while (DRI.d.a < LoadCommandCount) { - const LoadCommand *L = getLoadCommandInfo(DRI.d.a); - if (L->Type == macho::LCT_Symtab) { - const SymtabLoadCommand *S = - reinterpret_cast<const SymtabLoadCommand *>(L); - if (DRI.d.b < S->NumSymbolTableEntries) - return; - } - - DRI.d.a++; - DRI.d.b = 0; - } -} - -template<endianness E> -StringRef -MachOObjectFileMiddle<E>::getSectionFinalSegmentName(DataRefImpl Sec) const { - ArrayRef<char> Raw = getSectionRawFinalSegmentName(Sec); - return parseSegmentOrSectionName(Raw.data()); -} - -template<endianness E> -ArrayRef<char> -MachOObjectFileMiddle<E>::getSectionRawName(DataRefImpl Sec) const { - const SectionBase *Base = getSectionBase(Sec); - return ArrayRef<char>(Base->Name); -} - -template<endianness E> -ArrayRef<char> -MachOObjectFileMiddle<E>::getSectionRawFinalSegmentName(DataRefImpl Sec) const { - const SectionBase *Base = getSectionBase(Sec); - return ArrayRef<char>(Base->SegmentName); -} - -template<endianness E> -error_code MachOObjectFileMiddle<E>::getSymbolFlags(DataRefImpl DRI, - uint32_t &Result) const { - const SymbolTableEntryBase *Entry = getSymbolTableEntryBase(DRI); - - uint8_t MachOType = Entry->Type; - uint16_t MachOFlags = Entry->Flags; - - // 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; - - if (MachOType & MachO::NlistMaskExternal) { - Result |= SymbolRef::SF_Global; - if ((MachOType & MachO::NlistMaskType) == MachO::NListTypeUndefined) - Result |= SymbolRef::SF_Common; - } - - if (MachOFlags & (MachO::NListDescWeakRef | MachO::NListDescWeakDef)) - Result |= SymbolRef::SF_Weak; - - if ((MachOType & MachO::NlistMaskType) == MachO::NListTypeAbsolute) - Result |= SymbolRef::SF_Absolute; - - return object_error::success; -} - -template<endianness E> -error_code MachOObjectFileMiddle<E>::getSymbolType(DataRefImpl Symb, - SymbolRef::Type &Res) const { - const SymbolTableEntryBase *Entry = getSymbolTableEntryBase(Symb); - uint8_t n_type = Entry->Type; - - Res = SymbolRef::ST_Other; - - // If this is a STAB debugging symbol, we can do nothing more. - if (n_type & MachO::NlistMaskStab) { - Res = SymbolRef::ST_Debug; - return object_error::success; - } - - switch (n_type & MachO::NlistMaskType) { - case MachO::NListTypeUndefined : - Res = SymbolRef::ST_Unknown; - break; - case MachO::NListTypeSection : - Res = SymbolRef::ST_Function; - break; - } - return object_error::success; -} - -template<endianness E> -error_code MachOObjectFileMiddle<E>::getSymbolName(DataRefImpl Symb, - StringRef &Res) const { - const LoadCommand *L = getLoadCommandInfo(Symb.d.a); - const SymtabLoadCommand *S = reinterpret_cast<const SymtabLoadCommand *>(L); - StringRef StringTable = getData(S->StringTableOffset, S->StringTableSize); - const SymbolTableEntryBase *Entry = getSymbolTableEntryBase(Symb); - const char *Start = &StringTable.data()[Entry->StringIndex]; - Res = StringRef(Start); - return object_error::success; -} - -template<endianness E> -error_code -MachOObjectFileMiddle<E>::getSymbolSection(DataRefImpl Symb, - section_iterator &Res) const { - const SymbolTableEntryBase *Entry = getSymbolTableEntryBase(Symb); - uint8_t index = Entry->SectionIndex; - - if (index == 0) - Res = end_sections(); - else - Res = section_iterator(SectionRef(Sections[index-1], this)); - - return object_error::success; -} - - -template<endianness E> -error_code MachOObjectFileMiddle<E>::getSymbolNMTypeChar(DataRefImpl Symb, - char &Res) const { - const SymbolTableEntryBase *Entry = getSymbolTableEntryBase(Symb); - uint8_t Type = Entry->Type; - uint16_t Flags = Entry->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 = '?'; - break; - } - - if (Flags & (macho::STF_External | macho::STF_PrivateExtern)) - Char = toupper(static_cast<unsigned char>(Char)); - Res = Char; - return object_error::success; -} - -template<endianness E> -error_code -MachOObjectFileMiddle<E>::getSectionName(DataRefImpl Sec, - StringRef &Result) const { - ArrayRef<char> Raw = getSectionRawName(Sec); - Result = parseSegmentOrSectionName(Raw.data()); - return object_error::success; -} - -template<endianness E> -error_code MachOObjectFileMiddle<E>::getSymbolNext(DataRefImpl Symb, - SymbolRef &Res) const { - Symb.d.b++; - moveToNextSymbol(Symb); - Res = SymbolRef(Symb, this); - return object_error::success; -} - -template<endianness E> -symbol_iterator MachOObjectFileMiddle<E>::begin_symbols() const { - // DRI.d.a = segment number; DRI.d.b = symbol index. - DataRefImpl DRI; - moveToNextSymbol(DRI); - return symbol_iterator(SymbolRef(DRI, this)); -} - -template<endianness E> -unsigned MachOObjectFileMiddle<E>::getArch() const { - switch (getCPUType()) { - case llvm::MachO::CPUTypeI386: - return Triple::x86; - case llvm::MachO::CPUTypeX86_64: - return Triple::x86_64; - case llvm::MachO::CPUTypeARM: - return Triple::arm; - case llvm::MachO::CPUTypePowerPC: - return Triple::ppc; - case llvm::MachO::CPUTypePowerPC64: - return Triple::ppc64; - default: - return Triple::UnknownArch; - } -} - -template<endianness E> -StringRef MachOObjectFileMiddle<E>::getFileFormatName() const { - unsigned CPUType = getCPUType(); - if (!is64Bit()) { - switch (CPUType) { - case llvm::MachO::CPUTypeI386: - return "Mach-O 32-bit i386"; - case llvm::MachO::CPUTypeARM: - return "Mach-O arm"; - case llvm::MachO::CPUTypePowerPC: - return "Mach-O 32-bit ppc"; - default: - assert((CPUType & llvm::MachO::CPUArchABI64) == 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::CPUArchABI64) - == llvm::MachO::CPUArchABI64 && - "32-bit object file when we're 64-bit?"); - - switch (CPUType) { - case llvm::MachO::CPUTypeX86_64: - return "Mach-O 64-bit x86-64"; - case llvm::MachO::CPUTypePowerPC64: - return "Mach-O 64-bit ppc64"; - default: - return "Mach-O 64-bit unknown"; - } -} - -template<endianness E> -symbol_iterator MachOObjectFileMiddle<E>::end_symbols() const { - DataRefImpl DRI; - DRI.d.a = getHeader()->NumLoadCommands; - return symbol_iterator(SymbolRef(DRI, this)); -} - -template<endianness E> -section_iterator MachOObjectFileMiddle<E>::end_sections() const { - DataRefImpl DRI; - DRI.d.a = getHeader()->NumLoadCommands; - return section_iterator(SectionRef(DRI, this)); -} - -template<endianness E> -bool MachOObjectFileMiddle<E>::classof(const Binary *v) { - return isa<MachOObjectFile<MachOType<E, false> > >(v) || - isa<MachOObjectFile<MachOType<E, true> > >(v); -} - -template<class MachOT> -MachOObjectFile<MachOT>::MachOObjectFile(MemoryBuffer *Object, - error_code &ec) : - MachOObjectFileMiddle<TargetEndianness>(Object, Is64Bits, ec) { - DataRefImpl DRI; - moveToNextSection(DRI); - uint32_t LoadCommandCount = this->getHeader()->NumLoadCommands; - while (DRI.d.a < LoadCommandCount) { - this->Sections.push_back(DRI); - DRI.d.b++; - moveToNextSection(DRI); - } -} - -template<class MachOT> -bool MachOObjectFile<MachOT>::classof(const Binary *v) { - return v->getType() == - Base::getMachOType(TargetEndianness == support::little, Is64Bits); -} - -template<class MachOT> -const typename MachOObjectFile<MachOT>::Section * -MachOObjectFile<MachOT>::getSection(DataRefImpl DRI) const { - const SectionBase *Addr = this->getSectionBase(DRI); - return reinterpret_cast<const Section*>(Addr); -} - -template<class MachOT> -const typename MachOObjectFile<MachOT>::SymbolTableEntry * -MachOObjectFile<MachOT>::getSymbolTableEntry(DataRefImpl DRI) const { - const SymbolTableEntryBase *Base = this->getSymbolTableEntryBase(DRI); - return reinterpret_cast<const SymbolTableEntry*>(Base); -} - -template<class MachOT> -const typename MachOObjectFile<MachOT>::RelocationEntry * -MachOObjectFile<MachOT>::getRelocation(DataRefImpl Rel) const { - const Section *Sect = getSection(this->Sections[Rel.d.b]); - uint32_t RelOffset = Sect->RelocationTableOffset; - uint64_t Offset = RelOffset + Rel.d.a * sizeof(RelocationEntry); - StringRef Data = this->getData(Offset, sizeof(RelocationEntry)); - return reinterpret_cast<const RelocationEntry*>(Data.data()); -} - -template<class MachOT> -error_code -MachOObjectFile<MachOT>::getSectionAddress(DataRefImpl Sec, - uint64_t &Res) const { - const Section *Sect = getSection(Sec); - Res = Sect->Address; - return object_error::success; -} - -template<class MachOT> -error_code -MachOObjectFile<MachOT>::getSectionSize(DataRefImpl Sec, - uint64_t &Res) const { - const Section *Sect = getSection(Sec); - Res = Sect->Size; - return object_error::success; -} -template<class MachOT> -error_code -MachOObjectFile<MachOT>::getSectionContents(DataRefImpl Sec, - StringRef &Res) const { - const Section *Sect = getSection(Sec); - Res = this->getData(Sect->Offset, Sect->Size); - return object_error::success; -} - -template<class MachOT> -error_code -MachOObjectFile<MachOT>::getSectionAlignment(DataRefImpl Sec, - uint64_t &Res) const { - const Section *Sect = getSection(Sec); - Res = uint64_t(1) << Sect->Align; - return object_error::success; -} - -template<class MachOT> -error_code -MachOObjectFile<MachOT>::isSectionText(DataRefImpl Sec, bool &Res) const { - const Section *Sect = getSection(Sec); - Res = Sect->Flags & macho::SF_PureInstructions; - return object_error::success; -} - -template<class MachOT> -error_code -MachOObjectFile<MachOT>::isSectionZeroInit(DataRefImpl Sec, bool &Res) const { - const Section *Sect = getSection(Sec); - unsigned SectionType = Sect->Flags & MachO::SectionFlagMaskSectionType; - Res = SectionType == MachO::SectionTypeZeroFill || - SectionType == MachO::SectionTypeZeroFillLarge; - return object_error::success; -} - -template<class MachOT> -relocation_iterator -MachOObjectFile<MachOT>::getSectionRelEnd(DataRefImpl Sec) const { - const Section *Sect = getSection(Sec); - uint32_t LastReloc = Sect->NumRelocationTableEntries; - DataRefImpl Ret; - Ret.d.a = LastReloc; - Ret.d.b = this->getSectionIndex(Sec); - return relocation_iterator(RelocationRef(Ret, this)); -} - -template<class MachOT> -error_code -MachOObjectFile<MachOT>::getRelocationAddress(DataRefImpl Rel, - uint64_t &Res) const { - const Section *Sect = getSection(this->Sections[Rel.d.b]); - uint64_t SectAddress = Sect->Address; - const RelocationEntry *RE = getRelocation(Rel); - - uint64_t RelAddr; - if (this->isRelocationScattered(RE)) - RelAddr = RE->Address & 0xFFFFFF; - else - RelAddr = RE->Address; - - Res = SectAddress + RelAddr; - return object_error::success; -} - -template<class MachOT> -error_code -MachOObjectFile<MachOT>::getRelocationOffset(DataRefImpl Rel, - uint64_t &Res) const { - const RelocationEntry *RE = getRelocation(Rel); - if (this->isRelocationScattered(RE)) - Res = RE->Address & 0xFFFFFF; - else - Res = RE->Address; - return object_error::success; -} - -template<class MachOT> -error_code -MachOObjectFile<MachOT>::getRelocationSymbol(DataRefImpl Rel, - SymbolRef &Res) const { - const RelocationEntry *RE = getRelocation(Rel); - uint32_t SymbolIdx = RE->SymbolNum; - bool isExtern = RE->External; - - DataRefImpl Sym; - this->moveToNextSymbol(Sym); - if (isExtern) { - for (unsigned i = 0; i < SymbolIdx; i++) { - Sym.d.b++; - this->moveToNextSymbol(Sym); - assert(Sym.d.a < this->getHeader()->NumLoadCommands && - "Relocation symbol index out of range!"); - } - } - Res = SymbolRef(Sym, this); - return object_error::success; -} - -template<class MachOT> -error_code MachOObjectFile<MachOT>::getRelocationType(DataRefImpl Rel, - uint64_t &Res) const { - const RelocationEntry *RE = getRelocation(Rel); - Res = this->getRelocationTypeImpl(RE); - return object_error::success; -} - -template<class MachOT> -error_code -MachOObjectFile<MachOT>::getRelocationTypeName(DataRefImpl Rel, - SmallVectorImpl<char> &Result) const { - // TODO: Support scattered relocations. - StringRef res; - const RelocationEntry *RE = getRelocation(Rel); - - unsigned Arch = this->getArch(); - - unsigned r_type = this->getRelocationTypeImpl(RE); - - switch (Arch) { - case Triple::x86: { - static const char *const Table[] = { - "GENERIC_RELOC_VANILLA", - "GENERIC_RELOC_PAIR", - "GENERIC_RELOC_SECTDIFF", - "GENERIC_RELOC_PB_LA_PTR", - "GENERIC_RELOC_LOCAL_SECTDIFF", - "GENERIC_RELOC_TLV" }; - - if (r_type > 6) - res = "Unknown"; - else - res = Table[r_type]; - break; - } - case Triple::x86_64: { - static const char *const Table[] = { - "X86_64_RELOC_UNSIGNED", - "X86_64_RELOC_SIGNED", - "X86_64_RELOC_BRANCH", - "X86_64_RELOC_GOT_LOAD", - "X86_64_RELOC_GOT", - "X86_64_RELOC_SUBTRACTOR", - "X86_64_RELOC_SIGNED_1", - "X86_64_RELOC_SIGNED_2", - "X86_64_RELOC_SIGNED_4", - "X86_64_RELOC_TLV" }; - - if (r_type > 9) - res = "Unknown"; - else - res = Table[r_type]; - break; - } - case Triple::arm: { - static const char *const Table[] = { - "ARM_RELOC_VANILLA", - "ARM_RELOC_PAIR", - "ARM_RELOC_SECTDIFF", - "ARM_RELOC_LOCAL_SECTDIFF", - "ARM_RELOC_PB_LA_PTR", - "ARM_RELOC_BR24", - "ARM_THUMB_RELOC_BR22", - "ARM_THUMB_32BIT_BRANCH", - "ARM_RELOC_HALF", - "ARM_RELOC_HALF_SECTDIFF" }; - - if (r_type > 9) - res = "Unknown"; - else - res = Table[r_type]; - break; - } - case Triple::ppc: { - static const char *const Table[] = { - "PPC_RELOC_VANILLA", - "PPC_RELOC_PAIR", - "PPC_RELOC_BR14", - "PPC_RELOC_BR24", - "PPC_RELOC_HI16", - "PPC_RELOC_LO16", - "PPC_RELOC_HA16", - "PPC_RELOC_LO14", - "PPC_RELOC_SECTDIFF", - "PPC_RELOC_PB_LA_PTR", - "PPC_RELOC_HI16_SECTDIFF", - "PPC_RELOC_LO16_SECTDIFF", - "PPC_RELOC_HA16_SECTDIFF", - "PPC_RELOC_JBSR", - "PPC_RELOC_LO14_SECTDIFF", - "PPC_RELOC_LOCAL_SECTDIFF" }; - - res = Table[r_type]; - break; - } - case Triple::UnknownArch: - res = "Unknown"; - break; - } - Result.append(res.begin(), res.end()); - return object_error::success; -} - -template<class MachOT> -error_code -MachOObjectFile<MachOT>::getRelocationValueString(DataRefImpl Rel, - SmallVectorImpl<char> &Result) const { - const RelocationEntry *RE = getRelocation(Rel); - - unsigned Arch = this->getArch(); - bool IsScattered = this->isRelocationScattered(RE); - - std::string fmtbuf; - raw_string_ostream fmt(fmtbuf); - - unsigned Type = this->getRelocationTypeImpl(RE); - bool IsPCRel = this->isRelocationPCRel(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->PCRel; - - switch (Type) { - case macho::RIT_X86_64_GOTLoad: // X86_64_RELOC_GOT_LOAD - case macho::RIT_X86_64_GOT: { // X86_64_RELOC_GOT - this->printRelocationTargetName(RE, fmt); - fmt << "@GOT"; - if (isPCRel) fmt << "PCREL"; - break; - } - case macho::RIT_X86_64_Subtractor: { // X86_64_RELOC_SUBTRACTOR - DataRefImpl RelNext = Rel; - RelNext.d.a++; - const RelocationEntry *RENext = getRelocation(RelNext); - - // X86_64_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->Type; - if (RType != 0) - 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. - this->printRelocationTargetName(RENext, fmt); - fmt << "-"; - this->printRelocationTargetName(RE, fmt); - break; - } - case macho::RIT_X86_64_TLV: - this->printRelocationTargetName(RE, fmt); - fmt << "@TLV"; - if (isPCRel) fmt << "P"; - break; - case macho::RIT_X86_64_Signed1: // X86_64_RELOC_SIGNED1 - this->printRelocationTargetName(RE, fmt); - fmt << "-1"; - break; - case macho::RIT_X86_64_Signed2: // X86_64_RELOC_SIGNED2 - this->printRelocationTargetName(RE, fmt); - fmt << "-2"; - break; - case macho::RIT_X86_64_Signed4: // X86_64_RELOC_SIGNED4 - this->printRelocationTargetName(RE, fmt); - fmt << "-4"; - break; - default: - this->printRelocationTargetName(RE, fmt); - break; - } - // X86 and ARM share some relocation types in common. - } else if (Arch == Triple::x86 || Arch == Triple::arm) { - // Generic relocation types... - switch (Type) { - case macho::RIT_Pair: // GENERIC_RELOC_PAIR - prints no info - return object_error::success; - case macho::RIT_Difference: { // GENERIC_RELOC_SECTDIFF - DataRefImpl RelNext = Rel; - RelNext.d.a++; - const RelocationEntry *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->Address & macho::RF_Scattered); - unsigned RType; - if (isNextScattered) - RType = (RENext->Address >> 24) & 0xF; - else - RType = RENext->Type; - if (RType != 1) - report_fatal_error("Expected GENERIC_RELOC_PAIR after " - "GENERIC_RELOC_SECTDIFF."); - - this->printRelocationTargetName(RE, fmt); - fmt << "-"; - this->printRelocationTargetName(RENext, fmt); - break; - } - } - - if (Arch == Triple::x86) { - // All X86 relocations that need special printing were already - // handled in the generic code. - switch (Type) { - case macho::RIT_Generic_LocalDifference:{// GENERIC_RELOC_LOCAL_SECTDIFF - DataRefImpl RelNext = Rel; - RelNext.d.a++; - const RelocationEntry *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->Address & macho::RF_Scattered); - unsigned RType; - if (isNextScattered) - RType = (RENext->Address >> 24) & 0xF; - else - RType = RENext->Type; - if (RType != 1) - report_fatal_error("Expected GENERIC_RELOC_PAIR after " - "GENERIC_RELOC_LOCAL_SECTDIFF."); - - this->printRelocationTargetName(RE, fmt); - fmt << "-"; - this->printRelocationTargetName(RENext, fmt); - break; - } - case macho::RIT_Generic_TLV: { - this->printRelocationTargetName(RE, fmt); - fmt << "@TLV"; - if (IsPCRel) fmt << "P"; - break; - } - default: - this->printRelocationTargetName(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 - // 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->Address >> 28) & 1; - else - isUpper = (RE->Length >> 1) & 1; - - if (isUpper) - fmt << ":upper16:("; - else - fmt << ":lower16:("; - this->printRelocationTargetName(RE, fmt); - - DataRefImpl RelNext = Rel; - RelNext.d.a++; - const RelocationEntry *RENext = getRelocation(RelNext); - - // ARM half relocs must be followed by a relocation of type - // ARM_RELOC_PAIR. - bool isNextScattered = (Arch != Triple::x86_64) && - (RENext->Address & macho::RF_Scattered); - unsigned RType; - if (isNextScattered) - RType = (RENext->Address >> 24) & 0xF; - else - RType = RENext->Type; - - if (RType != 1) - report_fatal_error("Expected ARM_RELOC_PAIR after " - "GENERIC_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::RIT_ARM_HalfDifference) { - fmt << "-"; - this->printRelocationTargetName(RENext, fmt); - } - - fmt << ")"; - break; - } - default: { - this->printRelocationTargetName(RE, fmt); - } - } - } - } else - this->printRelocationTargetName(RE, fmt); - - fmt.flush(); - Result.append(fmtbuf.begin(), fmtbuf.end()); - return object_error::success; -} - -template<class MachOT> -error_code -MachOObjectFile<MachOT>::getRelocationHidden(DataRefImpl Rel, - bool &Result) const { - const RelocationEntry *RE = getRelocation(Rel); - unsigned Arch = this->getArch(); - unsigned Type = this->getRelocationTypeImpl(RE); - - 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; - } 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) { - DataRefImpl RelPrev = Rel; - RelPrev.d.a--; - const RelocationEntry *REPrev = this->getRelocation(RelPrev); + virtual error_code getLibraryNext(DataRefImpl LibData, LibraryRef &Res) const; + virtual error_code getLibraryPath(DataRefImpl LibData, StringRef &Res) const; - unsigned PrevType = REPrev->Type; + virtual symbol_iterator begin_symbols() const; + virtual symbol_iterator end_symbols() const; - if (PrevType == macho::RIT_X86_64_Subtractor) Result = true; - } - } + virtual symbol_iterator begin_dynamic_symbols() const; + virtual symbol_iterator end_dynamic_symbols() const; - return object_error::success; -} + virtual section_iterator begin_sections() const; + virtual section_iterator end_sections() const; -template<class MachOT> -error_code -MachOObjectFile<MachOT>::getSymbolFileOffset(DataRefImpl Symb, - uint64_t &Res) const { - const SymbolTableEntry *Entry = getSymbolTableEntry(Symb); - Res = Entry->Value; - if (Entry->SectionIndex) { - const Section *Sec = - this->getSection(this->Sections[Entry->SectionIndex-1]); - Res += Sec->Offset - Sec->Address; - } + virtual library_iterator begin_libraries_needed() const; + virtual library_iterator end_libraries_needed() const; - return object_error::success; -} + virtual uint8_t getBytesInAddress() const; -template<class MachOT> -error_code -MachOObjectFile<MachOT>::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; - } + virtual StringRef getFileFormatName() const; + virtual unsigned getArch() const; - uint64_t SectBegin, SectEnd; - getSectionAddress(Sec, SectBegin); - getSectionSize(Sec, SectEnd); - SectEnd += SectBegin; + virtual StringRef getLoadName() const; - const SymbolTableEntry *Entry = getSymbolTableEntry(Symb); - uint64_t SymAddr= Entry->Value; - Result = (SymAddr >= SectBegin) && (SymAddr < SectEnd); + // In a MachO file, sections have a segment name. This is used in the .o + // files. They have a single segment, but this field specifies which segment + // a section should be put in in the final object. + StringRef getSectionFinalSegmentName(DataRefImpl Sec) const; - return object_error::success; -} + // Names are stored as 16 bytes. These returns the raw 16 bytes without + // interpreting them as a C string. + ArrayRef<char> getSectionRawName(DataRefImpl Sec) const; + ArrayRef<char> getSectionRawFinalSegmentName(DataRefImpl Sec) const; -template<class MachOT> -error_code MachOObjectFile<MachOT>::getSymbolAddress(DataRefImpl Symb, - uint64_t &Res) const { - const SymbolTableEntry *Entry = getSymbolTableEntry(Symb); - Res = Entry->Value; - return object_error::success; -} + // MachO specific Info about relocations. + bool isRelocationScattered(const macho::RelocationEntry &RE) const; + unsigned getPlainRelocationSymbolNum(const macho::RelocationEntry &RE) const; + bool getPlainRelocationExternal(const macho::RelocationEntry &RE) const; + bool getScatteredRelocationScattered(const macho::RelocationEntry &RE) const; + uint32_t getScatteredRelocationValue(const macho::RelocationEntry &RE) const; + unsigned getAnyRelocationAddress(const macho::RelocationEntry &RE) const; + unsigned getAnyRelocationPCRel(const macho::RelocationEntry &RE) const; + unsigned getAnyRelocationLength(const macho::RelocationEntry &RE) const; + unsigned getAnyRelocationType(const macho::RelocationEntry &RE) const; + + // Walk load commands. + LoadCommandInfo getFirstLoadCommandInfo() const; + LoadCommandInfo getNextLoadCommandInfo(const LoadCommandInfo &L) const; + + // MachO specific structures. + macho::Section getSection(DataRefImpl DRI) const; + macho::Section64 getSection64(DataRefImpl DRI) const; + macho::SymbolTableEntry getSymbolTableEntry(DataRefImpl DRI) const; + macho::Symbol64TableEntry getSymbol64TableEntry(DataRefImpl DRI) const; + macho::LinkeditDataLoadCommand + getLinkeditDataLoadCommand(const LoadCommandInfo &L) const; + macho::RelocationEntry getRelocation(DataRefImpl Rel) const; + macho::Header getHeader() const; + macho::SymtabLoadCommand getSymtabLoadCommand() const; -template<class MachOT> -error_code MachOObjectFile<MachOT>::getSymbolSize(DataRefImpl DRI, - uint64_t &Result) const { - uint32_t LoadCommandCount = this->getHeader()->NumLoadCommands; - uint64_t BeginOffset; - uint64_t EndOffset = 0; - uint8_t SectionIndex; + bool is64Bit() const; + void ReadULEB128s(uint64_t Index, SmallVectorImpl<uint64_t> &Out) const; - const SymbolTableEntry *Entry = getSymbolTableEntry(DRI); - BeginOffset = Entry->Value; - SectionIndex = Entry->SectionIndex; - if (!SectionIndex) { - uint32_t flags = SymbolRef::SF_None; - this->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) { - this->moveToNextSymbol(DRI); - if (DRI.d.a < LoadCommandCount) { - Entry = getSymbolTableEntry(DRI); - if (Entry->SectionIndex == SectionIndex && Entry->Value > BeginOffset) - if (!EndOffset || Entry->Value < EndOffset) - EndOffset = Entry->Value; - } - DRI.d.b++; - } - if (!EndOffset) { - uint64_t Size; - this->getSectionSize(this->Sections[SectionIndex-1], Size); - this->getSectionAddress(this->Sections[SectionIndex-1], EndOffset); - EndOffset += Size; + static bool classof(const Binary *v) { + return v->isMachO(); } - Result = EndOffset - BeginOffset; - return object_error::success; -} - -template<class MachOT> -error_code MachOObjectFile<MachOT>::getSectionNext(DataRefImpl Sec, - SectionRef &Res) const { - Sec.d.b++; - moveToNextSection(Sec); - Res = SectionRef(Sec, this); - return object_error::success; -} - -template<class MachOT> -section_iterator MachOObjectFile<MachOT>::begin_sections() const { - DataRefImpl DRI; - moveToNextSection(DRI); - return section_iterator(SectionRef(DRI, this)); -} -template<class MachOT> -void MachOObjectFile<MachOT>::moveToNextSection(DataRefImpl &DRI) const { - uint32_t LoadCommandCount = this->getHeader()->NumLoadCommands; - while (DRI.d.a < LoadCommandCount) { - const LoadCommand *Command = this->getLoadCommandInfo(DRI.d.a); - if (Command->Type == SegmentLoadType) { - const SegmentLoadCommand *SegmentLoadCmd = - reinterpret_cast<const SegmentLoadCommand*>(Command); - if (DRI.d.b < SegmentLoadCmd->NumSections) - return; - } - - DRI.d.a++; - DRI.d.b = 0; - } -} +private: + typedef SmallVector<const char*, 1> SectionList; + SectionList Sections; + const char *SymtabLoadCmd; +}; } } diff --git a/lib/Object/MachOObjectFile.cpp b/lib/Object/MachOObjectFile.cpp index 192e755..f5910dd 100644 --- a/lib/Object/MachOObjectFile.cpp +++ b/lib/Object/MachOObjectFile.cpp @@ -15,9 +15,9 @@ #include "llvm/Object/MachO.h" #include "llvm/ADT/Triple.h" #include "llvm/Object/MachOFormat.h" -#include "llvm/Support/Casting.h" #include "llvm/Support/DataExtractor.h" #include "llvm/Support/Format.h" +#include "llvm/Support/Host.h" #include "llvm/Support/MemoryBuffer.h" #include <cctype> #include <cstring> @@ -29,98 +29,222 @@ using namespace object; namespace llvm { namespace object { -MachOObjectFileBase::MachOObjectFileBase(MemoryBuffer *Object, - bool IsLittleEndian, bool Is64bits, - error_code &ec) - : ObjectFile(getMachOType(IsLittleEndian, Is64bits), Object) { +struct SymbolTableEntryBase { + uint32_t StringIndex; + uint8_t Type; + uint8_t SectionIndex; + uint16_t Flags; +}; + +struct SectionBase { + char Name[16]; + char SegmentName[16]; +}; + +template<typename T> +static void SwapValue(T &Value) { + Value = sys::SwapByteOrder(Value); } -bool MachOObjectFileBase::is64Bit() const { - return isa<MachOObjectFileLE64>(this) || isa<MachOObjectFileBE64>(this); +template<typename T> +static void SwapStruct(T &Value); + +template<> +void SwapStruct(macho::RelocationEntry &H) { + SwapValue(H.Word0); + SwapValue(H.Word1); } -void MachOObjectFileBase::ReadULEB128s(uint64_t Index, - SmallVectorImpl<uint64_t> &Out) const { - DataExtractor extractor(ObjectFile::getData(), true, 0); +template<> +void SwapStruct(macho::LoadCommand &L) { + SwapValue(L.Type); + SwapValue(L.Size); +} - uint32_t offset = Index; - uint64_t data = 0; - while (uint64_t delta = extractor.getULEB128(&offset)) { - data += delta; - Out.push_back(data); - } +template<> +void SwapStruct(SymbolTableEntryBase &S) { + SwapValue(S.StringIndex); + SwapValue(S.Flags); } -unsigned MachOObjectFileBase::getHeaderSize() const { - return is64Bit() ? macho::Header64Size : macho::Header32Size; +template<> +void SwapStruct(macho::Section &S) { + SwapValue(S.Address); + SwapValue(S.Size); + SwapValue(S.Offset); + SwapValue(S.Align); + SwapValue(S.RelocationTableOffset); + SwapValue(S.NumRelocationTableEntries); + SwapValue(S.Flags); + SwapValue(S.Reserved1); + SwapValue(S.Reserved2); } -StringRef MachOObjectFileBase::getData(size_t Offset, size_t Size) const { - return ObjectFile::getData().substr(Offset, Size); +template<> +void SwapStruct(macho::Section64 &S) { + SwapValue(S.Address); + SwapValue(S.Size); + SwapValue(S.Offset); + SwapValue(S.Align); + SwapValue(S.RelocationTableOffset); + SwapValue(S.NumRelocationTableEntries); + SwapValue(S.Flags); + SwapValue(S.Reserved1); + SwapValue(S.Reserved2); + SwapValue(S.Reserved3); } -ObjectFile *ObjectFile::createMachOObjectFile(MemoryBuffer *Buffer) { - StringRef Magic = Buffer->getBuffer().slice(0, 4); - error_code ec; - ObjectFile *Ret; - if (Magic == "\xFE\xED\xFA\xCE") - Ret = new MachOObjectFileBE32(Buffer, ec); - else if (Magic == "\xCE\xFA\xED\xFE") - Ret = new MachOObjectFileLE32(Buffer, ec); - else if (Magic == "\xFE\xED\xFA\xCF") - Ret = new MachOObjectFileBE64(Buffer, ec); - else if (Magic == "\xCF\xFA\xED\xFE") - Ret = new MachOObjectFileLE64(Buffer, ec); - else - return NULL; +template<> +void SwapStruct(macho::SymbolTableEntry &S) { + SwapValue(S.StringIndex); + SwapValue(S.Flags); + SwapValue(S.Value); +} - if (ec) - return NULL; - return Ret; +template<> +void SwapStruct(macho::Symbol64TableEntry &S) { + SwapValue(S.StringIndex); + SwapValue(S.Flags); + SwapValue(S.Value); } -/*===-- Symbols -----------------------------------------------------------===*/ +template<> +void SwapStruct(macho::Header &H) { + SwapValue(H.Magic); + SwapValue(H.CPUType); + SwapValue(H.CPUSubtype); + SwapValue(H.FileType); + SwapValue(H.NumLoadCommands); + SwapValue(H.SizeOfLoadCommands); + SwapValue(H.Flags); +} -error_code MachOObjectFileBase::getSymbolValue(DataRefImpl Symb, - uint64_t &Val) const { - report_fatal_error("getSymbolValue unimplemented in MachOObjectFileBase"); +template<> +void SwapStruct(macho::SymtabLoadCommand &C) { + SwapValue(C.Type); + SwapValue(C.Size); + SwapValue(C.SymbolTableOffset); + SwapValue(C.NumSymbolTableEntries); + SwapValue(C.StringTableOffset); + SwapValue(C.StringTableSize); } -symbol_iterator MachOObjectFileBase::begin_dynamic_symbols() const { - // TODO: implement - report_fatal_error("Dynamic symbols unimplemented in MachOObjectFileBase"); +template<> +void SwapStruct(macho::LinkeditDataLoadCommand &C) { + SwapValue(C.Type); + SwapValue(C.Size); + SwapValue(C.DataOffset); + SwapValue(C.DataSize); } -symbol_iterator MachOObjectFileBase::end_dynamic_symbols() const { - // TODO: implement - report_fatal_error("Dynamic symbols unimplemented in MachOObjectFileBase"); +template<> +void SwapStruct(macho::SegmentLoadCommand &C) { + SwapValue(C.Type); + SwapValue(C.Size); + SwapValue(C.VMAddress); + SwapValue(C.VMSize); + SwapValue(C.FileOffset); + SwapValue(C.FileSize); + SwapValue(C.MaxVMProtection); + SwapValue(C.InitialVMProtection); + SwapValue(C.NumSections); + SwapValue(C.Flags); } -library_iterator MachOObjectFileBase::begin_libraries_needed() const { - // TODO: implement - report_fatal_error("Needed libraries unimplemented in MachOObjectFileBase"); +template<> +void SwapStruct(macho::Segment64LoadCommand &C) { + SwapValue(C.Type); + SwapValue(C.Size); + SwapValue(C.VMAddress); + SwapValue(C.VMSize); + SwapValue(C.FileOffset); + SwapValue(C.FileSize); + SwapValue(C.MaxVMProtection); + SwapValue(C.InitialVMProtection); + SwapValue(C.NumSections); + SwapValue(C.Flags); } -library_iterator MachOObjectFileBase::end_libraries_needed() const { - // TODO: implement - report_fatal_error("Needed libraries unimplemented in MachOObjectFileBase"); +static bool isSwappedEndian(const MachOObjectFile *O) { + return O->isLittleEndian() != sys::IsLittleEndianHost; } -StringRef MachOObjectFileBase::getLoadName() const { - // TODO: Implement - report_fatal_error("get_load_name() unimplemented in MachOObjectFileBase"); +static macho::SegmentLoadCommand +getSegmentLoadCommand(const MachOObjectFile *O, + const MachOObjectFile::LoadCommandInfo &L) { + macho::SegmentLoadCommand Cmd; + memcpy(&Cmd, L.Ptr, sizeof(macho::SegmentLoadCommand)); + if (isSwappedEndian(O)) + SwapStruct(Cmd); + return Cmd; +} + +static macho::Segment64LoadCommand +getSegment64LoadCommand(const MachOObjectFile *O, + const MachOObjectFile::LoadCommandInfo &L) { + macho::Segment64LoadCommand Cmd; + memcpy(&Cmd, L.Ptr, sizeof(macho::Segment64LoadCommand)); + if (isSwappedEndian(O)) + SwapStruct(Cmd); + return Cmd; +} + +static uint32_t +getSegmentLoadCommandNumSections(const MachOObjectFile *O, + const MachOObjectFile::LoadCommandInfo &L) { + if (O->is64Bit()) { + macho::Segment64LoadCommand S = getSegment64LoadCommand(O, L); + return S.NumSections; + } + macho::SegmentLoadCommand S = getSegmentLoadCommand(O, L); + return S.NumSections; } -/*===-- Sections ----------------------------------------------------------===*/ +static const SectionBase * +getSectionBase(const MachOObjectFile *O, MachOObjectFile::LoadCommandInfo L, + unsigned Sec) { + uintptr_t CommandAddr = reinterpret_cast<uintptr_t>(L.Ptr); -std::size_t MachOObjectFileBase::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); + bool Is64 = O->is64Bit(); + unsigned SegmentLoadSize = Is64 ? sizeof(macho::Segment64LoadCommand) : + sizeof(macho::SegmentLoadCommand); + unsigned SectionSize = Is64 ? sizeof(macho::Section64) : + sizeof(macho::Section); + + uintptr_t SectionAddr = CommandAddr + SegmentLoadSize + Sec * SectionSize; + return reinterpret_cast<const SectionBase*>(SectionAddr); +} + +static const char *getPtr(const MachOObjectFile *O, size_t Offset) { + return O->getData().substr(Offset, 1).data(); +} + +static const char *getSymbolTableEntryPtr(const MachOObjectFile *O, + DataRefImpl DRI) { + macho::SymtabLoadCommand S = O->getSymtabLoadCommand(); + + unsigned Index = DRI.d.b; + + unsigned SymbolTableEntrySize = O->is64Bit() ? + sizeof(macho::Symbol64TableEntry) : + sizeof(macho::SymbolTableEntry); + + uint64_t Offset = S.SymbolTableOffset + Index * SymbolTableEntrySize; + return getPtr(O, Offset); +} + +static SymbolTableEntryBase +getSymbolTableEntryBase(const MachOObjectFile *O, DataRefImpl DRI) { + const char *P = getSymbolTableEntryPtr(O, DRI); + SymbolTableEntryBase Ret; + memcpy(&Ret, P, sizeof(SymbolTableEntryBase)); + if (isSwappedEndian(O)) + SwapStruct(Ret); + + return Ret; } -StringRef MachOObjectFileBase::parseSegmentOrSectionName(const char *P) const { +static StringRef parseSegmentOrSectionName(const char *P) { if (P[15] == 0) // Null terminated. return P; @@ -128,14 +252,470 @@ StringRef MachOObjectFileBase::parseSegmentOrSectionName(const char *P) const { return StringRef(P, 16); } -error_code MachOObjectFileBase::isSectionData(DataRefImpl DRI, +// Helper to advance a section or symbol iterator multiple increments at a time. +template<class T> +static error_code advance(T &it, size_t Val) { + error_code ec; + while (Val--) { + it.increment(ec); + } + return ec; +} + +template<class T> +static void advanceTo(T &it, size_t Val) { + if (error_code ec = advance(it, Val)) + report_fatal_error(ec.message()); +} + +static unsigned getCPUType(const MachOObjectFile *O) { + return O->getHeader().CPUType; +} + +static void printRelocationTargetName(const MachOObjectFile *O, + const macho::RelocationEntry &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); + + error_code ec; + for (symbol_iterator SI = O->begin_symbols(), SE = O->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 = O->begin_sections(), SE = O->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 = O->getPlainRelocationExternal(RE); + uint64_t Val = O->getAnyRelocationAddress(RE); + + if (isExtern) { + symbol_iterator SI = O->begin_symbols(); + advanceTo(SI, Val); + SI->getName(S); + } else { + section_iterator SI = O->begin_sections(); + advanceTo(SI, Val); + SI->getName(S); + } + + fmt << S; +} + +static uint32_t getPlainRelocationAddress(const macho::RelocationEntry &RE) { + return RE.Word0; +} + +static unsigned +getScatteredRelocationAddress(const macho::RelocationEntry &RE) { + return RE.Word0 & 0xffffff; +} + +static bool getPlainRelocationPCRel(const MachOObjectFile *O, + const macho::RelocationEntry &RE) { + if (O->isLittleEndian()) + return (RE.Word1 >> 24) & 1; + return (RE.Word1 >> 7) & 1; +} + +static bool +getScatteredRelocationPCRel(const MachOObjectFile *O, + const macho::RelocationEntry &RE) { + return (RE.Word0 >> 30) & 1; +} + +static unsigned getPlainRelocationLength(const MachOObjectFile *O, + const macho::RelocationEntry &RE) { + if (O->isLittleEndian()) + return (RE.Word1 >> 25) & 3; + return (RE.Word1 >> 5) & 3; +} + +static unsigned +getScatteredRelocationLength(const macho::RelocationEntry &RE) { + return (RE.Word0 >> 28) & 3; +} + +static unsigned getPlainRelocationType(const MachOObjectFile *O, + const macho::RelocationEntry &RE) { + if (O->isLittleEndian()) + return RE.Word1 >> 28; + return RE.Word1 & 0xf; +} + +static unsigned getScatteredRelocationType(const macho::RelocationEntry &RE) { + return (RE.Word0 >> 24) & 0xf; +} + +static uint32_t getSectionFlags(const MachOObjectFile *O, + DataRefImpl Sec) { + if (O->is64Bit()) { + macho::Section64 Sect = O->getSection64(Sec); + return Sect.Flags; + } + macho::Section Sect = O->getSection(Sec); + return Sect.Flags; +} + +MachOObjectFile::MachOObjectFile(MemoryBuffer *Object, + bool IsLittleEndian, bool Is64bits, + error_code &ec) + : ObjectFile(getMachOType(IsLittleEndian, Is64bits), Object), + SymtabLoadCmd(NULL) { + uint32_t LoadCommandCount = this->getHeader().NumLoadCommands; + macho::LoadCommandType SegmentLoadType = is64Bit() ? + macho::LCT_Segment64 : macho::LCT_Segment; + + MachOObjectFile::LoadCommandInfo Load = getFirstLoadCommandInfo(); + for (unsigned I = 0; I < LoadCommandCount; ++I) { + if (Load.C.Type == macho::LCT_Symtab) { + assert(!SymtabLoadCmd && "Multiple symbol tables"); + SymtabLoadCmd = Load.Ptr; + } + + if (Load.C.Type == SegmentLoadType) { + uint32_t NumSections = getSegmentLoadCommandNumSections(this, Load); + for (unsigned J = 0; J < NumSections; ++J) { + const SectionBase *Sec = getSectionBase(this, Load, J); + Sections.push_back(reinterpret_cast<const char*>(Sec)); + } + } + Load = getNextLoadCommandInfo(Load); + } +} + +error_code MachOObjectFile::getSymbolNext(DataRefImpl Symb, + SymbolRef &Res) const { + Symb.d.b++; + Res = SymbolRef(Symb, this); + return object_error::success; +} + +error_code MachOObjectFile::getSymbolName(DataRefImpl Symb, + StringRef &Res) const { + macho::SymtabLoadCommand S = getSymtabLoadCommand(); + const char *StringTable = getPtr(this, S.StringTableOffset); + SymbolTableEntryBase Entry = getSymbolTableEntryBase(this, Symb); + const char *Start = &StringTable[Entry.StringIndex]; + Res = StringRef(Start); + return object_error::success; +} + +error_code MachOObjectFile::getSymbolAddress(DataRefImpl Symb, + uint64_t &Res) const { + if (is64Bit()) { + macho::Symbol64TableEntry Entry = getSymbol64TableEntry(Symb); + Res = Entry.Value; + } else { + macho::SymbolTableEntry Entry = getSymbolTableEntry(Symb); + Res = Entry.Value; + } + return object_error::success; +} + +error_code +MachOObjectFile::getSymbolFileOffset(DataRefImpl Symb, + uint64_t &Res) const { + SymbolTableEntryBase Entry = getSymbolTableEntryBase(this, Symb); + getSymbolAddress(Symb, Res); + if (Entry.SectionIndex) { + uint64_t Delta; + DataRefImpl SecRel; + SecRel.d.a = Entry.SectionIndex-1; + if (is64Bit()) { + macho::Section64 Sec = getSection64(SecRel); + Delta = Sec.Offset - Sec.Address; + } else { + macho::Section Sec = getSection(SecRel); + Delta = Sec.Offset - Sec.Address; + } + + Res += Delta; + } + + return object_error::success; +} + +error_code MachOObjectFile::getSymbolSize(DataRefImpl DRI, + uint64_t &Result) const { + uint64_t BeginOffset; + uint64_t EndOffset = 0; + uint8_t SectionIndex; + + SymbolTableEntryBase Entry = getSymbolTableEntryBase(this, DRI); + uint64_t Value; + getSymbolAddress(DRI, Value); + + BeginOffset = Value; + + SectionIndex = Entry.SectionIndex; + if (!SectionIndex) { + uint32_t flags = SymbolRef::SF_None; + this->getSymbolFlags(DRI, flags); + 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 + macho::SymtabLoadCommand Symtab = getSymtabLoadCommand(); + DRI.d.b = 0; + while (DRI.d.b <= Symtab.NumSymbolTableEntries) { + Entry = getSymbolTableEntryBase(this, DRI); + getSymbolAddress(DRI, Value); + if (Entry.SectionIndex == SectionIndex && Value > BeginOffset) + if (!EndOffset || Value < EndOffset) + EndOffset = Value; + DRI.d.b++; + } + 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 { + SymbolTableEntryBase Entry = getSymbolTableEntryBase(this, Symb); + uint8_t n_type = Entry.Type; + + Res = SymbolRef::ST_Other; + + // If this is a STAB debugging symbol, we can do nothing more. + if (n_type & MachO::NlistMaskStab) { + Res = SymbolRef::ST_Debug; + return object_error::success; + } + + switch (n_type & MachO::NlistMaskType) { + case MachO::NListTypeUndefined : + Res = SymbolRef::ST_Unknown; + break; + case MachO::NListTypeSection : + Res = SymbolRef::ST_Function; + break; + } + return object_error::success; +} + +error_code MachOObjectFile::getSymbolNMTypeChar(DataRefImpl Symb, + char &Res) const { + SymbolTableEntryBase Entry = getSymbolTableEntryBase(this, Symb); + uint8_t Type = Entry.Type; + uint16_t Flags = Entry.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 = '?'; + break; + } + + if (Flags & (macho::STF_External | macho::STF_PrivateExtern)) + Char = toupper(static_cast<unsigned char>(Char)); + Res = Char; + return object_error::success; +} + +error_code MachOObjectFile::getSymbolFlags(DataRefImpl DRI, + uint32_t &Result) const { + SymbolTableEntryBase Entry = getSymbolTableEntryBase(this, DRI); + + uint8_t MachOType = Entry.Type; + uint16_t MachOFlags = Entry.Flags; + + // 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; + + if (MachOType & MachO::NlistMaskExternal) { + Result |= SymbolRef::SF_Global; + if ((MachOType & MachO::NlistMaskType) == MachO::NListTypeUndefined) + Result |= SymbolRef::SF_Common; + } + + 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 { + SymbolTableEntryBase Entry = getSymbolTableEntryBase(this, Symb); + uint8_t index = Entry.SectionIndex; + + if (index == 0) { + Res = end_sections(); + } else { + DataRefImpl DRI; + DRI.d.a = index - 1; + Res = section_iterator(SectionRef(DRI, this)); + } + + return object_error::success; +} + +error_code MachOObjectFile::getSymbolValue(DataRefImpl Symb, + uint64_t &Val) const { + report_fatal_error("getSymbolValue unimplemented in MachOObjectFile"); +} + +error_code MachOObjectFile::getSectionNext(DataRefImpl Sec, + SectionRef &Res) const { + Sec.d.a++; + Res = SectionRef(Sec, this); + return object_error::success; +} + +error_code +MachOObjectFile::getSectionName(DataRefImpl Sec, + StringRef &Result) const { + ArrayRef<char> Raw = getSectionRawName(Sec); + Result = parseSegmentOrSectionName(Raw.data()); + return object_error::success; +} + +error_code +MachOObjectFile::getSectionAddress(DataRefImpl Sec, + uint64_t &Res) const { + if (is64Bit()) { + macho::Section64 Sect = getSection64(Sec); + Res = Sect.Address; + } else { + macho::Section Sect = getSection(Sec); + Res = Sect.Address; + } + return object_error::success; +} + +error_code +MachOObjectFile::getSectionSize(DataRefImpl Sec, + uint64_t &Res) const { + if (is64Bit()) { + macho::Section64 Sect = getSection64(Sec); + Res = Sect.Size; + } else { + macho::Section Sect = getSection(Sec); + Res = Sect.Size; + } + + return object_error::success; +} + +error_code +MachOObjectFile::getSectionContents(DataRefImpl Sec, + StringRef &Res) const { + uint32_t Offset; + uint64_t Size; + + if (is64Bit()) { + macho::Section64 Sect = getSection64(Sec); + Offset = Sect.Offset; + Size = Sect.Size; + } else { + 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 Sec, + uint64_t &Res) const { + uint32_t Align; + if (is64Bit()) { + macho::Section64 Sect = getSection64(Sec); + Align = Sect.Align; + } else { + macho::Section Sect = getSection(Sec); + Align = Sect.Align; + } + + Res = uint64_t(1) << Align; + return object_error::success; +} + +error_code +MachOObjectFile::isSectionText(DataRefImpl Sec, bool &Res) const { + uint32_t Flags = getSectionFlags(this, Sec); + Res = Flags & macho::SF_PureInstructions; + return object_error::success; +} + +error_code MachOObjectFile::isSectionData(DataRefImpl DRI, bool &Result) const { // FIXME: Unimplemented. Result = false; return object_error::success; } -error_code MachOObjectFileBase::isSectionBSS(DataRefImpl DRI, +error_code MachOObjectFile::isSectionBSS(DataRefImpl DRI, bool &Result) const { // FIXME: Unimplemented. Result = false; @@ -143,21 +723,30 @@ error_code MachOObjectFileBase::isSectionBSS(DataRefImpl DRI, } error_code -MachOObjectFileBase::isSectionRequiredForExecution(DataRefImpl Sec, +MachOObjectFile::isSectionRequiredForExecution(DataRefImpl Sec, bool &Result) const { // FIXME: Unimplemented. Result = true; return object_error::success; } -error_code MachOObjectFileBase::isSectionVirtual(DataRefImpl Sec, +error_code MachOObjectFile::isSectionVirtual(DataRefImpl Sec, bool &Result) const { // FIXME: Unimplemented. Result = false; return object_error::success; } -error_code MachOObjectFileBase::isSectionReadOnlyData(DataRefImpl Sec, +error_code +MachOObjectFile::isSectionZeroInit(DataRefImpl Sec, bool &Res) const { + uint32_t Flags = getSectionFlags(this, Sec); + unsigned SectionType = Flags & MachO::SectionFlagMaskSectionType; + Res = SectionType == MachO::SectionTypeZeroFill || + SectionType == MachO::SectionTypeZeroFillLarge; + return object_error::success; +} + +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 @@ -168,44 +757,752 @@ error_code MachOObjectFileBase::isSectionReadOnlyData(DataRefImpl Sec, return object_error::success; } -relocation_iterator MachOObjectFileBase::getSectionRelBegin(DataRefImpl Sec) const { +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; +} + +relocation_iterator MachOObjectFile::getSectionRelBegin(DataRefImpl Sec) const { DataRefImpl ret; - ret.d.b = getSectionIndex(Sec); + ret.d.b = Sec.d.a; return relocation_iterator(RelocationRef(ret, this)); } +relocation_iterator +MachOObjectFile::getSectionRelEnd(DataRefImpl Sec) const { + uint32_t LastReloc; + if (is64Bit()) { + macho::Section64 Sect = getSection64(Sec); + LastReloc = Sect.NumRelocationTableEntries; + } else { + macho::Section Sect = getSection(Sec); + LastReloc = Sect.NumRelocationTableEntries; + } -/*===-- Relocations -------------------------------------------------------===*/ + DataRefImpl Ret; + Ret.d.a = LastReloc; + Ret.d.b = Sec.d.a; + return relocation_iterator(RelocationRef(Ret, this)); +} -error_code MachOObjectFileBase::getRelocationNext(DataRefImpl Rel, +error_code MachOObjectFile::getRelocationNext(DataRefImpl Rel, RelocationRef &Res) const { ++Rel.d.a; Res = RelocationRef(Rel, this); return object_error::success; } -error_code MachOObjectFileBase::getLibraryNext(DataRefImpl LibData, - LibraryRef &Res) const { - report_fatal_error("Needed libraries unimplemented in MachOObjectFileBase"); +error_code +MachOObjectFile::getRelocationAddress(DataRefImpl Rel, + uint64_t &Res) const { + uint64_t SectAddress; + DataRefImpl Sec; + Sec.d.a = Rel.d.b; + if (is64Bit()) { + macho::Section64 Sect = getSection64(Sec); + SectAddress = Sect.Address; + } else { + macho::Section Sect = getSection(Sec); + SectAddress = Sect.Address; + } + + macho::RelocationEntry RE = getRelocation(Rel); + uint64_t RelAddr = getAnyRelocationAddress(RE); + Res = SectAddress + RelAddr; + return object_error::success; } -error_code MachOObjectFileBase::getLibraryPath(DataRefImpl LibData, - StringRef &Res) const { - report_fatal_error("Needed libraries unimplemented in MachOObjectFileBase"); +error_code MachOObjectFile::getRelocationOffset(DataRefImpl Rel, + uint64_t &Res) const { + macho::RelocationEntry RE = getRelocation(Rel); + Res = getAnyRelocationAddress(RE); + return object_error::success; } -error_code MachOObjectFileBase::getRelocationAdditionalInfo(DataRefImpl Rel, - int64_t &Res) const { +error_code +MachOObjectFile::getRelocationSymbol(DataRefImpl Rel, + SymbolRef &Res) const { + macho::RelocationEntry RE = getRelocation(Rel); + uint32_t SymbolIdx = getPlainRelocationSymbolNum(RE); + bool isExtern = getPlainRelocationExternal(RE); + + DataRefImpl Sym; + if (isExtern) { + Sym.d.b = SymbolIdx; + } + Res = SymbolRef(Sym, this); + return object_error::success; +} + +error_code MachOObjectFile::getRelocationType(DataRefImpl Rel, + uint64_t &Res) const { + macho::RelocationEntry RE = getRelocation(Rel); + Res = getAnyRelocationType(RE); + return object_error::success; +} + +error_code +MachOObjectFile::getRelocationTypeName(DataRefImpl Rel, + SmallVectorImpl<char> &Result) const { + StringRef res; + uint64_t RType; + getRelocationType(Rel, RType); + + unsigned Arch = this->getArch(); + + switch (Arch) { + case Triple::x86: { + static const char *const Table[] = { + "GENERIC_RELOC_VANILLA", + "GENERIC_RELOC_PAIR", + "GENERIC_RELOC_SECTDIFF", + "GENERIC_RELOC_PB_LA_PTR", + "GENERIC_RELOC_LOCAL_SECTDIFF", + "GENERIC_RELOC_TLV" }; + + if (RType > 6) + res = "Unknown"; + else + res = Table[RType]; + break; + } + case Triple::x86_64: { + static const char *const Table[] = { + "X86_64_RELOC_UNSIGNED", + "X86_64_RELOC_SIGNED", + "X86_64_RELOC_BRANCH", + "X86_64_RELOC_GOT_LOAD", + "X86_64_RELOC_GOT", + "X86_64_RELOC_SUBTRACTOR", + "X86_64_RELOC_SIGNED_1", + "X86_64_RELOC_SIGNED_2", + "X86_64_RELOC_SIGNED_4", + "X86_64_RELOC_TLV" }; + + if (RType > 9) + res = "Unknown"; + else + res = Table[RType]; + break; + } + case Triple::arm: { + static const char *const Table[] = { + "ARM_RELOC_VANILLA", + "ARM_RELOC_PAIR", + "ARM_RELOC_SECTDIFF", + "ARM_RELOC_LOCAL_SECTDIFF", + "ARM_RELOC_PB_LA_PTR", + "ARM_RELOC_BR24", + "ARM_THUMB_RELOC_BR22", + "ARM_THUMB_32BIT_BRANCH", + "ARM_RELOC_HALF", + "ARM_RELOC_HALF_SECTDIFF" }; + + if (RType > 9) + res = "Unknown"; + else + res = Table[RType]; + break; + } + case Triple::ppc: { + static const char *const Table[] = { + "PPC_RELOC_VANILLA", + "PPC_RELOC_PAIR", + "PPC_RELOC_BR14", + "PPC_RELOC_BR24", + "PPC_RELOC_HI16", + "PPC_RELOC_LO16", + "PPC_RELOC_HA16", + "PPC_RELOC_LO14", + "PPC_RELOC_SECTDIFF", + "PPC_RELOC_PB_LA_PTR", + "PPC_RELOC_HI16_SECTDIFF", + "PPC_RELOC_LO16_SECTDIFF", + "PPC_RELOC_HA16_SECTDIFF", + "PPC_RELOC_JBSR", + "PPC_RELOC_LO14_SECTDIFF", + "PPC_RELOC_LOCAL_SECTDIFF" }; + + res = Table[RType]; + break; + } + case Triple::UnknownArch: + res = "Unknown"; + break; + } + Result.append(res.begin(), res.end()); + return object_error::success; +} + +error_code MachOObjectFile::getRelocationAdditionalInfo(DataRefImpl Rel, + int64_t &Res) const { Res = 0; return object_error::success; } +error_code +MachOObjectFile::getRelocationValueString(DataRefImpl Rel, + SmallVectorImpl<char> &Result) const { + macho::RelocationEntry 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::RIT_X86_64_GOTLoad: // X86_64_RELOC_GOT_LOAD + case macho::RIT_X86_64_GOT: { // 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 + DataRefImpl RelNext = Rel; + RelNext.d.a++; + macho::RelocationEntry RENext = getRelocation(RelNext); + + // X86_64_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 != 0) + 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(this, RENext, fmt); + fmt << "-"; + printRelocationTargetName(this, RE, fmt); + break; + } + case macho::RIT_X86_64_TLV: + printRelocationTargetName(this, RE, fmt); + fmt << "@TLV"; + if (isPCRel) fmt << "P"; + break; + case macho::RIT_X86_64_Signed1: // X86_64_RELOC_SIGNED1 + printRelocationTargetName(this, RE, fmt); + fmt << "-1"; + break; + case macho::RIT_X86_64_Signed2: // X86_64_RELOC_SIGNED2 + printRelocationTargetName(this, RE, fmt); + fmt << "-2"; + break; + case macho::RIT_X86_64_Signed4: // X86_64_RELOC_SIGNED4 + 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) { + // Generic relocation types... + switch (Type) { + case macho::RIT_Pair: // GENERIC_RELOC_PAIR - prints no info + return object_error::success; + case macho::RIT_Difference: { // GENERIC_RELOC_SECTDIFF + DataRefImpl RelNext = Rel; + RelNext.d.a++; + macho::RelocationEntry RENext = getRelocation(RelNext); -/*===-- Miscellaneous -----------------------------------------------------===*/ + // X86 sect diff's must be followed by a relocation of type + // GENERIC_RELOC_PAIR. + unsigned RType = getAnyRelocationType(RENext); -uint8_t MachOObjectFileBase::getBytesInAddress() const { + if (RType != 1) + 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) { + // All X86 relocations that need special printing were already + // handled in the generic code. + switch (Type) { + case macho::RIT_Generic_LocalDifference:{// GENERIC_RELOC_LOCAL_SECTDIFF + DataRefImpl RelNext = Rel; + RelNext.d.a++; + macho::RelocationEntry RENext = getRelocation(RelNext); + + // X86 sect diff's must be followed by a relocation of type + // GENERIC_RELOC_PAIR. + unsigned RType = getAnyRelocationType(RENext); + if (RType != 1) + report_fatal_error("Expected GENERIC_RELOC_PAIR after " + "GENERIC_RELOC_LOCAL_SECTDIFF."); + + printRelocationTargetName(this, RE, fmt); + fmt << "-"; + printRelocationTargetName(this, RENext, fmt); + break; + } + case macho::RIT_Generic_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::RIT_ARM_Half: // ARM_RELOC_HALF + case macho::RIT_ARM_HalfDifference: { // 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; + RelNext.d.a++; + macho::RelocationEntry RENext = getRelocation(RelNext); + + // ARM half relocs must be followed by a relocation of type + // ARM_RELOC_PAIR. + unsigned RType = getAnyRelocationType(RENext); + if (RType != 1) + report_fatal_error("Expected ARM_RELOC_PAIR after " + "GENERIC_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::RIT_ARM_HalfDifference) { + 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; +} + +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) { + if (Type == macho::RIT_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) { + DataRefImpl RelPrev = Rel; + RelPrev.d.a--; + uint64_t PrevType; + getRelocationType(RelPrev, PrevType); + if (PrevType == macho::RIT_X86_64_Subtractor) + Result = true; + } + } + + return object_error::success; +} + +error_code MachOObjectFile::getLibraryNext(DataRefImpl LibData, + LibraryRef &Res) const { + report_fatal_error("Needed libraries unimplemented in MachOObjectFile"); +} + +error_code MachOObjectFile::getLibraryPath(DataRefImpl LibData, + StringRef &Res) const { + report_fatal_error("Needed libraries unimplemented in MachOObjectFile"); +} + +symbol_iterator MachOObjectFile::begin_symbols() const { + // DRI.d.a = segment number; DRI.d.b = symbol index. + DataRefImpl DRI; + return symbol_iterator(SymbolRef(DRI, this)); +} + +symbol_iterator MachOObjectFile::end_symbols() const { + DataRefImpl DRI; + if (SymtabLoadCmd) { + macho::SymtabLoadCommand Symtab = getSymtabLoadCommand(); + DRI.d.b = Symtab.NumSymbolTableEntries; + } + return symbol_iterator(SymbolRef(DRI, this)); +} + +symbol_iterator MachOObjectFile::begin_dynamic_symbols() const { + // TODO: implement + report_fatal_error("Dynamic symbols unimplemented in MachOObjectFile"); +} + +symbol_iterator MachOObjectFile::end_dynamic_symbols() const { + // TODO: implement + report_fatal_error("Dynamic symbols unimplemented in MachOObjectFile"); +} + +section_iterator MachOObjectFile::begin_sections() const { + DataRefImpl DRI; + return section_iterator(SectionRef(DRI, this)); +} + +section_iterator MachOObjectFile::end_sections() const { + DataRefImpl DRI; + DRI.d.a = Sections.size(); + return section_iterator(SectionRef(DRI, this)); +} + +library_iterator MachOObjectFile::begin_libraries_needed() const { + // TODO: implement + report_fatal_error("Needed libraries unimplemented in MachOObjectFile"); +} + +library_iterator MachOObjectFile::end_libraries_needed() const { + // TODO: implement + report_fatal_error("Needed libraries unimplemented in MachOObjectFile"); +} + +uint8_t MachOObjectFile::getBytesInAddress() const { return is64Bit() ? 8 : 4; } +StringRef MachOObjectFile::getFileFormatName() const { + unsigned CPUType = getCPUType(this); + if (!is64Bit()) { + switch (CPUType) { + case llvm::MachO::CPUTypeI386: + return "Mach-O 32-bit i386"; + case llvm::MachO::CPUTypeARM: + return "Mach-O arm"; + case llvm::MachO::CPUTypePowerPC: + return "Mach-O 32-bit ppc"; + default: + assert((CPUType & llvm::MachO::CPUArchABI64) == 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::CPUArchABI64) + == llvm::MachO::CPUArchABI64 && + "32-bit object file when we're 64-bit?"); + + switch (CPUType) { + case llvm::MachO::CPUTypeX86_64: + return "Mach-O 64-bit x86-64"; + case llvm::MachO::CPUTypePowerPC64: + return "Mach-O 64-bit ppc64"; + default: + return "Mach-O 64-bit unknown"; + } +} + +unsigned MachOObjectFile::getArch() const { + switch (getCPUType(this)) { + case llvm::MachO::CPUTypeI386: + return Triple::x86; + case llvm::MachO::CPUTypeX86_64: + return Triple::x86_64; + case llvm::MachO::CPUTypeARM: + return Triple::arm; + case llvm::MachO::CPUTypePowerPC: + return Triple::ppc; + case llvm::MachO::CPUTypePowerPC64: + return Triple::ppc64; + default: + return Triple::UnknownArch; + } +} + +StringRef MachOObjectFile::getLoadName() const { + // TODO: Implement + report_fatal_error("get_load_name() unimplemented in MachOObjectFile"); +} + +StringRef +MachOObjectFile::getSectionFinalSegmentName(DataRefImpl Sec) const { + ArrayRef<char> Raw = getSectionRawFinalSegmentName(Sec); + return parseSegmentOrSectionName(Raw.data()); +} + +ArrayRef<char> +MachOObjectFile::getSectionRawName(DataRefImpl Sec) const { + const SectionBase *Base = + reinterpret_cast<const SectionBase*>(Sections[Sec.d.a]); + return ArrayRef<char>(Base->Name); +} + +ArrayRef<char> +MachOObjectFile::getSectionRawFinalSegmentName(DataRefImpl Sec) const { + const SectionBase *Base = + reinterpret_cast<const SectionBase*>(Sections[Sec.d.a]); + return ArrayRef<char>(Base->SegmentName); +} + +bool +MachOObjectFile::isRelocationScattered(const macho::RelocationEntry &RE) + const { + if (getCPUType(this) == llvm::MachO::CPUTypeX86_64) + return false; + return getPlainRelocationAddress(RE) & macho::RF_Scattered; +} + +unsigned MachOObjectFile::getPlainRelocationSymbolNum(const macho::RelocationEntry &RE) const { + if (isLittleEndian()) + return RE.Word1 & 0xffffff; + return RE.Word1 >> 8; +} + +bool MachOObjectFile::getPlainRelocationExternal(const macho::RelocationEntry &RE) const { + if (isLittleEndian()) + return (RE.Word1 >> 27) & 1; + return (RE.Word1 >> 4) & 1; +} + +bool +MachOObjectFile::getScatteredRelocationScattered(const macho::RelocationEntry &RE) const { + return RE.Word0 >> 31; +} + +uint32_t +MachOObjectFile::getScatteredRelocationValue(const macho::RelocationEntry &RE) const { + return RE.Word1; +} + +unsigned +MachOObjectFile::getAnyRelocationAddress(const macho::RelocationEntry &RE) const { + if (isRelocationScattered(RE)) + return getScatteredRelocationAddress(RE); + return getPlainRelocationAddress(RE); +} + +unsigned +MachOObjectFile::getAnyRelocationPCRel(const macho::RelocationEntry &RE) const { + if (isRelocationScattered(RE)) + return getScatteredRelocationPCRel(this, RE); + return getPlainRelocationPCRel(this, RE); +} + +unsigned +MachOObjectFile::getAnyRelocationLength(const macho::RelocationEntry &RE) const { + if (isRelocationScattered(RE)) + return getScatteredRelocationLength(RE); + return getPlainRelocationLength(this, RE); +} + +unsigned +MachOObjectFile::getAnyRelocationType(const macho::RelocationEntry &RE) const { + if (isRelocationScattered(RE)) + return getScatteredRelocationType(RE); + return getPlainRelocationType(this, RE); +} + +MachOObjectFile::LoadCommandInfo +MachOObjectFile::getFirstLoadCommandInfo() const { + MachOObjectFile::LoadCommandInfo Load; + + unsigned HeaderSize = is64Bit() ? macho::Header64Size : macho::Header32Size; + Load.Ptr = getPtr(this, HeaderSize); + memcpy(&Load.C, Load.Ptr, sizeof(macho::LoadCommand)); + if (isSwappedEndian(this)) + SwapStruct(Load.C); + return Load; +} + +MachOObjectFile::LoadCommandInfo +MachOObjectFile::getNextLoadCommandInfo(const LoadCommandInfo &L) const { + MachOObjectFile::LoadCommandInfo Next; + Next.Ptr = L.Ptr + L.C.Size; + memcpy(&Next.C, Next.Ptr, sizeof(macho::LoadCommand)); + if (isSwappedEndian(this)) + SwapStruct(Next.C); + return Next; +} + +macho::Section MachOObjectFile::getSection(DataRefImpl DRI) const { + const SectionBase *Addr = + reinterpret_cast<const SectionBase*>(Sections[DRI.d.a]); + macho::Section Ret; + memcpy(&Ret, Addr, sizeof(macho::Section)); + if (isSwappedEndian(this)) + SwapStruct(Ret); + return Ret; +} + +macho::Section64 MachOObjectFile::getSection64(DataRefImpl DRI) const { + const SectionBase *Addr = + reinterpret_cast<const SectionBase*>(Sections[DRI.d.a]); + macho::Section64 Ret; + memcpy(&Ret, Addr, sizeof(macho::Section64)); + if (isSwappedEndian(this)) + SwapStruct(Ret); + return Ret; +} + +macho::SymbolTableEntry +MachOObjectFile::getSymbolTableEntry(DataRefImpl DRI) const { + const char *P = getSymbolTableEntryPtr(this, DRI); + macho::SymbolTableEntry Ret; + memcpy(&Ret, P, sizeof(macho::SymbolTableEntry)); + if (isSwappedEndian(this)) + SwapStruct(Ret); + return Ret; +} + +macho::Symbol64TableEntry +MachOObjectFile::getSymbol64TableEntry(DataRefImpl DRI) const { + const char *P = getSymbolTableEntryPtr(this, DRI); + macho::Symbol64TableEntry Ret; + memcpy(&Ret, P, sizeof(macho::Symbol64TableEntry)); + if (isSwappedEndian(this)) + SwapStruct(Ret); + return Ret; +} + +macho::LinkeditDataLoadCommand +MachOObjectFile::getLinkeditDataLoadCommand(const MachOObjectFile::LoadCommandInfo &L) const { + macho::LinkeditDataLoadCommand Cmd; + memcpy(&Cmd, L.Ptr, sizeof(macho::LinkeditDataLoadCommand)); + if (isSwappedEndian(this)) + SwapStruct(Cmd); + return Cmd; +} + +macho::RelocationEntry +MachOObjectFile::getRelocation(DataRefImpl Rel) const { + uint32_t RelOffset; + DataRefImpl Sec; + Sec.d.a = Rel.d.b; + if (is64Bit()) { + macho::Section64 Sect = getSection64(Sec); + RelOffset = Sect.RelocationTableOffset; + } else { + macho::Section Sect = getSection(Sec); + RelOffset = Sect.RelocationTableOffset; + } + + uint64_t Offset = RelOffset + Rel.d.a * sizeof(macho::RelocationEntry); + + macho::RelocationEntry Ret; + memcpy(&Ret, getPtr(this, Offset), sizeof(macho::RelocationEntry)); + if (isSwappedEndian(this)) + SwapStruct(Ret); + + return Ret; +} + +macho::Header MachOObjectFile::getHeader() const { + macho::Header H; + memcpy(&H, getPtr(this, 0), sizeof(macho::Header)); + if (isSwappedEndian(this)) + SwapStruct(H); + return H; +} + +macho::SymtabLoadCommand +MachOObjectFile::getSymtabLoadCommand() const { + macho::SymtabLoadCommand Cmd; + memcpy(&Cmd, SymtabLoadCmd, sizeof(macho::SymtabLoadCommand)); + if (isSwappedEndian(this)) + SwapStruct(Cmd); + return Cmd; +} + +bool MachOObjectFile::is64Bit() const { + return getType() == getMachOType(false, true) || + getType() == getMachOType(true, true); +} + +void MachOObjectFile::ReadULEB128s(uint64_t Index, + SmallVectorImpl<uint64_t> &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); + } +} + +ObjectFile *ObjectFile::createMachOObjectFile(MemoryBuffer *Buffer) { + StringRef Magic = Buffer->getBuffer().slice(0, 4); + error_code ec; + ObjectFile *Ret; + if (Magic == "\xFE\xED\xFA\xCE") + Ret = new MachOObjectFile(Buffer, false, false, ec); + else if (Magic == "\xCE\xFA\xED\xFE") + Ret = new MachOObjectFile(Buffer, true, false, ec); + else if (Magic == "\xFE\xED\xFA\xCF") + Ret = new MachOObjectFile(Buffer, false, true, ec); + else if (Magic == "\xCF\xFA\xED\xFE") + Ret = new MachOObjectFile(Buffer, true, true, ec); + else + return NULL; + + if (ec) + return NULL; + return Ret; +} + } // end namespace object } // end namespace llvm diff --git a/test/tools/llvm-readobj/Inputs/trivial.obj.macho-arm b/test/tools/llvm-readobj/Inputs/trivial.obj.macho-arm Binary files differnew file mode 100644 index 0000000..117df9e --- /dev/null +++ b/test/tools/llvm-readobj/Inputs/trivial.obj.macho-arm diff --git a/test/tools/llvm-readobj/relocations.test b/test/tools/llvm-readobj/relocations.test index 6dc08ee..c23a7fe 100644 --- a/test/tools/llvm-readobj/relocations.test +++ b/test/tools/llvm-readobj/relocations.test @@ -10,6 +10,8 @@ RUN: llvm-readobj -r %p/Inputs/trivial.obj.macho-ppc \ RUN: | FileCheck %s -check-prefix MACHO-PPC RUN: llvm-readobj -r %p/Inputs/trivial.obj.macho-ppc64 \ RUN: | FileCheck %s -check-prefix MACHO-PPC64 +RUN: llvm-readobj -r -expand-relocs %p/Inputs/trivial.obj.macho-arm \ +RUN: | FileCheck %s -check-prefix MACHO-ARM COFF: Relocations [ COFF-NEXT: Section (1) .text { @@ -82,3 +84,90 @@ MACHO-PPC64-NEXT: Section __la_symbol_ptr { MACHO-PPC64-NEXT: 0x0 0 3 1 0 dyld_stub_binding_helper MACHO-PPC64-NEXT: } MACHO-PPC64-NEXT: ] + + +MACHO-ARM: Relocations [ +MACHO-ARM-NEXT: Section __text { +MACHO-ARM-NEXT: Relocation { +MACHO-ARM-NEXT: Offset: 0x38 +MACHO-ARM-NEXT: PCRel: 0 +MACHO-ARM-NEXT: Length: 2 +MACHO-ARM-NEXT: Extern: N/A +MACHO-ARM-NEXT: Type: ARM_RELOC_SECTDIFF (2) +MACHO-ARM-NEXT: Symbol: _b +MACHO-ARM-NEXT: Scattered: 1 +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: Relocation { +MACHO-ARM-NEXT: Offset: 0x0 +MACHO-ARM-NEXT: PCRel: 0 +MACHO-ARM-NEXT: Length: 2 +MACHO-ARM-NEXT: Extern: N/A +MACHO-ARM-NEXT: Type: ARM_RELOC_PAIR (1) +MACHO-ARM-NEXT: Symbol: _b +MACHO-ARM-NEXT: Scattered: 1 +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: Relocation { +MACHO-ARM-NEXT: Offset: 0x20 +MACHO-ARM-NEXT: PCRel: 1 +MACHO-ARM-NEXT: Length: 2 +MACHO-ARM-NEXT: Extern: 1 +MACHO-ARM-NEXT: Type: ARM_RELOC_BR24 (5) +MACHO-ARM-NEXT: Symbol: _g +MACHO-ARM-NEXT: Scattered: 0 +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: Relocation { +MACHO-ARM-NEXT: Offset: 0x1C +MACHO-ARM-NEXT: PCRel: 0 +MACHO-ARM-NEXT: Length: 1 +MACHO-ARM-NEXT: Extern: 1 +MACHO-ARM-NEXT: Type: ARM_RELOC_HALF (8) +MACHO-ARM-NEXT: Symbol: _g +MACHO-ARM-NEXT: Scattered: 0 +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: Relocation { +MACHO-ARM-NEXT: Offset: 0x0 +MACHO-ARM-NEXT: PCRel: 0 +MACHO-ARM-NEXT: Length: 1 +MACHO-ARM-NEXT: Extern: 0 +MACHO-ARM-NEXT: Type: ARM_RELOC_PAIR (1) +MACHO-ARM-NEXT: Symbol: _b +MACHO-ARM-NEXT: Scattered: 0 +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: Relocation { +MACHO-ARM-NEXT: Offset: 0x18 +MACHO-ARM-NEXT: PCRel: 0 +MACHO-ARM-NEXT: Length: 0 +MACHO-ARM-NEXT: Extern: 1 +MACHO-ARM-NEXT: Type: ARM_RELOC_HALF (8) +MACHO-ARM-NEXT: Symbol: _g +MACHO-ARM-NEXT: Scattered: 0 +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: Relocation { +MACHO-ARM-NEXT: Offset: 0x0 +MACHO-ARM-NEXT: PCRel: 0 +MACHO-ARM-NEXT: Length: 0 +MACHO-ARM-NEXT: Extern: 0 +MACHO-ARM-NEXT: Type: ARM_RELOC_PAIR (1) +MACHO-ARM-NEXT: Symbol: _b +MACHO-ARM-NEXT: Scattered: 0 +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: Relocation { +MACHO-ARM-NEXT: Offset: 0xC +MACHO-ARM-NEXT: PCRel: 0 +MACHO-ARM-NEXT: Length: 2 +MACHO-ARM-NEXT: Extern: N/A +MACHO-ARM-NEXT: Type: ARM_RELOC_SECTDIFF (2) +MACHO-ARM-NEXT: Symbol: _b +MACHO-ARM-NEXT: Scattered: 1 +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: Relocation { +MACHO-ARM-NEXT: Offset: 0x0 +MACHO-ARM-NEXT: PCRel: 0 +MACHO-ARM-NEXT: Length: 2 +MACHO-ARM-NEXT: Extern: N/A +MACHO-ARM-NEXT: Type: ARM_RELOC_PAIR (1) +MACHO-ARM-NEXT: Symbol: _b +MACHO-ARM-NEXT: Scattered: 1 +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: ] diff --git a/test/tools/llvm-readobj/sections-ext.test b/test/tools/llvm-readobj/sections-ext.test index 3e42ab9..526ddfe 100644 --- a/test/tools/llvm-readobj/sections-ext.test +++ b/test/tools/llvm-readobj/sections-ext.test @@ -10,6 +10,8 @@ RUN: llvm-readobj -s -st -sr -sd %p/Inputs/trivial.obj.macho-ppc \ RUN: | FileCheck %s -check-prefix MACHO-PPC RUN: llvm-readobj -s -st -sr -sd %p/Inputs/trivial.obj.macho-ppc64 \ RUN: | FileCheck %s -check-prefix MACHO-PPC64 +RUN: llvm-readobj -expand-relocs -s -st -sr -sd %p/Inputs/trivial.obj.macho-arm \ +RUN: | FileCheck %s -check-prefix MACHO-ARM COFF: Sections [ COFF-NEXT: Section { @@ -562,3 +564,278 @@ MACHO-PPC64-NEXT: 0000: 00000000 00000000 |........| MACHO-PPC64-NEXT: ) MACHO-PPC64-NEXT: } MACHO-PPC64-NEXT: ] + +MACHO-ARM: Sections [ +MACHO-ARM-NEXT: Section { +MACHO-ARM-NEXT: Index: 0 +MACHO-ARM-NEXT: Name: __text (5F 5F 74 65 78 74 00 00 00 00 00 00 00 00 00 00) +MACHO-ARM-NEXT: Segment: __TEXT (5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00) +MACHO-ARM-NEXT: Address: 0x0 +MACHO-ARM-NEXT: Size: 0x3C +MACHO-ARM-NEXT: Offset: 664 +MACHO-ARM-NEXT: Alignment: 2 +MACHO-ARM-NEXT: RelocationOffset: 0x2E0 +MACHO-ARM-NEXT: RelocationCount: 9 +MACHO-ARM-NEXT: Type: 0x0 +MACHO-ARM-NEXT: Attributes [ (0x800004) +MACHO-ARM-NEXT: PureInstructions (0x800000) +MACHO-ARM-NEXT: SomeInstructions (0x4) +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: Reserved1: 0x0 +MACHO-ARM-NEXT: Reserved2: 0x0 +MACHO-ARM-NEXT: Relocations [ +MACHO-ARM-NEXT: Relocation { +MACHO-ARM-NEXT: Offset: 0x38 +MACHO-ARM-NEXT: PCRel: 0 +MACHO-ARM-NEXT: Length: 2 +MACHO-ARM-NEXT: Extern: N/A +MACHO-ARM-NEXT: Type: ARM_RELOC_SECTDIFF (2) +MACHO-ARM-NEXT: Symbol: _b +MACHO-ARM-NEXT: Scattered: 1 +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: Relocation { +MACHO-ARM-NEXT: Offset: 0x0 +MACHO-ARM-NEXT: PCRel: 0 +MACHO-ARM-NEXT: Length: 2 +MACHO-ARM-NEXT: Extern: N/A +MACHO-ARM-NEXT: Type: ARM_RELOC_PAIR (1) +MACHO-ARM-NEXT: Symbol: _b +MACHO-ARM-NEXT: Scattered: 1 +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: Relocation { +MACHO-ARM-NEXT: Offset: 0x20 +MACHO-ARM-NEXT: PCRel: 1 +MACHO-ARM-NEXT: Length: 2 +MACHO-ARM-NEXT: Extern: 1 +MACHO-ARM-NEXT: Type: ARM_RELOC_BR24 (5) +MACHO-ARM-NEXT: Symbol: _g +MACHO-ARM-NEXT: Scattered: 0 +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: Relocation { +MACHO-ARM-NEXT: Offset: 0x1C +MACHO-ARM-NEXT: PCRel: 0 +MACHO-ARM-NEXT: Length: 1 +MACHO-ARM-NEXT: Extern: 1 +MACHO-ARM-NEXT: Type: ARM_RELOC_HALF (8) +MACHO-ARM-NEXT: Symbol: _g +MACHO-ARM-NEXT: Scattered: 0 +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: Relocation { +MACHO-ARM-NEXT: Offset: 0x0 +MACHO-ARM-NEXT: PCRel: 0 +MACHO-ARM-NEXT: Length: 1 +MACHO-ARM-NEXT: Extern: 0 +MACHO-ARM-NEXT: Type: ARM_RELOC_PAIR (1) +MACHO-ARM-NEXT: Symbol: _b +MACHO-ARM-NEXT: Scattered: 0 +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: Relocation { +MACHO-ARM-NEXT: Offset: 0x18 +MACHO-ARM-NEXT: PCRel: 0 +MACHO-ARM-NEXT: Length: 0 +MACHO-ARM-NEXT: Extern: 1 +MACHO-ARM-NEXT: Type: ARM_RELOC_HALF (8) +MACHO-ARM-NEXT: Symbol: _g +MACHO-ARM-NEXT: Scattered: 0 +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: Relocation { +MACHO-ARM-NEXT: Offset: 0x0 +MACHO-ARM-NEXT: PCRel: 0 +MACHO-ARM-NEXT: Length: 0 +MACHO-ARM-NEXT: Extern: 0 +MACHO-ARM-NEXT: Type: ARM_RELOC_PAIR (1) +MACHO-ARM-NEXT: Symbol: _b +MACHO-ARM-NEXT: Scattered: 0 +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: Relocation { +MACHO-ARM-NEXT: Offset: 0xC +MACHO-ARM-NEXT: PCRel: 0 +MACHO-ARM-NEXT: Length: 2 +MACHO-ARM-NEXT: Extern: N/A +MACHO-ARM-NEXT: Type: ARM_RELOC_SECTDIFF (2) +MACHO-ARM-NEXT: Symbol: _b +MACHO-ARM-NEXT: Scattered: 1 +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: Relocation { +MACHO-ARM-NEXT: Offset: 0x0 +MACHO-ARM-NEXT: PCRel: 0 +MACHO-ARM-NEXT: Length: 2 +MACHO-ARM-NEXT: Extern: N/A +MACHO-ARM-NEXT: Type: ARM_RELOC_PAIR (1) +MACHO-ARM-NEXT: Symbol: _b +MACHO-ARM-NEXT: Scattered: 1 +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: Symbols [ +MACHO-ARM-NEXT: Symbol { +MACHO-ARM-NEXT: Name: _f (4) +MACHO-ARM-NEXT: Type: 0xF +MACHO-ARM-NEXT: Section: __text (0x1) +MACHO-ARM-NEXT: RefType: UndefinedNonLazy (0x0) +MACHO-ARM-NEXT: Flags [ (0x0) +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: Value: 0x10 +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: Symbol { +MACHO-ARM-NEXT: Name: _h (1) +MACHO-ARM-NEXT: Type: 0xF +MACHO-ARM-NEXT: Section: __text (0x1) +MACHO-ARM-NEXT: RefType: UndefinedNonLazy (0x0) +MACHO-ARM-NEXT: Flags [ (0x0) +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: Value: 0x0 +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: SectionData ( +MACHO-ARM-NEXT: 0000: 04009FE5 00009FE7 1EFF2FE1 38000000 |........../.8...| +MACHO-ARM-NEXT: 0010: 80402DE9 0D70A0E1 000000E3 000040E3 |.@-..p........@.| +MACHO-ARM-NEXT: 0020: F6FFFFEB 0C009FE5 00009FE7 000090E5 |................| +MACHO-ARM-NEXT: 0030: 8040BDE8 1EFF2FE1 10000000 |.@..../.....| +MACHO-ARM-NEXT: ) +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: Section { +MACHO-ARM-NEXT: Index: 1 +MACHO-ARM-NEXT: Name: __textcoal_nt (5F 5F 74 65 78 74 63 6F 61 6C 5F 6E 74 00 00 00) +MACHO-ARM-NEXT: Segment: __TEXT (5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00) +MACHO-ARM-NEXT: Address: 0x3C +MACHO-ARM-NEXT: Size: 0x0 +MACHO-ARM-NEXT: Offset: 724 +MACHO-ARM-NEXT: Alignment: 0 +MACHO-ARM-NEXT: RelocationOffset: 0x0 +MACHO-ARM-NEXT: RelocationCount: 0 +MACHO-ARM-NEXT: Type: 0xB +MACHO-ARM-NEXT: Attributes [ (0x800000) +MACHO-ARM-NEXT: PureInstructions (0x800000) +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: Reserved1: 0x0 +MACHO-ARM-NEXT: Reserved2: 0x0 +MACHO-ARM-NEXT: Relocations [ +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: Symbols [ +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: SectionData ( +MACHO-ARM-NEXT: ) +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: Section { +MACHO-ARM-NEXT: Index: 2 +MACHO-ARM-NEXT: Name: __const_coal (5F 5F 63 6F 6E 73 74 5F 63 6F 61 6C 00 00 00 00) +MACHO-ARM-NEXT: Segment: __TEXT (5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00) +MACHO-ARM-NEXT: Address: 0x3C +MACHO-ARM-NEXT: Size: 0x0 +MACHO-ARM-NEXT: Offset: 724 +MACHO-ARM-NEXT: Alignment: 0 +MACHO-ARM-NEXT: RelocationOffset: 0x0 +MACHO-ARM-NEXT: RelocationCount: 0 +MACHO-ARM-NEXT: Type: 0xB +MACHO-ARM-NEXT: Attributes [ (0x0) +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: Reserved1: 0x0 +MACHO-ARM-NEXT: Reserved2: 0x0 +MACHO-ARM-NEXT: Relocations [ +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: Symbols [ +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: SectionData ( +MACHO-ARM-NEXT: ) +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: Section { +MACHO-ARM-NEXT: Index: 3 +MACHO-ARM-NEXT: Name: __picsymbolstub4 (5F 5F 70 69 63 73 79 6D 62 6F 6C 73 74 75 62 34) +MACHO-ARM-NEXT: Segment: __TEXT (5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00) +MACHO-ARM-NEXT: Address: 0x3C +MACHO-ARM-NEXT: Size: 0x0 +MACHO-ARM-NEXT: Offset: 724 +MACHO-ARM-NEXT: Alignment: 0 +MACHO-ARM-NEXT: RelocationOffset: 0x0 +MACHO-ARM-NEXT: RelocationCount: 0 +MACHO-ARM-NEXT: Type: 0x8 +MACHO-ARM-NEXT: Attributes [ (0x0) +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: Reserved1: 0x0 +MACHO-ARM-NEXT: Reserved2: 0x10 +MACHO-ARM-NEXT: Relocations [ +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: Symbols [ +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: SectionData ( +MACHO-ARM-NEXT: ) +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: Section { +MACHO-ARM-NEXT: Index: 4 +MACHO-ARM-NEXT: Name: __StaticInit (5F 5F 53 74 61 74 69 63 49 6E 69 74 00 00 00 00) +MACHO-ARM-NEXT: Segment: __TEXT (5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00) +MACHO-ARM-NEXT: Address: 0x3C +MACHO-ARM-NEXT: Size: 0x0 +MACHO-ARM-NEXT: Offset: 724 +MACHO-ARM-NEXT: Alignment: 0 +MACHO-ARM-NEXT: RelocationOffset: 0x0 +MACHO-ARM-NEXT: RelocationCount: 0 +MACHO-ARM-NEXT: Type: 0x0 +MACHO-ARM-NEXT: Attributes [ (0x800000) +MACHO-ARM-NEXT: PureInstructions (0x800000) +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: Reserved1: 0x0 +MACHO-ARM-NEXT: Reserved2: 0x0 +MACHO-ARM-NEXT: Relocations [ +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: Symbols [ +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: SectionData ( +MACHO-ARM-NEXT: ) +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: Section { +MACHO-ARM-NEXT: Index: 5 +MACHO-ARM-NEXT: Name: __data (5F 5F 64 61 74 61 00 00 00 00 00 00 00 00 00 00) +MACHO-ARM-NEXT: Segment: __DATA (5F 5F 44 41 54 41 00 00 00 00 00 00 00 00 00 00) +MACHO-ARM-NEXT: Address: 0x3C +MACHO-ARM-NEXT: Size: 0x4 +MACHO-ARM-NEXT: Offset: 724 +MACHO-ARM-NEXT: Alignment: 2 +MACHO-ARM-NEXT: RelocationOffset: 0x0 +MACHO-ARM-NEXT: RelocationCount: 0 +MACHO-ARM-NEXT: Type: 0x0 +MACHO-ARM-NEXT: Attributes [ (0x0) +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: Reserved1: 0x0 +MACHO-ARM-NEXT: Reserved2: 0x0 +MACHO-ARM-NEXT: Relocations [ +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: Symbols [ +MACHO-ARM-NEXT: Symbol { +MACHO-ARM-NEXT: Name: _b (10) +MACHO-ARM-NEXT: Type: 0xF +MACHO-ARM-NEXT: Section: __data (0x6) +MACHO-ARM-NEXT: RefType: UndefinedNonLazy (0x0) +MACHO-ARM-NEXT: Flags [ (0x0) +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: Value: 0x3C +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: SectionData ( +MACHO-ARM-NEXT: 0000: 2A000000 |*...| +MACHO-ARM-NEXT: ) +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: Section { +MACHO-ARM-NEXT: Index: 6 +MACHO-ARM-NEXT: Name: __nl_symbol_ptr (5F 5F 6E 6C 5F 73 79 6D 62 6F 6C 5F 70 74 72 00) +MACHO-ARM-NEXT: Segment: __DATA (5F 5F 44 41 54 41 00 00 00 00 00 00 00 00 00 00) +MACHO-ARM-NEXT: Address: 0x40 +MACHO-ARM-NEXT: Size: 0x8 +MACHO-ARM-NEXT: Offset: 728 +MACHO-ARM-NEXT: Alignment: 2 +MACHO-ARM-NEXT: RelocationOffset: 0x0 +MACHO-ARM-NEXT: RelocationCount: 0 +MACHO-ARM-NEXT: Type: 0x6 +MACHO-ARM-NEXT: Attributes [ (0x0) +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: Reserved1: 0x0 +MACHO-ARM-NEXT: Reserved2: 0x0 +MACHO-ARM-NEXT: Relocations [ +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: Symbols [ +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: SectionData ( +MACHO-ARM-NEXT: 0000: 00000000 00000000 |........| +MACHO-ARM-NEXT: ) +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: ] diff --git a/test/tools/llvm-readobj/sections.test b/test/tools/llvm-readobj/sections.test index b569682..16f1131 100644 --- a/test/tools/llvm-readobj/sections.test +++ b/test/tools/llvm-readobj/sections.test @@ -10,6 +10,8 @@ RUN: llvm-readobj -s %p/Inputs/trivial.obj.macho-ppc \ RUN: | FileCheck %s -check-prefix MACHO-PPC RUN: llvm-readobj -s %p/Inputs/trivial.obj.macho-ppc64 \ RUN: | FileCheck %s -check-prefix MACHO-PPC64 +RUN: llvm-readobj -s %p/Inputs/trivial.obj.macho-arm \ +RUN: | FileCheck %s -check-prefix MACHO-ARM COFF: Sections [ COFF-NEXT: Section { @@ -329,3 +331,122 @@ MACHO-PPC64-NEXT: Reserved1: 0x2 MACHO-PPC64-NEXT: Reserved2: 0x0 MACHO-PPC64-NEXT: } MACHO-PPC64-NEXT: ] + +MACHO-ARM: Sections [ +MACHO-ARM-NEXT: Section { +MACHO-ARM-NEXT: Index: 0 +MACHO-ARM-NEXT: Name: __text (5F 5F 74 65 78 74 00 00 00 00 00 00 00 00 00 00) +MACHO-ARM-NEXT: Segment: __TEXT (5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00) +MACHO-ARM-NEXT: Address: 0x0 +MACHO-ARM-NEXT: Size: 0x3C +MACHO-ARM-NEXT: Offset: 664 +MACHO-ARM-NEXT: Alignment: 2 +MACHO-ARM-NEXT: RelocationOffset: 0x2E0 +MACHO-ARM-NEXT: RelocationCount: 9 +MACHO-ARM-NEXT: Type: 0x0 +MACHO-ARM-NEXT: Attributes [ (0x800004) +MACHO-ARM-NEXT: PureInstructions (0x800000) +MACHO-ARM-NEXT: SomeInstructions (0x4) +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: Reserved1: 0x0 +MACHO-ARM-NEXT: Reserved2: 0x0 +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: Section { +MACHO-ARM-NEXT: Index: 1 +MACHO-ARM-NEXT: Name: __textcoal_nt (5F 5F 74 65 78 74 63 6F 61 6C 5F 6E 74 00 00 00) +MACHO-ARM-NEXT: Segment: __TEXT (5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00) +MACHO-ARM-NEXT: Address: 0x3C +MACHO-ARM-NEXT: Size: 0x0 +MACHO-ARM-NEXT: Offset: 724 +MACHO-ARM-NEXT: Alignment: 0 +MACHO-ARM-NEXT: RelocationOffset: 0x0 +MACHO-ARM-NEXT: RelocationCount: 0 +MACHO-ARM-NEXT: Type: 0xB +MACHO-ARM-NEXT: Attributes [ (0x800000) +MACHO-ARM-NEXT: PureInstructions (0x800000) +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: Reserved1: 0x0 +MACHO-ARM-NEXT: Reserved2: 0x0 +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: Section { +MACHO-ARM-NEXT: Index: 2 +MACHO-ARM-NEXT: Name: __const_coal (5F 5F 63 6F 6E 73 74 5F 63 6F 61 6C 00 00 00 00) +MACHO-ARM-NEXT: Segment: __TEXT (5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00) +MACHO-ARM-NEXT: Address: 0x3C +MACHO-ARM-NEXT: Size: 0x0 +MACHO-ARM-NEXT: Offset: 724 +MACHO-ARM-NEXT: Alignment: 0 +MACHO-ARM-NEXT: RelocationOffset: 0x0 +MACHO-ARM-NEXT: RelocationCount: 0 +MACHO-ARM-NEXT: Type: 0xB +MACHO-ARM-NEXT: Attributes [ (0x0) +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: Reserved1: 0x0 +MACHO-ARM-NEXT: Reserved2: 0x0 +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: Section { +MACHO-ARM-NEXT: Index: 3 +MACHO-ARM-NEXT: Name: __picsymbolstub4 (5F 5F 70 69 63 73 79 6D 62 6F 6C 73 74 75 62 34) +MACHO-ARM-NEXT: Segment: __TEXT (5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00) +MACHO-ARM-NEXT: Address: 0x3C +MACHO-ARM-NEXT: Size: 0x0 +MACHO-ARM-NEXT: Offset: 724 +MACHO-ARM-NEXT: Alignment: 0 +MACHO-ARM-NEXT: RelocationOffset: 0x0 +MACHO-ARM-NEXT: RelocationCount: 0 +MACHO-ARM-NEXT: Type: 0x8 +MACHO-ARM-NEXT: Attributes [ (0x0) +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: Reserved1: 0x0 +MACHO-ARM-NEXT: Reserved2: 0x10 +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: Section { +MACHO-ARM-NEXT: Index: 4 +MACHO-ARM-NEXT: Name: __StaticInit (5F 5F 53 74 61 74 69 63 49 6E 69 74 00 00 00 00) +MACHO-ARM-NEXT: Segment: __TEXT (5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00) +MACHO-ARM-NEXT: Address: 0x3C +MACHO-ARM-NEXT: Size: 0x0 +MACHO-ARM-NEXT: Offset: 724 +MACHO-ARM-NEXT: Alignment: 0 +MACHO-ARM-NEXT: RelocationOffset: 0x0 +MACHO-ARM-NEXT: RelocationCount: 0 +MACHO-ARM-NEXT: Type: 0x0 +MACHO-ARM-NEXT: Attributes [ (0x800000) +MACHO-ARM-NEXT: PureInstructions (0x800000) +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: Reserved1: 0x0 +MACHO-ARM-NEXT: Reserved2: 0x0 +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: Section { +MACHO-ARM-NEXT: Index: 5 +MACHO-ARM-NEXT: Name: __data (5F 5F 64 61 74 61 00 00 00 00 00 00 00 00 00 00) +MACHO-ARM-NEXT: Segment: __DATA (5F 5F 44 41 54 41 00 00 00 00 00 00 00 00 00 00) +MACHO-ARM-NEXT: Address: 0x3C +MACHO-ARM-NEXT: Size: 0x4 +MACHO-ARM-NEXT: Offset: 724 +MACHO-ARM-NEXT: Alignment: 2 +MACHO-ARM-NEXT: RelocationOffset: 0x0 +MACHO-ARM-NEXT: RelocationCount: 0 +MACHO-ARM-NEXT: Type: 0x0 +MACHO-ARM-NEXT: Attributes [ (0x0) +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: Reserved1: 0x0 +MACHO-ARM-NEXT: Reserved2: 0x0 +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT: Section { +MACHO-ARM-NEXT: Index: 6 +MACHO-ARM-NEXT: Name: __nl_symbol_ptr (5F 5F 6E 6C 5F 73 79 6D 62 6F 6C 5F 70 74 72 00) +MACHO-ARM-NEXT: Segment: __DATA (5F 5F 44 41 54 41 00 00 00 00 00 00 00 00 00 00) +MACHO-ARM-NEXT: Address: 0x40 +MACHO-ARM-NEXT: Size: 0x8 +MACHO-ARM-NEXT: Offset: 728 +MACHO-ARM-NEXT: Alignment: 2 +MACHO-ARM-NEXT: RelocationOffset: 0x0 +MACHO-ARM-NEXT: RelocationCount: 0 +MACHO-ARM-NEXT: Type: 0x6 +MACHO-ARM-NEXT: Attributes [ (0x0) +MACHO-ARM-NEXT: ] +MACHO-ARM-NEXT: Reserved1: 0x0 +MACHO-ARM-NEXT: Reserved2: 0x0 +MACHO-ARM-NEXT: } +MACHO-ARM-NEXT:] diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp index 4b6cb5f..e4d9ce2 100644 --- a/tools/llvm-objdump/MachODump.cpp +++ b/tools/llvm-objdump/MachODump.cpp @@ -53,7 +53,7 @@ static cl::opt<bool> static cl::opt<std::string> DSYMFile("dsym", cl::desc("Use .dSYM file for debug info")); -static const Target *GetTarget(const MachOObjectFileBase *MachOObj) { +static const Target *GetTarget(const MachOObjectFile *MachOObj) { // Figure out the target triple. if (TripleName.empty()) { llvm::Triple TT("unknown-unknown-unknown"); @@ -93,7 +93,7 @@ struct SymbolSorter { // Print additional information about an address, if available. static void DumpAddress(uint64_t Address, ArrayRef<SectionRef> Sections, - const MachOObjectFileBase *MachOObj, raw_ostream &OS) { + const MachOObjectFile *MachOObj, raw_ostream &OS) { for (unsigned i = 0; i != Sections.size(); ++i) { uint64_t SectAddr = 0, SectSize = 0; Sections[i].getAddress(SectAddr); @@ -184,14 +184,12 @@ static void emitDOTFile(const char *FileName, const MCFunction &f, Out << "}\n"; } -template<endianness E> static void -getSectionsAndSymbols(const typename MachOObjectFileMiddle<E>::Header *Header, - const MachOObjectFileMiddle<E> *MachOObj, +getSectionsAndSymbols(const macho::Header Header, + MachOObjectFile *MachOObj, std::vector<SectionRef> &Sections, std::vector<SymbolRef> &Symbols, SmallVectorImpl<uint64_t> &FoundFns) { - typedef MachOObjectFileMiddle<E> ObjType; error_code ec; for (symbol_iterator SI = MachOObj->begin_symbols(), SE = MachOObj->end_symbols(); SI != SE; SI.increment(ec)) @@ -205,23 +203,23 @@ getSectionsAndSymbols(const typename MachOObjectFileMiddle<E>::Header *Header, Sections.push_back(*SI); } - for (unsigned i = 0; i != Header->NumLoadCommands; ++i) { - const typename ObjType::LoadCommand *Command = - MachOObj->getLoadCommandInfo(i); - if (Command->Type == macho::LCT_FunctionStarts) { + MachOObjectFile::LoadCommandInfo Command = + MachOObj->getFirstLoadCommandInfo(); + for (unsigned i = 0; i != Header.NumLoadCommands; ++i) { + if (Command.C.Type == macho::LCT_FunctionStarts) { // We found a function starts segment, parse the addresses for later // consumption. - const typename ObjType::LinkeditDataLoadCommand *LLC = - reinterpret_cast<const typename ObjType::LinkeditDataLoadCommand*>(Command); + macho::LinkeditDataLoadCommand LLC = + MachOObj->getLinkeditDataLoadCommand(Command); - MachOObj->ReadULEB128s(LLC->DataOffset, FoundFns); + MachOObj->ReadULEB128s(LLC.DataOffset, FoundFns); } + Command = MachOObj->getNextLoadCommandInfo(Command); } } -template<endianness E> static void DisassembleInputMachO2(StringRef Filename, - MachOObjectFileMiddle<E> *MachOOF); + MachOObjectFile *MachOOF); void llvm::DisassembleInputMachO(StringRef Filename) { OwningPtr<MemoryBuffer> Buff; @@ -231,20 +229,14 @@ void llvm::DisassembleInputMachO(StringRef Filename) { return; } - OwningPtr<MachOObjectFileBase> MachOOF(static_cast<MachOObjectFileBase*>( + OwningPtr<MachOObjectFile> MachOOF(static_cast<MachOObjectFile*>( ObjectFile::createMachOObjectFile(Buff.take()))); - if (MachOObjectFileLE *O = dyn_cast<MachOObjectFileLE>(MachOOF.get())) { - DisassembleInputMachO2(Filename, O); - return; - } - MachOObjectFileBE *O = cast<MachOObjectFileBE>(MachOOF.get()); - DisassembleInputMachO2(Filename, O); + DisassembleInputMachO2(Filename, MachOOF.get()); } -template<endianness E> static void DisassembleInputMachO2(StringRef Filename, - MachOObjectFileMiddle<E> *MachOOF) { + MachOObjectFile *MachOOF) { const Target *TheTarget = GetTarget(MachOOF); if (!TheTarget) { // GetTarget prints out stuff. @@ -273,8 +265,7 @@ static void DisassembleInputMachO2(StringRef Filename, outs() << '\n' << Filename << ":\n\n"; - const typename MachOObjectFileMiddle<E>::Header *Header = - MachOOF->getHeader(); + macho::Header Header = MachOOF->getHeader(); std::vector<SectionRef> Sections; std::vector<SymbolRef> Symbols; diff --git a/tools/llvm-objdump/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp index 6f4b101..9985599 100644 --- a/tools/llvm-objdump/llvm-objdump.cpp +++ b/tools/llvm-objdump/llvm-objdump.cpp @@ -191,14 +191,6 @@ bool llvm::RelocAddressLess(RelocationRef a, RelocationRef b) { return a_addr < b_addr; } -StringRef -getSectionFinalSegmentName(const MachOObjectFileBase *MachO, DataRefImpl DR) { - if (const MachOObjectFileLE *O = dyn_cast<MachOObjectFileLE>(MachO)) - return O->getSectionFinalSegmentName(DR); - const MachOObjectFileBE *O = dyn_cast<MachOObjectFileBE>(MachO); - return O->getSectionFinalSegmentName(DR); -} - static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { const Target *TheTarget = getTarget(Obj); // getTarget() will have already issued a diagnostic if necessary, so @@ -263,10 +255,10 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { std::sort(Rels.begin(), Rels.end(), RelocAddressLess); StringRef SegmentName = ""; - if (const MachOObjectFileBase *MachO = - dyn_cast<const MachOObjectFileBase>(Obj)) { + if (const MachOObjectFile *MachO = + dyn_cast<const MachOObjectFile>(Obj)) { DataRefImpl DR = i->getRawDataRefImpl(); - SegmentName = getSectionFinalSegmentName(MachO, DR); + SegmentName = MachO->getSectionFinalSegmentName(DR); } StringRef name; if (error(i->getName(name))) break; @@ -608,10 +600,10 @@ static void PrintSymbolTable(const ObjectFile *o) { else if (Section == o->end_sections()) outs() << "*UND*"; else { - if (const MachOObjectFileBase *MachO = - dyn_cast<const MachOObjectFileBase>(o)) { + if (const MachOObjectFile *MachO = + dyn_cast<const MachOObjectFile>(o)) { DataRefImpl DR = Section->getRawDataRefImpl(); - StringRef SegmentName = getSectionFinalSegmentName(MachO, DR); + StringRef SegmentName = MachO->getSectionFinalSegmentName(DR); outs() << SegmentName << ","; } StringRef SectionName; diff --git a/tools/llvm-readobj/MachODumper.cpp b/tools/llvm-readobj/MachODumper.cpp index d4eaae6..54de49c 100644 --- a/tools/llvm-readobj/MachODumper.cpp +++ b/tools/llvm-readobj/MachODumper.cpp @@ -27,7 +27,7 @@ namespace { class MachODumper : public ObjDumper { public: - MachODumper(const MachOObjectFileBase *Obj, StreamWriter& Writer) + MachODumper(const MachOObjectFile *Obj, StreamWriter& Writer) : ObjDumper(Writer) , Obj(Obj) { } @@ -43,14 +43,12 @@ private: void printRelocation(section_iterator SecI, relocation_iterator RelI); - template<support::endianness E> - void printRelocation(const MachOObjectFileMiddle<E> *Obj, + void printRelocation(const MachOObjectFile *Obj, section_iterator SecI, relocation_iterator RelI); - template<support::endianness E> - void printSections(const MachOObjectFileMiddle<E> *Obj); + void printSections(const MachOObjectFile *Obj); - const MachOObjectFileBase *Obj; + const MachOObjectFile *Obj; }; } // namespace @@ -61,7 +59,7 @@ namespace llvm { error_code createMachODumper(const object::ObjectFile *Obj, StreamWriter& Writer, OwningPtr<ObjDumper> &Result) { - const MachOObjectFileBase *MachOObj = dyn_cast<MachOObjectFileBase>(Obj); + const MachOObjectFile *MachOObj = dyn_cast<MachOObjectFile>(Obj); if (!MachOObj) return readobj_error::unsupported_obj_file_format; @@ -164,59 +162,53 @@ namespace { }; } -template<class MachOT> -static void getSection(const MachOObjectFile<MachOT> *Obj, - DataRefImpl DRI, +static void getSection(const MachOObjectFile *Obj, + DataRefImpl Sec, MachOSection &Section) { - const typename MachOObjectFile<MachOT>::Section *Sect = Obj->getSection(DRI); - Section.Address = Sect->Address; - Section.Size = Sect->Size; - Section.Offset = Sect->Offset; - Section.Alignment = Sect->Align; - Section.RelocationTableOffset = Sect->RelocationTableOffset; - Section.NumRelocationTableEntries = Sect->NumRelocationTableEntries; - Section.Flags = Sect->Flags; - Section.Reserved1 = Sect->Reserved1; - Section.Reserved2 = Sect->Reserved2; -} - -static void getSection(const MachOObjectFileBase *Obj, - DataRefImpl DRI, - MachOSection &Section) { - if (const MachOObjectFileLE32 *O = dyn_cast<MachOObjectFileLE32>(Obj)) - return getSection(O, DRI, Section); - if (const MachOObjectFileLE64 *O = dyn_cast<MachOObjectFileLE64>(Obj)) - return getSection(O, DRI, Section); - if (const MachOObjectFileBE32 *O = dyn_cast<MachOObjectFileBE32>(Obj)) - return getSection(O, DRI, Section); - const MachOObjectFileBE64 *O = cast<MachOObjectFileBE64>(Obj); - getSection(O, DRI, Section); + if (!Obj->is64Bit()) { + macho::Section Sect = Obj->getSection(Sec); + Section.Address = Sect.Address; + Section.Size = Sect.Size; + Section.Offset = Sect.Offset; + Section.Alignment = Sect.Align; + Section.RelocationTableOffset = Sect.RelocationTableOffset; + Section.NumRelocationTableEntries = Sect.NumRelocationTableEntries; + Section.Flags = Sect.Flags; + Section.Reserved1 = Sect.Reserved1; + Section.Reserved2 = Sect.Reserved2; + return; + } + macho::Section64 Sect = Obj->getSection64(Sec); + Section.Address = Sect.Address; + Section.Size = Sect.Size; + Section.Offset = Sect.Offset; + Section.Alignment = Sect.Align; + Section.RelocationTableOffset = Sect.RelocationTableOffset; + Section.NumRelocationTableEntries = Sect.NumRelocationTableEntries; + Section.Flags = Sect.Flags; + Section.Reserved1 = Sect.Reserved1; + Section.Reserved2 = Sect.Reserved2; } -template<class MachOT> -static void getSymbol(const MachOObjectFile<MachOT> *Obj, - DataRefImpl DRI, - MachOSymbol &Symbol) { - const typename MachOObjectFile<MachOT>::SymbolTableEntry *Entry = - Obj->getSymbolTableEntry(DRI); - Symbol.StringIndex = Entry->StringIndex; - Symbol.Type = Entry->Type; - Symbol.SectionIndex = Entry->SectionIndex; - Symbol.Flags = Entry->Flags; - Symbol.Value = Entry->Value; -} -static void getSymbol(const MachOObjectFileBase *Obj, +static void getSymbol(const MachOObjectFile *Obj, DataRefImpl DRI, MachOSymbol &Symbol) { - if (const MachOObjectFileLE32 *O = dyn_cast<MachOObjectFileLE32>(Obj)) - return getSymbol(O, DRI, Symbol); - if (const MachOObjectFileLE64 *O = dyn_cast<MachOObjectFileLE64>(Obj)) - return getSymbol(O, DRI, Symbol); - if (const MachOObjectFileBE32 *O = dyn_cast<MachOObjectFileBE32>(Obj)) - return getSymbol(O, DRI, Symbol); - const MachOObjectFileBE64 *O = cast<MachOObjectFileBE64>(Obj); - getSymbol(O, DRI, Symbol); + if (!Obj->is64Bit()) { + macho::SymbolTableEntry Entry = Obj->getSymbolTableEntry(DRI); + Symbol.StringIndex = Entry.StringIndex; + Symbol.Type = Entry.Type; + Symbol.SectionIndex = Entry.SectionIndex; + Symbol.Flags = Entry.Flags; + Symbol.Value = Entry.Value; + return; + } + macho::Symbol64TableEntry Entry = Obj->getSymbol64TableEntry(DRI); + Symbol.StringIndex = Entry.StringIndex; + Symbol.Type = Entry.Type; + Symbol.SectionIndex = Entry.SectionIndex; + Symbol.Flags = Entry.Flags; + Symbol.Value = Entry.Value; } void MachODumper::printFileHeaders() { @@ -224,14 +216,10 @@ void MachODumper::printFileHeaders() { } void MachODumper::printSections() { - if (const MachOObjectFileLE *O = dyn_cast<MachOObjectFileLE>(Obj)) - return printSections(O); - const MachOObjectFileBE *O = cast<MachOObjectFileBE>(Obj); - return printSections(O); + return printSections(Obj); } -template<support::endianness E> -void MachODumper::printSections(const MachOObjectFileMiddle<E> *Obj) { +void MachODumper::printSections(const MachOObjectFile *Obj) { ListScope Group(W, "Sections"); int SectionIndex = -1; @@ -344,14 +332,10 @@ void MachODumper::printRelocations() { void MachODumper::printRelocation(section_iterator SecI, relocation_iterator RelI) { - if (const MachOObjectFileLE *O = dyn_cast<MachOObjectFileLE>(Obj)) - return printRelocation(O, SecI, RelI); - const MachOObjectFileBE *O = cast<MachOObjectFileBE>(Obj); - return printRelocation(O, SecI, RelI); + return printRelocation(Obj, SecI, RelI); } -template<support::endianness E> -void MachODumper::printRelocation(const MachOObjectFileMiddle<E> *Obj, +void MachODumper::printRelocation(const MachOObjectFile *Obj, section_iterator SecI, relocation_iterator RelI) { uint64_t Offset; @@ -364,31 +348,30 @@ void MachODumper::printRelocation(const MachOObjectFileMiddle<E> *Obj, if (error(Symbol.getName(SymbolName))) return; DataRefImpl DR = RelI->getRawDataRefImpl(); - const typename MachOObjectFileMiddle<E>::RelocationEntry *RE = - Obj->getRelocation(DR); + macho::RelocationEntry RE = Obj->getRelocation(DR); bool IsScattered = Obj->isRelocationScattered(RE); if (opts::ExpandRelocs) { DictScope Group(W, "Relocation"); W.printHex("Offset", Offset); - W.printNumber("PCRel", Obj->isRelocationPCRel(RE)); - W.printNumber("Length", Obj->getRelocationLength(RE)); + W.printNumber("PCRel", Obj->getAnyRelocationPCRel(RE)); + W.printNumber("Length", Obj->getAnyRelocationLength(RE)); if (IsScattered) W.printString("Extern", StringRef("N/A")); else - W.printNumber("Extern", RE->External); - W.printNumber("Type", RelocName, RE->Type); + W.printNumber("Extern", Obj->getPlainRelocationExternal(RE)); + W.printNumber("Type", RelocName, Obj->getAnyRelocationType(RE)); W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-"); W.printNumber("Scattered", IsScattered); } else { raw_ostream& OS = W.startLine(); OS << W.hex(Offset) - << " " << Obj->isRelocationPCRel(RE) - << " " << Obj->getRelocationLength(RE); + << " " << Obj->getAnyRelocationPCRel(RE) + << " " << Obj->getAnyRelocationLength(RE); if (IsScattered) OS << " n/a"; else - OS << " " << RE->External; + OS << " " << Obj->getPlainRelocationExternal(RE); OS << " " << RelocName << " " << IsScattered << " " << (SymbolName.size() > 0 ? SymbolName : "-") diff --git a/tools/llvm-symbolizer/LLVMSymbolize.cpp b/tools/llvm-symbolizer/LLVMSymbolize.cpp index ffe8712..29d91a0 100644 --- a/tools/llvm-symbolizer/LLVMSymbolize.cpp +++ b/tools/llvm-symbolizer/LLVMSymbolize.cpp @@ -233,7 +233,7 @@ LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) { // On Darwin we may find DWARF in separate object file in // resource directory. ObjectFile *DbgObj = Obj; - if (isa<MachOObjectFileBase>(Obj)) { + if (isa<MachOObjectFile>(Obj)) { const std::string &ResourceName = getDarwinDWARFResourceForModule(ModuleName); ObjectFile *ResourceObj = getObjectFile(ResourceName); |