From: Daniel Dunbar Date: Sat, 27 Nov 2010 08:22:29 +0000 (+0000) Subject: macho-dump: Add support for dumping segment load commands. X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=4ba1f5e0011fa0c17ff121634bf8e88270f3b52e;p=oota-llvm.git macho-dump: Add support for dumping segment load commands. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@120203 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/Object/MachOFormat.h b/include/llvm/Object/MachOFormat.h index 87e4f4241ce..c0c61e1a83b 100644 --- a/include/llvm/Object/MachOFormat.h +++ b/include/llvm/Object/MachOFormat.h @@ -146,6 +146,39 @@ namespace macho { uint32_t Size; }; + /// @name Load Command Structures + /// @{ + + struct SegmentLoadCommand { + uint32_t Type; + uint32_t Size; + char Name[16]; + uint32_t VMAddress; + uint32_t VMSize; + uint32_t FileOffset; + uint32_t FileSize; + uint32_t MaxVMProtection; + uint32_t InitialVMProtection; + uint32_t NumSections; + uint32_t Flags; + }; + + struct Segment64LoadCommand { + uint32_t Type; + uint32_t Size; + char Name[16]; + uint64_t VMAddress; + uint64_t VMSize; + uint64_t FileOffset; + uint64_t FileSize; + uint32_t MaxVMProtection; + uint32_t InitialVMProtection; + uint32_t NumSections; + uint32_t Flags; + }; + + /// @} + // See . enum SymbolTypeType { STT_Undefined = 0x00, diff --git a/include/llvm/Object/MachOObject.h b/include/llvm/Object/MachOObject.h index 49007686812..af235e2b0ff 100644 --- a/include/llvm/Object/MachOObject.h +++ b/include/llvm/Object/MachOObject.h @@ -11,6 +11,7 @@ #define LLVM_OBJECT_MACHOOBJECT_H #include +#include "llvm/ADT/InMemoryStruct.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Object/MachOFormat.h" @@ -88,6 +89,7 @@ public: /// @{ bool isLittleEndian() const { return IsLittleEndian; } + bool isSwappedEndian() const { return IsSwappedEndian; } bool is64Bit() const { return Is64Bit; } unsigned getHeaderSize() const { @@ -111,6 +113,13 @@ public: /// \brief Retrieve the information for the given load command. const LoadCommandInfo &getLoadCommandInfo(unsigned Index) const; + void ReadSegmentLoadCommand( + const LoadCommandInfo &LCI, + InMemoryStruct &Res) const; + void ReadSegment64LoadCommand( + const LoadCommandInfo &LCI, + InMemoryStruct &Res) const; + /// @} }; diff --git a/lib/Object/MachOObject.cpp b/lib/Object/MachOObject.cpp index 5c17dfcfe9c..ce817d6cac2 100644 --- a/lib/Object/MachOObject.cpp +++ b/lib/Object/MachOObject.cpp @@ -16,11 +16,43 @@ using namespace llvm; using namespace llvm::object; +/* Translation Utilities */ + template static void SwapValue(T &Value) { Value = sys::SwapByteOrder(Value); } +template +static void SwapStruct(T &Value); + +template +static void ReadInMemoryStruct(const MachOObject &MOO, + StringRef Buffer, uint64_t Base, + InMemoryStruct &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_), @@ -120,3 +152,39 @@ MachOObject::getLoadCommandInfo(unsigned Index) const { return LoadCommands[Index]; } + +template<> +static 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 &Res) const { + ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res); +} + +template<> +static 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 &Res) const { + ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res); +} diff --git a/tools/macho-dump/macho-dump.cpp b/tools/macho-dump/macho-dump.cpp index 8bfd1890c64..34a95276652 100644 --- a/tools/macho-dump/macho-dump.cpp +++ b/tools/macho-dump/macho-dump.cpp @@ -65,20 +65,73 @@ static int DumpHeader(MachOObject &Obj) { return 0; } +static void DumpSegmentCommandData(StringRef Name, + uint64_t VMAddr, uint64_t VMSize, + uint64_t FileOffset, uint64_t FileSize, + uint32_t MaxProt, uint32_t InitProt, + uint32_t NumSections, uint32_t Flags) { + outs() << " ('segment_name', '"; + outs().write_escaped(Name, /*UseHexEscapes=*/true) << "')\n"; + outs() << " ('vm_addr', " << VMAddr << ")\n"; + outs() << " ('vm_size', " << VMSize << ")\n"; + outs() << " ('file_offset', " << FileOffset << ")\n"; + outs() << " ('file_size', " << FileSize << ")\n"; + outs() << " ('maxprot', " << MaxProt << ")\n"; + outs() << " ('initprot', " << InitProt << ")\n"; + outs() << " ('num_sections', " << NumSections << ")\n"; + outs() << " ('flags', " << Flags << ")\n"; +} + +static int DumpSegmentCommand(MachOObject &Obj, + const MachOObject::LoadCommandInfo &LCI) { + InMemoryStruct SLC; + Obj.ReadSegmentLoadCommand(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); + + return 0; +} +static int DumpSegment64Command(MachOObject &Obj, + const MachOObject::LoadCommandInfo &LCI) { + InMemoryStruct 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); + + 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) { + case macho::LCT_Segment: + Res = DumpSegmentCommand(Obj, LCI); + break; + case macho::LCT_Segment64: + Res = DumpSegment64Command(Obj, LCI); + break; default: Warning("unknown load command: " + Twine(LCI.Command.Type)); break; } outs() << " ),\n"; - return 0; + return Res; } int main(int argc, char **argv) { @@ -104,10 +157,12 @@ int main(int argc, char **argv) { return Res; // Print the load commands. + int Res = 0; outs() << "('load_commands', [\n"; for (unsigned i = 0; i != InputObject->getHeader().NumLoadCommands; ++i) - DumpLoadCommand(*InputObject, i); + if ((Res = DumpLoadCommand(*InputObject, i))) + break; outs() << "])\n"; - return 0; + return Res; }