diff options
Diffstat (limited to 'lib/Object')
-rw-r--r-- | lib/Object/MachOObject.cpp | 83 |
1 files changed, 80 insertions, 3 deletions
diff --git a/lib/Object/MachOObject.cpp b/lib/Object/MachOObject.cpp index de87605..5c17dfc 100644 --- a/lib/Object/MachOObject.cpp +++ b/lib/Object/MachOObject.cpp @@ -10,13 +10,49 @@ #include "llvm/Object/MachOObject.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/System/Host.h" +#include "llvm/System/SwapByteOrder.h" using namespace llvm; -using namespace object; +using namespace llvm::object; + +template<typename T> +static void SwapValue(T &Value) { + Value = sys::SwapByteOrder(Value); +} MachOObject::MachOObject(MemoryBuffer *Buffer_, bool IsLittleEndian_, bool Is64Bit_) - : Buffer(Buffer_), IsLittleEndian(IsLittleEndian_), Is64Bit(Is64Bit_) { + : Buffer(Buffer_), IsLittleEndian(IsLittleEndian_), Is64Bit(Is64Bit_), + IsSwappedEndian(IsLittleEndian != sys::isLittleEndianHost()), + 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, @@ -33,13 +69,54 @@ MachOObject *MachOObject::LoadFromBuffer(MemoryBuffer *Buffer, IsLittleEndian = true; Is64Bit = true; } else { - *ErrorStr = "not a Mach object file"; + 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(); } + +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]; +} |