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