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