Home | History | Annotate | Download | only in Object
      1 //===- MachOObject.cpp - Mach-O Object File Wrapper -----------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "llvm/Object/MachOObject.h"
     11 #include "llvm/ADT/StringRef.h"
     12 #include "llvm/ADT/SmallVector.h"
     13 #include "llvm/Support/MemoryBuffer.h"
     14 #include "llvm/Support/Host.h"
     15 #include "llvm/Support/SwapByteOrder.h"
     16 #include "llvm/Support/raw_ostream.h"
     17 #include "llvm/Support/Debug.h"
     18 
     19 using namespace llvm;
     20 using namespace llvm::object;
     21 
     22 /* Translation Utilities */
     23 
     24 template<typename T>
     25 static void SwapValue(T &Value) {
     26   Value = sys::SwapByteOrder(Value);
     27 }
     28 
     29 template<typename T>
     30 static void SwapStruct(T &Value);
     31 
     32 template<typename T>
     33 static void ReadInMemoryStruct(const MachOObject &MOO,
     34                                StringRef Buffer, uint64_t Base,
     35                                InMemoryStruct<T> &Res) {
     36   typedef T struct_type;
     37   uint64_t Size = sizeof(struct_type);
     38 
     39   // Check that the buffer contains the expected data.
     40   if (Base + Size >  Buffer.size()) {
     41     Res = 0;
     42     return;
     43   }
     44 
     45   // Check whether we can return a direct pointer.
     46   struct_type *Ptr = (struct_type *) (Buffer.data() + Base);
     47   if (!MOO.isSwappedEndian()) {
     48     Res = Ptr;
     49     return;
     50   }
     51 
     52   // Otherwise, copy the struct and translate the values.
     53   Res = *Ptr;
     54   SwapStruct(*Res);
     55 }
     56 
     57 /* *** */
     58 
     59 MachOObject::MachOObject(MemoryBuffer *Buffer_, bool IsLittleEndian_,
     60                          bool Is64Bit_)
     61   : Buffer(Buffer_), IsLittleEndian(IsLittleEndian_), Is64Bit(Is64Bit_),
     62     IsSwappedEndian(IsLittleEndian != sys::isLittleEndianHost()),
     63     HasStringTable(false), LoadCommands(0), NumLoadedCommands(0) {
     64   // Load the common header.
     65   memcpy(&Header, Buffer->getBuffer().data(), sizeof(Header));
     66   if (IsSwappedEndian) {
     67     SwapValue(Header.Magic);
     68     SwapValue(Header.CPUType);
     69     SwapValue(Header.CPUSubtype);
     70     SwapValue(Header.FileType);
     71     SwapValue(Header.NumLoadCommands);
     72     SwapValue(Header.SizeOfLoadCommands);
     73     SwapValue(Header.Flags);
     74   }
     75 
     76   if (is64Bit()) {
     77     memcpy(&Header64Ext, Buffer->getBuffer().data() + sizeof(Header),
     78            sizeof(Header64Ext));
     79     if (IsSwappedEndian) {
     80       SwapValue(Header64Ext.Reserved);
     81     }
     82   }
     83 
     84   // Create the load command array if sane.
     85   if (getHeader().NumLoadCommands < (1 << 20))
     86     LoadCommands = new LoadCommandInfo[getHeader().NumLoadCommands];
     87 }
     88 
     89 MachOObject::~MachOObject() {
     90   delete [] LoadCommands;
     91 }
     92 
     93 MachOObject *MachOObject::LoadFromBuffer(MemoryBuffer *Buffer,
     94                                          std::string *ErrorStr) {
     95   // First, check the magic value and initialize the basic object info.
     96   bool IsLittleEndian = false, Is64Bit = false;
     97   StringRef Magic = Buffer->getBuffer().slice(0, 4);
     98   if (Magic == "\xFE\xED\xFA\xCE") {
     99   }  else if (Magic == "\xCE\xFA\xED\xFE") {
    100     IsLittleEndian = true;
    101   } else if (Magic == "\xFE\xED\xFA\xCF") {
    102     Is64Bit = true;
    103   } else if (Magic == "\xCF\xFA\xED\xFE") {
    104     IsLittleEndian = true;
    105     Is64Bit = true;
    106   } else {
    107     if (ErrorStr) *ErrorStr = "not a Mach object file (invalid magic)";
    108     return 0;
    109   }
    110 
    111   // Ensure that the at least the full header is present.
    112   unsigned HeaderSize = Is64Bit ? macho::Header64Size : macho::Header32Size;
    113   if (Buffer->getBufferSize() < HeaderSize) {
    114     if (ErrorStr) *ErrorStr = "not a Mach object file (invalid header)";
    115     return 0;
    116   }
    117 
    118   OwningPtr<MachOObject> Object(new MachOObject(Buffer, IsLittleEndian,
    119                                                 Is64Bit));
    120 
    121   // Check for bogus number of load commands.
    122   if (Object->getHeader().NumLoadCommands >= (1 << 20)) {
    123     if (ErrorStr) *ErrorStr = "not a Mach object file (unreasonable header)";
    124     return 0;
    125   }
    126 
    127   if (ErrorStr) *ErrorStr = "";
    128   return Object.take();
    129 }
    130 
    131 StringRef MachOObject::getData(size_t Offset, size_t Size) const {
    132   return Buffer->getBuffer().substr(Offset,Size);
    133 }
    134 
    135 void MachOObject::RegisterStringTable(macho::SymtabLoadCommand &SLC) {
    136   HasStringTable = true;
    137   StringTable = Buffer->getBuffer().substr(SLC.StringTableOffset,
    138                                            SLC.StringTableSize);
    139 }
    140 
    141 const MachOObject::LoadCommandInfo &
    142 MachOObject::getLoadCommandInfo(unsigned Index) const {
    143   assert(Index < getHeader().NumLoadCommands && "Invalid index!");
    144 
    145   // Load the command, if necessary.
    146   if (Index >= NumLoadedCommands) {
    147     uint64_t Offset;
    148     if (Index == 0) {
    149       Offset = getHeaderSize();
    150     } else {
    151       const LoadCommandInfo &Prev = getLoadCommandInfo(Index - 1);
    152       Offset = Prev.Offset + Prev.Command.Size;
    153     }
    154 
    155     LoadCommandInfo &Info = LoadCommands[Index];
    156     memcpy(&Info.Command, Buffer->getBuffer().data() + Offset,
    157            sizeof(macho::LoadCommand));
    158     if (IsSwappedEndian) {
    159       SwapValue(Info.Command.Type);
    160       SwapValue(Info.Command.Size);
    161     }
    162     Info.Offset = Offset;
    163     NumLoadedCommands = Index + 1;
    164   }
    165 
    166   return LoadCommands[Index];
    167 }
    168 
    169 template<>
    170 void SwapStruct(macho::SegmentLoadCommand &Value) {
    171   SwapValue(Value.Type);
    172   SwapValue(Value.Size);
    173   SwapValue(Value.VMAddress);
    174   SwapValue(Value.VMSize);
    175   SwapValue(Value.FileOffset);
    176   SwapValue(Value.FileSize);
    177   SwapValue(Value.MaxVMProtection);
    178   SwapValue(Value.InitialVMProtection);
    179   SwapValue(Value.NumSections);
    180   SwapValue(Value.Flags);
    181 }
    182 void MachOObject::ReadSegmentLoadCommand(const LoadCommandInfo &LCI,
    183                          InMemoryStruct<macho::SegmentLoadCommand> &Res) const {
    184   ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res);
    185 }
    186 
    187 template<>
    188 void SwapStruct(macho::Segment64LoadCommand &Value) {
    189   SwapValue(Value.Type);
    190   SwapValue(Value.Size);
    191   SwapValue(Value.VMAddress);
    192   SwapValue(Value.VMSize);
    193   SwapValue(Value.FileOffset);
    194   SwapValue(Value.FileSize);
    195   SwapValue(Value.MaxVMProtection);
    196   SwapValue(Value.InitialVMProtection);
    197   SwapValue(Value.NumSections);
    198   SwapValue(Value.Flags);
    199 }
    200 void MachOObject::ReadSegment64LoadCommand(const LoadCommandInfo &LCI,
    201                        InMemoryStruct<macho::Segment64LoadCommand> &Res) const {
    202   ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res);
    203 }
    204 
    205 template<>
    206 void SwapStruct(macho::SymtabLoadCommand &Value) {
    207   SwapValue(Value.Type);
    208   SwapValue(Value.Size);
    209   SwapValue(Value.SymbolTableOffset);
    210   SwapValue(Value.NumSymbolTableEntries);
    211   SwapValue(Value.StringTableOffset);
    212   SwapValue(Value.StringTableSize);
    213 }
    214 void MachOObject::ReadSymtabLoadCommand(const LoadCommandInfo &LCI,
    215                           InMemoryStruct<macho::SymtabLoadCommand> &Res) const {
    216   ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res);
    217 }
    218 
    219 template<>
    220 void SwapStruct(macho::DysymtabLoadCommand &Value) {
    221   SwapValue(Value.Type);
    222   SwapValue(Value.Size);
    223   SwapValue(Value.LocalSymbolsIndex);
    224   SwapValue(Value.NumLocalSymbols);
    225   SwapValue(Value.ExternalSymbolsIndex);
    226   SwapValue(Value.NumExternalSymbols);
    227   SwapValue(Value.UndefinedSymbolsIndex);
    228   SwapValue(Value.NumUndefinedSymbols);
    229   SwapValue(Value.TOCOffset);
    230   SwapValue(Value.NumTOCEntries);
    231   SwapValue(Value.ModuleTableOffset);
    232   SwapValue(Value.NumModuleTableEntries);
    233   SwapValue(Value.ReferenceSymbolTableOffset);
    234   SwapValue(Value.NumReferencedSymbolTableEntries);
    235   SwapValue(Value.IndirectSymbolTableOffset);
    236   SwapValue(Value.NumIndirectSymbolTableEntries);
    237   SwapValue(Value.ExternalRelocationTableOffset);
    238   SwapValue(Value.NumExternalRelocationTableEntries);
    239   SwapValue(Value.LocalRelocationTableOffset);
    240   SwapValue(Value.NumLocalRelocationTableEntries);
    241 }
    242 void MachOObject::ReadDysymtabLoadCommand(const LoadCommandInfo &LCI,
    243                         InMemoryStruct<macho::DysymtabLoadCommand> &Res) const {
    244   ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res);
    245 }
    246 
    247 template<>
    248 void SwapStruct(macho::LinkeditDataLoadCommand &Value) {
    249   SwapValue(Value.Type);
    250   SwapValue(Value.Size);
    251   SwapValue(Value.DataOffset);
    252   SwapValue(Value.DataSize);
    253 }
    254 void MachOObject::ReadLinkeditDataLoadCommand(const LoadCommandInfo &LCI,
    255                     InMemoryStruct<macho::LinkeditDataLoadCommand> &Res) const {
    256   ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res);
    257 }
    258 
    259 template<>
    260 void SwapStruct(macho::IndirectSymbolTableEntry &Value) {
    261   SwapValue(Value.Index);
    262 }
    263 void
    264 MachOObject::ReadIndirectSymbolTableEntry(const macho::DysymtabLoadCommand &DLC,
    265                                           unsigned Index,
    266                    InMemoryStruct<macho::IndirectSymbolTableEntry> &Res) const {
    267   uint64_t Offset = (DLC.IndirectSymbolTableOffset +
    268                      Index * sizeof(macho::IndirectSymbolTableEntry));
    269   ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res);
    270 }
    271 
    272 
    273 template<>
    274 void SwapStruct(macho::Section &Value) {
    275   SwapValue(Value.Address);
    276   SwapValue(Value.Size);
    277   SwapValue(Value.Offset);
    278   SwapValue(Value.Align);
    279   SwapValue(Value.RelocationTableOffset);
    280   SwapValue(Value.NumRelocationTableEntries);
    281   SwapValue(Value.Flags);
    282   SwapValue(Value.Reserved1);
    283   SwapValue(Value.Reserved2);
    284 }
    285 void MachOObject::ReadSection(const LoadCommandInfo &LCI,
    286                               unsigned Index,
    287                               InMemoryStruct<macho::Section> &Res) const {
    288   assert(LCI.Command.Type == macho::LCT_Segment &&
    289          "Unexpected load command info!");
    290   uint64_t Offset = (LCI.Offset + sizeof(macho::SegmentLoadCommand) +
    291                      Index * sizeof(macho::Section));
    292   ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res);
    293 }
    294 
    295 template<>
    296 void SwapStruct(macho::Section64 &Value) {
    297   SwapValue(Value.Address);
    298   SwapValue(Value.Size);
    299   SwapValue(Value.Offset);
    300   SwapValue(Value.Align);
    301   SwapValue(Value.RelocationTableOffset);
    302   SwapValue(Value.NumRelocationTableEntries);
    303   SwapValue(Value.Flags);
    304   SwapValue(Value.Reserved1);
    305   SwapValue(Value.Reserved2);
    306   SwapValue(Value.Reserved3);
    307 }
    308 void MachOObject::ReadSection64(const LoadCommandInfo &LCI,
    309                                 unsigned Index,
    310                                 InMemoryStruct<macho::Section64> &Res) const {
    311   assert(LCI.Command.Type == macho::LCT_Segment64 &&
    312          "Unexpected load command info!");
    313   uint64_t Offset = (LCI.Offset + sizeof(macho::Segment64LoadCommand) +
    314                      Index * sizeof(macho::Section64));
    315   ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res);
    316 }
    317 
    318 template<>
    319 void SwapStruct(macho::RelocationEntry &Value) {
    320   SwapValue(Value.Word0);
    321   SwapValue(Value.Word1);
    322 }
    323 void MachOObject::ReadRelocationEntry(uint64_t RelocationTableOffset,
    324                                       unsigned Index,
    325                             InMemoryStruct<macho::RelocationEntry> &Res) const {
    326   uint64_t Offset = (RelocationTableOffset +
    327                      Index * sizeof(macho::RelocationEntry));
    328   ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res);
    329 }
    330 
    331 template<>
    332 void SwapStruct(macho::SymbolTableEntry &Value) {
    333   SwapValue(Value.StringIndex);
    334   SwapValue(Value.Flags);
    335   SwapValue(Value.Value);
    336 }
    337 void MachOObject::ReadSymbolTableEntry(uint64_t SymbolTableOffset,
    338                                        unsigned Index,
    339                            InMemoryStruct<macho::SymbolTableEntry> &Res) const {
    340   uint64_t Offset = (SymbolTableOffset +
    341                      Index * sizeof(macho::SymbolTableEntry));
    342   ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res);
    343 }
    344 
    345 template<>
    346 void SwapStruct(macho::Symbol64TableEntry &Value) {
    347   SwapValue(Value.StringIndex);
    348   SwapValue(Value.Flags);
    349   SwapValue(Value.Value);
    350 }
    351 void MachOObject::ReadSymbol64TableEntry(uint64_t SymbolTableOffset,
    352                                        unsigned Index,
    353                          InMemoryStruct<macho::Symbol64TableEntry> &Res) const {
    354   uint64_t Offset = (SymbolTableOffset +
    355                      Index * sizeof(macho::Symbol64TableEntry));
    356   ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res);
    357 }
    358 
    359 
    360 void MachOObject::ReadULEB128s(uint64_t Index,
    361                                SmallVectorImpl<uint64_t> &Out) const {
    362   const char *ptr = Buffer->getBufferStart() + Index;
    363   uint64_t data = 0;
    364   uint64_t delta = 0;
    365   uint32_t shift = 0;
    366   while (true) {
    367     assert(ptr < Buffer->getBufferEnd() && "index out of bounds");
    368     assert(shift < 64 && "too big for uint64_t");
    369 
    370     uint8_t byte = *ptr++;
    371     delta |= ((byte & 0x7F) << shift);
    372     shift += 7;
    373     if (byte < 0x80) {
    374       if (delta == 0)
    375         break;
    376       data += delta;
    377       Out.push_back(data);
    378       delta = 0;
    379       shift = 0;
    380     }
    381   }
    382 }
    383 
    384 /* ** */
    385 // Object Dumping Facilities
    386 void MachOObject::dump() const { print(dbgs()); dbgs() << '\n'; }
    387 void MachOObject::dumpHeader() const { printHeader(dbgs()); dbgs() << '\n'; }
    388 
    389 void MachOObject::printHeader(raw_ostream &O) const {
    390   O << "('cputype', " << Header.CPUType << ")\n";
    391   O << "('cpusubtype', " << Header.CPUSubtype << ")\n";
    392   O << "('filetype', " << Header.FileType << ")\n";
    393   O << "('num_load_commands', " << Header.NumLoadCommands << ")\n";
    394   O << "('load_commands_size', " << Header.SizeOfLoadCommands << ")\n";
    395   O << "('flag', " << Header.Flags << ")\n";
    396 
    397   // Print extended header if 64-bit.
    398   if (is64Bit())
    399     O << "('reserved', " << Header64Ext.Reserved << ")\n";
    400 }
    401 
    402 void MachOObject::print(raw_ostream &O) const {
    403   O << "Header:\n";
    404   printHeader(O);
    405   O << "Load Commands:\n";
    406 
    407   O << "Buffer:\n";
    408 }
    409