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