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/MachO.h" 17 #include "llvm/Object/MachOFormat.h" 18 #include "llvm/Support/Format.h" 19 #include "llvm/Support/MemoryBuffer.h" 20 21 #include <cctype> 22 #include <cstring> 23 #include <limits> 24 25 using namespace llvm; 26 using namespace object; 27 28 namespace llvm { 29 namespace object { 30 31 MachOObjectFile::MachOObjectFile(MemoryBuffer *Object, MachOObject *MOO, 32 error_code &ec) 33 : ObjectFile(Binary::isMachO, Object, ec), 34 MachOObj(MOO), 35 RegisteredStringTable(std::numeric_limits<uint32_t>::max()) { 36 DataRefImpl DRI; 37 DRI.d.a = DRI.d.b = 0; 38 moveToNextSection(DRI); 39 uint32_t LoadCommandCount = MachOObj->getHeader().NumLoadCommands; 40 while (DRI.d.a < LoadCommandCount) { 41 Sections.push_back(DRI); 42 DRI.d.b++; 43 moveToNextSection(DRI); 44 } 45 } 46 47 48 ObjectFile *ObjectFile::createMachOObjectFile(MemoryBuffer *Buffer) { 49 error_code ec; 50 std::string Err; 51 MachOObject *MachOObj = MachOObject::LoadFromBuffer(Buffer, &Err); 52 if (!MachOObj) 53 return NULL; 54 return new MachOObjectFile(Buffer, MachOObj, ec); 55 } 56 57 /*===-- Symbols -----------------------------------------------------------===*/ 58 59 void MachOObjectFile::moveToNextSymbol(DataRefImpl &DRI) const { 60 uint32_t LoadCommandCount = MachOObj->getHeader().NumLoadCommands; 61 while (DRI.d.a < LoadCommandCount) { 62 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 63 if (LCI.Command.Type == macho::LCT_Symtab) { 64 InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd; 65 MachOObj->ReadSymtabLoadCommand(LCI, SymtabLoadCmd); 66 if (DRI.d.b < SymtabLoadCmd->NumSymbolTableEntries) 67 return; 68 } 69 70 DRI.d.a++; 71 DRI.d.b = 0; 72 } 73 } 74 75 void MachOObjectFile::getSymbolTableEntry(DataRefImpl DRI, 76 InMemoryStruct<macho::SymbolTableEntry> &Res) const { 77 InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd; 78 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 79 MachOObj->ReadSymtabLoadCommand(LCI, SymtabLoadCmd); 80 81 if (RegisteredStringTable != DRI.d.a) { 82 MachOObj->RegisterStringTable(*SymtabLoadCmd); 83 RegisteredStringTable = DRI.d.a; 84 } 85 86 MachOObj->ReadSymbolTableEntry(SymtabLoadCmd->SymbolTableOffset, DRI.d.b, 87 Res); 88 } 89 90 void MachOObjectFile::getSymbol64TableEntry(DataRefImpl DRI, 91 InMemoryStruct<macho::Symbol64TableEntry> &Res) const { 92 InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd; 93 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 94 MachOObj->ReadSymtabLoadCommand(LCI, SymtabLoadCmd); 95 96 if (RegisteredStringTable != DRI.d.a) { 97 MachOObj->RegisterStringTable(*SymtabLoadCmd); 98 RegisteredStringTable = DRI.d.a; 99 } 100 101 MachOObj->ReadSymbol64TableEntry(SymtabLoadCmd->SymbolTableOffset, DRI.d.b, 102 Res); 103 } 104 105 106 error_code MachOObjectFile::getSymbolNext(DataRefImpl DRI, 107 SymbolRef &Result) const { 108 DRI.d.b++; 109 moveToNextSymbol(DRI); 110 Result = SymbolRef(DRI, this); 111 return object_error::success; 112 } 113 114 error_code MachOObjectFile::getSymbolName(DataRefImpl DRI, 115 StringRef &Result) const { 116 if (MachOObj->is64Bit()) { 117 InMemoryStruct<macho::Symbol64TableEntry> Entry; 118 getSymbol64TableEntry(DRI, Entry); 119 Result = MachOObj->getStringAtIndex(Entry->StringIndex); 120 } else { 121 InMemoryStruct<macho::SymbolTableEntry> Entry; 122 getSymbolTableEntry(DRI, Entry); 123 Result = MachOObj->getStringAtIndex(Entry->StringIndex); 124 } 125 return object_error::success; 126 } 127 128 error_code MachOObjectFile::getSymbolFileOffset(DataRefImpl DRI, 129 uint64_t &Result) const { 130 if (MachOObj->is64Bit()) { 131 InMemoryStruct<macho::Symbol64TableEntry> Entry; 132 getSymbol64TableEntry(DRI, Entry); 133 Result = Entry->Value; 134 if (Entry->SectionIndex) { 135 InMemoryStruct<macho::Section64> Section; 136 getSection64(Sections[Entry->SectionIndex-1], Section); 137 Result += Section->Offset - Section->Address; 138 } 139 } else { 140 InMemoryStruct<macho::SymbolTableEntry> Entry; 141 getSymbolTableEntry(DRI, Entry); 142 Result = Entry->Value; 143 if (Entry->SectionIndex) { 144 InMemoryStruct<macho::Section> Section; 145 getSection(Sections[Entry->SectionIndex-1], Section); 146 Result += Section->Offset - Section->Address; 147 } 148 } 149 150 return object_error::success; 151 } 152 153 error_code MachOObjectFile::getSymbolAddress(DataRefImpl DRI, 154 uint64_t &Result) const { 155 if (MachOObj->is64Bit()) { 156 InMemoryStruct<macho::Symbol64TableEntry> Entry; 157 getSymbol64TableEntry(DRI, Entry); 158 Result = Entry->Value; 159 } else { 160 InMemoryStruct<macho::SymbolTableEntry> Entry; 161 getSymbolTableEntry(DRI, Entry); 162 Result = Entry->Value; 163 } 164 return object_error::success; 165 } 166 167 error_code MachOObjectFile::getSymbolSize(DataRefImpl DRI, 168 uint64_t &Result) const { 169 uint32_t LoadCommandCount = MachOObj->getHeader().NumLoadCommands; 170 uint64_t BeginOffset; 171 uint64_t EndOffset = 0; 172 uint8_t SectionIndex; 173 if (MachOObj->is64Bit()) { 174 InMemoryStruct<macho::Symbol64TableEntry> Entry; 175 getSymbol64TableEntry(DRI, Entry); 176 BeginOffset = Entry->Value; 177 SectionIndex = Entry->SectionIndex; 178 if (!SectionIndex) { 179 Result = UnknownAddressOrSize; 180 return object_error::success; 181 } 182 DRI.d.b++; 183 moveToNextSymbol(DRI); 184 if (DRI.d.a < LoadCommandCount) { 185 getSymbol64TableEntry(DRI, Entry); 186 if (Entry->SectionIndex == SectionIndex) 187 EndOffset += Entry->Value; 188 } 189 } else { 190 InMemoryStruct<macho::SymbolTableEntry> Entry; 191 getSymbolTableEntry(DRI, Entry); 192 BeginOffset = Entry->Value; 193 SectionIndex = Entry->SectionIndex; 194 if (!SectionIndex) { 195 Result = UnknownAddressOrSize; 196 return object_error::success; 197 } 198 DRI.d.b++; 199 moveToNextSymbol(DRI); 200 if (DRI.d.a < LoadCommandCount) { 201 getSymbolTableEntry(DRI, Entry); 202 if (Entry->SectionIndex == SectionIndex) 203 EndOffset += Entry->Value; 204 } 205 } 206 if (!EndOffset) { 207 uint64_t Size; 208 getSectionSize(Sections[SectionIndex-1], Size); 209 getSectionAddress(Sections[SectionIndex-1], EndOffset); 210 EndOffset += Size; 211 } 212 Result = EndOffset - BeginOffset; 213 return object_error::success; 214 } 215 216 error_code MachOObjectFile::getSymbolNMTypeChar(DataRefImpl DRI, 217 char &Result) const { 218 uint8_t Type, Flags; 219 if (MachOObj->is64Bit()) { 220 InMemoryStruct<macho::Symbol64TableEntry> Entry; 221 getSymbol64TableEntry(DRI, Entry); 222 Type = Entry->Type; 223 Flags = Entry->Flags; 224 } else { 225 InMemoryStruct<macho::SymbolTableEntry> Entry; 226 getSymbolTableEntry(DRI, Entry); 227 Type = Entry->Type; 228 Flags = Entry->Flags; 229 } 230 231 char Char; 232 switch (Type & macho::STF_TypeMask) { 233 case macho::STT_Undefined: 234 Char = 'u'; 235 break; 236 case macho::STT_Absolute: 237 case macho::STT_Section: 238 Char = 's'; 239 break; 240 default: 241 Char = '?'; 242 break; 243 } 244 245 if (Flags & (macho::STF_External | macho::STF_PrivateExtern)) 246 Char = toupper(Char); 247 Result = Char; 248 return object_error::success; 249 } 250 251 error_code MachOObjectFile::isSymbolInternal(DataRefImpl DRI, 252 bool &Result) const { 253 if (MachOObj->is64Bit()) { 254 InMemoryStruct<macho::Symbol64TableEntry> Entry; 255 getSymbol64TableEntry(DRI, Entry); 256 Result = Entry->Flags & macho::STF_StabsEntryMask; 257 } else { 258 InMemoryStruct<macho::SymbolTableEntry> Entry; 259 getSymbolTableEntry(DRI, Entry); 260 Result = Entry->Flags & macho::STF_StabsEntryMask; 261 } 262 return object_error::success; 263 } 264 265 error_code MachOObjectFile::isSymbolGlobal(DataRefImpl Symb, bool &Res) const { 266 267 if (MachOObj->is64Bit()) { 268 InMemoryStruct<macho::Symbol64TableEntry> Entry; 269 getSymbol64TableEntry(Symb, Entry); 270 Res = Entry->Type & MachO::NlistMaskExternal; 271 } else { 272 InMemoryStruct<macho::SymbolTableEntry> Entry; 273 getSymbolTableEntry(Symb, Entry); 274 Res = Entry->Type & MachO::NlistMaskExternal; 275 } 276 return object_error::success; 277 } 278 279 error_code MachOObjectFile::isSymbolWeak(DataRefImpl Symb, bool &Res) const { 280 281 if (MachOObj->is64Bit()) { 282 InMemoryStruct<macho::Symbol64TableEntry> Entry; 283 getSymbol64TableEntry(Symb, Entry); 284 Res = Entry->Flags & (MachO::NListDescWeakRef | MachO::NListDescWeakDef); 285 } else { 286 InMemoryStruct<macho::SymbolTableEntry> Entry; 287 getSymbolTableEntry(Symb, Entry); 288 Res = Entry->Flags & (MachO::NListDescWeakRef | MachO::NListDescWeakDef); 289 } 290 return object_error::success; 291 } 292 293 error_code MachOObjectFile::isSymbolAbsolute(DataRefImpl Symb, bool &Res) const{ 294 uint8_t n_type; 295 if (MachOObj->is64Bit()) { 296 InMemoryStruct<macho::Symbol64TableEntry> Entry; 297 getSymbol64TableEntry(Symb, Entry); 298 n_type = Entry->Type; 299 } else { 300 InMemoryStruct<macho::SymbolTableEntry> Entry; 301 getSymbolTableEntry(Symb, Entry); 302 n_type = Entry->Type; 303 } 304 305 Res = (n_type & MachO::NlistMaskType) == MachO::NListTypeAbsolute; 306 return object_error::success; 307 } 308 309 error_code MachOObjectFile::getSymbolSection(DataRefImpl Symb, 310 section_iterator &Res) const { 311 uint8_t index; 312 if (MachOObj->is64Bit()) { 313 InMemoryStruct<macho::Symbol64TableEntry> Entry; 314 getSymbol64TableEntry(Symb, Entry); 315 index = Entry->SectionIndex; 316 } else { 317 InMemoryStruct<macho::SymbolTableEntry> Entry; 318 getSymbolTableEntry(Symb, Entry); 319 index = Entry->SectionIndex; 320 } 321 322 if (index == 0) 323 Res = end_sections(); 324 else 325 Res = section_iterator(SectionRef(Sections[index-1], this)); 326 327 return object_error::success; 328 } 329 330 error_code MachOObjectFile::getSymbolType(DataRefImpl Symb, 331 SymbolRef::Type &Res) const { 332 uint8_t n_type; 333 if (MachOObj->is64Bit()) { 334 InMemoryStruct<macho::Symbol64TableEntry> Entry; 335 getSymbol64TableEntry(Symb, Entry); 336 n_type = Entry->Type; 337 } else { 338 InMemoryStruct<macho::SymbolTableEntry> Entry; 339 getSymbolTableEntry(Symb, Entry); 340 n_type = Entry->Type; 341 } 342 Res = SymbolRef::ST_Other; 343 344 // If this is a STAB debugging symbol, we can do nothing more. 345 if (n_type & MachO::NlistMaskStab) { 346 Res = SymbolRef::ST_Debug; 347 return object_error::success; 348 } 349 350 switch (n_type & MachO::NlistMaskType) { 351 case MachO::NListTypeUndefined : 352 Res = SymbolRef::ST_External; 353 break; 354 case MachO::NListTypeSection : 355 Res = SymbolRef::ST_Function; 356 break; 357 } 358 return object_error::success; 359 } 360 361 362 symbol_iterator MachOObjectFile::begin_symbols() const { 363 // DRI.d.a = segment number; DRI.d.b = symbol index. 364 DataRefImpl DRI; 365 DRI.d.a = DRI.d.b = 0; 366 moveToNextSymbol(DRI); 367 return symbol_iterator(SymbolRef(DRI, this)); 368 } 369 370 symbol_iterator MachOObjectFile::end_symbols() const { 371 DataRefImpl DRI; 372 DRI.d.a = MachOObj->getHeader().NumLoadCommands; 373 DRI.d.b = 0; 374 return symbol_iterator(SymbolRef(DRI, this)); 375 } 376 377 378 /*===-- Sections ----------------------------------------------------------===*/ 379 380 void MachOObjectFile::moveToNextSection(DataRefImpl &DRI) const { 381 uint32_t LoadCommandCount = MachOObj->getHeader().NumLoadCommands; 382 while (DRI.d.a < LoadCommandCount) { 383 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 384 if (LCI.Command.Type == macho::LCT_Segment) { 385 InMemoryStruct<macho::SegmentLoadCommand> SegmentLoadCmd; 386 MachOObj->ReadSegmentLoadCommand(LCI, SegmentLoadCmd); 387 if (DRI.d.b < SegmentLoadCmd->NumSections) 388 return; 389 } else if (LCI.Command.Type == macho::LCT_Segment64) { 390 InMemoryStruct<macho::Segment64LoadCommand> Segment64LoadCmd; 391 MachOObj->ReadSegment64LoadCommand(LCI, Segment64LoadCmd); 392 if (DRI.d.b < Segment64LoadCmd->NumSections) 393 return; 394 } 395 396 DRI.d.a++; 397 DRI.d.b = 0; 398 } 399 } 400 401 error_code MachOObjectFile::getSectionNext(DataRefImpl DRI, 402 SectionRef &Result) const { 403 DRI.d.b++; 404 moveToNextSection(DRI); 405 Result = SectionRef(DRI, this); 406 return object_error::success; 407 } 408 409 void 410 MachOObjectFile::getSection(DataRefImpl DRI, 411 InMemoryStruct<macho::Section> &Res) const { 412 InMemoryStruct<macho::SegmentLoadCommand> SLC; 413 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 414 MachOObj->ReadSegmentLoadCommand(LCI, SLC); 415 MachOObj->ReadSection(LCI, DRI.d.b, Res); 416 } 417 418 std::size_t MachOObjectFile::getSectionIndex(DataRefImpl Sec) const { 419 SectionList::const_iterator loc = 420 std::find(Sections.begin(), Sections.end(), Sec); 421 assert(loc != Sections.end() && "Sec is not a valid section!"); 422 return std::distance(Sections.begin(), loc); 423 } 424 425 void 426 MachOObjectFile::getSection64(DataRefImpl DRI, 427 InMemoryStruct<macho::Section64> &Res) const { 428 InMemoryStruct<macho::Segment64LoadCommand> SLC; 429 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 430 MachOObj->ReadSegment64LoadCommand(LCI, SLC); 431 MachOObj->ReadSection64(LCI, DRI.d.b, Res); 432 } 433 434 static bool is64BitLoadCommand(const MachOObject *MachOObj, DataRefImpl DRI) { 435 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 436 if (LCI.Command.Type == macho::LCT_Segment64) 437 return true; 438 assert(LCI.Command.Type == macho::LCT_Segment && "Unexpected Type."); 439 return false; 440 } 441 442 error_code MachOObjectFile::getSectionName(DataRefImpl DRI, 443 StringRef &Result) const { 444 // FIXME: thread safety. 445 static char result[34]; 446 if (is64BitLoadCommand(MachOObj, DRI)) { 447 InMemoryStruct<macho::Segment64LoadCommand> SLC; 448 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 449 MachOObj->ReadSegment64LoadCommand(LCI, SLC); 450 InMemoryStruct<macho::Section64> Sect; 451 MachOObj->ReadSection64(LCI, DRI.d.b, Sect); 452 453 strcpy(result, Sect->SegmentName); 454 strcat(result, ","); 455 strcat(result, Sect->Name); 456 } else { 457 InMemoryStruct<macho::SegmentLoadCommand> SLC; 458 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 459 MachOObj->ReadSegmentLoadCommand(LCI, SLC); 460 InMemoryStruct<macho::Section> Sect; 461 MachOObj->ReadSection(LCI, DRI.d.b, Sect); 462 463 strcpy(result, Sect->SegmentName); 464 strcat(result, ","); 465 strcat(result, Sect->Name); 466 } 467 Result = StringRef(result); 468 return object_error::success; 469 } 470 471 error_code MachOObjectFile::getSectionAddress(DataRefImpl DRI, 472 uint64_t &Result) const { 473 if (is64BitLoadCommand(MachOObj, DRI)) { 474 InMemoryStruct<macho::Section64> Sect; 475 getSection64(DRI, Sect); 476 Result = Sect->Address; 477 } else { 478 InMemoryStruct<macho::Section> Sect; 479 getSection(DRI, Sect); 480 Result = Sect->Address; 481 } 482 return object_error::success; 483 } 484 485 error_code MachOObjectFile::getSectionSize(DataRefImpl DRI, 486 uint64_t &Result) const { 487 if (is64BitLoadCommand(MachOObj, DRI)) { 488 InMemoryStruct<macho::Section64> Sect; 489 getSection64(DRI, Sect); 490 Result = Sect->Size; 491 } else { 492 InMemoryStruct<macho::Section> Sect; 493 getSection(DRI, Sect); 494 Result = Sect->Size; 495 } 496 return object_error::success; 497 } 498 499 error_code MachOObjectFile::getSectionContents(DataRefImpl DRI, 500 StringRef &Result) const { 501 if (is64BitLoadCommand(MachOObj, DRI)) { 502 InMemoryStruct<macho::Section64> Sect; 503 getSection64(DRI, Sect); 504 Result = MachOObj->getData(Sect->Offset, Sect->Size); 505 } else { 506 InMemoryStruct<macho::Section> Sect; 507 getSection(DRI, Sect); 508 Result = MachOObj->getData(Sect->Offset, Sect->Size); 509 } 510 return object_error::success; 511 } 512 513 error_code MachOObjectFile::getSectionAlignment(DataRefImpl DRI, 514 uint64_t &Result) const { 515 if (is64BitLoadCommand(MachOObj, DRI)) { 516 InMemoryStruct<macho::Section64> Sect; 517 getSection64(DRI, Sect); 518 Result = uint64_t(1) << Sect->Align; 519 } else { 520 InMemoryStruct<macho::Section> Sect; 521 getSection(DRI, Sect); 522 Result = uint64_t(1) << Sect->Align; 523 } 524 return object_error::success; 525 } 526 527 error_code MachOObjectFile::isSectionText(DataRefImpl DRI, 528 bool &Result) const { 529 if (is64BitLoadCommand(MachOObj, DRI)) { 530 InMemoryStruct<macho::Section64> Sect; 531 getSection64(DRI, Sect); 532 Result = !strcmp(Sect->Name, "__text"); 533 } else { 534 InMemoryStruct<macho::Section> Sect; 535 getSection(DRI, Sect); 536 Result = !strcmp(Sect->Name, "__text"); 537 } 538 return object_error::success; 539 } 540 541 error_code MachOObjectFile::isSectionData(DataRefImpl DRI, 542 bool &Result) const { 543 // FIXME: Unimplemented. 544 Result = false; 545 return object_error::success; 546 } 547 548 error_code MachOObjectFile::isSectionBSS(DataRefImpl DRI, 549 bool &Result) const { 550 // FIXME: Unimplemented. 551 Result = false; 552 return object_error::success; 553 } 554 555 error_code MachOObjectFile::sectionContainsSymbol(DataRefImpl Sec, 556 DataRefImpl Symb, 557 bool &Result) const { 558 SymbolRef::Type ST; 559 getSymbolType(Symb, ST); 560 if (ST == SymbolRef::ST_External) { 561 Result = false; 562 return object_error::success; 563 } 564 565 uint64_t SectBegin, SectEnd; 566 getSectionAddress(Sec, SectBegin); 567 getSectionSize(Sec, SectEnd); 568 SectEnd += SectBegin; 569 570 if (MachOObj->is64Bit()) { 571 InMemoryStruct<macho::Symbol64TableEntry> Entry; 572 getSymbol64TableEntry(Symb, Entry); 573 uint64_t SymAddr= Entry->Value; 574 Result = (SymAddr >= SectBegin) && (SymAddr < SectEnd); 575 } else { 576 InMemoryStruct<macho::SymbolTableEntry> Entry; 577 getSymbolTableEntry(Symb, Entry); 578 uint64_t SymAddr= Entry->Value; 579 Result = (SymAddr >= SectBegin) && (SymAddr < SectEnd); 580 } 581 582 return object_error::success; 583 } 584 585 relocation_iterator MachOObjectFile::getSectionRelBegin(DataRefImpl Sec) const { 586 DataRefImpl ret; 587 ret.d.a = 0; 588 ret.d.b = getSectionIndex(Sec); 589 return relocation_iterator(RelocationRef(ret, this)); 590 } 591 relocation_iterator MachOObjectFile::getSectionRelEnd(DataRefImpl Sec) const { 592 uint32_t last_reloc; 593 if (is64BitLoadCommand(MachOObj, Sec)) { 594 InMemoryStruct<macho::Section64> Sect; 595 getSection64(Sec, Sect); 596 last_reloc = Sect->NumRelocationTableEntries; 597 } else { 598 InMemoryStruct<macho::Section> Sect; 599 getSection(Sec, Sect); 600 last_reloc = Sect->NumRelocationTableEntries; 601 } 602 DataRefImpl ret; 603 ret.d.a = last_reloc; 604 ret.d.b = getSectionIndex(Sec); 605 return relocation_iterator(RelocationRef(ret, this)); 606 } 607 608 section_iterator MachOObjectFile::begin_sections() const { 609 DataRefImpl DRI; 610 DRI.d.a = DRI.d.b = 0; 611 moveToNextSection(DRI); 612 return section_iterator(SectionRef(DRI, this)); 613 } 614 615 section_iterator MachOObjectFile::end_sections() const { 616 DataRefImpl DRI; 617 DRI.d.a = MachOObj->getHeader().NumLoadCommands; 618 DRI.d.b = 0; 619 return section_iterator(SectionRef(DRI, this)); 620 } 621 622 /*===-- Relocations -------------------------------------------------------===*/ 623 624 void MachOObjectFile:: 625 getRelocation(DataRefImpl Rel, 626 InMemoryStruct<macho::RelocationEntry> &Res) const { 627 uint32_t relOffset; 628 if (MachOObj->is64Bit()) { 629 InMemoryStruct<macho::Section64> Sect; 630 getSection64(Sections[Rel.d.b], Sect); 631 relOffset = Sect->RelocationTableOffset; 632 } else { 633 InMemoryStruct<macho::Section> Sect; 634 getSection(Sections[Rel.d.b], Sect); 635 relOffset = Sect->RelocationTableOffset; 636 } 637 MachOObj->ReadRelocationEntry(relOffset, Rel.d.a, Res); 638 } 639 error_code MachOObjectFile::getRelocationNext(DataRefImpl Rel, 640 RelocationRef &Res) const { 641 ++Rel.d.a; 642 Res = RelocationRef(Rel, this); 643 return object_error::success; 644 } 645 error_code MachOObjectFile::getRelocationAddress(DataRefImpl Rel, 646 uint64_t &Res) const { 647 const uint8_t* sectAddress = 0; 648 if (MachOObj->is64Bit()) { 649 InMemoryStruct<macho::Section64> Sect; 650 getSection64(Sections[Rel.d.b], Sect); 651 sectAddress += Sect->Address; 652 } else { 653 InMemoryStruct<macho::Section> Sect; 654 getSection(Sections[Rel.d.b], Sect); 655 sectAddress += Sect->Address; 656 } 657 InMemoryStruct<macho::RelocationEntry> RE; 658 getRelocation(Rel, RE); 659 660 unsigned Arch = getArch(); 661 bool isScattered = (Arch != Triple::x86_64) && 662 (RE->Word0 & macho::RF_Scattered); 663 uint64_t RelAddr = 0; 664 if (isScattered) 665 RelAddr = RE->Word0 & 0xFFFFFF; 666 else 667 RelAddr = RE->Word0; 668 669 Res = reinterpret_cast<uintptr_t>(sectAddress + RelAddr); 670 return object_error::success; 671 } 672 error_code MachOObjectFile::getRelocationOffset(DataRefImpl Rel, 673 uint64_t &Res) const { 674 InMemoryStruct<macho::RelocationEntry> RE; 675 getRelocation(Rel, RE); 676 677 unsigned Arch = getArch(); 678 bool isScattered = (Arch != Triple::x86_64) && 679 (RE->Word0 & macho::RF_Scattered); 680 if (isScattered) 681 Res = RE->Word0 & 0xFFFFFF; 682 else 683 Res = RE->Word0; 684 return object_error::success; 685 } 686 error_code MachOObjectFile::getRelocationSymbol(DataRefImpl Rel, 687 SymbolRef &Res) const { 688 InMemoryStruct<macho::RelocationEntry> RE; 689 getRelocation(Rel, RE); 690 uint32_t SymbolIdx = RE->Word1 & 0xffffff; 691 bool isExtern = (RE->Word1 >> 27) & 1; 692 693 DataRefImpl Sym; 694 Sym.d.a = Sym.d.b = 0; 695 moveToNextSymbol(Sym); 696 if (isExtern) { 697 for (unsigned i = 0; i < SymbolIdx; i++) { 698 Sym.d.b++; 699 moveToNextSymbol(Sym); 700 assert(Sym.d.a < MachOObj->getHeader().NumLoadCommands && 701 "Relocation symbol index out of range!"); 702 } 703 } 704 Res = SymbolRef(Sym, this); 705 return object_error::success; 706 } 707 error_code MachOObjectFile::getRelocationType(DataRefImpl Rel, 708 uint64_t &Res) const { 709 InMemoryStruct<macho::RelocationEntry> RE; 710 getRelocation(Rel, RE); 711 Res = RE->Word0; 712 Res <<= 32; 713 Res |= RE->Word1; 714 return object_error::success; 715 } 716 error_code MachOObjectFile::getRelocationTypeName(DataRefImpl Rel, 717 SmallVectorImpl<char> &Result) const { 718 // TODO: Support scattered relocations. 719 StringRef res; 720 InMemoryStruct<macho::RelocationEntry> RE; 721 getRelocation(Rel, RE); 722 723 unsigned Arch = getArch(); 724 bool isScattered = (Arch != Triple::x86_64) && 725 (RE->Word0 & macho::RF_Scattered); 726 727 unsigned r_type; 728 if (isScattered) 729 r_type = (RE->Word0 >> 24) & 0xF; 730 else 731 r_type = (RE->Word1 >> 28) & 0xF; 732 733 switch (Arch) { 734 case Triple::x86: { 735 const char* Table[] = { 736 "GENERIC_RELOC_VANILLA", 737 "GENERIC_RELOC_PAIR", 738 "GENERIC_RELOC_SECTDIFF", 739 "GENERIC_RELOC_PB_LA_PTR", 740 "GENERIC_RELOC_LOCAL_SECTDIFF", 741 "GENERIC_RELOC_TLV" }; 742 743 if (r_type > 6) 744 res = "Unknown"; 745 else 746 res = Table[r_type]; 747 break; 748 } 749 case Triple::x86_64: { 750 const char* Table[] = { 751 "X86_64_RELOC_UNSIGNED", 752 "X86_64_RELOC_SIGNED", 753 "X86_64_RELOC_BRANCH", 754 "X86_64_RELOC_GOT_LOAD", 755 "X86_64_RELOC_GOT", 756 "X86_64_RELOC_SUBTRACTOR", 757 "X86_64_RELOC_SIGNED_1", 758 "X86_64_RELOC_SIGNED_2", 759 "X86_64_RELOC_SIGNED_4", 760 "X86_64_RELOC_TLV" }; 761 762 if (r_type > 9) 763 res = "Unknown"; 764 else 765 res = Table[r_type]; 766 break; 767 } 768 case Triple::arm: { 769 const char* Table[] = { 770 "ARM_RELOC_VANILLA", 771 "ARM_RELOC_PAIR", 772 "ARM_RELOC_SECTDIFF", 773 "ARM_RELOC_LOCAL_SECTDIFF", 774 "ARM_RELOC_PB_LA_PTR", 775 "ARM_RELOC_BR24", 776 "ARM_THUMB_RELOC_BR22", 777 "ARM_THUMB_32BIT_BRANCH", 778 "ARM_RELOC_HALF", 779 "ARM_RELOC_HALF_SECTDIFF" }; 780 781 if (r_type > 9) 782 res = "Unknown"; 783 else 784 res = Table[r_type]; 785 break; 786 } 787 case Triple::ppc: { 788 const char* Table[] = { 789 "PPC_RELOC_VANILLA", 790 "PPC_RELOC_PAIR", 791 "PPC_RELOC_BR14", 792 "PPC_RELOC_BR24", 793 "PPC_RELOC_HI16", 794 "PPC_RELOC_LO16", 795 "PPC_RELOC_HA16", 796 "PPC_RELOC_LO14", 797 "PPC_RELOC_SECTDIFF", 798 "PPC_RELOC_PB_LA_PTR", 799 "PPC_RELOC_HI16_SECTDIFF", 800 "PPC_RELOC_LO16_SECTDIFF", 801 "PPC_RELOC_HA16_SECTDIFF", 802 "PPC_RELOC_JBSR", 803 "PPC_RELOC_LO14_SECTDIFF", 804 "PPC_RELOC_LOCAL_SECTDIFF" }; 805 806 res = Table[r_type]; 807 break; 808 } 809 case Triple::UnknownArch: 810 res = "Unknown"; 811 break; 812 } 813 Result.append(res.begin(), res.end()); 814 return object_error::success; 815 } 816 error_code MachOObjectFile::getRelocationAdditionalInfo(DataRefImpl Rel, 817 int64_t &Res) const { 818 InMemoryStruct<macho::RelocationEntry> RE; 819 getRelocation(Rel, RE); 820 bool isExtern = (RE->Word1 >> 27) & 1; 821 Res = 0; 822 if (!isExtern) { 823 const uint8_t* sectAddress = base(); 824 if (MachOObj->is64Bit()) { 825 InMemoryStruct<macho::Section64> Sect; 826 getSection64(Sections[Rel.d.b], Sect); 827 sectAddress += Sect->Offset; 828 } else { 829 InMemoryStruct<macho::Section> Sect; 830 getSection(Sections[Rel.d.b], Sect); 831 sectAddress += Sect->Offset; 832 } 833 Res = reinterpret_cast<uintptr_t>(sectAddress); 834 } 835 return object_error::success; 836 } 837 838 // Helper to advance a section or symbol iterator multiple increments at a time. 839 template<class T> 840 error_code advance(T &it, size_t Val) { 841 error_code ec; 842 while (Val--) { 843 it.increment(ec); 844 } 845 return ec; 846 } 847 848 template<class T> 849 void advanceTo(T &it, size_t Val) { 850 if (error_code ec = advance(it, Val)) 851 report_fatal_error(ec.message()); 852 } 853 854 void MachOObjectFile::printRelocationTargetName( 855 InMemoryStruct<macho::RelocationEntry>& RE, 856 raw_string_ostream &fmt) const { 857 unsigned Arch = getArch(); 858 bool isScattered = (Arch != Triple::x86_64) && 859 (RE->Word0 & macho::RF_Scattered); 860 861 // Target of a scattered relocation is an address. In the interest of 862 // generating pretty output, scan through the symbol table looking for a 863 // symbol that aligns with that address. If we find one, print it. 864 // Otherwise, we just print the hex address of the target. 865 if (isScattered) { 866 uint32_t Val = RE->Word1; 867 868 error_code ec; 869 for (symbol_iterator SI = begin_symbols(), SE = end_symbols(); SI != SE; 870 SI.increment(ec)) { 871 if (ec) report_fatal_error(ec.message()); 872 873 uint64_t Addr; 874 StringRef Name; 875 876 if ((ec = SI->getAddress(Addr))) 877 report_fatal_error(ec.message()); 878 if (Addr != Val) continue; 879 if ((ec = SI->getName(Name))) 880 report_fatal_error(ec.message()); 881 fmt << Name; 882 return; 883 } 884 885 // If we couldn't find a symbol that this relocation refers to, try 886 // to find a section beginning instead. 887 for (section_iterator SI = begin_sections(), SE = end_sections(); SI != SE; 888 SI.increment(ec)) { 889 if (ec) report_fatal_error(ec.message()); 890 891 uint64_t Addr; 892 StringRef Name; 893 894 if ((ec = SI->getAddress(Addr))) 895 report_fatal_error(ec.message()); 896 if (Addr != Val) continue; 897 if ((ec = SI->getName(Name))) 898 report_fatal_error(ec.message()); 899 fmt << Name; 900 return; 901 } 902 903 fmt << format("0x%x", Val); 904 return; 905 } 906 907 StringRef S; 908 bool isExtern = (RE->Word1 >> 27) & 1; 909 uint32_t Val = RE->Word1 & 0xFFFFFF; 910 911 if (isExtern) { 912 symbol_iterator SI = begin_symbols(); 913 advanceTo(SI, Val); 914 SI->getName(S); 915 } else { 916 section_iterator SI = begin_sections(); 917 advanceTo(SI, Val); 918 SI->getName(S); 919 } 920 921 fmt << S; 922 } 923 924 error_code MachOObjectFile::getRelocationValueString(DataRefImpl Rel, 925 SmallVectorImpl<char> &Result) const { 926 InMemoryStruct<macho::RelocationEntry> RE; 927 getRelocation(Rel, RE); 928 929 unsigned Arch = getArch(); 930 bool isScattered = (Arch != Triple::x86_64) && 931 (RE->Word0 & macho::RF_Scattered); 932 933 std::string fmtbuf; 934 raw_string_ostream fmt(fmtbuf); 935 936 unsigned Type; 937 if (isScattered) 938 Type = (RE->Word0 >> 24) & 0xF; 939 else 940 Type = (RE->Word1 >> 28) & 0xF; 941 942 bool isPCRel; 943 if (isScattered) 944 isPCRel = ((RE->Word0 >> 30) & 1); 945 else 946 isPCRel = ((RE->Word1 >> 24) & 1); 947 948 // Determine any addends that should be displayed with the relocation. 949 // These require decoding the relocation type, which is triple-specific. 950 951 // X86_64 has entirely custom relocation types. 952 if (Arch == Triple::x86_64) { 953 bool isPCRel = ((RE->Word1 >> 24) & 1); 954 955 switch (Type) { 956 case macho::RIT_X86_64_GOTLoad: // X86_64_RELOC_GOT_LOAD 957 case macho::RIT_X86_64_GOT: { // X86_64_RELOC_GOT 958 printRelocationTargetName(RE, fmt); 959 fmt << "@GOT"; 960 if (isPCRel) fmt << "PCREL"; 961 break; 962 } 963 case macho::RIT_X86_64_Subtractor: { // X86_64_RELOC_SUBTRACTOR 964 InMemoryStruct<macho::RelocationEntry> RENext; 965 DataRefImpl RelNext = Rel; 966 RelNext.d.a++; 967 getRelocation(RelNext, RENext); 968 969 // X86_64_SUBTRACTOR must be followed by a relocation of type 970 // X86_64_RELOC_UNSIGNED. 971 // NOTE: Scattered relocations don't exist on x86_64. 972 unsigned RType = (RENext->Word1 >> 28) & 0xF; 973 if (RType != 0) 974 report_fatal_error("Expected X86_64_RELOC_UNSIGNED after " 975 "X86_64_RELOC_SUBTRACTOR."); 976 977 // The X86_64_RELOC_UNSIGNED contains the minuend symbol, 978 // X86_64_SUBTRACTOR contains to the subtrahend. 979 printRelocationTargetName(RENext, fmt); 980 fmt << "-"; 981 printRelocationTargetName(RE, fmt); 982 } 983 case macho::RIT_X86_64_TLV: 984 printRelocationTargetName(RE, fmt); 985 fmt << "@TLV"; 986 if (isPCRel) fmt << "P"; 987 break; 988 case macho::RIT_X86_64_Signed1: // X86_64_RELOC_SIGNED1 989 printRelocationTargetName(RE, fmt); 990 fmt << "-1"; 991 break; 992 case macho::RIT_X86_64_Signed2: // X86_64_RELOC_SIGNED2 993 printRelocationTargetName(RE, fmt); 994 fmt << "-2"; 995 break; 996 case macho::RIT_X86_64_Signed4: // X86_64_RELOC_SIGNED4 997 printRelocationTargetName(RE, fmt); 998 fmt << "-4"; 999 break; 1000 default: 1001 printRelocationTargetName(RE, fmt); 1002 break; 1003 } 1004 // X86 and ARM share some relocation types in common. 1005 } else if (Arch == Triple::x86 || Arch == Triple::arm) { 1006 // Generic relocation types... 1007 switch (Type) { 1008 case macho::RIT_Pair: // GENERIC_RELOC_PAIR - prints no info 1009 return object_error::success; 1010 case macho::RIT_Difference: { // GENERIC_RELOC_SECTDIFF 1011 InMemoryStruct<macho::RelocationEntry> RENext; 1012 DataRefImpl RelNext = Rel; 1013 RelNext.d.a++; 1014 getRelocation(RelNext, RENext); 1015 1016 // X86 sect diff's must be followed by a relocation of type 1017 // GENERIC_RELOC_PAIR. 1018 bool isNextScattered = (Arch != Triple::x86_64) && 1019 (RENext->Word0 & macho::RF_Scattered); 1020 unsigned RType; 1021 if (isNextScattered) 1022 RType = (RENext->Word0 >> 24) & 0xF; 1023 else 1024 RType = (RENext->Word1 >> 28) & 0xF; 1025 if (RType != 1) 1026 report_fatal_error("Expected GENERIC_RELOC_PAIR after " 1027 "GENERIC_RELOC_SECTDIFF."); 1028 1029 printRelocationTargetName(RE, fmt); 1030 fmt << "-"; 1031 printRelocationTargetName(RENext, fmt); 1032 break; 1033 } 1034 } 1035 1036 if (Arch == Triple::x86) { 1037 // All X86 relocations that need special printing were already 1038 // handled in the generic code. 1039 switch (Type) { 1040 case macho::RIT_Generic_LocalDifference:{// GENERIC_RELOC_LOCAL_SECTDIFF 1041 InMemoryStruct<macho::RelocationEntry> RENext; 1042 DataRefImpl RelNext = Rel; 1043 RelNext.d.a++; 1044 getRelocation(RelNext, RENext); 1045 1046 // X86 sect diff's must be followed by a relocation of type 1047 // GENERIC_RELOC_PAIR. 1048 bool isNextScattered = (Arch != Triple::x86_64) && 1049 (RENext->Word0 & macho::RF_Scattered); 1050 unsigned RType; 1051 if (isNextScattered) 1052 RType = (RENext->Word0 >> 24) & 0xF; 1053 else 1054 RType = (RENext->Word1 >> 28) & 0xF; 1055 if (RType != 1) 1056 report_fatal_error("Expected GENERIC_RELOC_PAIR after " 1057 "GENERIC_RELOC_LOCAL_SECTDIFF."); 1058 1059 printRelocationTargetName(RE, fmt); 1060 fmt << "-"; 1061 printRelocationTargetName(RENext, fmt); 1062 break; 1063 } 1064 case macho::RIT_Generic_TLV: { 1065 printRelocationTargetName(RE, fmt); 1066 fmt << "@TLV"; 1067 if (isPCRel) fmt << "P"; 1068 break; 1069 } 1070 default: 1071 printRelocationTargetName(RE, fmt); 1072 } 1073 } else { // ARM-specific relocations 1074 switch (Type) { 1075 case macho::RIT_ARM_Half: // ARM_RELOC_HALF 1076 case macho::RIT_ARM_HalfDifference: { // ARM_RELOC_HALF_SECTDIFF 1077 // Half relocations steal a bit from the length field to encode 1078 // whether this is an upper16 or a lower16 relocation. 1079 bool isUpper; 1080 if (isScattered) 1081 isUpper = (RE->Word0 >> 28) & 1; 1082 else 1083 isUpper = (RE->Word1 >> 25) & 1; 1084 1085 if (isUpper) 1086 fmt << ":upper16:("; 1087 else 1088 fmt << ":lower16:("; 1089 printRelocationTargetName(RE, fmt); 1090 1091 InMemoryStruct<macho::RelocationEntry> RENext; 1092 DataRefImpl RelNext = Rel; 1093 RelNext.d.a++; 1094 getRelocation(RelNext, RENext); 1095 1096 // ARM half relocs must be followed by a relocation of type 1097 // ARM_RELOC_PAIR. 1098 bool isNextScattered = (Arch != Triple::x86_64) && 1099 (RENext->Word0 & macho::RF_Scattered); 1100 unsigned RType; 1101 if (isNextScattered) 1102 RType = (RENext->Word0 >> 24) & 0xF; 1103 else 1104 RType = (RENext->Word1 >> 28) & 0xF; 1105 1106 if (RType != 1) 1107 report_fatal_error("Expected ARM_RELOC_PAIR after " 1108 "GENERIC_RELOC_HALF"); 1109 1110 // NOTE: The half of the target virtual address is stashed in the 1111 // address field of the secondary relocation, but we can't reverse 1112 // engineer the constant offset from it without decoding the movw/movt 1113 // instruction to find the other half in its immediate field. 1114 1115 // ARM_RELOC_HALF_SECTDIFF encodes the second section in the 1116 // symbol/section pointer of the follow-on relocation. 1117 if (Type == macho::RIT_ARM_HalfDifference) { 1118 fmt << "-"; 1119 printRelocationTargetName(RENext, fmt); 1120 } 1121 1122 fmt << ")"; 1123 break; 1124 } 1125 default: { 1126 printRelocationTargetName(RE, fmt); 1127 } 1128 } 1129 } 1130 } else 1131 printRelocationTargetName(RE, fmt); 1132 1133 fmt.flush(); 1134 Result.append(fmtbuf.begin(), fmtbuf.end()); 1135 return object_error::success; 1136 } 1137 1138 error_code MachOObjectFile::getRelocationHidden(DataRefImpl Rel, 1139 bool &Result) const { 1140 InMemoryStruct<macho::RelocationEntry> RE; 1141 getRelocation(Rel, RE); 1142 1143 unsigned Arch = getArch(); 1144 bool isScattered = (Arch != Triple::x86_64) && 1145 (RE->Word0 & macho::RF_Scattered); 1146 unsigned Type; 1147 if (isScattered) 1148 Type = (RE->Word0 >> 24) & 0xF; 1149 else 1150 Type = (RE->Word1 >> 28) & 0xF; 1151 1152 Result = false; 1153 1154 // On arches that use the generic relocations, GENERIC_RELOC_PAIR 1155 // is always hidden. 1156 if (Arch == Triple::x86 || Arch == Triple::arm) { 1157 if (Type == macho::RIT_Pair) Result = true; 1158 } else if (Arch == Triple::x86_64) { 1159 // On x86_64, X86_64_RELOC_UNSIGNED is hidden only when it follows 1160 // an X864_64_RELOC_SUBTRACTOR. 1161 if (Type == macho::RIT_X86_64_Unsigned && Rel.d.a > 0) { 1162 DataRefImpl RelPrev = Rel; 1163 RelPrev.d.a--; 1164 InMemoryStruct<macho::RelocationEntry> REPrev; 1165 getRelocation(RelPrev, REPrev); 1166 1167 unsigned PrevType = (REPrev->Word1 >> 28) & 0xF; 1168 1169 if (PrevType == macho::RIT_X86_64_Subtractor) Result = true; 1170 } 1171 } 1172 1173 return object_error::success; 1174 } 1175 1176 /*===-- Miscellaneous -----------------------------------------------------===*/ 1177 1178 uint8_t MachOObjectFile::getBytesInAddress() const { 1179 return MachOObj->is64Bit() ? 8 : 4; 1180 } 1181 1182 StringRef MachOObjectFile::getFileFormatName() const { 1183 if (!MachOObj->is64Bit()) { 1184 switch (MachOObj->getHeader().CPUType) { 1185 case llvm::MachO::CPUTypeI386: 1186 return "Mach-O 32-bit i386"; 1187 case llvm::MachO::CPUTypeARM: 1188 return "Mach-O arm"; 1189 case llvm::MachO::CPUTypePowerPC: 1190 return "Mach-O 32-bit ppc"; 1191 default: 1192 assert((MachOObj->getHeader().CPUType & llvm::MachO::CPUArchABI64) == 0 && 1193 "64-bit object file when we're not 64-bit?"); 1194 return "Mach-O 32-bit unknown"; 1195 } 1196 } 1197 1198 switch (MachOObj->getHeader().CPUType) { 1199 case llvm::MachO::CPUTypeX86_64: 1200 return "Mach-O 64-bit x86-64"; 1201 case llvm::MachO::CPUTypePowerPC64: 1202 return "Mach-O 64-bit ppc64"; 1203 default: 1204 assert((MachOObj->getHeader().CPUType & llvm::MachO::CPUArchABI64) == 1 && 1205 "32-bit object file when we're 64-bit?"); 1206 return "Mach-O 64-bit unknown"; 1207 } 1208 } 1209 1210 unsigned MachOObjectFile::getArch() const { 1211 switch (MachOObj->getHeader().CPUType) { 1212 case llvm::MachO::CPUTypeI386: 1213 return Triple::x86; 1214 case llvm::MachO::CPUTypeX86_64: 1215 return Triple::x86_64; 1216 case llvm::MachO::CPUTypeARM: 1217 return Triple::arm; 1218 case llvm::MachO::CPUTypePowerPC: 1219 return Triple::ppc; 1220 case llvm::MachO::CPUTypePowerPC64: 1221 return Triple::ppc64; 1222 default: 1223 return Triple::UnknownArch; 1224 } 1225 } 1226 1227 } // end namespace object 1228 } // end namespace llvm 1229