1 //===- MachOObjectFile.cpp - Mach-O object file binding ---------*- C++ -*-===// 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 // This file defines the MachOObjectFile class, which binds the MachOObject 11 // class to the generic ObjectFile wrapper. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "llvm/ADT/Triple.h" 16 #include "llvm/Object/MachOFormat.h" 17 #include "llvm/Object/MachOObject.h" 18 #include "llvm/Object/ObjectFile.h" 19 #include "llvm/Support/MemoryBuffer.h" 20 #include "llvm/Support/MachO.h" 21 22 #include <cctype> 23 #include <cstring> 24 #include <limits> 25 26 using namespace llvm; 27 using namespace object; 28 29 namespace llvm { 30 31 typedef MachOObject::LoadCommandInfo LoadCommandInfo; 32 33 class MachOObjectFile : public ObjectFile { 34 public: 35 MachOObjectFile(MemoryBuffer *Object, MachOObject *MOO, error_code &ec) 36 : ObjectFile(Binary::isMachO, Object, ec), 37 MachOObj(MOO), 38 RegisteredStringTable(std::numeric_limits<uint32_t>::max()) {} 39 40 virtual symbol_iterator begin_symbols() const; 41 virtual symbol_iterator end_symbols() const; 42 virtual section_iterator begin_sections() const; 43 virtual section_iterator end_sections() const; 44 45 virtual uint8_t getBytesInAddress() const; 46 virtual StringRef getFileFormatName() const; 47 virtual unsigned getArch() const; 48 49 protected: 50 virtual error_code getSymbolNext(DataRefImpl Symb, SymbolRef &Res) const; 51 virtual error_code getSymbolName(DataRefImpl Symb, StringRef &Res) const; 52 virtual error_code getSymbolAddress(DataRefImpl Symb, uint64_t &Res) const; 53 virtual error_code getSymbolSize(DataRefImpl Symb, uint64_t &Res) const; 54 virtual error_code getSymbolNMTypeChar(DataRefImpl Symb, char &Res) const; 55 virtual error_code isSymbolInternal(DataRefImpl Symb, bool &Res) const; 56 57 virtual error_code getSectionNext(DataRefImpl Sec, SectionRef &Res) const; 58 virtual error_code getSectionName(DataRefImpl Sec, StringRef &Res) const; 59 virtual error_code getSectionAddress(DataRefImpl Sec, uint64_t &Res) const; 60 virtual error_code getSectionSize(DataRefImpl Sec, uint64_t &Res) const; 61 virtual error_code getSectionContents(DataRefImpl Sec, StringRef &Res) const; 62 virtual error_code isSectionText(DataRefImpl Sec, bool &Res) const; 63 virtual error_code sectionContainsSymbol(DataRefImpl DRI, DataRefImpl S, 64 bool &Result) const; 65 66 private: 67 MachOObject *MachOObj; 68 mutable uint32_t RegisteredStringTable; 69 70 void moveToNextSection(DataRefImpl &DRI) const; 71 void getSymbolTableEntry(DataRefImpl DRI, 72 InMemoryStruct<macho::SymbolTableEntry> &Res) const; 73 void getSymbol64TableEntry(DataRefImpl DRI, 74 InMemoryStruct<macho::Symbol64TableEntry> &Res) const; 75 void moveToNextSymbol(DataRefImpl &DRI) const; 76 void getSection(DataRefImpl DRI, InMemoryStruct<macho::Section> &Res) const; 77 void getSection64(DataRefImpl DRI, 78 InMemoryStruct<macho::Section64> &Res) const; 79 }; 80 81 ObjectFile *ObjectFile::createMachOObjectFile(MemoryBuffer *Buffer) { 82 error_code ec; 83 std::string Err; 84 MachOObject *MachOObj = MachOObject::LoadFromBuffer(Buffer, &Err); 85 if (!MachOObj) 86 return NULL; 87 return new MachOObjectFile(Buffer, MachOObj, ec); 88 } 89 90 /*===-- Symbols -----------------------------------------------------------===*/ 91 92 void MachOObjectFile::moveToNextSymbol(DataRefImpl &DRI) const { 93 uint32_t LoadCommandCount = MachOObj->getHeader().NumLoadCommands; 94 while (DRI.d.a < LoadCommandCount) { 95 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 96 if (LCI.Command.Type == macho::LCT_Symtab) { 97 InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd; 98 MachOObj->ReadSymtabLoadCommand(LCI, SymtabLoadCmd); 99 if (DRI.d.b < SymtabLoadCmd->NumSymbolTableEntries) 100 return; 101 } 102 103 DRI.d.a++; 104 DRI.d.b = 0; 105 } 106 } 107 108 void MachOObjectFile::getSymbolTableEntry(DataRefImpl DRI, 109 InMemoryStruct<macho::SymbolTableEntry> &Res) const { 110 InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd; 111 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 112 MachOObj->ReadSymtabLoadCommand(LCI, SymtabLoadCmd); 113 114 if (RegisteredStringTable != DRI.d.a) { 115 MachOObj->RegisterStringTable(*SymtabLoadCmd); 116 RegisteredStringTable = DRI.d.a; 117 } 118 119 MachOObj->ReadSymbolTableEntry(SymtabLoadCmd->SymbolTableOffset, DRI.d.b, 120 Res); 121 } 122 123 void MachOObjectFile::getSymbol64TableEntry(DataRefImpl DRI, 124 InMemoryStruct<macho::Symbol64TableEntry> &Res) const { 125 InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd; 126 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 127 MachOObj->ReadSymtabLoadCommand(LCI, SymtabLoadCmd); 128 129 if (RegisteredStringTable != DRI.d.a) { 130 MachOObj->RegisterStringTable(*SymtabLoadCmd); 131 RegisteredStringTable = DRI.d.a; 132 } 133 134 MachOObj->ReadSymbol64TableEntry(SymtabLoadCmd->SymbolTableOffset, DRI.d.b, 135 Res); 136 } 137 138 139 error_code MachOObjectFile::getSymbolNext(DataRefImpl DRI, 140 SymbolRef &Result) const { 141 DRI.d.b++; 142 moveToNextSymbol(DRI); 143 Result = SymbolRef(DRI, this); 144 return object_error::success; 145 } 146 147 error_code MachOObjectFile::getSymbolName(DataRefImpl DRI, 148 StringRef &Result) const { 149 if (MachOObj->is64Bit()) { 150 InMemoryStruct<macho::Symbol64TableEntry> Entry; 151 getSymbol64TableEntry(DRI, Entry); 152 Result = MachOObj->getStringAtIndex(Entry->StringIndex); 153 } else { 154 InMemoryStruct<macho::SymbolTableEntry> Entry; 155 getSymbolTableEntry(DRI, Entry); 156 Result = MachOObj->getStringAtIndex(Entry->StringIndex); 157 } 158 return object_error::success; 159 } 160 161 error_code MachOObjectFile::getSymbolAddress(DataRefImpl DRI, 162 uint64_t &Result) const { 163 if (MachOObj->is64Bit()) { 164 InMemoryStruct<macho::Symbol64TableEntry> Entry; 165 getSymbol64TableEntry(DRI, Entry); 166 Result = Entry->Value; 167 } else { 168 InMemoryStruct<macho::SymbolTableEntry> Entry; 169 getSymbolTableEntry(DRI, Entry); 170 Result = Entry->Value; 171 } 172 return object_error::success; 173 } 174 175 error_code MachOObjectFile::getSymbolSize(DataRefImpl DRI, 176 uint64_t &Result) const { 177 Result = UnknownAddressOrSize; 178 return object_error::success; 179 } 180 181 error_code MachOObjectFile::getSymbolNMTypeChar(DataRefImpl DRI, 182 char &Result) const { 183 uint8_t Type, Flags; 184 if (MachOObj->is64Bit()) { 185 InMemoryStruct<macho::Symbol64TableEntry> Entry; 186 getSymbol64TableEntry(DRI, Entry); 187 Type = Entry->Type; 188 Flags = Entry->Flags; 189 } else { 190 InMemoryStruct<macho::SymbolTableEntry> Entry; 191 getSymbolTableEntry(DRI, Entry); 192 Type = Entry->Type; 193 Flags = Entry->Flags; 194 } 195 196 char Char; 197 switch (Type & macho::STF_TypeMask) { 198 case macho::STT_Undefined: 199 Char = 'u'; 200 break; 201 case macho::STT_Absolute: 202 case macho::STT_Section: 203 Char = 's'; 204 break; 205 default: 206 Char = '?'; 207 break; 208 } 209 210 if (Flags & (macho::STF_External | macho::STF_PrivateExtern)) 211 Char = toupper(Char); 212 Result = Char; 213 return object_error::success; 214 } 215 216 error_code MachOObjectFile::isSymbolInternal(DataRefImpl DRI, 217 bool &Result) const { 218 if (MachOObj->is64Bit()) { 219 InMemoryStruct<macho::Symbol64TableEntry> Entry; 220 getSymbol64TableEntry(DRI, Entry); 221 Result = Entry->Flags & macho::STF_StabsEntryMask; 222 } else { 223 InMemoryStruct<macho::SymbolTableEntry> Entry; 224 getSymbolTableEntry(DRI, Entry); 225 Result = Entry->Flags & macho::STF_StabsEntryMask; 226 } 227 return object_error::success; 228 } 229 230 ObjectFile::symbol_iterator MachOObjectFile::begin_symbols() const { 231 // DRI.d.a = segment number; DRI.d.b = symbol index. 232 DataRefImpl DRI; 233 DRI.d.a = DRI.d.b = 0; 234 moveToNextSymbol(DRI); 235 return symbol_iterator(SymbolRef(DRI, this)); 236 } 237 238 ObjectFile::symbol_iterator MachOObjectFile::end_symbols() const { 239 DataRefImpl DRI; 240 DRI.d.a = MachOObj->getHeader().NumLoadCommands; 241 DRI.d.b = 0; 242 return symbol_iterator(SymbolRef(DRI, this)); 243 } 244 245 246 /*===-- Sections ----------------------------------------------------------===*/ 247 248 void MachOObjectFile::moveToNextSection(DataRefImpl &DRI) const { 249 uint32_t LoadCommandCount = MachOObj->getHeader().NumLoadCommands; 250 while (DRI.d.a < LoadCommandCount) { 251 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 252 if (LCI.Command.Type == macho::LCT_Segment) { 253 InMemoryStruct<macho::SegmentLoadCommand> SegmentLoadCmd; 254 MachOObj->ReadSegmentLoadCommand(LCI, SegmentLoadCmd); 255 if (DRI.d.b < SegmentLoadCmd->NumSections) 256 return; 257 } else if (LCI.Command.Type == macho::LCT_Segment64) { 258 InMemoryStruct<macho::Segment64LoadCommand> Segment64LoadCmd; 259 MachOObj->ReadSegment64LoadCommand(LCI, Segment64LoadCmd); 260 if (DRI.d.b < Segment64LoadCmd->NumSections) 261 return; 262 } 263 264 DRI.d.a++; 265 DRI.d.b = 0; 266 } 267 } 268 269 error_code MachOObjectFile::getSectionNext(DataRefImpl DRI, 270 SectionRef &Result) const { 271 DRI.d.b++; 272 moveToNextSection(DRI); 273 Result = SectionRef(DRI, this); 274 return object_error::success; 275 } 276 277 void 278 MachOObjectFile::getSection(DataRefImpl DRI, 279 InMemoryStruct<macho::Section> &Res) const { 280 InMemoryStruct<macho::SegmentLoadCommand> SLC; 281 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 282 MachOObj->ReadSegmentLoadCommand(LCI, SLC); 283 MachOObj->ReadSection(LCI, DRI.d.b, Res); 284 } 285 286 void 287 MachOObjectFile::getSection64(DataRefImpl DRI, 288 InMemoryStruct<macho::Section64> &Res) const { 289 InMemoryStruct<macho::Segment64LoadCommand> SLC; 290 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 291 MachOObj->ReadSegment64LoadCommand(LCI, SLC); 292 MachOObj->ReadSection64(LCI, DRI.d.b, Res); 293 } 294 295 static bool is64BitLoadCommand(const MachOObject *MachOObj, DataRefImpl DRI) { 296 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 297 if (LCI.Command.Type == macho::LCT_Segment64) 298 return true; 299 assert(LCI.Command.Type == macho::LCT_Segment && "Unexpected Type."); 300 return false; 301 } 302 303 error_code MachOObjectFile::getSectionName(DataRefImpl DRI, 304 StringRef &Result) const { 305 // FIXME: thread safety. 306 static char result[34]; 307 if (is64BitLoadCommand(MachOObj, DRI)) { 308 InMemoryStruct<macho::Segment64LoadCommand> SLC; 309 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 310 MachOObj->ReadSegment64LoadCommand(LCI, SLC); 311 InMemoryStruct<macho::Section64> Sect; 312 MachOObj->ReadSection64(LCI, DRI.d.b, Sect); 313 314 strcpy(result, Sect->SegmentName); 315 strcat(result, ","); 316 strcat(result, Sect->Name); 317 } else { 318 InMemoryStruct<macho::SegmentLoadCommand> SLC; 319 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 320 MachOObj->ReadSegmentLoadCommand(LCI, SLC); 321 InMemoryStruct<macho::Section> Sect; 322 MachOObj->ReadSection(LCI, DRI.d.b, Sect); 323 324 strcpy(result, Sect->SegmentName); 325 strcat(result, ","); 326 strcat(result, Sect->Name); 327 } 328 Result = StringRef(result); 329 return object_error::success; 330 } 331 332 error_code MachOObjectFile::getSectionAddress(DataRefImpl DRI, 333 uint64_t &Result) const { 334 if (is64BitLoadCommand(MachOObj, DRI)) { 335 InMemoryStruct<macho::Section64> Sect; 336 getSection64(DRI, Sect); 337 Result = Sect->Address; 338 } else { 339 InMemoryStruct<macho::Section> Sect; 340 getSection(DRI, Sect); 341 Result = Sect->Address; 342 } 343 return object_error::success; 344 } 345 346 error_code MachOObjectFile::getSectionSize(DataRefImpl DRI, 347 uint64_t &Result) const { 348 if (is64BitLoadCommand(MachOObj, DRI)) { 349 InMemoryStruct<macho::Section64> Sect; 350 getSection64(DRI, Sect); 351 Result = Sect->Size; 352 } else { 353 InMemoryStruct<macho::Section> Sect; 354 getSection(DRI, Sect); 355 Result = Sect->Size; 356 } 357 return object_error::success; 358 } 359 360 error_code MachOObjectFile::getSectionContents(DataRefImpl DRI, 361 StringRef &Result) const { 362 if (is64BitLoadCommand(MachOObj, DRI)) { 363 InMemoryStruct<macho::Section64> Sect; 364 getSection64(DRI, Sect); 365 Result = MachOObj->getData(Sect->Offset, Sect->Size); 366 } else { 367 InMemoryStruct<macho::Section> Sect; 368 getSection(DRI, Sect); 369 Result = MachOObj->getData(Sect->Offset, Sect->Size); 370 } 371 return object_error::success; 372 } 373 374 error_code MachOObjectFile::isSectionText(DataRefImpl DRI, 375 bool &Result) const { 376 if (is64BitLoadCommand(MachOObj, DRI)) { 377 InMemoryStruct<macho::Section64> Sect; 378 getSection64(DRI, Sect); 379 Result = !strcmp(Sect->Name, "__text"); 380 } else { 381 InMemoryStruct<macho::Section> Sect; 382 getSection(DRI, Sect); 383 Result = !strcmp(Sect->Name, "__text"); 384 } 385 return object_error::success; 386 } 387 388 error_code MachOObjectFile::sectionContainsSymbol(DataRefImpl Sec, 389 DataRefImpl Symb, 390 bool &Result) const { 391 if (MachOObj->is64Bit()) { 392 InMemoryStruct<macho::Symbol64TableEntry> Entry; 393 getSymbol64TableEntry(Symb, Entry); 394 Result = Entry->SectionIndex == 1 + Sec.d.a + Sec.d.b; 395 } else { 396 InMemoryStruct<macho::SymbolTableEntry> Entry; 397 getSymbolTableEntry(Symb, Entry); 398 Result = Entry->SectionIndex == 1 + Sec.d.a + Sec.d.b; 399 } 400 return object_error::success; 401 } 402 403 ObjectFile::section_iterator MachOObjectFile::begin_sections() const { 404 DataRefImpl DRI; 405 DRI.d.a = DRI.d.b = 0; 406 moveToNextSection(DRI); 407 return section_iterator(SectionRef(DRI, this)); 408 } 409 410 ObjectFile::section_iterator MachOObjectFile::end_sections() const { 411 DataRefImpl DRI; 412 DRI.d.a = MachOObj->getHeader().NumLoadCommands; 413 DRI.d.b = 0; 414 return section_iterator(SectionRef(DRI, this)); 415 } 416 417 /*===-- Miscellaneous -----------------------------------------------------===*/ 418 419 uint8_t MachOObjectFile::getBytesInAddress() const { 420 return MachOObj->is64Bit() ? 8 : 4; 421 } 422 423 StringRef MachOObjectFile::getFileFormatName() const { 424 if (!MachOObj->is64Bit()) { 425 switch (MachOObj->getHeader().CPUType) { 426 case llvm::MachO::CPUTypeI386: 427 return "Mach-O 32-bit i386"; 428 case llvm::MachO::CPUTypeARM: 429 return "Mach-O arm"; 430 case llvm::MachO::CPUTypePowerPC: 431 return "Mach-O 32-bit ppc"; 432 default: 433 assert((MachOObj->getHeader().CPUType & llvm::MachO::CPUArchABI64) == 0 && 434 "64-bit object file when we're not 64-bit?"); 435 return "Mach-O 32-bit unknown"; 436 } 437 } 438 439 switch (MachOObj->getHeader().CPUType) { 440 case llvm::MachO::CPUTypeX86_64: 441 return "Mach-O 64-bit x86-64"; 442 case llvm::MachO::CPUTypePowerPC64: 443 return "Mach-O 64-bit ppc64"; 444 default: 445 assert((MachOObj->getHeader().CPUType & llvm::MachO::CPUArchABI64) == 1 && 446 "32-bit object file when we're 64-bit?"); 447 return "Mach-O 64-bit unknown"; 448 } 449 } 450 451 unsigned MachOObjectFile::getArch() const { 452 switch (MachOObj->getHeader().CPUType) { 453 case llvm::MachO::CPUTypeI386: 454 return Triple::x86; 455 case llvm::MachO::CPUTypeX86_64: 456 return Triple::x86_64; 457 case llvm::MachO::CPUTypeARM: 458 return Triple::arm; 459 case llvm::MachO::CPUTypePowerPC: 460 return Triple::ppc; 461 case llvm::MachO::CPUTypePowerPC64: 462 return Triple::ppc64; 463 default: 464 return Triple::UnknownArch; 465 } 466 } 467 468 } // end namespace llvm 469 470