diff options
Diffstat (limited to 'contrib/llvm/lib/Object')
-rw-r--r-- | contrib/llvm/lib/Object/Archive.cpp | 272 | ||||
-rw-r--r-- | contrib/llvm/lib/Object/Binary.cpp | 103 | ||||
-rw-r--r-- | contrib/llvm/lib/Object/COFFObjectFile.cpp | 789 | ||||
-rw-r--r-- | contrib/llvm/lib/Object/ELFObjectFile.cpp | 50 | ||||
-rw-r--r-- | contrib/llvm/lib/Object/Error.cpp | 57 | ||||
-rw-r--r-- | contrib/llvm/lib/Object/MachOObject.cpp | 397 | ||||
-rw-r--r-- | contrib/llvm/lib/Object/MachOObjectFile.cpp | 1293 | ||||
-rw-r--r-- | contrib/llvm/lib/Object/Object.cpp | 218 | ||||
-rw-r--r-- | contrib/llvm/lib/Object/ObjectFile.cpp | 64 |
9 files changed, 3243 insertions, 0 deletions
diff --git a/contrib/llvm/lib/Object/Archive.cpp b/contrib/llvm/lib/Object/Archive.cpp new file mode 100644 index 0000000..c5f15ba --- /dev/null +++ b/contrib/llvm/lib/Object/Archive.cpp @@ -0,0 +1,272 @@ +//===- Archive.cpp - ar File Format implementation --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ArchiveObjectFile class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/Archive.h" +#include "llvm/ADT/APInt.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/MemoryBuffer.h" + +using namespace llvm; +using namespace object; + +static const char *Magic = "!<arch>\n"; + +namespace { +struct ArchiveMemberHeader { + char Name[16]; + char LastModified[12]; + char UID[6]; + char GID[6]; + char AccessMode[8]; + char Size[10]; //< Size of data, not including header or padding. + char Terminator[2]; + + ///! Get the name without looking up long names. + StringRef getName() const { + char EndCond; + if (Name[0] == '/' || Name[0] == '#') + EndCond = ' '; + else + EndCond = '/'; + StringRef::size_type end = StringRef(Name, sizeof(Name)).find(EndCond); + if (end == StringRef::npos) + end = sizeof(Name); + assert(end <= sizeof(Name) && end > 0); + // Don't include the EndCond if there is one. + return StringRef(Name, end); + } + + uint64_t getSize() const { + APInt ret; + StringRef(Size, sizeof(Size)).getAsInteger(10, ret); + return ret.getZExtValue(); + } +}; +} + +static const ArchiveMemberHeader *ToHeader(const char *base) { + return reinterpret_cast<const ArchiveMemberHeader *>(base); +} + + +static bool isInternalMember(const ArchiveMemberHeader &amh) { + const char *internals[] = { + "/", + "//", + "#_LLVM_SYM_TAB_#" + }; + + StringRef name = amh.getName(); + for (std::size_t i = 0; i < sizeof(internals) / sizeof(*internals); ++i) { + if (name == internals[i]) + return true; + } + return false; +} + +void Archive::anchor() { } + +Archive::Child Archive::Child::getNext() const { + size_t SpaceToSkip = sizeof(ArchiveMemberHeader) + + ToHeader(Data.data())->getSize(); + // If it's odd, add 1 to make it even. + if (SpaceToSkip & 1) + ++SpaceToSkip; + + const char *NextLoc = Data.data() + SpaceToSkip; + + // Check to see if this is past the end of the archive. + if (NextLoc >= Parent->Data->getBufferEnd()) + return Child(Parent, StringRef(0, 0)); + + size_t NextSize = sizeof(ArchiveMemberHeader) + + ToHeader(NextLoc)->getSize(); + + return Child(Parent, StringRef(NextLoc, NextSize)); +} + +error_code Archive::Child::getName(StringRef &Result) const { + StringRef name = ToHeader(Data.data())->getName(); + // Check if it's a special name. + if (name[0] == '/') { + if (name.size() == 1) { // Linker member. + Result = name; + return object_error::success; + } + if (name.size() == 2 && name[1] == '/') { // String table. + Result = name; + return object_error::success; + } + // It's a long name. + // Get the offset. + APInt offset; + name.substr(1).getAsInteger(10, offset); + const char *addr = Parent->StringTable->Data.begin() + + sizeof(ArchiveMemberHeader) + + offset.getZExtValue(); + // Verify it. + if (Parent->StringTable == Parent->end_children() + || addr < (Parent->StringTable->Data.begin() + + sizeof(ArchiveMemberHeader)) + || addr > (Parent->StringTable->Data.begin() + + sizeof(ArchiveMemberHeader) + + Parent->StringTable->getSize())) + return object_error::parse_failed; + Result = addr; + return object_error::success; + } else if (name.startswith("#1/")) { + APInt name_size; + name.substr(3).getAsInteger(10, name_size); + Result = Data.substr(0, name_size.getZExtValue()); + return object_error::success; + } + // It's a simple name. + if (name[name.size() - 1] == '/') + Result = name.substr(0, name.size() - 1); + else + Result = name; + return object_error::success; +} + +uint64_t Archive::Child::getSize() const { + uint64_t size = ToHeader(Data.data())->getSize(); + // Don't include attached name. + StringRef name = ToHeader(Data.data())->getName(); + if (name.startswith("#1/")) { + APInt name_size; + name.substr(3).getAsInteger(10, name_size); + size -= name_size.getZExtValue(); + } + return size; +} + +MemoryBuffer *Archive::Child::getBuffer() const { + StringRef name; + if (getName(name)) return NULL; + int size = sizeof(ArchiveMemberHeader); + if (name.startswith("#1/")) { + APInt name_size; + name.substr(3).getAsInteger(10, name_size); + size += name_size.getZExtValue(); + } + return MemoryBuffer::getMemBuffer(Data.substr(size, getSize()), + name, + false); +} + +error_code Archive::Child::getAsBinary(OwningPtr<Binary> &Result) const { + OwningPtr<Binary> ret; + if (error_code ec = + createBinary(getBuffer(), ret)) + return ec; + Result.swap(ret); + return object_error::success; +} + +Archive::Archive(MemoryBuffer *source, error_code &ec) + : Binary(Binary::ID_Archive, source) { + // Check for sufficient magic. + if (!source || source->getBufferSize() + < (8 + sizeof(ArchiveMemberHeader) + 2) // Smallest archive. + || StringRef(source->getBufferStart(), 8) != Magic) { + ec = object_error::invalid_file_type; + return; + } + + // Get the special members. + child_iterator i = begin_children(false); + child_iterator e = end_children(); + + if (i != e) ++i; // Nobody cares about the first member. + if (i != e) { + SymbolTable = i; + ++i; + } + if (i != e) { + StringTable = i; + } + + ec = object_error::success; +} + +Archive::child_iterator Archive::begin_children(bool skip_internal) const { + const char *Loc = Data->getBufferStart() + strlen(Magic); + size_t Size = sizeof(ArchiveMemberHeader) + + ToHeader(Loc)->getSize(); + Child c(this, StringRef(Loc, Size)); + // Skip internals at the beginning of an archive. + if (skip_internal && isInternalMember(*ToHeader(Loc))) + return c.getNext(); + return c; +} + +Archive::child_iterator Archive::end_children() const { + return Child(this, StringRef(0, 0)); +} + +error_code Archive::Symbol::getName(StringRef &Result) const { + Result = + StringRef(Parent->SymbolTable->getBuffer()->getBufferStart() + StringIndex); + return object_error::success; +} + +error_code Archive::Symbol::getMember(child_iterator &Result) const { + const char *buf = Parent->SymbolTable->getBuffer()->getBufferStart(); + uint32_t member_count = *reinterpret_cast<const support::ulittle32_t*>(buf); + const char *offsets = buf + 4; + buf += 4 + (member_count * 4); // Skip offsets. + const char *indicies = buf + 4; + + uint16_t offsetindex = + *(reinterpret_cast<const support::ulittle16_t*>(indicies) + + SymbolIndex); + + uint32_t offset = *(reinterpret_cast<const support::ulittle32_t*>(offsets) + + (offsetindex - 1)); + + const char *Loc = Parent->getData().begin() + offset; + size_t Size = sizeof(ArchiveMemberHeader) + + ToHeader(Loc)->getSize(); + Result = Child(Parent, StringRef(Loc, Size)); + + return object_error::success; +} + +Archive::Symbol Archive::Symbol::getNext() const { + Symbol t(*this); + // Go to one past next null. + t.StringIndex = + Parent->SymbolTable->getBuffer()->getBuffer().find('\0', t.StringIndex) + 1; + ++t.SymbolIndex; + return t; +} + +Archive::symbol_iterator Archive::begin_symbols() const { + const char *buf = SymbolTable->getBuffer()->getBufferStart(); + uint32_t member_count = *reinterpret_cast<const support::ulittle32_t*>(buf); + buf += 4 + (member_count * 4); // Skip offsets. + uint32_t symbol_count = *reinterpret_cast<const support::ulittle32_t*>(buf); + buf += 4 + (symbol_count * 2); // Skip indices. + uint32_t string_start_offset = + buf - SymbolTable->getBuffer()->getBufferStart(); + return symbol_iterator(Symbol(this, 0, string_start_offset)); +} + +Archive::symbol_iterator Archive::end_symbols() const { + const char *buf = SymbolTable->getBuffer()->getBufferStart(); + uint32_t member_count = *reinterpret_cast<const support::ulittle32_t*>(buf); + buf += 4 + (member_count * 4); // Skip offsets. + uint32_t symbol_count = *reinterpret_cast<const support::ulittle32_t*>(buf); + return symbol_iterator( + Symbol(this, symbol_count, 0)); +} diff --git a/contrib/llvm/lib/Object/Binary.cpp b/contrib/llvm/lib/Object/Binary.cpp new file mode 100644 index 0000000..4e528d8 --- /dev/null +++ b/contrib/llvm/lib/Object/Binary.cpp @@ -0,0 +1,103 @@ +//===- Binary.cpp - A generic binary file -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Binary class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/Binary.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" + +// Include headers for createBinary. +#include "llvm/Object/Archive.h" +#include "llvm/Object/COFF.h" +#include "llvm/Object/ObjectFile.h" + +using namespace llvm; +using namespace object; + +Binary::~Binary() { + delete Data; +} + +Binary::Binary(unsigned int Type, MemoryBuffer *Source) + : TypeID(Type) + , Data(Source) {} + +StringRef Binary::getData() const { + return Data->getBuffer(); +} + +StringRef Binary::getFileName() const { + return Data->getBufferIdentifier(); +} + +error_code object::createBinary(MemoryBuffer *Source, + OwningPtr<Binary> &Result) { + OwningPtr<MemoryBuffer> scopedSource(Source); + if (!Source) + return make_error_code(errc::invalid_argument); + if (Source->getBufferSize() < 64) + return object_error::invalid_file_type; + sys::LLVMFileType type = sys::IdentifyFileType(Source->getBufferStart(), + static_cast<unsigned>(Source->getBufferSize())); + error_code ec; + switch (type) { + case sys::Archive_FileType: { + OwningPtr<Binary> ret(new Archive(scopedSource.take(), ec)); + if (ec) return ec; + Result.swap(ret); + return object_error::success; + } + case sys::ELF_Relocatable_FileType: + case sys::ELF_Executable_FileType: + case sys::ELF_SharedObject_FileType: + case sys::ELF_Core_FileType: { + OwningPtr<Binary> ret( + ObjectFile::createELFObjectFile(scopedSource.take())); + if (!ret) + return object_error::invalid_file_type; + Result.swap(ret); + return object_error::success; + } + case sys::Mach_O_Object_FileType: + case sys::Mach_O_Executable_FileType: + case sys::Mach_O_FixedVirtualMemorySharedLib_FileType: + case sys::Mach_O_Core_FileType: + case sys::Mach_O_PreloadExecutable_FileType: + case sys::Mach_O_DynamicallyLinkedSharedLib_FileType: + case sys::Mach_O_DynamicLinker_FileType: + case sys::Mach_O_Bundle_FileType: + case sys::Mach_O_DynamicallyLinkedSharedLibStub_FileType: { + OwningPtr<Binary> ret( + ObjectFile::createMachOObjectFile(scopedSource.take())); + if (!ret) + return object_error::invalid_file_type; + Result.swap(ret); + return object_error::success; + } + case sys::COFF_FileType: { + OwningPtr<Binary> ret(new COFFObjectFile(scopedSource.take(), ec)); + if (ec) return ec; + Result.swap(ret); + return object_error::success; + } + default: // Unrecognized object file format. + return object_error::invalid_file_type; + } +} + +error_code object::createBinary(StringRef Path, OwningPtr<Binary> &Result) { + OwningPtr<MemoryBuffer> File; + if (error_code ec = MemoryBuffer::getFileOrSTDIN(Path, File)) + return ec; + return createBinary(File.take(), Result); +} diff --git a/contrib/llvm/lib/Object/COFFObjectFile.cpp b/contrib/llvm/lib/Object/COFFObjectFile.cpp new file mode 100644 index 0000000..bd27a56 --- /dev/null +++ b/contrib/llvm/lib/Object/COFFObjectFile.cpp @@ -0,0 +1,789 @@ +//===- COFFObjectFile.cpp - COFF object file implementation -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the COFFObjectFile class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/COFF.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Triple.h" + +using namespace llvm; +using namespace object; + +namespace { +using support::ulittle8_t; +using support::ulittle16_t; +using support::ulittle32_t; +using support::little16_t; +} + +namespace { +// Returns false if size is greater than the buffer size. And sets ec. +bool checkSize(const MemoryBuffer *m, error_code &ec, uint64_t size) { + if (m->getBufferSize() < size) { + ec = object_error::unexpected_eof; + return false; + } + return true; +} + +// Returns false if any bytes in [addr, addr + size) fall outsize of m. +bool checkAddr(const MemoryBuffer *m, + error_code &ec, + uintptr_t addr, + uint64_t size) { + if (addr + size < addr || + addr + size < size || + addr + size > uintptr_t(m->getBufferEnd())) { + ec = object_error::unexpected_eof; + return false; + } + return true; +} +} + +const coff_symbol *COFFObjectFile::toSymb(DataRefImpl Symb) const { + const coff_symbol *addr = reinterpret_cast<const coff_symbol*>(Symb.p); + +# ifndef NDEBUG + // Verify that the symbol points to a valid entry in the symbol table. + uintptr_t offset = uintptr_t(addr) - uintptr_t(base()); + if (offset < Header->PointerToSymbolTable + || offset >= Header->PointerToSymbolTable + + (Header->NumberOfSymbols * sizeof(coff_symbol))) + report_fatal_error("Symbol was outside of symbol table."); + + assert((offset - Header->PointerToSymbolTable) % sizeof(coff_symbol) + == 0 && "Symbol did not point to the beginning of a symbol"); +# endif + + return addr; +} + +const coff_section *COFFObjectFile::toSec(DataRefImpl Sec) const { + const coff_section *addr = reinterpret_cast<const coff_section*>(Sec.p); + +# ifndef NDEBUG + // Verify that the section points to a valid entry in the section table. + if (addr < SectionTable + || addr >= (SectionTable + Header->NumberOfSections)) + report_fatal_error("Section was outside of section table."); + + uintptr_t offset = uintptr_t(addr) - uintptr_t(SectionTable); + assert(offset % sizeof(coff_section) == 0 && + "Section did not point to the beginning of a section"); +# endif + + return addr; +} + +error_code COFFObjectFile::getSymbolNext(DataRefImpl Symb, + SymbolRef &Result) const { + const coff_symbol *symb = toSymb(Symb); + symb += 1 + symb->NumberOfAuxSymbols; + Symb.p = reinterpret_cast<uintptr_t>(symb); + Result = SymbolRef(Symb, this); + return object_error::success; +} + + error_code COFFObjectFile::getSymbolName(DataRefImpl Symb, + StringRef &Result) const { + const coff_symbol *symb = toSymb(Symb); + return getSymbolName(symb, Result); +} + +error_code COFFObjectFile::getSymbolFileOffset(DataRefImpl Symb, + uint64_t &Result) const { + const coff_symbol *symb = toSymb(Symb); + const coff_section *Section = NULL; + if (error_code ec = getSection(symb->SectionNumber, Section)) + return ec; + char Type; + if (error_code ec = getSymbolNMTypeChar(Symb, Type)) + return ec; + if (Type == 'U' || Type == 'w') + Result = UnknownAddressOrSize; + else if (Section) + Result = Section->PointerToRawData + symb->Value; + else + Result = symb->Value; + return object_error::success; +} + +error_code COFFObjectFile::getSymbolAddress(DataRefImpl Symb, + uint64_t &Result) const { + const coff_symbol *symb = toSymb(Symb); + const coff_section *Section = NULL; + if (error_code ec = getSection(symb->SectionNumber, Section)) + return ec; + char Type; + if (error_code ec = getSymbolNMTypeChar(Symb, Type)) + return ec; + if (Type == 'U' || Type == 'w') + Result = UnknownAddressOrSize; + else if (Section) + Result = Section->VirtualAddress + symb->Value; + else + Result = symb->Value; + return object_error::success; +} + +error_code COFFObjectFile::getSymbolType(DataRefImpl Symb, + SymbolRef::Type &Result) const { + const coff_symbol *symb = toSymb(Symb); + Result = SymbolRef::ST_Other; + if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL && + symb->SectionNumber == COFF::IMAGE_SYM_UNDEFINED) { + Result = SymbolRef::ST_Unknown; + } else { + if (symb->getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION) { + Result = SymbolRef::ST_Function; + } else { + char Type; + if (error_code ec = getSymbolNMTypeChar(Symb, Type)) + return ec; + if (Type == 'r' || Type == 'R') { + Result = SymbolRef::ST_Data; + } + } + } + return object_error::success; +} + +error_code COFFObjectFile::getSymbolFlags(DataRefImpl Symb, + uint32_t &Result) const { + const coff_symbol *symb = toSymb(Symb); + Result = SymbolRef::SF_None; + + // TODO: Correctly set SF_FormatSpecific, SF_ThreadLocal, SF_Common + + if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL && + symb->SectionNumber == COFF::IMAGE_SYM_UNDEFINED) + Result |= SymbolRef::SF_Undefined; + + // TODO: This are certainly too restrictive. + if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL) + Result |= SymbolRef::SF_Global; + + if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL) + Result |= SymbolRef::SF_Weak; + + if (symb->SectionNumber == COFF::IMAGE_SYM_ABSOLUTE) + Result |= SymbolRef::SF_Absolute; + + return object_error::success; +} + +error_code COFFObjectFile::getSymbolSize(DataRefImpl Symb, + uint64_t &Result) const { + // FIXME: Return the correct size. This requires looking at all the symbols + // in the same section as this symbol, and looking for either the next + // symbol, or the end of the section. + const coff_symbol *symb = toSymb(Symb); + const coff_section *Section = NULL; + if (error_code ec = getSection(symb->SectionNumber, Section)) + return ec; + char Type; + if (error_code ec = getSymbolNMTypeChar(Symb, Type)) + return ec; + if (Type == 'U' || Type == 'w') + Result = UnknownAddressOrSize; + else if (Section) + Result = Section->SizeOfRawData - symb->Value; + else + Result = 0; + return object_error::success; +} + +error_code COFFObjectFile::getSymbolNMTypeChar(DataRefImpl Symb, + char &Result) const { + const coff_symbol *symb = toSymb(Symb); + StringRef name; + if (error_code ec = getSymbolName(Symb, name)) + return ec; + char ret = StringSwitch<char>(name) + .StartsWith(".debug", 'N') + .StartsWith(".sxdata", 'N') + .Default('?'); + + if (ret != '?') { + Result = ret; + return object_error::success; + } + + uint32_t Characteristics = 0; + if (symb->SectionNumber > 0) { + const coff_section *Section = NULL; + if (error_code ec = getSection(symb->SectionNumber, Section)) + return ec; + Characteristics = Section->Characteristics; + } + + switch (symb->SectionNumber) { + case COFF::IMAGE_SYM_UNDEFINED: + // Check storage classes. + if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL) { + Result = 'w'; + return object_error::success; // Don't do ::toupper. + } else if (symb->Value != 0) // Check for common symbols. + ret = 'c'; + else + ret = 'u'; + break; + case COFF::IMAGE_SYM_ABSOLUTE: + ret = 'a'; + break; + case COFF::IMAGE_SYM_DEBUG: + ret = 'n'; + break; + default: + // Check section type. + if (Characteristics & COFF::IMAGE_SCN_CNT_CODE) + ret = 't'; + else if ( Characteristics & COFF::IMAGE_SCN_MEM_READ + && ~Characteristics & COFF::IMAGE_SCN_MEM_WRITE) // Read only. + ret = 'r'; + else if (Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA) + ret = 'd'; + else if (Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) + ret = 'b'; + else if (Characteristics & COFF::IMAGE_SCN_LNK_INFO) + ret = 'i'; + + // Check for section symbol. + else if ( symb->StorageClass == COFF::IMAGE_SYM_CLASS_STATIC + && symb->Value == 0) + ret = 's'; + } + + if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL) + ret = ::toupper(ret); + + Result = ret; + return object_error::success; +} + +error_code COFFObjectFile::getSymbolSection(DataRefImpl Symb, + section_iterator &Result) const { + const coff_symbol *symb = toSymb(Symb); + if (symb->SectionNumber <= COFF::IMAGE_SYM_UNDEFINED) + Result = end_sections(); + else { + const coff_section *sec = 0; + if (error_code ec = getSection(symb->SectionNumber, sec)) return ec; + DataRefImpl Sec; + Sec.p = reinterpret_cast<uintptr_t>(sec); + Result = section_iterator(SectionRef(Sec, this)); + } + return object_error::success; +} + +error_code COFFObjectFile::getSectionNext(DataRefImpl Sec, + SectionRef &Result) const { + const coff_section *sec = toSec(Sec); + sec += 1; + Sec.p = reinterpret_cast<uintptr_t>(sec); + Result = SectionRef(Sec, this); + return object_error::success; +} + +error_code COFFObjectFile::getSectionName(DataRefImpl Sec, + StringRef &Result) const { + const coff_section *sec = toSec(Sec); + return getSectionName(sec, Result); +} + +error_code COFFObjectFile::getSectionAddress(DataRefImpl Sec, + uint64_t &Result) const { + const coff_section *sec = toSec(Sec); + Result = sec->VirtualAddress; + return object_error::success; +} + +error_code COFFObjectFile::getSectionSize(DataRefImpl Sec, + uint64_t &Result) const { + const coff_section *sec = toSec(Sec); + Result = sec->SizeOfRawData; + return object_error::success; +} + +error_code COFFObjectFile::getSectionContents(DataRefImpl Sec, + StringRef &Result) const { + const coff_section *sec = toSec(Sec); + ArrayRef<uint8_t> Res; + error_code EC = getSectionContents(sec, Res); + Result = StringRef(reinterpret_cast<const char*>(Res.data()), Res.size()); + return EC; +} + +error_code COFFObjectFile::getSectionAlignment(DataRefImpl Sec, + uint64_t &Res) const { + const coff_section *sec = toSec(Sec); + if (!sec) + return object_error::parse_failed; + Res = uint64_t(1) << (((sec->Characteristics & 0x00F00000) >> 20) - 1); + return object_error::success; +} + +error_code COFFObjectFile::isSectionText(DataRefImpl Sec, + bool &Result) const { + const coff_section *sec = toSec(Sec); + Result = sec->Characteristics & COFF::IMAGE_SCN_CNT_CODE; + return object_error::success; +} + +error_code COFFObjectFile::isSectionData(DataRefImpl Sec, + bool &Result) const { + const coff_section *sec = toSec(Sec); + Result = sec->Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA; + return object_error::success; +} + +error_code COFFObjectFile::isSectionBSS(DataRefImpl Sec, + bool &Result) const { + const coff_section *sec = toSec(Sec); + Result = sec->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA; + return object_error::success; +} + +error_code COFFObjectFile::isSectionRequiredForExecution(DataRefImpl Sec, + bool &Result) const { + // FIXME: Unimplemented + Result = true; + return object_error::success; +} + +error_code COFFObjectFile::isSectionVirtual(DataRefImpl Sec, + bool &Result) const { + const coff_section *sec = toSec(Sec); + Result = sec->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA; + return object_error::success; +} + +error_code COFFObjectFile::isSectionZeroInit(DataRefImpl Sec, + bool &Result) const { + // FIXME: Unimplemented + Result = false; + return object_error::success; +} + +error_code COFFObjectFile::sectionContainsSymbol(DataRefImpl Sec, + DataRefImpl Symb, + bool &Result) const { + const coff_section *sec = toSec(Sec); + const coff_symbol *symb = toSymb(Symb); + const coff_section *symb_sec = 0; + if (error_code ec = getSection(symb->SectionNumber, symb_sec)) return ec; + if (symb_sec == sec) + Result = true; + else + Result = false; + return object_error::success; +} + +relocation_iterator COFFObjectFile::getSectionRelBegin(DataRefImpl Sec) const { + const coff_section *sec = toSec(Sec); + DataRefImpl ret; + if (sec->NumberOfRelocations == 0) + ret.p = 0; + else + ret.p = reinterpret_cast<uintptr_t>(base() + sec->PointerToRelocations); + + return relocation_iterator(RelocationRef(ret, this)); +} + +relocation_iterator COFFObjectFile::getSectionRelEnd(DataRefImpl Sec) const { + const coff_section *sec = toSec(Sec); + DataRefImpl ret; + if (sec->NumberOfRelocations == 0) + ret.p = 0; + else + ret.p = reinterpret_cast<uintptr_t>( + reinterpret_cast<const coff_relocation*>( + base() + sec->PointerToRelocations) + + sec->NumberOfRelocations); + + return relocation_iterator(RelocationRef(ret, this)); +} + +COFFObjectFile::COFFObjectFile(MemoryBuffer *Object, error_code &ec) + : ObjectFile(Binary::ID_COFF, Object, ec) + , Header(0) + , SectionTable(0) + , SymbolTable(0) + , StringTable(0) + , StringTableSize(0) { + // Check that we at least have enough room for a header. + if (!checkSize(Data, ec, sizeof(coff_file_header))) return; + + // The actual starting location of the COFF header in the file. This can be + // non-zero in PE/COFF files. + uint64_t HeaderStart = 0; + + // Check if this is a PE/COFF file. + if (base()[0] == 0x4d && base()[1] == 0x5a) { + // PE/COFF, seek through MS-DOS compatibility stub and 4-byte + // PE signature to find 'normal' COFF header. + if (!checkSize(Data, ec, 0x3c + 8)) return; + HeaderStart = *reinterpret_cast<const ulittle16_t *>(base() + 0x3c); + // Check the PE header. ("PE\0\0") + if (std::memcmp(base() + HeaderStart, "PE\0\0", 4) != 0) { + ec = object_error::parse_failed; + return; + } + HeaderStart += 4; // Skip the PE Header. + } + + Header = reinterpret_cast<const coff_file_header *>(base() + HeaderStart); + if (!checkAddr(Data, ec, uintptr_t(Header), sizeof(coff_file_header))) + return; + + SectionTable = + reinterpret_cast<const coff_section *>( base() + + HeaderStart + + sizeof(coff_file_header) + + Header->SizeOfOptionalHeader); + if (!checkAddr(Data, ec, uintptr_t(SectionTable), + Header->NumberOfSections * sizeof(coff_section))) + return; + + if (Header->PointerToSymbolTable != 0) { + SymbolTable = + reinterpret_cast<const coff_symbol *>(base() + + Header->PointerToSymbolTable); + if (!checkAddr(Data, ec, uintptr_t(SymbolTable), + Header->NumberOfSymbols * sizeof(coff_symbol))) + return; + + // Find string table. + StringTable = reinterpret_cast<const char *>(base()) + + Header->PointerToSymbolTable + + Header->NumberOfSymbols * sizeof(coff_symbol); + if (!checkAddr(Data, ec, uintptr_t(StringTable), sizeof(ulittle32_t))) + return; + + StringTableSize = *reinterpret_cast<const ulittle32_t *>(StringTable); + if (!checkAddr(Data, ec, uintptr_t(StringTable), StringTableSize)) + return; + // Check that the string table is null terminated if has any in it. + if (StringTableSize < 4 + || (StringTableSize > 4 && StringTable[StringTableSize - 1] != 0)) { + ec = object_error::parse_failed; + return; + } + } + + ec = object_error::success; +} + +symbol_iterator COFFObjectFile::begin_symbols() const { + DataRefImpl ret; + ret.p = reinterpret_cast<intptr_t>(SymbolTable); + return symbol_iterator(SymbolRef(ret, this)); +} + +symbol_iterator COFFObjectFile::end_symbols() const { + // The symbol table ends where the string table begins. + DataRefImpl ret; + ret.p = reinterpret_cast<intptr_t>(StringTable); + return symbol_iterator(SymbolRef(ret, this)); +} + +symbol_iterator COFFObjectFile::begin_dynamic_symbols() const { + // TODO: implement + report_fatal_error("Dynamic symbols unimplemented in COFFObjectFile"); +} + +symbol_iterator COFFObjectFile::end_dynamic_symbols() const { + // TODO: implement + report_fatal_error("Dynamic symbols unimplemented in COFFObjectFile"); +} + +library_iterator COFFObjectFile::begin_libraries_needed() const { + // TODO: implement + report_fatal_error("Libraries needed unimplemented in COFFObjectFile"); +} + +library_iterator COFFObjectFile::end_libraries_needed() const { + // TODO: implement + report_fatal_error("Libraries needed unimplemented in COFFObjectFile"); +} + +StringRef COFFObjectFile::getLoadName() const { + // COFF does not have this field. + return ""; +} + + +section_iterator COFFObjectFile::begin_sections() const { + DataRefImpl ret; + ret.p = reinterpret_cast<intptr_t>(SectionTable); + return section_iterator(SectionRef(ret, this)); +} + +section_iterator COFFObjectFile::end_sections() const { + DataRefImpl ret; + ret.p = reinterpret_cast<intptr_t>(SectionTable + Header->NumberOfSections); + return section_iterator(SectionRef(ret, this)); +} + +uint8_t COFFObjectFile::getBytesInAddress() const { + return getArch() == Triple::x86_64 ? 8 : 4; +} + +StringRef COFFObjectFile::getFileFormatName() const { + switch(Header->Machine) { + case COFF::IMAGE_FILE_MACHINE_I386: + return "COFF-i386"; + case COFF::IMAGE_FILE_MACHINE_AMD64: + return "COFF-x86-64"; + default: + return "COFF-<unknown arch>"; + } +} + +unsigned COFFObjectFile::getArch() const { + switch(Header->Machine) { + case COFF::IMAGE_FILE_MACHINE_I386: + return Triple::x86; + case COFF::IMAGE_FILE_MACHINE_AMD64: + return Triple::x86_64; + default: + return Triple::UnknownArch; + } +} + +error_code COFFObjectFile::getHeader(const coff_file_header *&Res) const { + Res = Header; + return object_error::success; +} + +error_code COFFObjectFile::getSection(int32_t index, + const coff_section *&Result) const { + // Check for special index values. + if (index == COFF::IMAGE_SYM_UNDEFINED || + index == COFF::IMAGE_SYM_ABSOLUTE || + index == COFF::IMAGE_SYM_DEBUG) + Result = NULL; + else if (index > 0 && index <= Header->NumberOfSections) + // We already verified the section table data, so no need to check again. + Result = SectionTable + (index - 1); + else + return object_error::parse_failed; + return object_error::success; +} + +error_code COFFObjectFile::getString(uint32_t offset, + StringRef &Result) const { + if (StringTableSize <= 4) + // Tried to get a string from an empty string table. + return object_error::parse_failed; + if (offset >= StringTableSize) + return object_error::unexpected_eof; + Result = StringRef(StringTable + offset); + return object_error::success; +} + +error_code COFFObjectFile::getSymbol(uint32_t index, + const coff_symbol *&Result) const { + if (index < Header->NumberOfSymbols) + Result = SymbolTable + index; + else + return object_error::parse_failed; + return object_error::success; +} + +error_code COFFObjectFile::getSymbolName(const coff_symbol *symbol, + StringRef &Res) const { + // Check for string table entry. First 4 bytes are 0. + if (symbol->Name.Offset.Zeroes == 0) { + uint32_t Offset = symbol->Name.Offset.Offset; + if (error_code ec = getString(Offset, Res)) + return ec; + return object_error::success; + } + + if (symbol->Name.ShortName[7] == 0) + // Null terminated, let ::strlen figure out the length. + Res = StringRef(symbol->Name.ShortName); + else + // Not null terminated, use all 8 bytes. + Res = StringRef(symbol->Name.ShortName, 8); + return object_error::success; +} + +error_code COFFObjectFile::getSectionName(const coff_section *Sec, + StringRef &Res) const { + StringRef Name; + if (Sec->Name[7] == 0) + // Null terminated, let ::strlen figure out the length. + Name = Sec->Name; + else + // Not null terminated, use all 8 bytes. + Name = StringRef(Sec->Name, 8); + + // Check for string table entry. First byte is '/'. + if (Name[0] == '/') { + uint32_t Offset; + if (Name.substr(1).getAsInteger(10, Offset)) + return object_error::parse_failed; + if (error_code ec = getString(Offset, Name)) + return ec; + } + + Res = Name; + return object_error::success; +} + +error_code COFFObjectFile::getSectionContents(const coff_section *Sec, + ArrayRef<uint8_t> &Res) const { + // The only thing that we need to verify is that the contents is contained + // within the file bounds. We don't need to make sure it doesn't cover other + // data, as there's nothing that says that is not allowed. + uintptr_t ConStart = uintptr_t(base()) + Sec->PointerToRawData; + uintptr_t ConEnd = ConStart + Sec->SizeOfRawData; + if (ConEnd > uintptr_t(Data->getBufferEnd())) + return object_error::parse_failed; + Res = ArrayRef<uint8_t>(reinterpret_cast<const unsigned char*>(ConStart), + Sec->SizeOfRawData); + return object_error::success; +} + +const coff_relocation *COFFObjectFile::toRel(DataRefImpl Rel) const { + return reinterpret_cast<const coff_relocation*>(Rel.p); +} +error_code COFFObjectFile::getRelocationNext(DataRefImpl Rel, + RelocationRef &Res) const { + Rel.p = reinterpret_cast<uintptr_t>( + reinterpret_cast<const coff_relocation*>(Rel.p) + 1); + Res = RelocationRef(Rel, this); + return object_error::success; +} +error_code COFFObjectFile::getRelocationAddress(DataRefImpl Rel, + uint64_t &Res) const { + Res = toRel(Rel)->VirtualAddress; + return object_error::success; +} +error_code COFFObjectFile::getRelocationOffset(DataRefImpl Rel, + uint64_t &Res) const { + Res = toRel(Rel)->VirtualAddress; + return object_error::success; +} +error_code COFFObjectFile::getRelocationSymbol(DataRefImpl Rel, + SymbolRef &Res) const { + const coff_relocation* R = toRel(Rel); + DataRefImpl Symb; + Symb.p = reinterpret_cast<uintptr_t>(SymbolTable + R->SymbolTableIndex); + Res = SymbolRef(Symb, this); + return object_error::success; +} +error_code COFFObjectFile::getRelocationType(DataRefImpl Rel, + uint64_t &Res) const { + const coff_relocation* R = toRel(Rel); + Res = R->Type; + return object_error::success; +} + +#define LLVM_COFF_SWITCH_RELOC_TYPE_NAME(enum) \ + case COFF::enum: res = #enum; break; + +error_code COFFObjectFile::getRelocationTypeName(DataRefImpl Rel, + SmallVectorImpl<char> &Result) const { + const coff_relocation *reloc = toRel(Rel); + StringRef res; + switch (Header->Machine) { + case COFF::IMAGE_FILE_MACHINE_AMD64: + switch (reloc->Type) { + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ABSOLUTE); + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR64); + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR32); + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR32NB); + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32); + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_1); + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_2); + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_3); + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_4); + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_5); + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECTION); + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECREL); + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECREL7); + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_TOKEN); + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SREL32); + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_PAIR); + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SSPAN32); + default: + res = "Unknown"; + } + break; + case COFF::IMAGE_FILE_MACHINE_I386: + switch (reloc->Type) { + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_ABSOLUTE); + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR16); + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_REL16); + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR32); + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR32NB); + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SEG12); + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECTION); + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECREL); + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_TOKEN); + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECREL7); + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_REL32); + default: + res = "Unknown"; + } + break; + default: + res = "Unknown"; + } + Result.append(res.begin(), res.end()); + return object_error::success; +} + +#undef LLVM_COFF_SWITCH_RELOC_TYPE_NAME + +error_code COFFObjectFile::getRelocationAdditionalInfo(DataRefImpl Rel, + int64_t &Res) const { + Res = 0; + return object_error::success; +} +error_code COFFObjectFile::getRelocationValueString(DataRefImpl Rel, + SmallVectorImpl<char> &Result) const { + const coff_relocation *reloc = toRel(Rel); + const coff_symbol *symb = 0; + if (error_code ec = getSymbol(reloc->SymbolTableIndex, symb)) return ec; + DataRefImpl sym; + sym.p = reinterpret_cast<uintptr_t>(symb); + StringRef symname; + if (error_code ec = getSymbolName(sym, symname)) return ec; + Result.append(symname.begin(), symname.end()); + return object_error::success; +} + +error_code COFFObjectFile::getLibraryNext(DataRefImpl LibData, + LibraryRef &Result) const { + report_fatal_error("getLibraryNext not implemented in COFFObjectFile"); +} + +error_code COFFObjectFile::getLibraryPath(DataRefImpl LibData, + StringRef &Result) const { + report_fatal_error("getLibraryPath not implemented in COFFObjectFile"); +} + +namespace llvm { + + ObjectFile *ObjectFile::createCOFFObjectFile(MemoryBuffer *Object) { + error_code ec; + return new COFFObjectFile(Object, ec); + } + +} // end namespace llvm diff --git a/contrib/llvm/lib/Object/ELFObjectFile.cpp b/contrib/llvm/lib/Object/ELFObjectFile.cpp new file mode 100644 index 0000000..ab5f810 --- /dev/null +++ b/contrib/llvm/lib/Object/ELFObjectFile.cpp @@ -0,0 +1,50 @@ +//===- ELFObjectFile.cpp - ELF object file implementation -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Part of the ELFObjectFile class implementation. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/ELF.h" + +namespace llvm { + +using namespace object; + +namespace { + std::pair<unsigned char, unsigned char> + getElfArchType(MemoryBuffer *Object) { + if (Object->getBufferSize() < ELF::EI_NIDENT) + return std::make_pair((uint8_t)ELF::ELFCLASSNONE,(uint8_t)ELF::ELFDATANONE); + return std::make_pair( (uint8_t)Object->getBufferStart()[ELF::EI_CLASS] + , (uint8_t)Object->getBufferStart()[ELF::EI_DATA]); + } +} + +// Creates an in-memory object-file by default: createELFObjectFile(Buffer) +ObjectFile *ObjectFile::createELFObjectFile(MemoryBuffer *Object) { + std::pair<unsigned char, unsigned char> Ident = getElfArchType(Object); + error_code ec; + + if (Ident.first == ELF::ELFCLASS32 && Ident.second == ELF::ELFDATA2LSB) + return new ELFObjectFile<support::little, false>(Object, ec); + else if (Ident.first == ELF::ELFCLASS32 && Ident.second == ELF::ELFDATA2MSB) + return new ELFObjectFile<support::big, false>(Object, ec); + else if (Ident.first == ELF::ELFCLASS64 && Ident.second == ELF::ELFDATA2MSB) + return new ELFObjectFile<support::big, true>(Object, ec); + else if (Ident.first == ELF::ELFCLASS64 && Ident.second == ELF::ELFDATA2LSB) { + ELFObjectFile<support::little, true> *result = + new ELFObjectFile<support::little, true>(Object, ec); + return result; + } + + report_fatal_error("Buffer is not an ELF object file!"); +} + +} // end namespace llvm diff --git a/contrib/llvm/lib/Object/Error.cpp b/contrib/llvm/lib/Object/Error.cpp new file mode 100644 index 0000000..2594625 --- /dev/null +++ b/contrib/llvm/lib/Object/Error.cpp @@ -0,0 +1,57 @@ +//===- Error.cpp - system_error extensions for Object -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines a new error_category for the Object library. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/Error.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; +using namespace object; + +namespace { +class _object_error_category : public _do_message { +public: + virtual const char* name() const; + virtual std::string message(int ev) const; + virtual error_condition default_error_condition(int ev) const; +}; +} + +const char *_object_error_category::name() const { + return "llvm.object"; +} + +std::string _object_error_category::message(int ev) const { + switch (ev) { + case object_error::success: return "Success"; + case object_error::invalid_file_type: + return "The file was not recognized as a valid object file"; + case object_error::parse_failed: + return "Invalid data was encountered while parsing the file"; + case object_error::unexpected_eof: + return "The end of the file was unexpectedly encountered"; + default: + llvm_unreachable("An enumerator of object_error does not have a message " + "defined."); + } +} + +error_condition _object_error_category::default_error_condition(int ev) const { + if (ev == object_error::success) + return errc::success; + return errc::invalid_argument; +} + +const error_category &object::object_category() { + static _object_error_category o; + return o; +} diff --git a/contrib/llvm/lib/Object/MachOObject.cpp b/contrib/llvm/lib/Object/MachOObject.cpp new file mode 100644 index 0000000..b7e5cdc --- /dev/null +++ b/contrib/llvm/lib/Object/MachOObject.cpp @@ -0,0 +1,397 @@ +//===- MachOObject.cpp - Mach-O Object File Wrapper -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/MachOObject.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/SwapByteOrder.h" + +using namespace llvm; +using namespace llvm::object; + +/* Translation Utilities */ + +template<typename T> +static void SwapValue(T &Value) { + Value = sys::SwapByteOrder(Value); +} + +template<typename T> +static void SwapStruct(T &Value); + +template<typename T> +static void ReadInMemoryStruct(const MachOObject &MOO, + StringRef Buffer, uint64_t Base, + InMemoryStruct<T> &Res) { + typedef T struct_type; + uint64_t Size = sizeof(struct_type); + + // Check that the buffer contains the expected data. + if (Base + Size > Buffer.size()) { + Res = 0; + return; + } + + // Check whether we can return a direct pointer. + struct_type *Ptr = (struct_type *) (Buffer.data() + Base); + if (!MOO.isSwappedEndian()) { + Res = Ptr; + return; + } + + // Otherwise, copy the struct and translate the values. + Res = *Ptr; + SwapStruct(*Res); +} + +/* *** */ + +MachOObject::MachOObject(MemoryBuffer *Buffer_, bool IsLittleEndian_, + bool Is64Bit_) + : Buffer(Buffer_), IsLittleEndian(IsLittleEndian_), Is64Bit(Is64Bit_), + IsSwappedEndian(IsLittleEndian != sys::isLittleEndianHost()), + HasStringTable(false), LoadCommands(0), NumLoadedCommands(0) { + // Load the common header. + memcpy(&Header, Buffer->getBuffer().data(), sizeof(Header)); + if (IsSwappedEndian) { + SwapValue(Header.Magic); + SwapValue(Header.CPUType); + SwapValue(Header.CPUSubtype); + SwapValue(Header.FileType); + SwapValue(Header.NumLoadCommands); + SwapValue(Header.SizeOfLoadCommands); + SwapValue(Header.Flags); + } + + if (is64Bit()) { + memcpy(&Header64Ext, Buffer->getBuffer().data() + sizeof(Header), + sizeof(Header64Ext)); + if (IsSwappedEndian) { + SwapValue(Header64Ext.Reserved); + } + } + + // Create the load command array if sane. + if (getHeader().NumLoadCommands < (1 << 20)) + LoadCommands = new LoadCommandInfo[getHeader().NumLoadCommands]; +} + +MachOObject::~MachOObject() { + delete [] LoadCommands; +} + +MachOObject *MachOObject::LoadFromBuffer(MemoryBuffer *Buffer, + std::string *ErrorStr) { + // First, check the magic value and initialize the basic object info. + bool IsLittleEndian = false, Is64Bit = false; + StringRef Magic = Buffer->getBuffer().slice(0, 4); + if (Magic == "\xFE\xED\xFA\xCE") { + } else if (Magic == "\xCE\xFA\xED\xFE") { + IsLittleEndian = true; + } else if (Magic == "\xFE\xED\xFA\xCF") { + Is64Bit = true; + } else if (Magic == "\xCF\xFA\xED\xFE") { + IsLittleEndian = true; + Is64Bit = true; + } else { + if (ErrorStr) *ErrorStr = "not a Mach object file (invalid magic)"; + return 0; + } + + // Ensure that the at least the full header is present. + unsigned HeaderSize = Is64Bit ? macho::Header64Size : macho::Header32Size; + if (Buffer->getBufferSize() < HeaderSize) { + if (ErrorStr) *ErrorStr = "not a Mach object file (invalid header)"; + return 0; + } + + OwningPtr<MachOObject> Object(new MachOObject(Buffer, IsLittleEndian, + Is64Bit)); + + // Check for bogus number of load commands. + if (Object->getHeader().NumLoadCommands >= (1 << 20)) { + if (ErrorStr) *ErrorStr = "not a Mach object file (unreasonable header)"; + return 0; + } + + if (ErrorStr) *ErrorStr = ""; + return Object.take(); +} + +StringRef MachOObject::getData(size_t Offset, size_t Size) const { + return Buffer->getBuffer().substr(Offset,Size); +} + +void MachOObject::RegisterStringTable(macho::SymtabLoadCommand &SLC) { + HasStringTable = true; + StringTable = Buffer->getBuffer().substr(SLC.StringTableOffset, + SLC.StringTableSize); +} + +const MachOObject::LoadCommandInfo & +MachOObject::getLoadCommandInfo(unsigned Index) const { + assert(Index < getHeader().NumLoadCommands && "Invalid index!"); + + // Load the command, if necessary. + if (Index >= NumLoadedCommands) { + uint64_t Offset; + if (Index == 0) { + Offset = getHeaderSize(); + } else { + const LoadCommandInfo &Prev = getLoadCommandInfo(Index - 1); + Offset = Prev.Offset + Prev.Command.Size; + } + + LoadCommandInfo &Info = LoadCommands[Index]; + memcpy(&Info.Command, Buffer->getBuffer().data() + Offset, + sizeof(macho::LoadCommand)); + if (IsSwappedEndian) { + SwapValue(Info.Command.Type); + SwapValue(Info.Command.Size); + } + Info.Offset = Offset; + NumLoadedCommands = Index + 1; + } + + return LoadCommands[Index]; +} + +template<> +void SwapStruct(macho::SegmentLoadCommand &Value) { + SwapValue(Value.Type); + SwapValue(Value.Size); + SwapValue(Value.VMAddress); + SwapValue(Value.VMSize); + SwapValue(Value.FileOffset); + SwapValue(Value.FileSize); + SwapValue(Value.MaxVMProtection); + SwapValue(Value.InitialVMProtection); + SwapValue(Value.NumSections); + SwapValue(Value.Flags); +} +void MachOObject::ReadSegmentLoadCommand(const LoadCommandInfo &LCI, + InMemoryStruct<macho::SegmentLoadCommand> &Res) const { + ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res); +} + +template<> +void SwapStruct(macho::Segment64LoadCommand &Value) { + SwapValue(Value.Type); + SwapValue(Value.Size); + SwapValue(Value.VMAddress); + SwapValue(Value.VMSize); + SwapValue(Value.FileOffset); + SwapValue(Value.FileSize); + SwapValue(Value.MaxVMProtection); + SwapValue(Value.InitialVMProtection); + SwapValue(Value.NumSections); + SwapValue(Value.Flags); +} +void MachOObject::ReadSegment64LoadCommand(const LoadCommandInfo &LCI, + InMemoryStruct<macho::Segment64LoadCommand> &Res) const { + ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res); +} + +template<> +void SwapStruct(macho::SymtabLoadCommand &Value) { + SwapValue(Value.Type); + SwapValue(Value.Size); + SwapValue(Value.SymbolTableOffset); + SwapValue(Value.NumSymbolTableEntries); + SwapValue(Value.StringTableOffset); + SwapValue(Value.StringTableSize); +} +void MachOObject::ReadSymtabLoadCommand(const LoadCommandInfo &LCI, + InMemoryStruct<macho::SymtabLoadCommand> &Res) const { + ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res); +} + +template<> +void SwapStruct(macho::DysymtabLoadCommand &Value) { + SwapValue(Value.Type); + SwapValue(Value.Size); + SwapValue(Value.LocalSymbolsIndex); + SwapValue(Value.NumLocalSymbols); + SwapValue(Value.ExternalSymbolsIndex); + SwapValue(Value.NumExternalSymbols); + SwapValue(Value.UndefinedSymbolsIndex); + SwapValue(Value.NumUndefinedSymbols); + SwapValue(Value.TOCOffset); + SwapValue(Value.NumTOCEntries); + SwapValue(Value.ModuleTableOffset); + SwapValue(Value.NumModuleTableEntries); + SwapValue(Value.ReferenceSymbolTableOffset); + SwapValue(Value.NumReferencedSymbolTableEntries); + SwapValue(Value.IndirectSymbolTableOffset); + SwapValue(Value.NumIndirectSymbolTableEntries); + SwapValue(Value.ExternalRelocationTableOffset); + SwapValue(Value.NumExternalRelocationTableEntries); + SwapValue(Value.LocalRelocationTableOffset); + SwapValue(Value.NumLocalRelocationTableEntries); +} +void MachOObject::ReadDysymtabLoadCommand(const LoadCommandInfo &LCI, + InMemoryStruct<macho::DysymtabLoadCommand> &Res) const { + ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res); +} + +template<> +void SwapStruct(macho::LinkeditDataLoadCommand &Value) { + SwapValue(Value.Type); + SwapValue(Value.Size); + SwapValue(Value.DataOffset); + SwapValue(Value.DataSize); +} +void MachOObject::ReadLinkeditDataLoadCommand(const LoadCommandInfo &LCI, + InMemoryStruct<macho::LinkeditDataLoadCommand> &Res) const { + ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res); +} + +template<> +void SwapStruct(macho::IndirectSymbolTableEntry &Value) { + SwapValue(Value.Index); +} +void +MachOObject::ReadIndirectSymbolTableEntry(const macho::DysymtabLoadCommand &DLC, + unsigned Index, + InMemoryStruct<macho::IndirectSymbolTableEntry> &Res) const { + uint64_t Offset = (DLC.IndirectSymbolTableOffset + + Index * sizeof(macho::IndirectSymbolTableEntry)); + ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res); +} + + +template<> +void SwapStruct(macho::Section &Value) { + SwapValue(Value.Address); + SwapValue(Value.Size); + SwapValue(Value.Offset); + SwapValue(Value.Align); + SwapValue(Value.RelocationTableOffset); + SwapValue(Value.NumRelocationTableEntries); + SwapValue(Value.Flags); + SwapValue(Value.Reserved1); + SwapValue(Value.Reserved2); +} +void MachOObject::ReadSection(const LoadCommandInfo &LCI, + unsigned Index, + InMemoryStruct<macho::Section> &Res) const { + assert(LCI.Command.Type == macho::LCT_Segment && + "Unexpected load command info!"); + uint64_t Offset = (LCI.Offset + sizeof(macho::SegmentLoadCommand) + + Index * sizeof(macho::Section)); + ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res); +} + +template<> +void SwapStruct(macho::Section64 &Value) { + SwapValue(Value.Address); + SwapValue(Value.Size); + SwapValue(Value.Offset); + SwapValue(Value.Align); + SwapValue(Value.RelocationTableOffset); + SwapValue(Value.NumRelocationTableEntries); + SwapValue(Value.Flags); + SwapValue(Value.Reserved1); + SwapValue(Value.Reserved2); + SwapValue(Value.Reserved3); +} +void MachOObject::ReadSection64(const LoadCommandInfo &LCI, + unsigned Index, + InMemoryStruct<macho::Section64> &Res) const { + assert(LCI.Command.Type == macho::LCT_Segment64 && + "Unexpected load command info!"); + uint64_t Offset = (LCI.Offset + sizeof(macho::Segment64LoadCommand) + + Index * sizeof(macho::Section64)); + ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res); +} + +template<> +void SwapStruct(macho::RelocationEntry &Value) { + SwapValue(Value.Word0); + SwapValue(Value.Word1); +} +void MachOObject::ReadRelocationEntry(uint64_t RelocationTableOffset, + unsigned Index, + InMemoryStruct<macho::RelocationEntry> &Res) const { + uint64_t Offset = (RelocationTableOffset + + Index * sizeof(macho::RelocationEntry)); + ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res); +} + +template<> +void SwapStruct(macho::SymbolTableEntry &Value) { + SwapValue(Value.StringIndex); + SwapValue(Value.Flags); + SwapValue(Value.Value); +} +void MachOObject::ReadSymbolTableEntry(uint64_t SymbolTableOffset, + unsigned Index, + InMemoryStruct<macho::SymbolTableEntry> &Res) const { + uint64_t Offset = (SymbolTableOffset + + Index * sizeof(macho::SymbolTableEntry)); + ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res); +} + +template<> +void SwapStruct(macho::Symbol64TableEntry &Value) { + SwapValue(Value.StringIndex); + SwapValue(Value.Flags); + SwapValue(Value.Value); +} +void MachOObject::ReadSymbol64TableEntry(uint64_t SymbolTableOffset, + unsigned Index, + InMemoryStruct<macho::Symbol64TableEntry> &Res) const { + uint64_t Offset = (SymbolTableOffset + + Index * sizeof(macho::Symbol64TableEntry)); + ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res); +} + + +void MachOObject::ReadULEB128s(uint64_t Index, + SmallVectorImpl<uint64_t> &Out) const { + DataExtractor extractor(Buffer->getBuffer(), true, 0); + + uint32_t offset = Index; + uint64_t data = 0; + while (uint64_t delta = extractor.getULEB128(&offset)) { + data += delta; + Out.push_back(data); + } +} + +/* ** */ +// Object Dumping Facilities +void MachOObject::dump() const { print(dbgs()); dbgs() << '\n'; } +void MachOObject::dumpHeader() const { printHeader(dbgs()); dbgs() << '\n'; } + +void MachOObject::printHeader(raw_ostream &O) const { + O << "('cputype', " << Header.CPUType << ")\n"; + O << "('cpusubtype', " << Header.CPUSubtype << ")\n"; + O << "('filetype', " << Header.FileType << ")\n"; + O << "('num_load_commands', " << Header.NumLoadCommands << ")\n"; + O << "('load_commands_size', " << Header.SizeOfLoadCommands << ")\n"; + O << "('flag', " << Header.Flags << ")\n"; + + // Print extended header if 64-bit. + if (is64Bit()) + O << "('reserved', " << Header64Ext.Reserved << ")\n"; +} + +void MachOObject::print(raw_ostream &O) const { + O << "Header:\n"; + printHeader(O); + O << "Load Commands:\n"; + + O << "Buffer:\n"; +} diff --git a/contrib/llvm/lib/Object/MachOObjectFile.cpp b/contrib/llvm/lib/Object/MachOObjectFile.cpp new file mode 100644 index 0000000..3bcda17 --- /dev/null +++ b/contrib/llvm/lib/Object/MachOObjectFile.cpp @@ -0,0 +1,1293 @@ +//===- MachOObjectFile.cpp - Mach-O object file binding ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the MachOObjectFile class, which binds the MachOObject +// class to the generic ObjectFile wrapper. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/Triple.h" +#include "llvm/Object/MachO.h" +#include "llvm/Object/MachOFormat.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/MemoryBuffer.h" + +#include <cctype> +#include <cstring> +#include <limits> + +using namespace llvm; +using namespace object; + +namespace llvm { +namespace object { + +MachOObjectFile::MachOObjectFile(MemoryBuffer *Object, MachOObject *MOO, + error_code &ec) + : ObjectFile(Binary::ID_MachO, Object, ec), + MachOObj(MOO), + RegisteredStringTable(std::numeric_limits<uint32_t>::max()) { + DataRefImpl DRI; + moveToNextSection(DRI); + uint32_t LoadCommandCount = MachOObj->getHeader().NumLoadCommands; + while (DRI.d.a < LoadCommandCount) { + Sections.push_back(DRI); + DRI.d.b++; + moveToNextSection(DRI); + } +} + + +ObjectFile *ObjectFile::createMachOObjectFile(MemoryBuffer *Buffer) { + error_code ec; + std::string Err; + MachOObject *MachOObj = MachOObject::LoadFromBuffer(Buffer, &Err); + if (!MachOObj) + return NULL; + return new MachOObjectFile(Buffer, MachOObj, ec); +} + +/*===-- Symbols -----------------------------------------------------------===*/ + +void MachOObjectFile::moveToNextSymbol(DataRefImpl &DRI) const { + uint32_t LoadCommandCount = MachOObj->getHeader().NumLoadCommands; + while (DRI.d.a < LoadCommandCount) { + LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); + if (LCI.Command.Type == macho::LCT_Symtab) { + InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd; + MachOObj->ReadSymtabLoadCommand(LCI, SymtabLoadCmd); + if (DRI.d.b < SymtabLoadCmd->NumSymbolTableEntries) + return; + } + + DRI.d.a++; + DRI.d.b = 0; + } +} + +void MachOObjectFile::getSymbolTableEntry(DataRefImpl DRI, + InMemoryStruct<macho::SymbolTableEntry> &Res) const { + InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd; + LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); + MachOObj->ReadSymtabLoadCommand(LCI, SymtabLoadCmd); + + if (RegisteredStringTable != DRI.d.a) { + MachOObj->RegisterStringTable(*SymtabLoadCmd); + RegisteredStringTable = DRI.d.a; + } + + MachOObj->ReadSymbolTableEntry(SymtabLoadCmd->SymbolTableOffset, DRI.d.b, + Res); +} + +void MachOObjectFile::getSymbol64TableEntry(DataRefImpl DRI, + InMemoryStruct<macho::Symbol64TableEntry> &Res) const { + InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd; + LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); + MachOObj->ReadSymtabLoadCommand(LCI, SymtabLoadCmd); + + if (RegisteredStringTable != DRI.d.a) { + MachOObj->RegisterStringTable(*SymtabLoadCmd); + RegisteredStringTable = DRI.d.a; + } + + MachOObj->ReadSymbol64TableEntry(SymtabLoadCmd->SymbolTableOffset, DRI.d.b, + Res); +} + + +error_code MachOObjectFile::getSymbolNext(DataRefImpl DRI, + SymbolRef &Result) const { + DRI.d.b++; + moveToNextSymbol(DRI); + Result = SymbolRef(DRI, this); + return object_error::success; +} + +error_code MachOObjectFile::getSymbolName(DataRefImpl DRI, + StringRef &Result) const { + if (MachOObj->is64Bit()) { + InMemoryStruct<macho::Symbol64TableEntry> Entry; + getSymbol64TableEntry(DRI, Entry); + Result = MachOObj->getStringAtIndex(Entry->StringIndex); + } else { + InMemoryStruct<macho::SymbolTableEntry> Entry; + getSymbolTableEntry(DRI, Entry); + Result = MachOObj->getStringAtIndex(Entry->StringIndex); + } + return object_error::success; +} + +error_code MachOObjectFile::getSymbolFileOffset(DataRefImpl DRI, + uint64_t &Result) const { + if (MachOObj->is64Bit()) { + InMemoryStruct<macho::Symbol64TableEntry> Entry; + getSymbol64TableEntry(DRI, Entry); + Result = Entry->Value; + if (Entry->SectionIndex) { + InMemoryStruct<macho::Section64> Section; + getSection64(Sections[Entry->SectionIndex-1], Section); + Result += Section->Offset - Section->Address; + } + } else { + InMemoryStruct<macho::SymbolTableEntry> Entry; + getSymbolTableEntry(DRI, Entry); + Result = Entry->Value; + if (Entry->SectionIndex) { + InMemoryStruct<macho::Section> Section; + getSection(Sections[Entry->SectionIndex-1], Section); + Result += Section->Offset - Section->Address; + } + } + + return object_error::success; +} + +error_code MachOObjectFile::getSymbolAddress(DataRefImpl DRI, + uint64_t &Result) const { + if (MachOObj->is64Bit()) { + InMemoryStruct<macho::Symbol64TableEntry> Entry; + getSymbol64TableEntry(DRI, Entry); + Result = Entry->Value; + } else { + InMemoryStruct<macho::SymbolTableEntry> Entry; + getSymbolTableEntry(DRI, Entry); + Result = Entry->Value; + } + return object_error::success; +} + +error_code MachOObjectFile::getSymbolSize(DataRefImpl DRI, + uint64_t &Result) const { + uint32_t LoadCommandCount = MachOObj->getHeader().NumLoadCommands; + uint64_t BeginOffset; + uint64_t EndOffset = 0; + uint8_t SectionIndex; + if (MachOObj->is64Bit()) { + InMemoryStruct<macho::Symbol64TableEntry> Entry; + getSymbol64TableEntry(DRI, Entry); + BeginOffset = Entry->Value; + SectionIndex = Entry->SectionIndex; + if (!SectionIndex) { + uint32_t flags = SymbolRef::SF_None; + getSymbolFlags(DRI, flags); + if (flags & SymbolRef::SF_Common) + Result = Entry->Value; + else + Result = UnknownAddressOrSize; + return object_error::success; + } + // Unfortunately symbols are unsorted so we need to touch all + // symbols from load command + DRI.d.b = 0; + uint32_t Command = DRI.d.a; + while (Command == DRI.d.a) { + moveToNextSymbol(DRI); + if (DRI.d.a < LoadCommandCount) { + getSymbol64TableEntry(DRI, Entry); + if (Entry->SectionIndex == SectionIndex && Entry->Value > BeginOffset) + if (!EndOffset || Entry->Value < EndOffset) + EndOffset = Entry->Value; + } + DRI.d.b++; + } + } else { + InMemoryStruct<macho::SymbolTableEntry> Entry; + getSymbolTableEntry(DRI, Entry); + BeginOffset = Entry->Value; + SectionIndex = Entry->SectionIndex; + if (!SectionIndex) { + uint32_t flags = SymbolRef::SF_None; + getSymbolFlags(DRI, flags); + if (flags & SymbolRef::SF_Common) + Result = Entry->Value; + else + Result = UnknownAddressOrSize; + return object_error::success; + } + // Unfortunately symbols are unsorted so we need to touch all + // symbols from load command + DRI.d.b = 0; + uint32_t Command = DRI.d.a; + while (Command == DRI.d.a) { + moveToNextSymbol(DRI); + if (DRI.d.a < LoadCommandCount) { + getSymbolTableEntry(DRI, Entry); + if (Entry->SectionIndex == SectionIndex && Entry->Value > BeginOffset) + if (!EndOffset || Entry->Value < EndOffset) + EndOffset = Entry->Value; + } + DRI.d.b++; + } + } + if (!EndOffset) { + uint64_t Size; + getSectionSize(Sections[SectionIndex-1], Size); + getSectionAddress(Sections[SectionIndex-1], EndOffset); + EndOffset += Size; + } + Result = EndOffset - BeginOffset; + return object_error::success; +} + +error_code MachOObjectFile::getSymbolNMTypeChar(DataRefImpl DRI, + char &Result) const { + uint8_t Type, Flags; + if (MachOObj->is64Bit()) { + InMemoryStruct<macho::Symbol64TableEntry> Entry; + getSymbol64TableEntry(DRI, Entry); + Type = Entry->Type; + Flags = Entry->Flags; + } else { + InMemoryStruct<macho::SymbolTableEntry> Entry; + getSymbolTableEntry(DRI, Entry); + Type = Entry->Type; + 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(Char); + Result = Char; + return object_error::success; +} + +error_code MachOObjectFile::getSymbolFlags(DataRefImpl DRI, + uint32_t &Result) const { + uint16_t MachOFlags; + uint8_t MachOType; + if (MachOObj->is64Bit()) { + InMemoryStruct<macho::Symbol64TableEntry> Entry; + getSymbol64TableEntry(DRI, Entry); + MachOFlags = Entry->Flags; + MachOType = Entry->Type; + } else { + InMemoryStruct<macho::SymbolTableEntry> Entry; + getSymbolTableEntry(DRI, Entry); + MachOFlags = Entry->Flags; + MachOType = Entry->Type; + } + + // 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 { + uint8_t index; + if (MachOObj->is64Bit()) { + InMemoryStruct<macho::Symbol64TableEntry> Entry; + getSymbol64TableEntry(Symb, Entry); + index = Entry->SectionIndex; + } else { + InMemoryStruct<macho::SymbolTableEntry> Entry; + getSymbolTableEntry(Symb, Entry); + index = Entry->SectionIndex; + } + + if (index == 0) + Res = end_sections(); + else + Res = section_iterator(SectionRef(Sections[index-1], this)); + + return object_error::success; +} + +error_code MachOObjectFile::getSymbolType(DataRefImpl Symb, + SymbolRef::Type &Res) const { + uint8_t n_type; + if (MachOObj->is64Bit()) { + InMemoryStruct<macho::Symbol64TableEntry> Entry; + getSymbol64TableEntry(Symb, Entry); + n_type = Entry->Type; + } else { + InMemoryStruct<macho::SymbolTableEntry> Entry; + getSymbolTableEntry(Symb, Entry); + 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; +} + + +symbol_iterator MachOObjectFile::begin_symbols() const { + // DRI.d.a = segment number; DRI.d.b = symbol index. + DataRefImpl DRI; + moveToNextSymbol(DRI); + return symbol_iterator(SymbolRef(DRI, this)); +} + +symbol_iterator MachOObjectFile::end_symbols() const { + DataRefImpl DRI; + DRI.d.a = MachOObj->getHeader().NumLoadCommands; + 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"); +} + +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"); +} + +StringRef MachOObjectFile::getLoadName() const { + // TODO: Implement + report_fatal_error("get_load_name() unimplemented in MachOObjectFile"); +} + +/*===-- Sections ----------------------------------------------------------===*/ + +void MachOObjectFile::moveToNextSection(DataRefImpl &DRI) const { + uint32_t LoadCommandCount = MachOObj->getHeader().NumLoadCommands; + while (DRI.d.a < LoadCommandCount) { + LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); + if (LCI.Command.Type == macho::LCT_Segment) { + InMemoryStruct<macho::SegmentLoadCommand> SegmentLoadCmd; + MachOObj->ReadSegmentLoadCommand(LCI, SegmentLoadCmd); + if (DRI.d.b < SegmentLoadCmd->NumSections) + return; + } else if (LCI.Command.Type == macho::LCT_Segment64) { + InMemoryStruct<macho::Segment64LoadCommand> Segment64LoadCmd; + MachOObj->ReadSegment64LoadCommand(LCI, Segment64LoadCmd); + if (DRI.d.b < Segment64LoadCmd->NumSections) + return; + } + + DRI.d.a++; + DRI.d.b = 0; + } +} + +error_code MachOObjectFile::getSectionNext(DataRefImpl DRI, + SectionRef &Result) const { + DRI.d.b++; + moveToNextSection(DRI); + Result = SectionRef(DRI, this); + return object_error::success; +} + +void +MachOObjectFile::getSection(DataRefImpl DRI, + InMemoryStruct<macho::Section> &Res) const { + InMemoryStruct<macho::SegmentLoadCommand> SLC; + LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); + MachOObj->ReadSegmentLoadCommand(LCI, SLC); + MachOObj->ReadSection(LCI, DRI.d.b, Res); +} + +std::size_t MachOObjectFile::getSectionIndex(DataRefImpl Sec) const { + SectionList::const_iterator loc = + std::find(Sections.begin(), Sections.end(), Sec); + assert(loc != Sections.end() && "Sec is not a valid section!"); + return std::distance(Sections.begin(), loc); +} + +void +MachOObjectFile::getSection64(DataRefImpl DRI, + InMemoryStruct<macho::Section64> &Res) const { + InMemoryStruct<macho::Segment64LoadCommand> SLC; + LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); + MachOObj->ReadSegment64LoadCommand(LCI, SLC); + MachOObj->ReadSection64(LCI, DRI.d.b, Res); +} + +static bool is64BitLoadCommand(const MachOObject *MachOObj, DataRefImpl DRI) { + LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); + if (LCI.Command.Type == macho::LCT_Segment64) + return true; + assert(LCI.Command.Type == macho::LCT_Segment && "Unexpected Type."); + return false; +} + +error_code MachOObjectFile::getSectionName(DataRefImpl DRI, + StringRef &Result) const { + // FIXME: thread safety. + static char result[34]; + if (is64BitLoadCommand(MachOObj, DRI)) { + InMemoryStruct<macho::Segment64LoadCommand> SLC; + LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); + MachOObj->ReadSegment64LoadCommand(LCI, SLC); + InMemoryStruct<macho::Section64> Sect; + MachOObj->ReadSection64(LCI, DRI.d.b, Sect); + + strcpy(result, Sect->SegmentName); + strcat(result, ","); + strcat(result, Sect->Name); + } else { + InMemoryStruct<macho::SegmentLoadCommand> SLC; + LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); + MachOObj->ReadSegmentLoadCommand(LCI, SLC); + InMemoryStruct<macho::Section> Sect; + MachOObj->ReadSection(LCI, DRI.d.b, Sect); + + strcpy(result, Sect->SegmentName); + strcat(result, ","); + strcat(result, Sect->Name); + } + Result = StringRef(result); + return object_error::success; +} + +error_code MachOObjectFile::getSectionAddress(DataRefImpl DRI, + uint64_t &Result) const { + if (is64BitLoadCommand(MachOObj, DRI)) { + InMemoryStruct<macho::Section64> Sect; + getSection64(DRI, Sect); + Result = Sect->Address; + } else { + InMemoryStruct<macho::Section> Sect; + getSection(DRI, Sect); + Result = Sect->Address; + } + return object_error::success; +} + +error_code MachOObjectFile::getSectionSize(DataRefImpl DRI, + uint64_t &Result) const { + if (is64BitLoadCommand(MachOObj, DRI)) { + InMemoryStruct<macho::Section64> Sect; + getSection64(DRI, Sect); + Result = Sect->Size; + } else { + InMemoryStruct<macho::Section> Sect; + getSection(DRI, Sect); + Result = Sect->Size; + } + return object_error::success; +} + +error_code MachOObjectFile::getSectionContents(DataRefImpl DRI, + StringRef &Result) const { + if (is64BitLoadCommand(MachOObj, DRI)) { + InMemoryStruct<macho::Section64> Sect; + getSection64(DRI, Sect); + Result = MachOObj->getData(Sect->Offset, Sect->Size); + } else { + InMemoryStruct<macho::Section> Sect; + getSection(DRI, Sect); + Result = MachOObj->getData(Sect->Offset, Sect->Size); + } + return object_error::success; +} + +error_code MachOObjectFile::getSectionAlignment(DataRefImpl DRI, + uint64_t &Result) const { + if (is64BitLoadCommand(MachOObj, DRI)) { + InMemoryStruct<macho::Section64> Sect; + getSection64(DRI, Sect); + Result = uint64_t(1) << Sect->Align; + } else { + InMemoryStruct<macho::Section> Sect; + getSection(DRI, Sect); + Result = uint64_t(1) << Sect->Align; + } + return object_error::success; +} + +error_code MachOObjectFile::isSectionText(DataRefImpl DRI, + bool &Result) const { + if (is64BitLoadCommand(MachOObj, DRI)) { + InMemoryStruct<macho::Section64> Sect; + getSection64(DRI, Sect); + Result = !strcmp(Sect->Name, "__text"); + } else { + InMemoryStruct<macho::Section> Sect; + getSection(DRI, Sect); + Result = !strcmp(Sect->Name, "__text"); + } + return object_error::success; +} + +error_code MachOObjectFile::isSectionData(DataRefImpl DRI, + bool &Result) const { + // FIXME: Unimplemented. + Result = false; + return object_error::success; +} + +error_code MachOObjectFile::isSectionBSS(DataRefImpl DRI, + bool &Result) const { + // FIXME: Unimplemented. + Result = false; + return object_error::success; +} + +error_code MachOObjectFile::isSectionRequiredForExecution(DataRefImpl Sec, + bool &Result) const { + // FIXME: Unimplemented + Result = true; + return object_error::success; +} + +error_code MachOObjectFile::isSectionVirtual(DataRefImpl Sec, + bool &Result) const { + // FIXME: Unimplemented + Result = false; + return object_error::success; +} + +error_code MachOObjectFile::isSectionZeroInit(DataRefImpl DRI, + bool &Result) const { + if (MachOObj->is64Bit()) { + InMemoryStruct<macho::Section64> Sect; + getSection64(DRI, Sect); + Result = (Sect->Flags & MachO::SectionTypeZeroFill || + Sect->Flags & MachO::SectionTypeZeroFillLarge); + } else { + InMemoryStruct<macho::Section> Sect; + getSection(DRI, Sect); + Result = (Sect->Flags & MachO::SectionTypeZeroFill || + Sect->Flags & MachO::SectionTypeZeroFillLarge); + } + + return object_error::success; +} + +error_code MachOObjectFile::sectionContainsSymbol(DataRefImpl Sec, + DataRefImpl Symb, + bool &Result) const { + SymbolRef::Type ST; + 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; + + if (MachOObj->is64Bit()) { + InMemoryStruct<macho::Symbol64TableEntry> Entry; + getSymbol64TableEntry(Symb, Entry); + uint64_t SymAddr= Entry->Value; + Result = (SymAddr >= SectBegin) && (SymAddr < SectEnd); + } else { + InMemoryStruct<macho::SymbolTableEntry> Entry; + getSymbolTableEntry(Symb, Entry); + uint64_t SymAddr= Entry->Value; + Result = (SymAddr >= SectBegin) && (SymAddr < SectEnd); + } + + return object_error::success; +} + +relocation_iterator MachOObjectFile::getSectionRelBegin(DataRefImpl Sec) const { + DataRefImpl ret; + ret.d.b = getSectionIndex(Sec); + return relocation_iterator(RelocationRef(ret, this)); +} +relocation_iterator MachOObjectFile::getSectionRelEnd(DataRefImpl Sec) const { + uint32_t last_reloc; + if (is64BitLoadCommand(MachOObj, Sec)) { + InMemoryStruct<macho::Section64> Sect; + getSection64(Sec, Sect); + last_reloc = Sect->NumRelocationTableEntries; + } else { + InMemoryStruct<macho::Section> Sect; + getSection(Sec, Sect); + last_reloc = Sect->NumRelocationTableEntries; + } + DataRefImpl ret; + ret.d.a = last_reloc; + ret.d.b = getSectionIndex(Sec); + return relocation_iterator(RelocationRef(ret, this)); +} + +section_iterator MachOObjectFile::begin_sections() const { + DataRefImpl DRI; + moveToNextSection(DRI); + return section_iterator(SectionRef(DRI, this)); +} + +section_iterator MachOObjectFile::end_sections() const { + DataRefImpl DRI; + DRI.d.a = MachOObj->getHeader().NumLoadCommands; + return section_iterator(SectionRef(DRI, this)); +} + +/*===-- Relocations -------------------------------------------------------===*/ + +void MachOObjectFile:: +getRelocation(DataRefImpl Rel, + InMemoryStruct<macho::RelocationEntry> &Res) const { + uint32_t relOffset; + if (MachOObj->is64Bit()) { + InMemoryStruct<macho::Section64> Sect; + getSection64(Sections[Rel.d.b], Sect); + relOffset = Sect->RelocationTableOffset; + } else { + InMemoryStruct<macho::Section> Sect; + getSection(Sections[Rel.d.b], Sect); + relOffset = Sect->RelocationTableOffset; + } + MachOObj->ReadRelocationEntry(relOffset, Rel.d.a, Res); +} +error_code MachOObjectFile::getRelocationNext(DataRefImpl Rel, + RelocationRef &Res) const { + ++Rel.d.a; + Res = RelocationRef(Rel, this); + return object_error::success; +} +error_code MachOObjectFile::getRelocationAddress(DataRefImpl Rel, + uint64_t &Res) const { + const uint8_t* sectAddress = 0; + if (MachOObj->is64Bit()) { + InMemoryStruct<macho::Section64> Sect; + getSection64(Sections[Rel.d.b], Sect); + sectAddress += Sect->Address; + } else { + InMemoryStruct<macho::Section> Sect; + getSection(Sections[Rel.d.b], Sect); + sectAddress += Sect->Address; + } + InMemoryStruct<macho::RelocationEntry> RE; + getRelocation(Rel, RE); + + unsigned Arch = getArch(); + bool isScattered = (Arch != Triple::x86_64) && + (RE->Word0 & macho::RF_Scattered); + uint64_t RelAddr = 0; + if (isScattered) + RelAddr = RE->Word0 & 0xFFFFFF; + else + RelAddr = RE->Word0; + + Res = reinterpret_cast<uintptr_t>(sectAddress + RelAddr); + return object_error::success; +} +error_code MachOObjectFile::getRelocationOffset(DataRefImpl Rel, + uint64_t &Res) const { + InMemoryStruct<macho::RelocationEntry> RE; + getRelocation(Rel, RE); + + unsigned Arch = getArch(); + bool isScattered = (Arch != Triple::x86_64) && + (RE->Word0 & macho::RF_Scattered); + if (isScattered) + Res = RE->Word0 & 0xFFFFFF; + else + Res = RE->Word0; + return object_error::success; +} +error_code MachOObjectFile::getRelocationSymbol(DataRefImpl Rel, + SymbolRef &Res) const { + InMemoryStruct<macho::RelocationEntry> RE; + getRelocation(Rel, RE); + uint32_t SymbolIdx = RE->Word1 & 0xffffff; + bool isExtern = (RE->Word1 >> 27) & 1; + + DataRefImpl Sym; + moveToNextSymbol(Sym); + if (isExtern) { + for (unsigned i = 0; i < SymbolIdx; i++) { + Sym.d.b++; + moveToNextSymbol(Sym); + assert(Sym.d.a < MachOObj->getHeader().NumLoadCommands && + "Relocation symbol index out of range!"); + } + } + Res = SymbolRef(Sym, this); + return object_error::success; +} +error_code MachOObjectFile::getRelocationType(DataRefImpl Rel, + uint64_t &Res) const { + InMemoryStruct<macho::RelocationEntry> RE; + getRelocation(Rel, RE); + Res = RE->Word0; + Res <<= 32; + Res |= RE->Word1; + return object_error::success; +} +error_code MachOObjectFile::getRelocationTypeName(DataRefImpl Rel, + SmallVectorImpl<char> &Result) const { + // TODO: Support scattered relocations. + StringRef res; + InMemoryStruct<macho::RelocationEntry> RE; + getRelocation(Rel, RE); + + unsigned Arch = getArch(); + bool isScattered = (Arch != Triple::x86_64) && + (RE->Word0 & macho::RF_Scattered); + + unsigned r_type; + if (isScattered) + r_type = (RE->Word0 >> 24) & 0xF; + else + r_type = (RE->Word1 >> 28) & 0xF; + + switch (Arch) { + case Triple::x86: { + const char* 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: { + const char* 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: { + const char* 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: { + const char* 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; +} +error_code MachOObjectFile::getRelocationAdditionalInfo(DataRefImpl Rel, + int64_t &Res) const { + InMemoryStruct<macho::RelocationEntry> RE; + getRelocation(Rel, RE); + bool isExtern = (RE->Word1 >> 27) & 1; + Res = 0; + if (!isExtern) { + const uint8_t* sectAddress = base(); + if (MachOObj->is64Bit()) { + InMemoryStruct<macho::Section64> Sect; + getSection64(Sections[Rel.d.b], Sect); + sectAddress += Sect->Offset; + } else { + InMemoryStruct<macho::Section> Sect; + getSection(Sections[Rel.d.b], Sect); + sectAddress += Sect->Offset; + } + Res = reinterpret_cast<uintptr_t>(sectAddress); + } + return object_error::success; +} + +// Helper to advance a section or symbol iterator multiple increments at a time. +template<class T> +error_code advance(T &it, size_t Val) { + error_code ec; + while (Val--) { + it.increment(ec); + } + return ec; +} + +template<class T> +void advanceTo(T &it, size_t Val) { + if (error_code ec = advance(it, Val)) + report_fatal_error(ec.message()); +} + +void MachOObjectFile::printRelocationTargetName( + InMemoryStruct<macho::RelocationEntry>& RE, + raw_string_ostream &fmt) const { + unsigned Arch = getArch(); + bool isScattered = (Arch != Triple::x86_64) && + (RE->Word0 & macho::RF_Scattered); + + // Target of a scattered relocation is an address. In the interest of + // generating pretty output, scan through the symbol table looking for a + // symbol that aligns with that address. If we find one, print it. + // Otherwise, we just print the hex address of the target. + if (isScattered) { + uint32_t Val = RE->Word1; + + error_code ec; + for (symbol_iterator SI = begin_symbols(), SE = end_symbols(); SI != SE; + SI.increment(ec)) { + if (ec) report_fatal_error(ec.message()); + + uint64_t Addr; + StringRef Name; + + if ((ec = SI->getAddress(Addr))) + report_fatal_error(ec.message()); + if (Addr != Val) continue; + if ((ec = SI->getName(Name))) + report_fatal_error(ec.message()); + fmt << Name; + return; + } + + // If we couldn't find a symbol that this relocation refers to, try + // to find a section beginning instead. + for (section_iterator SI = begin_sections(), SE = end_sections(); SI != SE; + SI.increment(ec)) { + if (ec) report_fatal_error(ec.message()); + + uint64_t Addr; + StringRef Name; + + if ((ec = SI->getAddress(Addr))) + report_fatal_error(ec.message()); + if (Addr != Val) continue; + if ((ec = SI->getName(Name))) + report_fatal_error(ec.message()); + fmt << Name; + return; + } + + fmt << format("0x%x", Val); + return; + } + + StringRef S; + bool isExtern = (RE->Word1 >> 27) & 1; + uint32_t Val = RE->Word1 & 0xFFFFFF; + + if (isExtern) { + symbol_iterator SI = begin_symbols(); + advanceTo(SI, Val); + SI->getName(S); + } else { + section_iterator SI = begin_sections(); + advanceTo(SI, Val); + SI->getName(S); + } + + fmt << S; +} + +error_code MachOObjectFile::getRelocationValueString(DataRefImpl Rel, + SmallVectorImpl<char> &Result) const { + InMemoryStruct<macho::RelocationEntry> RE; + getRelocation(Rel, RE); + + unsigned Arch = getArch(); + bool isScattered = (Arch != Triple::x86_64) && + (RE->Word0 & macho::RF_Scattered); + + std::string fmtbuf; + raw_string_ostream fmt(fmtbuf); + + unsigned Type; + if (isScattered) + Type = (RE->Word0 >> 24) & 0xF; + else + Type = (RE->Word1 >> 28) & 0xF; + + bool isPCRel; + if (isScattered) + isPCRel = ((RE->Word0 >> 30) & 1); + else + isPCRel = ((RE->Word1 >> 24) & 1); + + // Determine any addends that should be displayed with the relocation. + // These require decoding the relocation type, which is triple-specific. + + // X86_64 has entirely custom relocation types. + if (Arch == Triple::x86_64) { + bool isPCRel = ((RE->Word1 >> 24) & 1); + + switch (Type) { + case macho::RIT_X86_64_GOTLoad: // X86_64_RELOC_GOT_LOAD + case macho::RIT_X86_64_GOT: { // X86_64_RELOC_GOT + printRelocationTargetName(RE, fmt); + fmt << "@GOT"; + if (isPCRel) fmt << "PCREL"; + break; + } + case macho::RIT_X86_64_Subtractor: { // X86_64_RELOC_SUBTRACTOR + InMemoryStruct<macho::RelocationEntry> RENext; + DataRefImpl RelNext = Rel; + RelNext.d.a++; + getRelocation(RelNext, RENext); + + // 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->Word1 >> 28) & 0xF; + 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(RENext, fmt); + fmt << "-"; + printRelocationTargetName(RE, fmt); + } + case macho::RIT_X86_64_TLV: + printRelocationTargetName(RE, fmt); + fmt << "@TLV"; + if (isPCRel) fmt << "P"; + break; + case macho::RIT_X86_64_Signed1: // X86_64_RELOC_SIGNED1 + printRelocationTargetName(RE, fmt); + fmt << "-1"; + break; + case macho::RIT_X86_64_Signed2: // X86_64_RELOC_SIGNED2 + printRelocationTargetName(RE, fmt); + fmt << "-2"; + break; + case macho::RIT_X86_64_Signed4: // X86_64_RELOC_SIGNED4 + printRelocationTargetName(RE, fmt); + fmt << "-4"; + break; + default: + 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 + InMemoryStruct<macho::RelocationEntry> RENext; + DataRefImpl RelNext = Rel; + RelNext.d.a++; + getRelocation(RelNext, RENext); + + // X86 sect diff's must be followed by a relocation of type + // GENERIC_RELOC_PAIR. + bool isNextScattered = (Arch != Triple::x86_64) && + (RENext->Word0 & macho::RF_Scattered); + unsigned RType; + if (isNextScattered) + RType = (RENext->Word0 >> 24) & 0xF; + else + RType = (RENext->Word1 >> 28) & 0xF; + if (RType != 1) + report_fatal_error("Expected GENERIC_RELOC_PAIR after " + "GENERIC_RELOC_SECTDIFF."); + + printRelocationTargetName(RE, fmt); + fmt << "-"; + 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 + InMemoryStruct<macho::RelocationEntry> RENext; + DataRefImpl RelNext = Rel; + RelNext.d.a++; + getRelocation(RelNext, RENext); + + // X86 sect diff's must be followed by a relocation of type + // GENERIC_RELOC_PAIR. + bool isNextScattered = (Arch != Triple::x86_64) && + (RENext->Word0 & macho::RF_Scattered); + unsigned RType; + if (isNextScattered) + RType = (RENext->Word0 >> 24) & 0xF; + else + RType = (RENext->Word1 >> 28) & 0xF; + if (RType != 1) + report_fatal_error("Expected GENERIC_RELOC_PAIR after " + "GENERIC_RELOC_LOCAL_SECTDIFF."); + + printRelocationTargetName(RE, fmt); + fmt << "-"; + printRelocationTargetName(RENext, fmt); + break; + } + case macho::RIT_Generic_TLV: { + printRelocationTargetName(RE, fmt); + fmt << "@TLV"; + if (isPCRel) fmt << "P"; + break; + } + default: + 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->Word0 >> 28) & 1; + else + isUpper = (RE->Word1 >> 25) & 1; + + if (isUpper) + fmt << ":upper16:("; + else + fmt << ":lower16:("; + printRelocationTargetName(RE, fmt); + + InMemoryStruct<macho::RelocationEntry> RENext; + DataRefImpl RelNext = Rel; + RelNext.d.a++; + getRelocation(RelNext, RENext); + + // ARM half relocs must be followed by a relocation of type + // ARM_RELOC_PAIR. + bool isNextScattered = (Arch != Triple::x86_64) && + (RENext->Word0 & macho::RF_Scattered); + unsigned RType; + if (isNextScattered) + RType = (RENext->Word0 >> 24) & 0xF; + else + RType = (RENext->Word1 >> 28) & 0xF; + + if (RType != 1) + 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(RENext, fmt); + } + + fmt << ")"; + break; + } + default: { + printRelocationTargetName(RE, fmt); + } + } + } + } else + printRelocationTargetName(RE, fmt); + + fmt.flush(); + Result.append(fmtbuf.begin(), fmtbuf.end()); + return object_error::success; +} + +error_code MachOObjectFile::getRelocationHidden(DataRefImpl Rel, + bool &Result) const { + InMemoryStruct<macho::RelocationEntry> RE; + getRelocation(Rel, RE); + + unsigned Arch = getArch(); + bool isScattered = (Arch != Triple::x86_64) && + (RE->Word0 & macho::RF_Scattered); + unsigned Type; + if (isScattered) + Type = (RE->Word0 >> 24) & 0xF; + else + Type = (RE->Word1 >> 28) & 0xF; + + 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--; + InMemoryStruct<macho::RelocationEntry> REPrev; + getRelocation(RelPrev, REPrev); + + unsigned PrevType = (REPrev->Word1 >> 28) & 0xF; + + 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"); +} + + +/*===-- Miscellaneous -----------------------------------------------------===*/ + +uint8_t MachOObjectFile::getBytesInAddress() const { + return MachOObj->is64Bit() ? 8 : 4; +} + +StringRef MachOObjectFile::getFileFormatName() const { + if (!MachOObj->is64Bit()) { + switch (MachOObj->getHeader().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((MachOObj->getHeader().CPUType & llvm::MachO::CPUArchABI64) == 0 && + "64-bit object file when we're not 64-bit?"); + return "Mach-O 32-bit unknown"; + } + } + + switch (MachOObj->getHeader().CPUType) { + case llvm::MachO::CPUTypeX86_64: + return "Mach-O 64-bit x86-64"; + case llvm::MachO::CPUTypePowerPC64: + return "Mach-O 64-bit ppc64"; + default: + assert((MachOObj->getHeader().CPUType & llvm::MachO::CPUArchABI64) == 1 && + "32-bit object file when we're 64-bit?"); + return "Mach-O 64-bit unknown"; + } +} + +unsigned MachOObjectFile::getArch() const { + switch (MachOObj->getHeader().CPUType) { + case llvm::MachO::CPUTypeI386: + 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; + } +} + +} // end namespace object +} // end namespace llvm diff --git a/contrib/llvm/lib/Object/Object.cpp b/contrib/llvm/lib/Object/Object.cpp new file mode 100644 index 0000000..f061ea7 --- /dev/null +++ b/contrib/llvm/lib/Object/Object.cpp @@ -0,0 +1,218 @@ +//===- Object.cpp - C bindings to the object file library--------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the C bindings to the file-format-independent object +// library. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/ObjectFile.h" +#include "llvm-c/Object.h" + +using namespace llvm; +using namespace object; + +// ObjectFile creation +LLVMObjectFileRef LLVMCreateObjectFile(LLVMMemoryBufferRef MemBuf) { + return wrap(ObjectFile::createObjectFile(unwrap(MemBuf))); +} + +void LLVMDisposeObjectFile(LLVMObjectFileRef ObjectFile) { + delete unwrap(ObjectFile); +} + +// ObjectFile Section iterators +LLVMSectionIteratorRef LLVMGetSections(LLVMObjectFileRef ObjectFile) { + section_iterator SI = unwrap(ObjectFile)->begin_sections(); + return wrap(new section_iterator(SI)); +} + +void LLVMDisposeSectionIterator(LLVMSectionIteratorRef SI) { + delete unwrap(SI); +} + +LLVMBool LLVMIsSectionIteratorAtEnd(LLVMObjectFileRef ObjectFile, + LLVMSectionIteratorRef SI) { + return (*unwrap(SI) == unwrap(ObjectFile)->end_sections()) ? 1 : 0; +} + +void LLVMMoveToNextSection(LLVMSectionIteratorRef SI) { + error_code ec; + unwrap(SI)->increment(ec); + if (ec) report_fatal_error("LLVMMoveToNextSection failed: " + ec.message()); +} + +void LLVMMoveToContainingSection(LLVMSectionIteratorRef Sect, + LLVMSymbolIteratorRef Sym) { + if (error_code ec = (*unwrap(Sym))->getSection(*unwrap(Sect))) + report_fatal_error(ec.message()); +} + +// ObjectFile Symbol iterators +LLVMSymbolIteratorRef LLVMGetSymbols(LLVMObjectFileRef ObjectFile) { + symbol_iterator SI = unwrap(ObjectFile)->begin_symbols(); + return wrap(new symbol_iterator(SI)); +} + +void LLVMDisposeSymbolIterator(LLVMSymbolIteratorRef SI) { + delete unwrap(SI); +} + +LLVMBool LLVMIsSymbolIteratorAtEnd(LLVMObjectFileRef ObjectFile, + LLVMSymbolIteratorRef SI) { + return (*unwrap(SI) == unwrap(ObjectFile)->end_symbols()) ? 1 : 0; +} + +void LLVMMoveToNextSymbol(LLVMSymbolIteratorRef SI) { + error_code ec; + unwrap(SI)->increment(ec); + if (ec) report_fatal_error("LLVMMoveToNextSymbol failed: " + ec.message()); +} + +// SectionRef accessors +const char *LLVMGetSectionName(LLVMSectionIteratorRef SI) { + StringRef ret; + if (error_code ec = (*unwrap(SI))->getName(ret)) + report_fatal_error(ec.message()); + return ret.data(); +} + +uint64_t LLVMGetSectionSize(LLVMSectionIteratorRef SI) { + uint64_t ret; + if (error_code ec = (*unwrap(SI))->getSize(ret)) + report_fatal_error(ec.message()); + return ret; +} + +const char *LLVMGetSectionContents(LLVMSectionIteratorRef SI) { + StringRef ret; + if (error_code ec = (*unwrap(SI))->getContents(ret)) + report_fatal_error(ec.message()); + return ret.data(); +} + +uint64_t LLVMGetSectionAddress(LLVMSectionIteratorRef SI) { + uint64_t ret; + if (error_code ec = (*unwrap(SI))->getAddress(ret)) + report_fatal_error(ec.message()); + return ret; +} + +LLVMBool LLVMGetSectionContainsSymbol(LLVMSectionIteratorRef SI, + LLVMSymbolIteratorRef Sym) { + bool ret; + if (error_code ec = (*unwrap(SI))->containsSymbol(**unwrap(Sym), ret)) + report_fatal_error(ec.message()); + return ret; +} + +// Section Relocation iterators +LLVMRelocationIteratorRef LLVMGetRelocations(LLVMSectionIteratorRef Section) { + relocation_iterator SI = (*unwrap(Section))->begin_relocations(); + return wrap(new relocation_iterator(SI)); +} + +void LLVMDisposeRelocationIterator(LLVMRelocationIteratorRef SI) { + delete unwrap(SI); +} + +LLVMBool LLVMIsRelocationIteratorAtEnd(LLVMSectionIteratorRef Section, + LLVMRelocationIteratorRef SI) { + return (*unwrap(SI) == (*unwrap(Section))->end_relocations()) ? 1 : 0; +} + +void LLVMMoveToNextRelocation(LLVMRelocationIteratorRef SI) { + error_code ec; + unwrap(SI)->increment(ec); + if (ec) report_fatal_error("LLVMMoveToNextRelocation failed: " + + ec.message()); +} + + +// SymbolRef accessors +const char *LLVMGetSymbolName(LLVMSymbolIteratorRef SI) { + StringRef ret; + if (error_code ec = (*unwrap(SI))->getName(ret)) + report_fatal_error(ec.message()); + return ret.data(); +} + +uint64_t LLVMGetSymbolAddress(LLVMSymbolIteratorRef SI) { + uint64_t ret; + if (error_code ec = (*unwrap(SI))->getAddress(ret)) + report_fatal_error(ec.message()); + return ret; +} + +uint64_t LLVMGetSymbolFileOffset(LLVMSymbolIteratorRef SI) { + uint64_t ret; + if (error_code ec = (*unwrap(SI))->getFileOffset(ret)) + report_fatal_error(ec.message()); + return ret; +} + +uint64_t LLVMGetSymbolSize(LLVMSymbolIteratorRef SI) { + uint64_t ret; + if (error_code ec = (*unwrap(SI))->getSize(ret)) + report_fatal_error(ec.message()); + return ret; +} + +// RelocationRef accessors +uint64_t LLVMGetRelocationAddress(LLVMRelocationIteratorRef RI) { + uint64_t ret; + if (error_code ec = (*unwrap(RI))->getAddress(ret)) + report_fatal_error(ec.message()); + return ret; +} + +uint64_t LLVMGetRelocationOffset(LLVMRelocationIteratorRef RI) { + uint64_t ret; + if (error_code ec = (*unwrap(RI))->getOffset(ret)) + report_fatal_error(ec.message()); + return ret; +} + +LLVMSymbolIteratorRef LLVMGetRelocationSymbol(LLVMRelocationIteratorRef RI) { + SymbolRef ret; + if (error_code ec = (*unwrap(RI))->getSymbol(ret)) + report_fatal_error(ec.message()); + + return wrap(new symbol_iterator(ret)); +} + +uint64_t LLVMGetRelocationType(LLVMRelocationIteratorRef RI) { + uint64_t ret; + if (error_code ec = (*unwrap(RI))->getType(ret)) + report_fatal_error(ec.message()); + return ret; +} + +// NOTE: Caller takes ownership of returned string. +const char *LLVMGetRelocationTypeName(LLVMRelocationIteratorRef RI) { + SmallVector<char, 0> ret; + if (error_code ec = (*unwrap(RI))->getTypeName(ret)) + report_fatal_error(ec.message()); + + char *str = static_cast<char*>(malloc(ret.size())); + std::copy(ret.begin(), ret.end(), str); + return str; +} + +// NOTE: Caller takes ownership of returned string. +const char *LLVMGetRelocationValueString(LLVMRelocationIteratorRef RI) { + SmallVector<char, 0> ret; + if (error_code ec = (*unwrap(RI))->getValueString(ret)) + report_fatal_error(ec.message()); + + char *str = static_cast<char*>(malloc(ret.size())); + std::copy(ret.begin(), ret.end(), str); + return str; +} + diff --git a/contrib/llvm/lib/Object/ObjectFile.cpp b/contrib/llvm/lib/Object/ObjectFile.cpp new file mode 100644 index 0000000..b14df9a --- /dev/null +++ b/contrib/llvm/lib/Object/ObjectFile.cpp @@ -0,0 +1,64 @@ +//===- ObjectFile.cpp - File format independent object file -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a file format independent ObjectFile class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/ObjectFile.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/system_error.h" + +using namespace llvm; +using namespace object; + +void ObjectFile::anchor() { } + +ObjectFile::ObjectFile(unsigned int Type, MemoryBuffer *source, error_code &ec) + : Binary(Type, source) { +} + +ObjectFile *ObjectFile::createObjectFile(MemoryBuffer *Object) { + if (!Object || Object->getBufferSize() < 64) + return 0; + sys::LLVMFileType type = sys::IdentifyFileType(Object->getBufferStart(), + static_cast<unsigned>(Object->getBufferSize())); + switch (type) { + case sys::ELF_Relocatable_FileType: + case sys::ELF_Executable_FileType: + case sys::ELF_SharedObject_FileType: + case sys::ELF_Core_FileType: + return createELFObjectFile(Object); + case sys::Mach_O_Object_FileType: + case sys::Mach_O_Executable_FileType: + case sys::Mach_O_FixedVirtualMemorySharedLib_FileType: + case sys::Mach_O_Core_FileType: + case sys::Mach_O_PreloadExecutable_FileType: + case sys::Mach_O_DynamicallyLinkedSharedLib_FileType: + case sys::Mach_O_DynamicLinker_FileType: + case sys::Mach_O_Bundle_FileType: + case sys::Mach_O_DynamicallyLinkedSharedLibStub_FileType: + case sys::Mach_O_DSYMCompanion_FileType: + return createMachOObjectFile(Object); + case sys::COFF_FileType: + return createCOFFObjectFile(Object); + default: + llvm_unreachable("Unknown Object File Type"); + } +} + +ObjectFile *ObjectFile::createObjectFile(StringRef ObjectPath) { + OwningPtr<MemoryBuffer> File; + if (MemoryBuffer::getFile(ObjectPath, File)) + return NULL; + return createObjectFile(File.take()); +} |