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