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 361 void MachOObject::ReadULEB128s(uint64_t Index, 362 SmallVectorImpl<uint64_t> &Out) const { 363 DataExtractor extractor(Buffer->getBuffer(), true, 0); 364 365 uint32_t offset = Index; 366 uint64_t data = 0; 367 while (uint64_t delta = extractor.getULEB128(&offset)) { 368 data += delta; 369 Out.push_back(data); 370 } 371 } 372 373 /* ** */ 374 // Object Dumping Facilities 375 void MachOObject::dump() const { print(dbgs()); dbgs() << '\n'; } 376 void MachOObject::dumpHeader() const { printHeader(dbgs()); dbgs() << '\n'; } 377 378 void MachOObject::printHeader(raw_ostream &O) const { 379 O << "('cputype', " << Header.CPUType << ")\n"; 380 O << "('cpusubtype', " << Header.CPUSubtype << ")\n"; 381 O << "('filetype', " << Header.FileType << ")\n"; 382 O << "('num_load_commands', " << Header.NumLoadCommands << ")\n"; 383 O << "('load_commands_size', " << Header.SizeOfLoadCommands << ")\n"; 384 O << "('flag', " << Header.Flags << ")\n"; 385 386 // Print extended header if 64-bit. 387 if (is64Bit()) 388 O << "('reserved', " << Header64Ext.Reserved << ")\n"; 389 } 390 391 void MachOObject::print(raw_ostream &O) const { 392 O << "Header:\n"; 393 printHeader(O); 394 O << "Load Commands:\n"; 395 396 O << "Buffer:\n"; 397 } 398