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