Use llvm/Object/MachO.h in macho-dumper. Drop the old macho parser.

For Mach-O there were 2 implementations for parsing object files. A
standalone llvm/Object/MachOObject.h and llvm/Object/MachO.h which
implements the generic interface in llvm/Object/ObjectFile.h.

This patch adds the missing features to MachO.h, moves macho-dump to
use MachO.h and removes ObjectFile.h.

In addition to making sure that check-all is clean, I checked that the
new version produces exactly the same output in all Mach-O files in a
llvm+clang build directory (including executables and shared
libraries).

To test the performance, I ran macho-dump over all the files in a
llvm+clang build directory again, but this time redirecting the output
to /dev/null. Both the old and new versions take about 4.6 seconds
(2.5 user) to finish.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@180624 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Rafael Espindola 2013-04-26 20:07:33 +00:00
parent fbb2c7adc2
commit 2173e1839c
9 changed files with 344 additions and 973 deletions

View File

@ -1,77 +0,0 @@
//===- InMemoryStruct.h - Indirect Struct Access Smart Pointer --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_INMEMORYSTRUCT_H
#define LLVM_ADT_INMEMORYSTRUCT_H
#include <cassert>
namespace llvm {
/// \brief Helper object for abstracting access to an in-memory structure which
/// may require some kind of temporary storage.
///
/// This class is designed to be used for accessing file data structures which
/// in the common case can be accessed from a direct pointer to a memory mapped
/// object, but which in some cases may require indirect access to a temporary
/// structure (which, for example, may have undergone endianness translation).
template<typename T>
class InMemoryStruct {
typedef T value_type;
typedef value_type &reference;
typedef value_type *pointer;
typedef const value_type &const_reference;
typedef const value_type *const_pointer;
/// \brief The smart pointer target.
value_type *Target;
/// \brief A temporary object which can be used as a target of the smart
/// pointer.
value_type Contents;
private:
public:
InMemoryStruct() : Target(0) {}
InMemoryStruct(reference Value) : Target(&Contents), Contents(Value) {}
InMemoryStruct(pointer Value) : Target(Value) {}
InMemoryStruct(const InMemoryStruct<T> &Value) { *this = Value; }
void operator=(const InMemoryStruct<T> &Value) {
if (Value.Target != &Value.Contents) {
Target = Value.Target;
} else {
Target = &Contents;
Contents = Value.Contents;
}
}
const_reference operator*() const {
assert(Target && "Cannot dereference null pointer");
return *Target;
}
reference operator*() {
assert(Target && "Cannot dereference null pointer");
return *Target;
}
const_pointer operator->() const {
return Target;
}
pointer operator->() {
return Target;
}
operator bool() const { return Target != 0; }
};
}
#endif

View File

@ -106,6 +106,9 @@ public:
virtual StringRef getLoadName() const;
relocation_iterator getSectionRelBegin(unsigned Index) const;
relocation_iterator getSectionRelEnd(unsigned Index) const;
// In a MachO file, sections have a segment name. This is used in the .o
// files. They have a single segment, but this field specifies which segment
// a section should be put in in the final object.
@ -134,14 +137,32 @@ public:
// MachO specific structures.
macho::Section getSection(DataRefImpl DRI) const;
macho::Section64 getSection64(DataRefImpl DRI) const;
macho::Section getSection(const LoadCommandInfo &L, unsigned Index) const;
macho::Section64 getSection64(const LoadCommandInfo &L, unsigned Index) const;
macho::SymbolTableEntry getSymbolTableEntry(DataRefImpl DRI) const;
macho::Symbol64TableEntry getSymbol64TableEntry(DataRefImpl DRI) const;
macho::LinkeditDataLoadCommand
getLinkeditDataLoadCommand(const LoadCommandInfo &L) const;
macho::SegmentLoadCommand
getSegmentLoadCommand(const LoadCommandInfo &L) const;
macho::Segment64LoadCommand
getSegment64LoadCommand(const LoadCommandInfo &L) const;
macho::LinkerOptionsLoadCommand
getLinkerOptionsLoadCommand(const LoadCommandInfo &L) const;
macho::RelocationEntry getRelocation(DataRefImpl Rel) const;
macho::Header getHeader() const;
macho::Header64Ext getHeader64Ext() const;
macho::IndirectSymbolTableEntry
getIndirectSymbolTableEntry(const macho::DysymtabLoadCommand &DLC,
unsigned Index) const;
macho::DataInCodeTableEntry getDataInCodeTableEntry(uint32_t DataOffset,
unsigned Index) const;
macho::SymtabLoadCommand getSymtabLoadCommand() const;
macho::DysymtabLoadCommand getDysymtabLoadCommand() const;
StringRef getStringTableData() const;
bool is64Bit() const;
void ReadULEB128s(uint64_t Index, SmallVectorImpl<uint64_t> &Out) const;
@ -153,6 +174,7 @@ private:
typedef SmallVector<const char*, 1> SectionList;
SectionList Sections;
const char *SymtabLoadCmd;
const char *DysymtabLoadCmd;
};
}

View File

@ -1,212 +0,0 @@
//===- MachOObject.h - Mach-O Object File Wrapper ---------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_OBJECT_MACHOOBJECT_H
#define LLVM_OBJECT_MACHOOBJECT_H
#include "llvm/ADT/InMemoryStruct.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Object/MachOFormat.h"
#include <string>
namespace llvm {
class MemoryBuffer;
class raw_ostream;
namespace object {
/// \brief Wrapper object for manipulating Mach-O object files.
///
/// This class is designed to implement a full-featured, efficient, portable,
/// and robust Mach-O interface to Mach-O object files. It does not attempt to
/// smooth over rough edges in the Mach-O format or generalize access to object
/// independent features.
///
/// The class is designed around accessing the Mach-O object which is expected
/// to be fully loaded into memory.
///
/// This class is *not* suitable for concurrent use. For efficient operation,
/// the class uses APIs which rely on the ability to cache the results of
/// certain calls in internal objects which are not safe for concurrent
/// access. This allows the API to be zero-copy on the common paths.
//
// FIXME: It would be cool if we supported a "paged" MemoryBuffer
// implementation. This would allow us to implement a more sensible version of
// MemoryObject which can work like a MemoryBuffer, but be more efficient for
// objects which are in the current address space.
class MachOObject {
public:
struct LoadCommandInfo {
/// The load command information.
macho::LoadCommand Command;
/// The offset to the start of the load command in memory.
uint64_t Offset;
};
private:
OwningPtr<MemoryBuffer> Buffer;
/// Whether the object is little endian.
bool IsLittleEndian;
/// Whether the object is 64-bit.
bool Is64Bit;
/// Whether the object is swapped endianness from the host.
bool IsSwappedEndian;
/// Whether the string table has been registered.
bool HasStringTable;
/// The cached information on the load commands.
LoadCommandInfo *LoadCommands;
mutable unsigned NumLoadedCommands;
/// The cached copy of the header.
macho::Header Header;
macho::Header64Ext Header64Ext;
/// Cache string table information.
StringRef StringTable;
private:
MachOObject(MemoryBuffer *Buffer, bool IsLittleEndian, bool Is64Bit);
public:
~MachOObject();
/// \brief Load a Mach-O object from a MemoryBuffer object.
///
/// \param Buffer - The buffer to load the object from. This routine takes
/// exclusive ownership of the buffer (which is passed to the returned object
/// on success).
/// \param ErrorStr [out] - If given, will be set to a user readable error
/// message on failure.
/// \returns The loaded object, or null on error.
static MachOObject *LoadFromBuffer(MemoryBuffer *Buffer,
std::string *ErrorStr = 0);
/// @name File Information
/// @{
bool isLittleEndian() const { return IsLittleEndian; }
bool isSwappedEndian() const { return IsSwappedEndian; }
bool is64Bit() const { return Is64Bit; }
unsigned getHeaderSize() const {
return Is64Bit ? macho::Header64Size : macho::Header32Size;
}
StringRef getData(size_t Offset, size_t Size) const;
/// @}
/// @name String Table Data
/// @{
StringRef getStringTableData() const {
assert(HasStringTable && "String table has not been registered!");
return StringTable;
}
StringRef getStringAtIndex(unsigned Index) const {
size_t End = getStringTableData().find('\0', Index);
return getStringTableData().slice(Index, End);
}
void RegisterStringTable(macho::SymtabLoadCommand &SLC);
/// @}
/// @name Object Header Access
/// @{
const macho::Header &getHeader() const { return Header; }
const macho::Header64Ext &getHeader64Ext() const {
assert(is64Bit() && "Invalid access!");
return Header64Ext;
}
/// @}
/// @name Object Structure Access
/// @{
// TODO: Would be useful to have an iterator based version
// of this.
/// \brief Retrieve the information for the given load command.
const LoadCommandInfo &getLoadCommandInfo(unsigned Index) const;
void ReadSegmentLoadCommand(
const LoadCommandInfo &LCI,
InMemoryStruct<macho::SegmentLoadCommand> &Res) const;
void ReadSegment64LoadCommand(
const LoadCommandInfo &LCI,
InMemoryStruct<macho::Segment64LoadCommand> &Res) const;
void ReadSymtabLoadCommand(
const LoadCommandInfo &LCI,
InMemoryStruct<macho::SymtabLoadCommand> &Res) const;
void ReadDysymtabLoadCommand(
const LoadCommandInfo &LCI,
InMemoryStruct<macho::DysymtabLoadCommand> &Res) const;
void ReadLinkeditDataLoadCommand(
const LoadCommandInfo &LCI,
InMemoryStruct<macho::LinkeditDataLoadCommand> &Res) const;
void ReadLinkerOptionsLoadCommand(
const LoadCommandInfo &LCI,
InMemoryStruct<macho::LinkerOptionsLoadCommand> &Res) const;
void ReadIndirectSymbolTableEntry(
const macho::DysymtabLoadCommand &DLC,
unsigned Index,
InMemoryStruct<macho::IndirectSymbolTableEntry> &Res) const;
void ReadSection(
const LoadCommandInfo &LCI,
unsigned Index,
InMemoryStruct<macho::Section> &Res) const;
void ReadSection64(
const LoadCommandInfo &LCI,
unsigned Index,
InMemoryStruct<macho::Section64> &Res) const;
void ReadRelocationEntry(
uint64_t RelocationTableOffset, unsigned Index,
InMemoryStruct<macho::RelocationEntry> &Res) const;
void ReadSymbolTableEntry(
uint64_t SymbolTableOffset, unsigned Index,
InMemoryStruct<macho::SymbolTableEntry> &Res) const;
void ReadSymbol64TableEntry(
uint64_t SymbolTableOffset, unsigned Index,
InMemoryStruct<macho::Symbol64TableEntry> &Res) const;
void ReadDataInCodeTableEntry(
uint64_t TableOffset, unsigned Index,
InMemoryStruct<macho::DataInCodeTableEntry> &Res) const;
void ReadULEB128s(uint64_t Index, SmallVectorImpl<uint64_t> &Out) const;
/// @}
/// @name Object Dump Facilities
/// @{
/// dump - Support for debugging, callable in GDB: V->dump()
//
void dump() const;
void dumpHeader() const;
/// print - Implement operator<< on Value.
///
void print(raw_ostream &O) const;
void printHeader(raw_ostream &O) const;
/// @}
};
inline raw_ostream &operator<<(raw_ostream &OS, const MachOObject &V) {
V.print(OS);
return OS;
}
} // end namespace object
} // end namespace llvm
#endif

View File

@ -16,7 +16,7 @@
#include "RuntimeDyldImpl.h"
#include "llvm/ADT/IndexedMap.h"
#include "llvm/Object/MachOObject.h"
#include "llvm/Object/MachO.h"
#include "llvm/Support/Format.h"
using namespace llvm;

View File

@ -4,7 +4,6 @@ add_llvm_library(LLVMObject
COFFObjectFile.cpp
ELFObjectFile.cpp
Error.cpp
MachOObject.cpp
MachOObjectFile.cpp
Object.cpp
ObjectFile.cpp

View File

@ -1,422 +0,0 @@
//===- 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/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/DataExtractor.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SwapByteOrder.h"
#include "llvm/Support/raw_ostream.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 = reinterpret_cast<struct_type *>(
const_cast<char *>(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::LinkerOptionsLoadCommand &Value) {
SwapValue(Value.Type);
SwapValue(Value.Size);
SwapValue(Value.Count);
}
void MachOObject::ReadLinkerOptionsLoadCommand(const LoadCommandInfo &LCI,
InMemoryStruct<macho::LinkerOptionsLoadCommand> &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);
}
template<>
void SwapStruct(macho::DataInCodeTableEntry &Value) {
SwapValue(Value.Offset);
SwapValue(Value.Length);
SwapValue(Value.Kind);
}
void MachOObject::ReadDataInCodeTableEntry(uint64_t TableOffset,
unsigned Index,
InMemoryStruct<macho::DataInCodeTableEntry> &Res) const {
uint64_t Offset = (TableOffset +
Index * sizeof(macho::DataInCodeTableEntry));
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";
}

View File

@ -119,6 +119,11 @@ void SwapStruct(macho::Header &H) {
SwapValue(H.Flags);
}
template<>
void SwapStruct(macho::Header64Ext &E) {
SwapValue(E.Reserved);
}
template<>
void SwapStruct(macho::SymtabLoadCommand &C) {
SwapValue(C.Type);
@ -129,6 +134,30 @@ void SwapStruct(macho::SymtabLoadCommand &C) {
SwapValue(C.StringTableSize);
}
template<>
void SwapStruct(macho::DysymtabLoadCommand &C) {
SwapValue(C.Type);
SwapValue(C.Size);
SwapValue(C.LocalSymbolsIndex);
SwapValue(C.NumLocalSymbols);
SwapValue(C.ExternalSymbolsIndex);
SwapValue(C.NumExternalSymbols);
SwapValue(C.UndefinedSymbolsIndex);
SwapValue(C.NumUndefinedSymbols);
SwapValue(C.TOCOffset);
SwapValue(C.NumTOCEntries);
SwapValue(C.ModuleTableOffset);
SwapValue(C.NumModuleTableEntries);
SwapValue(C.ReferenceSymbolTableOffset);
SwapValue(C.NumReferencedSymbolTableEntries);
SwapValue(C.IndirectSymbolTableOffset);
SwapValue(C.NumIndirectSymbolTableEntries);
SwapValue(C.ExternalRelocationTableOffset);
SwapValue(C.NumExternalRelocationTableEntries);
SwapValue(C.LocalRelocationTableOffset);
SwapValue(C.NumLocalRelocationTableEntries);
}
template<>
void SwapStruct(macho::LinkeditDataLoadCommand &C) {
SwapValue(C.Type);
@ -165,6 +194,25 @@ void SwapStruct(macho::Segment64LoadCommand &C) {
SwapValue(C.Flags);
}
template<>
void SwapStruct(macho::IndirectSymbolTableEntry &C) {
SwapValue(C.Index);
}
template<>
void SwapStruct(macho::LinkerOptionsLoadCommand &C) {
SwapValue(C.Type);
SwapValue(C.Size);
SwapValue(C.Count);
}
template<>
void SwapStruct(macho::DataInCodeTableEntry &C) {
SwapValue(C.Offset);
SwapValue(C.Length);
SwapValue(C.Kind);
}
template<typename T>
T getStruct(const MachOObjectFile *O, const char *P) {
T Cmd;
@ -174,32 +222,20 @@ T getStruct(const MachOObjectFile *O, const char *P) {
return Cmd;
}
static macho::SegmentLoadCommand
getSegmentLoadCommand(const MachOObjectFile *O,
const MachOObjectFile::LoadCommandInfo &L) {
return getStruct<macho::SegmentLoadCommand>(O, L.Ptr);
}
static macho::Segment64LoadCommand
getSegment64LoadCommand(const MachOObjectFile *O,
const MachOObjectFile::LoadCommandInfo &L) {
return getStruct<macho::Segment64LoadCommand>(O, L.Ptr);
}
static uint32_t
getSegmentLoadCommandNumSections(const MachOObjectFile *O,
const MachOObjectFile::LoadCommandInfo &L) {
if (O->is64Bit()) {
macho::Segment64LoadCommand S = getSegment64LoadCommand(O, L);
macho::Segment64LoadCommand S = O->getSegment64LoadCommand(L);
return S.NumSections;
}
macho::SegmentLoadCommand S = getSegmentLoadCommand(O, L);
macho::SegmentLoadCommand S = O->getSegmentLoadCommand(L);
return S.NumSections;
}
static const SectionBase *
getSectionBase(const MachOObjectFile *O, MachOObjectFile::LoadCommandInfo L,
unsigned Sec) {
static const char *
getSectionPtr(const MachOObjectFile *O, MachOObjectFile::LoadCommandInfo L,
unsigned Sec) {
uintptr_t CommandAddr = reinterpret_cast<uintptr_t>(L.Ptr);
bool Is64 = O->is64Bit();
@ -209,7 +245,7 @@ getSectionBase(const MachOObjectFile *O, MachOObjectFile::LoadCommandInfo L,
sizeof(macho::Section);
uintptr_t SectionAddr = CommandAddr + SegmentLoadSize + Sec * SectionSize;
return reinterpret_cast<const SectionBase*>(SectionAddr);
return reinterpret_cast<const char*>(SectionAddr);
}
static const char *getPtr(const MachOObjectFile *O, size_t Offset) {
@ -377,7 +413,7 @@ MachOObjectFile::MachOObjectFile(MemoryBuffer *Object,
bool IsLittleEndian, bool Is64bits,
error_code &ec)
: ObjectFile(getMachOType(IsLittleEndian, Is64bits), Object),
SymtabLoadCmd(NULL) {
SymtabLoadCmd(NULL), DysymtabLoadCmd(NULL) {
uint32_t LoadCommandCount = this->getHeader().NumLoadCommands;
macho::LoadCommandType SegmentLoadType = is64Bit() ?
macho::LCT_Segment64 : macho::LCT_Segment;
@ -387,13 +423,14 @@ MachOObjectFile::MachOObjectFile(MemoryBuffer *Object,
if (Load.C.Type == macho::LCT_Symtab) {
assert(!SymtabLoadCmd && "Multiple symbol tables");
SymtabLoadCmd = Load.Ptr;
}
if (Load.C.Type == SegmentLoadType) {
} else if (Load.C.Type == macho::LCT_Dysymtab) {
assert(!DysymtabLoadCmd && "Multiple dynamic symbol tables");
DysymtabLoadCmd = Load.Ptr;
} else if (Load.C.Type == SegmentLoadType) {
uint32_t NumSections = getSegmentLoadCommandNumSections(this, Load);
for (unsigned J = 0; J < NumSections; ++J) {
const SectionBase *Sec = getSectionBase(this, Load, J);
Sections.push_back(reinterpret_cast<const char*>(Sec));
const char *Sec = getSectionPtr(this, Load, J);
Sections.push_back(Sec);
}
}
@ -416,10 +453,9 @@ error_code MachOObjectFile::getSymbolNext(DataRefImpl Symb,
error_code MachOObjectFile::getSymbolName(DataRefImpl Symb,
StringRef &Res) const {
macho::SymtabLoadCommand S = getSymtabLoadCommand();
const char *StringTable = getPtr(this, S.StringTableOffset);
StringRef StringTable = getStringTableData();
SymbolTableEntryBase Entry = getSymbolTableEntryBase(this, Symb);
const char *Start = &StringTable[Entry.StringIndex];
const char *Start = &StringTable.data()[Entry.StringIndex];
Res = StringRef(Start);
return object_error::success;
}
@ -1271,6 +1307,18 @@ StringRef MachOObjectFile::getLoadName() const {
report_fatal_error("get_load_name() unimplemented in MachOObjectFile");
}
relocation_iterator MachOObjectFile::getSectionRelBegin(unsigned Index) const {
DataRefImpl DRI;
DRI.d.a = Index;
return getSectionRelBegin(DRI);
}
relocation_iterator MachOObjectFile::getSectionRelEnd(unsigned Index) const {
DataRefImpl DRI;
DRI.d.a = Index;
return getSectionRelEnd(DRI);
}
StringRef
MachOObjectFile::getSectionFinalSegmentName(DataRefImpl Sec) const {
ArrayRef<char> Raw = getSectionRawFinalSegmentName(Sec);
@ -1375,6 +1423,18 @@ macho::Section64 MachOObjectFile::getSection64(DataRefImpl DRI) const {
return getStruct<macho::Section64>(this, Sections[DRI.d.a]);
}
macho::Section MachOObjectFile::getSection(const LoadCommandInfo &L,
unsigned Index) const {
const char *Sec = getSectionPtr(this, L, Index);
return getStruct<macho::Section>(this, Sec);
}
macho::Section64 MachOObjectFile::getSection64(const LoadCommandInfo &L,
unsigned Index) const {
const char *Sec = getSectionPtr(this, L, Index);
return getStruct<macho::Section64>(this, Sec);
}
macho::SymbolTableEntry
MachOObjectFile::getSymbolTableEntry(DataRefImpl DRI) const {
const char *P = reinterpret_cast<const char *>(DRI.p);
@ -1392,6 +1452,21 @@ MachOObjectFile::getLinkeditDataLoadCommand(const MachOObjectFile::LoadCommandIn
return getStruct<macho::LinkeditDataLoadCommand>(this, L.Ptr);
}
macho::SegmentLoadCommand
MachOObjectFile::getSegmentLoadCommand(const LoadCommandInfo &L) const {
return getStruct<macho::SegmentLoadCommand>(this, L.Ptr);
}
macho::Segment64LoadCommand
MachOObjectFile::getSegment64LoadCommand(const LoadCommandInfo &L) const {
return getStruct<macho::Segment64LoadCommand>(this, L.Ptr);
}
macho::LinkerOptionsLoadCommand
MachOObjectFile::getLinkerOptionsLoadCommand(const LoadCommandInfo &L) const {
return getStruct<macho::LinkerOptionsLoadCommand>(this, L.Ptr);
}
macho::RelocationEntry
MachOObjectFile::getRelocation(DataRefImpl Rel) const {
const char *P = reinterpret_cast<const char *>(Rel.p);
@ -1402,11 +1477,39 @@ macho::Header MachOObjectFile::getHeader() const {
return getStruct<macho::Header>(this, getPtr(this, 0));
}
macho::SymtabLoadCommand
MachOObjectFile::getSymtabLoadCommand() const {
macho::Header64Ext MachOObjectFile::getHeader64Ext() const {
return
getStruct<macho::Header64Ext>(this, getPtr(this, sizeof(macho::Header)));
}
macho::IndirectSymbolTableEntry MachOObjectFile::getIndirectSymbolTableEntry(
const macho::DysymtabLoadCommand &DLC,
unsigned Index) const {
uint64_t Offset = DLC.IndirectSymbolTableOffset +
Index * sizeof(macho::IndirectSymbolTableEntry);
return getStruct<macho::IndirectSymbolTableEntry>(this, getPtr(this, Offset));
}
macho::DataInCodeTableEntry
MachOObjectFile::getDataInCodeTableEntry(uint32_t DataOffset,
unsigned Index) const {
uint64_t Offset = DataOffset + Index * sizeof(macho::DataInCodeTableEntry);
return getStruct<macho::DataInCodeTableEntry>(this, getPtr(this, Offset));
}
macho::SymtabLoadCommand MachOObjectFile::getSymtabLoadCommand() const {
return getStruct<macho::SymtabLoadCommand>(this, SymtabLoadCmd);
}
macho::DysymtabLoadCommand MachOObjectFile::getDysymtabLoadCommand() const {
return getStruct<macho::DysymtabLoadCommand>(this, DysymtabLoadCmd);
}
StringRef MachOObjectFile::getStringTableData() const {
macho::SymtabLoadCommand S = getSymtabLoadCommand();
return getData().substr(S.StringTableOffset, S.StringTableSize);
}
bool MachOObjectFile::is64Bit() const {
return getType() == getMachOType(false, true) ||
getType() == getMachOType(true, true);

View File

@ -17,7 +17,7 @@
#include "llvm/ExecutionEngine/ObjectBuffer.h"
#include "llvm/ExecutionEngine/ObjectImage.h"
#include "llvm/ExecutionEngine/RuntimeDyld.h"
#include "llvm/Object/MachOObject.h"
#include "llvm/Object/MachO.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Memory.h"

View File

@ -11,9 +11,10 @@
//
//===----------------------------------------------------------------------===//
#include "llvm/Object/MachOObject.h"
#include "llvm/Object/MachO.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/ManagedStatic.h"
@ -66,7 +67,8 @@ static void DumpSegmentCommandData(StringRef Name,
outs() << " ('flags', " << Flags << ")\n";
}
static int DumpSectionData(MachOObject &Obj, unsigned Index, StringRef Name,
static int DumpSectionData(const MachOObjectFile &Obj, unsigned Index,
StringRef Name,
StringRef SegmentName, uint64_t Address,
uint64_t Size, uint32_t Offset,
uint32_t Align, uint32_t RelocationTableOffset,
@ -92,26 +94,22 @@ static int DumpSectionData(MachOObject &Obj, unsigned Index, StringRef Name,
outs() << " ),\n";
// Dump the relocation entries.
int Res = 0;
outs() << " ('_relocations', [\n";
for (unsigned i = 0; i != NumRelocationTableEntries; ++i) {
InMemoryStruct<macho::RelocationEntry> RE;
Obj.ReadRelocationEntry(RelocationTableOffset, i, RE);
if (!RE) {
Res = Error("unable to read relocation table entry '" + Twine(i) + "'");
break;
}
outs() << " # Relocation " << i << "\n";
outs() << " (('word-0', " << format("0x%x", RE->Word0) << "),\n";
outs() << " ('word-1', " << format("0x%x", RE->Word1) << ")),\n";
unsigned RelNum = 0;
error_code EC;
for (relocation_iterator I = Obj.getSectionRelBegin(Index),
E = Obj.getSectionRelEnd(Index); I != E; I.increment(EC), ++RelNum) {
macho::RelocationEntry RE = Obj.getRelocation(I->getRawDataRefImpl());
outs() << " # Relocation " << RelNum << "\n";
outs() << " (('word-0', " << format("0x%x", RE.Word0) << "),\n";
outs() << " ('word-1', " << format("0x%x", RE.Word1) << ")),\n";
}
outs() << " ])\n";
// Dump the section data, if requested.
if (ShowSectionData) {
outs() << " ('_section_data', '";
StringRef Data = Obj.getData(Offset, Size);
StringRef Data = Obj.getData().substr(Offset, Size);
for (unsigned i = 0; i != Data.size(); ++i) {
if (i && (i % 4) == 0)
outs() << ' ';
@ -121,208 +119,162 @@ static int DumpSectionData(MachOObject &Obj, unsigned Index, StringRef Name,
outs() << "')\n";
}
return Res;
return 0;
}
static int DumpSegmentCommand(MachOObject &Obj,
const MachOObject::LoadCommandInfo &LCI) {
InMemoryStruct<macho::SegmentLoadCommand> SLC;
Obj.ReadSegmentLoadCommand(LCI, SLC);
if (!SLC)
return Error("unable to read segment load command");
static int DumpSegmentCommand(const MachOObjectFile &Obj,
const MachOObjectFile::LoadCommandInfo &LCI) {
macho::SegmentLoadCommand SLC = Obj.getSegmentLoadCommand(LCI);
DumpSegmentCommandData(StringRef(SLC->Name, 16), SLC->VMAddress,
SLC->VMSize, SLC->FileOffset, SLC->FileSize,
SLC->MaxVMProtection, SLC->InitialVMProtection,
SLC->NumSections, SLC->Flags);
DumpSegmentCommandData(StringRef(SLC.Name, 16), SLC.VMAddress,
SLC.VMSize, SLC.FileOffset, SLC.FileSize,
SLC.MaxVMProtection, SLC.InitialVMProtection,
SLC.NumSections, SLC.Flags);
// Dump the sections.
int Res = 0;
outs() << " ('sections', [\n";
for (unsigned i = 0; i != SLC->NumSections; ++i) {
InMemoryStruct<macho::Section> Sect;
Obj.ReadSection(LCI, i, Sect);
if (!SLC) {
Res = Error("unable to read section '" + Twine(i) + "'");
break;
}
if ((Res = DumpSectionData(Obj, i, StringRef(Sect->Name, 16),
StringRef(Sect->SegmentName, 16), Sect->Address,
Sect->Size, Sect->Offset, Sect->Align,
Sect->RelocationTableOffset,
Sect->NumRelocationTableEntries, Sect->Flags,
Sect->Reserved1, Sect->Reserved2)))
break;
for (unsigned i = 0; i != SLC.NumSections; ++i) {
macho::Section Sect = Obj.getSection(LCI, i);
DumpSectionData(Obj, i, StringRef(Sect.Name, 16),
StringRef(Sect.SegmentName, 16), Sect.Address,
Sect.Size, Sect.Offset, Sect.Align,
Sect.RelocationTableOffset,
Sect.NumRelocationTableEntries, Sect.Flags,
Sect.Reserved1, Sect.Reserved2);
}
outs() << " ])\n";
return Res;
return 0;
}
static int DumpSegment64Command(MachOObject &Obj,
const MachOObject::LoadCommandInfo &LCI) {
InMemoryStruct<macho::Segment64LoadCommand> SLC;
Obj.ReadSegment64LoadCommand(LCI, SLC);
if (!SLC)
return Error("unable to read segment load command");
DumpSegmentCommandData(StringRef(SLC->Name, 16), SLC->VMAddress,
SLC->VMSize, SLC->FileOffset, SLC->FileSize,
SLC->MaxVMProtection, SLC->InitialVMProtection,
SLC->NumSections, SLC->Flags);
static int DumpSegment64Command(const MachOObjectFile &Obj,
const MachOObjectFile::LoadCommandInfo &LCI) {
macho::Segment64LoadCommand SLC = Obj.getSegment64LoadCommand(LCI);
DumpSegmentCommandData(StringRef(SLC.Name, 16), SLC.VMAddress,
SLC.VMSize, SLC.FileOffset, SLC.FileSize,
SLC.MaxVMProtection, SLC.InitialVMProtection,
SLC.NumSections, SLC.Flags);
// Dump the sections.
int Res = 0;
outs() << " ('sections', [\n";
for (unsigned i = 0; i != SLC->NumSections; ++i) {
InMemoryStruct<macho::Section64> Sect;
Obj.ReadSection64(LCI, i, Sect);
if (!SLC) {
Res = Error("unable to read section '" + Twine(i) + "'");
break;
}
for (unsigned i = 0; i != SLC.NumSections; ++i) {
macho::Section64 Sect = Obj.getSection64(LCI, i);
if ((Res = DumpSectionData(Obj, i, StringRef(Sect->Name, 16),
StringRef(Sect->SegmentName, 16), Sect->Address,
Sect->Size, Sect->Offset, Sect->Align,
Sect->RelocationTableOffset,
Sect->NumRelocationTableEntries, Sect->Flags,
Sect->Reserved1, Sect->Reserved2,
Sect->Reserved3)))
break;
DumpSectionData(Obj, i, StringRef(Sect.Name, 16),
StringRef(Sect.SegmentName, 16), Sect.Address,
Sect.Size, Sect.Offset, Sect.Align,
Sect.RelocationTableOffset,
Sect.NumRelocationTableEntries, Sect.Flags,
Sect.Reserved1, Sect.Reserved2,
Sect.Reserved3);
}
outs() << " ])\n";
return Res;
return 0;
}
static void DumpSymbolTableEntryData(MachOObject &Obj,
static void DumpSymbolTableEntryData(const MachOObjectFile &Obj,
unsigned Index, uint32_t StringIndex,
uint8_t Type, uint8_t SectionIndex,
uint16_t Flags, uint64_t Value) {
uint16_t Flags, uint64_t Value,
StringRef StringTable) {
const char *Name = &StringTable.data()[StringIndex];
outs() << " # Symbol " << Index << "\n";
outs() << " (('n_strx', " << StringIndex << ")\n";
outs() << " ('n_type', " << format("0x%x", Type) << ")\n";
outs() << " ('n_sect', " << uint32_t(SectionIndex) << ")\n";
outs() << " ('n_desc', " << Flags << ")\n";
outs() << " ('n_value', " << Value << ")\n";
outs() << " ('_string', '" << Obj.getStringAtIndex(StringIndex) << "')\n";
outs() << " ('_string', '" << Name << "')\n";
outs() << " ),\n";
}
static int DumpSymtabCommand(MachOObject &Obj,
const MachOObject::LoadCommandInfo &LCI) {
InMemoryStruct<macho::SymtabLoadCommand> SLC;
Obj.ReadSymtabLoadCommand(LCI, SLC);
if (!SLC)
return Error("unable to read segment load command");
static int DumpSymtabCommand(const MachOObjectFile &Obj) {
macho::SymtabLoadCommand SLC = Obj.getSymtabLoadCommand();
outs() << " ('symoff', " << SLC->SymbolTableOffset << ")\n";
outs() << " ('nsyms', " << SLC->NumSymbolTableEntries << ")\n";
outs() << " ('stroff', " << SLC->StringTableOffset << ")\n";
outs() << " ('strsize', " << SLC->StringTableSize << ")\n";
// Cache the string table data.
Obj.RegisterStringTable(*SLC);
outs() << " ('symoff', " << SLC.SymbolTableOffset << ")\n";
outs() << " ('nsyms', " << SLC.NumSymbolTableEntries << ")\n";
outs() << " ('stroff', " << SLC.StringTableOffset << ")\n";
outs() << " ('strsize', " << SLC.StringTableSize << ")\n";
// Dump the string data.
outs() << " ('_string_data', '";
outs().write_escaped(Obj.getStringTableData(),
StringRef StringTable = Obj.getStringTableData();
outs().write_escaped(StringTable,
/*UseHexEscapes=*/true) << "')\n";
// Dump the symbol table.
int Res = 0;
outs() << " ('_symbols', [\n";
for (unsigned i = 0; i != SLC->NumSymbolTableEntries; ++i) {
error_code EC;
unsigned SymNum = 0;
for (symbol_iterator I = Obj.begin_symbols(), E = Obj.end_symbols(); I != E;
I.increment(EC), ++SymNum) {
DataRefImpl DRI = I->getRawDataRefImpl();
if (Obj.is64Bit()) {
InMemoryStruct<macho::Symbol64TableEntry> STE;
Obj.ReadSymbol64TableEntry(SLC->SymbolTableOffset, i, STE);
if (!STE) {
Res = Error("unable to read symbol: '" + Twine(i) + "'");
break;
}
DumpSymbolTableEntryData(Obj, i, STE->StringIndex, STE->Type,
STE->SectionIndex, STE->Flags, STE->Value);
macho::Symbol64TableEntry STE = Obj.getSymbol64TableEntry(DRI);
DumpSymbolTableEntryData(Obj, SymNum, STE.StringIndex, STE.Type,
STE.SectionIndex, STE.Flags, STE.Value,
StringTable);
} else {
InMemoryStruct<macho::SymbolTableEntry> STE;
Obj.ReadSymbolTableEntry(SLC->SymbolTableOffset, i, STE);
if (!SLC) {
Res = Error("unable to read symbol: '" + Twine(i) + "'");
break;
}
DumpSymbolTableEntryData(Obj, i, STE->StringIndex, STE->Type,
STE->SectionIndex, STE->Flags, STE->Value);
macho::SymbolTableEntry STE = Obj.getSymbolTableEntry(DRI);
DumpSymbolTableEntryData(Obj, SymNum, STE.StringIndex, STE.Type,
STE.SectionIndex, STE.Flags, STE.Value,
StringTable);
}
}
outs() << " ])\n";
return Res;
return 0;
}
static int DumpDysymtabCommand(MachOObject &Obj,
const MachOObject::LoadCommandInfo &LCI) {
InMemoryStruct<macho::DysymtabLoadCommand> DLC;
Obj.ReadDysymtabLoadCommand(LCI, DLC);
if (!DLC)
return Error("unable to read segment load command");
static int DumpDysymtabCommand(const MachOObjectFile &Obj) {
macho::DysymtabLoadCommand DLC = Obj.getDysymtabLoadCommand();
outs() << " ('ilocalsym', " << DLC->LocalSymbolsIndex << ")\n";
outs() << " ('nlocalsym', " << DLC->NumLocalSymbols << ")\n";
outs() << " ('iextdefsym', " << DLC->ExternalSymbolsIndex << ")\n";
outs() << " ('nextdefsym', " << DLC->NumExternalSymbols << ")\n";
outs() << " ('iundefsym', " << DLC->UndefinedSymbolsIndex << ")\n";
outs() << " ('nundefsym', " << DLC->NumUndefinedSymbols << ")\n";
outs() << " ('tocoff', " << DLC->TOCOffset << ")\n";
outs() << " ('ntoc', " << DLC->NumTOCEntries << ")\n";
outs() << " ('modtaboff', " << DLC->ModuleTableOffset << ")\n";
outs() << " ('nmodtab', " << DLC->NumModuleTableEntries << ")\n";
outs() << " ('extrefsymoff', " << DLC->ReferenceSymbolTableOffset << ")\n";
outs() << " ('ilocalsym', " << DLC.LocalSymbolsIndex << ")\n";
outs() << " ('nlocalsym', " << DLC.NumLocalSymbols << ")\n";
outs() << " ('iextdefsym', " << DLC.ExternalSymbolsIndex << ")\n";
outs() << " ('nextdefsym', " << DLC.NumExternalSymbols << ")\n";
outs() << " ('iundefsym', " << DLC.UndefinedSymbolsIndex << ")\n";
outs() << " ('nundefsym', " << DLC.NumUndefinedSymbols << ")\n";
outs() << " ('tocoff', " << DLC.TOCOffset << ")\n";
outs() << " ('ntoc', " << DLC.NumTOCEntries << ")\n";
outs() << " ('modtaboff', " << DLC.ModuleTableOffset << ")\n";
outs() << " ('nmodtab', " << DLC.NumModuleTableEntries << ")\n";
outs() << " ('extrefsymoff', " << DLC.ReferenceSymbolTableOffset << ")\n";
outs() << " ('nextrefsyms', "
<< DLC->NumReferencedSymbolTableEntries << ")\n";
outs() << " ('indirectsymoff', " << DLC->IndirectSymbolTableOffset << ")\n";
<< DLC.NumReferencedSymbolTableEntries << ")\n";
outs() << " ('indirectsymoff', " << DLC.IndirectSymbolTableOffset << ")\n";
outs() << " ('nindirectsyms', "
<< DLC->NumIndirectSymbolTableEntries << ")\n";
outs() << " ('extreloff', " << DLC->ExternalRelocationTableOffset << ")\n";
outs() << " ('nextrel', " << DLC->NumExternalRelocationTableEntries << ")\n";
outs() << " ('locreloff', " << DLC->LocalRelocationTableOffset << ")\n";
outs() << " ('nlocrel', " << DLC->NumLocalRelocationTableEntries << ")\n";
<< DLC.NumIndirectSymbolTableEntries << ")\n";
outs() << " ('extreloff', " << DLC.ExternalRelocationTableOffset << ")\n";
outs() << " ('nextrel', " << DLC.NumExternalRelocationTableEntries << ")\n";
outs() << " ('locreloff', " << DLC.LocalRelocationTableOffset << ")\n";
outs() << " ('nlocrel', " << DLC.NumLocalRelocationTableEntries << ")\n";
// Dump the indirect symbol table.
int Res = 0;
outs() << " ('_indirect_symbols', [\n";
for (unsigned i = 0; i != DLC->NumIndirectSymbolTableEntries; ++i) {
InMemoryStruct<macho::IndirectSymbolTableEntry> ISTE;
Obj.ReadIndirectSymbolTableEntry(*DLC, i, ISTE);
if (!ISTE) {
Res = Error("unable to read segment load command");
break;
}
for (unsigned i = 0; i != DLC.NumIndirectSymbolTableEntries; ++i) {
macho::IndirectSymbolTableEntry ISTE =
Obj.getIndirectSymbolTableEntry(DLC, i);
outs() << " # Indirect Symbol " << i << "\n";
outs() << " (('symbol_index', "
<< format("0x%x", ISTE->Index) << "),),\n";
<< format("0x%x", ISTE.Index) << "),),\n";
}
outs() << " ])\n";
return Res;
return 0;
}
static int DumpLinkeditDataCommand(MachOObject &Obj,
const MachOObject::LoadCommandInfo &LCI) {
InMemoryStruct<macho::LinkeditDataLoadCommand> LLC;
Obj.ReadLinkeditDataLoadCommand(LCI, LLC);
if (!LLC)
return Error("unable to read segment load command");
outs() << " ('dataoff', " << LLC->DataOffset << ")\n"
<< " ('datasize', " << LLC->DataSize << ")\n"
static int
DumpLinkeditDataCommand(const MachOObjectFile &Obj,
const MachOObjectFile::LoadCommandInfo &LCI) {
macho::LinkeditDataLoadCommand LLC = Obj.getLinkeditDataLoadCommand(LCI);
outs() << " ('dataoff', " << LLC.DataOffset << ")\n"
<< " ('datasize', " << LLC.DataSize << ")\n"
<< " ('_addresses', [\n";
SmallVector<uint64_t, 8> Addresses;
Obj.ReadULEB128s(LLC->DataOffset, Addresses);
Obj.ReadULEB128s(LLC.DataOffset, Addresses);
for (unsigned i = 0, e = Addresses.size(); i != e; ++i)
outs() << " # Address " << i << '\n'
<< " ('address', " << format("0x%x", Addresses[i]) << "),\n";
@ -332,28 +284,22 @@ static int DumpLinkeditDataCommand(MachOObject &Obj,
return 0;
}
static int DumpDataInCodeDataCommand(MachOObject &Obj,
const MachOObject::LoadCommandInfo &LCI) {
InMemoryStruct<macho::LinkeditDataLoadCommand> LLC;
Obj.ReadLinkeditDataLoadCommand(LCI, LLC);
if (!LLC)
return Error("unable to read data-in-code load command");
outs() << " ('dataoff', " << LLC->DataOffset << ")\n"
<< " ('datasize', " << LLC->DataSize << ")\n"
static int
DumpDataInCodeDataCommand(const MachOObjectFile &Obj,
const MachOObjectFile::LoadCommandInfo &LCI) {
macho::LinkeditDataLoadCommand LLC = Obj.getLinkeditDataLoadCommand(LCI);
outs() << " ('dataoff', " << LLC.DataOffset << ")\n"
<< " ('datasize', " << LLC.DataSize << ")\n"
<< " ('_data_regions', [\n";
unsigned NumRegions = LLC->DataSize / 8;
unsigned NumRegions = LLC.DataSize / 8;
for (unsigned i = 0; i < NumRegions; ++i) {
InMemoryStruct<macho::DataInCodeTableEntry> DICE;
Obj.ReadDataInCodeTableEntry(LLC->DataOffset, i, DICE);
if (!DICE)
return Error("unable to read DataInCodeTableEntry");
macho::DataInCodeTableEntry DICE =
Obj.getDataInCodeTableEntry(LLC.DataOffset, i);
outs() << " # DICE " << i << "\n"
<< " ('offset', " << DICE->Offset << ")\n"
<< " ('length', " << DICE->Length << ")\n"
<< " ('kind', " << DICE->Kind << ")\n";
<< " ('offset', " << DICE.Offset << ")\n"
<< " ('length', " << DICE.Length << ")\n"
<< " ('kind', " << DICE.Kind << ")\n";
}
outs() <<" ])\n";
@ -361,99 +307,111 @@ static int DumpDataInCodeDataCommand(MachOObject &Obj,
return 0;
}
static int DumpLinkerOptionsCommand(MachOObject &Obj,
const MachOObject::LoadCommandInfo &LCI) {
InMemoryStruct<macho::LinkerOptionsLoadCommand> LOLC;
Obj.ReadLinkerOptionsLoadCommand(LCI, LOLC);
if (!LOLC)
return Error("unable to read linker options load command");
static int
DumpLinkerOptionsCommand(const MachOObjectFile &Obj,
const MachOObjectFile::LoadCommandInfo &LCI) {
macho::LinkerOptionsLoadCommand LOLC = Obj.getLinkerOptionsLoadCommand(LCI);
outs() << " ('count', " << LOLC.Count << ")\n"
<< " ('_strings', [\n";
outs() << " ('count', " << LOLC->Count << ")\n"
<< " ('_strings', [\n";
uint64_t DataSize = LOLC->Size - sizeof(macho::LinkerOptionsLoadCommand);
StringRef Data = Obj.getData(
LCI.Offset + sizeof(macho::LinkerOptionsLoadCommand), DataSize);
for (unsigned i = 0; i != LOLC->Count; ++i) {
std::pair<StringRef,StringRef> Split = Data.split('\0');
outs() << "\t\"";
outs().write_escaped(Split.first);
outs() << "\",\n";
Data = Split.second;
}
outs() <<" ])\n";
uint64_t DataSize = LOLC.Size - sizeof(macho::LinkerOptionsLoadCommand);
const char *P = LCI.Ptr + sizeof(macho::LinkerOptionsLoadCommand);
StringRef Data(P, DataSize);
for (unsigned i = 0; i != LOLC.Count; ++i) {
std::pair<StringRef,StringRef> Split = Data.split('\0');
outs() << "\t\"";
outs().write_escaped(Split.first);
outs() << "\",\n";
Data = Split.second;
}
outs() <<" ])\n";
return 0;
}
static int DumpLoadCommand(MachOObject &Obj, unsigned Index) {
const MachOObject::LoadCommandInfo &LCI = Obj.getLoadCommandInfo(Index);
int Res = 0;
outs() << " # Load Command " << Index << "\n"
<< " (('command', " << LCI.Command.Type << ")\n"
<< " ('size', " << LCI.Command.Size << ")\n";
switch (LCI.Command.Type) {
static int DumpLoadCommand(const MachOObjectFile &Obj,
MachOObjectFile::LoadCommandInfo &LCI) {
switch (LCI.C.Type) {
case macho::LCT_Segment:
Res = DumpSegmentCommand(Obj, LCI);
break;
return DumpSegmentCommand(Obj, LCI);
case macho::LCT_Segment64:
Res = DumpSegment64Command(Obj, LCI);
break;
return DumpSegment64Command(Obj, LCI);
case macho::LCT_Symtab:
Res = DumpSymtabCommand(Obj, LCI);
break;
return DumpSymtabCommand(Obj);
case macho::LCT_Dysymtab:
Res = DumpDysymtabCommand(Obj, LCI);
break;
return DumpDysymtabCommand(Obj);
case macho::LCT_CodeSignature:
case macho::LCT_SegmentSplitInfo:
case macho::LCT_FunctionStarts:
Res = DumpLinkeditDataCommand(Obj, LCI);
break;
return DumpLinkeditDataCommand(Obj, LCI);
case macho::LCT_DataInCode:
Res = DumpDataInCodeDataCommand(Obj, LCI);
break;
return DumpDataInCodeDataCommand(Obj, LCI);
case macho::LCT_LinkerOptions:
Res = DumpLinkerOptionsCommand(Obj, LCI);
break;
return DumpLinkerOptionsCommand(Obj, LCI);
default:
Warning("unknown load command: " + Twine(LCI.Command.Type));
break;
Warning("unknown load command: " + Twine(LCI.C.Type));
return 0;
}
outs() << " ),\n";
}
static int DumpLoadCommand(const MachOObjectFile &Obj, unsigned Index,
MachOObjectFile::LoadCommandInfo &LCI) {
outs() << " # Load Command " << Index << "\n"
<< " (('command', " << LCI.C.Type << ")\n"
<< " ('size', " << LCI.C.Size << ")\n";
int Res = DumpLoadCommand(Obj, LCI);
outs() << " ),\n";
return Res;
}
static void printHeader(const MachOObjectFile *Obj,
const macho::Header &Header) {
outs() << "('cputype', " << Header.CPUType << ")\n";
outs() << "('cpusubtype', " << Header.CPUSubtype << ")\n";
outs() << "('filetype', " << Header.FileType << ")\n";
outs() << "('num_load_commands', " << Header.NumLoadCommands << ")\n";
outs() << "('load_commands_size', " << Header.SizeOfLoadCommands << ")\n";
outs() << "('flag', " << Header.Flags << ")\n";
// Print extended header if 64-bit.
if (Obj->is64Bit()) {
macho::Header64Ext Header64Ext = Obj->getHeader64Ext();
outs() << "('reserved', " << Header64Ext.Reserved << ")\n";
}
}
int main(int argc, char **argv) {
ProgramName = argv[0];
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
cl::ParseCommandLineOptions(argc, argv, "llvm Mach-O dumping tool\n");
// Load the input file.
std::string ErrorStr;
OwningPtr<MemoryBuffer> InputBuffer;
if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFile, InputBuffer))
return Error("unable to read input: '" + ec.message() + "'");
OwningPtr<Binary> Binary;
if (error_code EC = createBinary(InputFile, Binary))
return Error("unable to read input: '" + EC.message() + "'");
// Construct the Mach-O wrapper object.
OwningPtr<MachOObject> InputObject(
MachOObject::LoadFromBuffer(InputBuffer.take(), &ErrorStr));
const MachOObjectFile *InputObject = dyn_cast<MachOObjectFile>(Binary.get());
if (!InputObject)
return Error("unable to load object: '" + ErrorStr + "'");
return Error("Not a MachO object");
// Print the header
InputObject->printHeader(outs());
macho::Header Header = InputObject->getHeader();
printHeader(InputObject, Header);
// Print the load commands.
int Res = 0;
MachOObjectFile::LoadCommandInfo Command =
InputObject->getFirstLoadCommandInfo();
outs() << "('load_commands', [\n";
for (unsigned i = 0; i != InputObject->getHeader().NumLoadCommands; ++i)
if ((Res = DumpLoadCommand(*InputObject, i)))
for (unsigned i = 0; ; ++i) {
if (DumpLoadCommand(*InputObject, i, Command))
break;
if (i == Header.NumLoadCommands - 1)
break;
Command = InputObject->getNextLoadCommandInfo(Command);
}
outs() << "])\n";
return Res;