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