diff options
Diffstat (limited to 'contrib/llvm/lib/Object/MachOObjectFile.cpp')
-rw-r--r-- | contrib/llvm/lib/Object/MachOObjectFile.cpp | 671 |
1 files changed, 671 insertions, 0 deletions
diff --git a/contrib/llvm/lib/Object/MachOObjectFile.cpp b/contrib/llvm/lib/Object/MachOObjectFile.cpp new file mode 100644 index 0000000..507df58 --- /dev/null +++ b/contrib/llvm/lib/Object/MachOObjectFile.cpp @@ -0,0 +1,671 @@ +//===- 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/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::isMachO, Object, ec), + MachOObj(MOO), + RegisteredStringTable(std::numeric_limits<uint32_t>::max()) { + DataRefImpl DRI; + DRI.d.a = DRI.d.b = 0; + 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::getSymbolOffset(DataRefImpl DRI, + uint64_t &Result) const { + uint64_t SectionOffset; + uint8_t SectionIndex; + if (MachOObj->is64Bit()) { + InMemoryStruct<macho::Symbol64TableEntry> Entry; + getSymbol64TableEntry(DRI, Entry); + Result = Entry->Value; + SectionIndex = Entry->SectionIndex; + } else { + InMemoryStruct<macho::SymbolTableEntry> Entry; + getSymbolTableEntry(DRI, Entry); + Result = Entry->Value; + SectionIndex = Entry->SectionIndex; + } + getSectionAddress(Sections[SectionIndex-1], SectionOffset); + Result -= SectionOffset; + + 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 { + Result = UnknownAddressOrSize; + 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::isSymbolInternal(DataRefImpl DRI, + bool &Result) const { + if (MachOObj->is64Bit()) { + InMemoryStruct<macho::Symbol64TableEntry> Entry; + getSymbol64TableEntry(DRI, Entry); + Result = Entry->Flags & macho::STF_StabsEntryMask; + } else { + InMemoryStruct<macho::SymbolTableEntry> Entry; + getSymbolTableEntry(DRI, Entry); + Result = Entry->Flags & macho::STF_StabsEntryMask; + } + return object_error::success; +} + +error_code MachOObjectFile::isSymbolGlobal(DataRefImpl Symb, bool &Res) const { + + if (MachOObj->is64Bit()) { + InMemoryStruct<macho::Symbol64TableEntry> Entry; + getSymbol64TableEntry(Symb, Entry); + Res = Entry->Type & MachO::NlistMaskExternal; + } else { + InMemoryStruct<macho::SymbolTableEntry> Entry; + getSymbolTableEntry(Symb, Entry); + Res = Entry->Type & MachO::NlistMaskExternal; + } + return object_error::success; +} + +error_code MachOObjectFile::getSymbolType(DataRefImpl Symb, + SymbolRef::SymbolType &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) + return object_error::success; + + switch (n_type & MachO::NlistMaskType) { + case MachO::NListTypeUndefined : + Res = SymbolRef::ST_External; + 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; + DRI.d.a = DRI.d.b = 0; + moveToNextSymbol(DRI); + return symbol_iterator(SymbolRef(DRI, this)); +} + +symbol_iterator MachOObjectFile::end_symbols() const { + DataRefImpl DRI; + DRI.d.a = MachOObj->getHeader().NumLoadCommands; + DRI.d.b = 0; + return symbol_iterator(SymbolRef(DRI, this)); +} + + +/*===-- 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::sectionContainsSymbol(DataRefImpl Sec, + DataRefImpl Symb, + bool &Result) const { + SymbolRef::SymbolType ST; + getSymbolType(Symb, ST); + if (ST == SymbolRef::ST_External) { + 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.a = 0; + 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; + DRI.d.a = DRI.d.b = 0; + moveToNextSection(DRI); + return section_iterator(SectionRef(DRI, this)); +} + +section_iterator MachOObjectFile::end_sections() const { + DataRefImpl DRI; + DRI.d.a = MachOObj->getHeader().NumLoadCommands; + DRI.d.b = 0; + 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 = 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; + } + InMemoryStruct<macho::RelocationEntry> RE; + getRelocation(Rel, RE); + Res = reinterpret_cast<uintptr_t>(sectAddress + 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; + Sym.d.a = Sym.d.b = 0; + 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, + uint32_t &Res) const { + InMemoryStruct<macho::RelocationEntry> RE; + getRelocation(Rel, RE); + Res = RE->Word1; + return object_error::success; +} +error_code MachOObjectFile::getRelocationTypeName(DataRefImpl Rel, + SmallVectorImpl<char> &Result) const { + 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; +} +error_code MachOObjectFile::getRelocationValueString(DataRefImpl Rel, + SmallVectorImpl<char> &Result) const { + return object_error::success; +} + +/*===-- 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 |