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 20using namespace llvm; 21using namespace llvm::object; 22 23/* Translation Utilities */ 24 25template<typename T> 26static void SwapValue(T &Value) { 27 Value = sys::SwapByteOrder(Value); 28} 29 30template<typename T> 31static void SwapStruct(T &Value); 32 33template<typename T> 34static 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 60MachOObject::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 90MachOObject::~MachOObject() { 91 delete [] LoadCommands; 92} 93 94MachOObject *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 132StringRef MachOObject::getData(size_t Offset, size_t Size) const { 133 return Buffer->getBuffer().substr(Offset,Size); 134} 135 136void MachOObject::RegisterStringTable(macho::SymtabLoadCommand &SLC) { 137 HasStringTable = true; 138 StringTable = Buffer->getBuffer().substr(SLC.StringTableOffset, 139 SLC.StringTableSize); 140} 141 142const MachOObject::LoadCommandInfo & 143MachOObject::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 170template<> 171void 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} 183void MachOObject::ReadSegmentLoadCommand(const LoadCommandInfo &LCI, 184 InMemoryStruct<macho::SegmentLoadCommand> &Res) const { 185 ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res); 186} 187 188template<> 189void 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} 201void MachOObject::ReadSegment64LoadCommand(const LoadCommandInfo &LCI, 202 InMemoryStruct<macho::Segment64LoadCommand> &Res) const { 203 ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res); 204} 205 206template<> 207void 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} 215void MachOObject::ReadSymtabLoadCommand(const LoadCommandInfo &LCI, 216 InMemoryStruct<macho::SymtabLoadCommand> &Res) const { 217 ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res); 218} 219 220template<> 221void 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} 243void MachOObject::ReadDysymtabLoadCommand(const LoadCommandInfo &LCI, 244 InMemoryStruct<macho::DysymtabLoadCommand> &Res) const { 245 ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res); 246} 247 248template<> 249void SwapStruct(macho::LinkeditDataLoadCommand &Value) { 250 SwapValue(Value.Type); 251 SwapValue(Value.Size); 252 SwapValue(Value.DataOffset); 253 SwapValue(Value.DataSize); 254} 255void MachOObject::ReadLinkeditDataLoadCommand(const LoadCommandInfo &LCI, 256 InMemoryStruct<macho::LinkeditDataLoadCommand> &Res) const { 257 ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res); 258} 259 260template<> 261void SwapStruct(macho::IndirectSymbolTableEntry &Value) { 262 SwapValue(Value.Index); 263} 264void 265MachOObject::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 274template<> 275void 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} 286void 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 296template<> 297void 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} 309void 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 319template<> 320void SwapStruct(macho::RelocationEntry &Value) { 321 SwapValue(Value.Word0); 322 SwapValue(Value.Word1); 323} 324void 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 332template<> 333void SwapStruct(macho::SymbolTableEntry &Value) { 334 SwapValue(Value.StringIndex); 335 SwapValue(Value.Flags); 336 SwapValue(Value.Value); 337} 338void 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 346template<> 347void SwapStruct(macho::Symbol64TableEntry &Value) { 348 SwapValue(Value.StringIndex); 349 SwapValue(Value.Flags); 350 SwapValue(Value.Value); 351} 352void 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 360template<> 361void SwapStruct(macho::DataInCodeTableEntry &Value) { 362 SwapValue(Value.Offset); 363 SwapValue(Value.Length); 364 SwapValue(Value.Kind); 365} 366void 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 374void 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 388void MachOObject::dump() const { print(dbgs()); dbgs() << '\n'; } 389void MachOObject::dumpHeader() const { printHeader(dbgs()); dbgs() << '\n'; } 390 391void 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 404void 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