1 //===--- XCOFFObjectFile.cpp - XCOFF object file implementation -----------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines the XCOFFObjectFile class. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "llvm/Object/XCOFFObjectFile.h" 14 #include "llvm/ADT/StringSwitch.h" 15 #include "llvm/MC/SubtargetFeature.h" 16 #include "llvm/Support/DataExtractor.h" 17 #include <cstddef> 18 #include <cstring> 19 20 namespace llvm { 21 22 using namespace XCOFF; 23 24 namespace object { 25 26 static const uint8_t FunctionSym = 0x20; 27 static const uint16_t NoRelMask = 0x0001; 28 static const size_t SymbolAuxTypeOffset = 17; 29 30 // Checks that [Ptr, Ptr + Size) bytes fall inside the memory buffer 31 // 'M'. Returns a pointer to the underlying object on success. 32 template <typename T> 33 static Expected<const T *> getObject(MemoryBufferRef M, const void *Ptr, 34 const uint64_t Size = sizeof(T)) { 35 uintptr_t Addr = reinterpret_cast<uintptr_t>(Ptr); 36 if (Error E = Binary::checkOffset(M, Addr, Size)) 37 return std::move(E); 38 return reinterpret_cast<const T *>(Addr); 39 } 40 41 static uintptr_t getWithOffset(uintptr_t Base, ptrdiff_t Offset) { 42 return reinterpret_cast<uintptr_t>(reinterpret_cast<const char *>(Base) + 43 Offset); 44 } 45 46 template <typename T> static const T *viewAs(uintptr_t in) { 47 return reinterpret_cast<const T *>(in); 48 } 49 50 static StringRef generateXCOFFFixedNameStringRef(const char *Name) { 51 auto NulCharPtr = 52 static_cast<const char *>(memchr(Name, '\0', XCOFF::NameSize)); 53 return NulCharPtr ? StringRef(Name, NulCharPtr - Name) 54 : StringRef(Name, XCOFF::NameSize); 55 } 56 57 template <typename T> StringRef XCOFFSectionHeader<T>::getName() const { 58 const T &DerivedXCOFFSectionHeader = static_cast<const T &>(*this); 59 return generateXCOFFFixedNameStringRef(DerivedXCOFFSectionHeader.Name); 60 } 61 62 template <typename T> uint16_t XCOFFSectionHeader<T>::getSectionType() const { 63 const T &DerivedXCOFFSectionHeader = static_cast<const T &>(*this); 64 return DerivedXCOFFSectionHeader.Flags & SectionFlagsTypeMask; 65 } 66 67 template <typename T> 68 bool XCOFFSectionHeader<T>::isReservedSectionType() const { 69 return getSectionType() & SectionFlagsReservedMask; 70 } 71 72 template <typename AddressType> 73 bool XCOFFRelocation<AddressType>::isRelocationSigned() const { 74 return Info & XR_SIGN_INDICATOR_MASK; 75 } 76 77 template <typename AddressType> 78 bool XCOFFRelocation<AddressType>::isFixupIndicated() const { 79 return Info & XR_FIXUP_INDICATOR_MASK; 80 } 81 82 template <typename AddressType> 83 uint8_t XCOFFRelocation<AddressType>::getRelocatedLength() const { 84 // The relocation encodes the bit length being relocated minus 1. Add back 85 // the 1 to get the actual length being relocated. 86 return (Info & XR_BIASED_LENGTH_MASK) + 1; 87 } 88 89 uintptr_t 90 XCOFFObjectFile::getAdvancedSymbolEntryAddress(uintptr_t CurrentAddress, 91 uint32_t Distance) { 92 return getWithOffset(CurrentAddress, Distance * XCOFF::SymbolTableEntrySize); 93 } 94 95 const XCOFF::SymbolAuxType * 96 XCOFFObjectFile::getSymbolAuxType(uintptr_t AuxEntryAddress) const { 97 assert(is64Bit() && "64-bit interface called on a 32-bit object file."); 98 return viewAs<XCOFF::SymbolAuxType>( 99 getWithOffset(AuxEntryAddress, SymbolAuxTypeOffset)); 100 } 101 102 void XCOFFObjectFile::checkSectionAddress(uintptr_t Addr, 103 uintptr_t TableAddress) const { 104 if (Addr < TableAddress) 105 report_fatal_error("Section header outside of section header table."); 106 107 uintptr_t Offset = Addr - TableAddress; 108 if (Offset >= getSectionHeaderSize() * getNumberOfSections()) 109 report_fatal_error("Section header outside of section header table."); 110 111 if (Offset % getSectionHeaderSize() != 0) 112 report_fatal_error( 113 "Section header pointer does not point to a valid section header."); 114 } 115 116 const XCOFFSectionHeader32 * 117 XCOFFObjectFile::toSection32(DataRefImpl Ref) const { 118 assert(!is64Bit() && "32-bit interface called on 64-bit object file."); 119 #ifndef NDEBUG 120 checkSectionAddress(Ref.p, getSectionHeaderTableAddress()); 121 #endif 122 return viewAs<XCOFFSectionHeader32>(Ref.p); 123 } 124 125 const XCOFFSectionHeader64 * 126 XCOFFObjectFile::toSection64(DataRefImpl Ref) const { 127 assert(is64Bit() && "64-bit interface called on a 32-bit object file."); 128 #ifndef NDEBUG 129 checkSectionAddress(Ref.p, getSectionHeaderTableAddress()); 130 #endif 131 return viewAs<XCOFFSectionHeader64>(Ref.p); 132 } 133 134 XCOFFSymbolRef XCOFFObjectFile::toSymbolRef(DataRefImpl Ref) const { 135 assert(Ref.p != 0 && "Symbol table pointer can not be nullptr!"); 136 #ifndef NDEBUG 137 checkSymbolEntryPointer(Ref.p); 138 #endif 139 return XCOFFSymbolRef(Ref, this); 140 } 141 142 const XCOFFFileHeader32 *XCOFFObjectFile::fileHeader32() const { 143 assert(!is64Bit() && "32-bit interface called on 64-bit object file."); 144 return static_cast<const XCOFFFileHeader32 *>(FileHeader); 145 } 146 147 const XCOFFFileHeader64 *XCOFFObjectFile::fileHeader64() const { 148 assert(is64Bit() && "64-bit interface called on a 32-bit object file."); 149 return static_cast<const XCOFFFileHeader64 *>(FileHeader); 150 } 151 152 const XCOFFAuxiliaryHeader32 *XCOFFObjectFile::auxiliaryHeader32() const { 153 assert(!is64Bit() && "32-bit interface called on 64-bit object file."); 154 return static_cast<const XCOFFAuxiliaryHeader32 *>(AuxiliaryHeader); 155 } 156 157 const XCOFFAuxiliaryHeader64 *XCOFFObjectFile::auxiliaryHeader64() const { 158 assert(is64Bit() && "64-bit interface called on a 32-bit object file."); 159 return static_cast<const XCOFFAuxiliaryHeader64 *>(AuxiliaryHeader); 160 } 161 162 template <typename T> const T *XCOFFObjectFile::sectionHeaderTable() const { 163 return static_cast<const T *>(SectionHeaderTable); 164 } 165 166 const XCOFFSectionHeader32 * 167 XCOFFObjectFile::sectionHeaderTable32() const { 168 assert(!is64Bit() && "32-bit interface called on 64-bit object file."); 169 return static_cast<const XCOFFSectionHeader32 *>(SectionHeaderTable); 170 } 171 172 const XCOFFSectionHeader64 * 173 XCOFFObjectFile::sectionHeaderTable64() const { 174 assert(is64Bit() && "64-bit interface called on a 32-bit object file."); 175 return static_cast<const XCOFFSectionHeader64 *>(SectionHeaderTable); 176 } 177 178 void XCOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const { 179 uintptr_t NextSymbolAddr = getAdvancedSymbolEntryAddress( 180 Symb.p, toSymbolRef(Symb).getNumberOfAuxEntries() + 1); 181 #ifndef NDEBUG 182 // This function is used by basic_symbol_iterator, which allows to 183 // point to the end-of-symbol-table address. 184 if (NextSymbolAddr != getEndOfSymbolTableAddress()) 185 checkSymbolEntryPointer(NextSymbolAddr); 186 #endif 187 Symb.p = NextSymbolAddr; 188 } 189 190 Expected<StringRef> 191 XCOFFObjectFile::getStringTableEntry(uint32_t Offset) const { 192 // The byte offset is relative to the start of the string table. 193 // A byte offset value of 0 is a null or zero-length symbol 194 // name. A byte offset in the range 1 to 3 (inclusive) points into the length 195 // field; as a soft-error recovery mechanism, we treat such cases as having an 196 // offset of 0. 197 if (Offset < 4) 198 return StringRef(nullptr, 0); 199 200 if (StringTable.Data != nullptr && StringTable.Size > Offset) 201 return (StringTable.Data + Offset); 202 203 return createError("entry with offset 0x" + Twine::utohexstr(Offset) + 204 " in a string table with size 0x" + 205 Twine::utohexstr(StringTable.Size) + " is invalid"); 206 } 207 208 StringRef XCOFFObjectFile::getStringTable() const { 209 // If the size is less than or equal to 4, then the string table contains no 210 // string data. 211 return StringRef(StringTable.Data, 212 StringTable.Size <= 4 ? 0 : StringTable.Size); 213 } 214 215 Expected<StringRef> 216 XCOFFObjectFile::getCFileName(const XCOFFFileAuxEnt *CFileEntPtr) const { 217 if (CFileEntPtr->NameInStrTbl.Magic != XCOFFSymbolRef::NAME_IN_STR_TBL_MAGIC) 218 return generateXCOFFFixedNameStringRef(CFileEntPtr->Name); 219 return getStringTableEntry(CFileEntPtr->NameInStrTbl.Offset); 220 } 221 222 Expected<StringRef> XCOFFObjectFile::getSymbolName(DataRefImpl Symb) const { 223 return toSymbolRef(Symb).getName(); 224 } 225 226 Expected<uint64_t> XCOFFObjectFile::getSymbolAddress(DataRefImpl Symb) const { 227 return toSymbolRef(Symb).getValue(); 228 } 229 230 uint64_t XCOFFObjectFile::getSymbolValueImpl(DataRefImpl Symb) const { 231 return toSymbolRef(Symb).getValue(); 232 } 233 234 uint32_t XCOFFObjectFile::getSymbolAlignment(DataRefImpl Symb) const { 235 uint64_t Result = 0; 236 XCOFFSymbolRef XCOFFSym = toSymbolRef(Symb); 237 if (XCOFFSym.isCsectSymbol()) { 238 Expected<XCOFFCsectAuxRef> CsectAuxRefOrError = 239 XCOFFSym.getXCOFFCsectAuxRef(); 240 if (!CsectAuxRefOrError) 241 // TODO: report the error up the stack. 242 consumeError(CsectAuxRefOrError.takeError()); 243 else 244 Result = 1ULL << CsectAuxRefOrError.get().getAlignmentLog2(); 245 } 246 return Result; 247 } 248 249 uint64_t XCOFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const { 250 uint64_t Result = 0; 251 XCOFFSymbolRef XCOFFSym = toSymbolRef(Symb); 252 if (XCOFFSym.isCsectSymbol()) { 253 Expected<XCOFFCsectAuxRef> CsectAuxRefOrError = 254 XCOFFSym.getXCOFFCsectAuxRef(); 255 if (!CsectAuxRefOrError) 256 // TODO: report the error up the stack. 257 consumeError(CsectAuxRefOrError.takeError()); 258 else { 259 XCOFFCsectAuxRef CsectAuxRef = CsectAuxRefOrError.get(); 260 assert(CsectAuxRef.getSymbolType() == XCOFF::XTY_CM); 261 Result = CsectAuxRef.getSectionOrLength(); 262 } 263 } 264 return Result; 265 } 266 267 Expected<SymbolRef::Type> 268 XCOFFObjectFile::getSymbolType(DataRefImpl Symb) const { 269 XCOFFSymbolRef XCOFFSym = toSymbolRef(Symb); 270 271 if (XCOFFSym.isFunction()) 272 return SymbolRef::ST_Function; 273 274 if (XCOFF::C_FILE == XCOFFSym.getStorageClass()) 275 return SymbolRef::ST_File; 276 277 int16_t SecNum = XCOFFSym.getSectionNumber(); 278 if (SecNum <= 0) 279 return SymbolRef::ST_Other; 280 281 Expected<DataRefImpl> SecDRIOrErr = 282 getSectionByNum(XCOFFSym.getSectionNumber()); 283 284 if (!SecDRIOrErr) 285 return SecDRIOrErr.takeError(); 286 287 DataRefImpl SecDRI = SecDRIOrErr.get(); 288 289 Expected<StringRef> SymNameOrError = XCOFFSym.getName(); 290 if (SymNameOrError) { 291 // The "TOC" symbol is treated as SymbolRef::ST_Other. 292 if (SymNameOrError.get() == "TOC") 293 return SymbolRef::ST_Other; 294 295 // The symbol for a section name is treated as SymbolRef::ST_Other. 296 StringRef SecName; 297 if (is64Bit()) 298 SecName = XCOFFObjectFile::toSection64(SecDRIOrErr.get())->getName(); 299 else 300 SecName = XCOFFObjectFile::toSection32(SecDRIOrErr.get())->getName(); 301 302 if (SecName == SymNameOrError.get()) 303 return SymbolRef::ST_Other; 304 } else 305 return SymNameOrError.takeError(); 306 307 if (isSectionData(SecDRI) || isSectionBSS(SecDRI)) 308 return SymbolRef::ST_Data; 309 310 if (isDebugSection(SecDRI)) 311 return SymbolRef::ST_Debug; 312 313 return SymbolRef::ST_Other; 314 } 315 316 Expected<section_iterator> 317 XCOFFObjectFile::getSymbolSection(DataRefImpl Symb) const { 318 const int16_t SectNum = toSymbolRef(Symb).getSectionNumber(); 319 320 if (isReservedSectionNumber(SectNum)) 321 return section_end(); 322 323 Expected<DataRefImpl> ExpSec = getSectionByNum(SectNum); 324 if (!ExpSec) 325 return ExpSec.takeError(); 326 327 return section_iterator(SectionRef(ExpSec.get(), this)); 328 } 329 330 void XCOFFObjectFile::moveSectionNext(DataRefImpl &Sec) const { 331 const char *Ptr = reinterpret_cast<const char *>(Sec.p); 332 Sec.p = reinterpret_cast<uintptr_t>(Ptr + getSectionHeaderSize()); 333 } 334 335 Expected<StringRef> XCOFFObjectFile::getSectionName(DataRefImpl Sec) const { 336 return generateXCOFFFixedNameStringRef(getSectionNameInternal(Sec)); 337 } 338 339 uint64_t XCOFFObjectFile::getSectionAddress(DataRefImpl Sec) const { 340 // Avoid ternary due to failure to convert the ubig32_t value to a unit64_t 341 // with MSVC. 342 if (is64Bit()) 343 return toSection64(Sec)->VirtualAddress; 344 345 return toSection32(Sec)->VirtualAddress; 346 } 347 348 uint64_t XCOFFObjectFile::getSectionIndex(DataRefImpl Sec) const { 349 // Section numbers in XCOFF are numbered beginning at 1. A section number of 350 // zero is used to indicate that a symbol is being imported or is undefined. 351 if (is64Bit()) 352 return toSection64(Sec) - sectionHeaderTable64() + 1; 353 else 354 return toSection32(Sec) - sectionHeaderTable32() + 1; 355 } 356 357 uint64_t XCOFFObjectFile::getSectionSize(DataRefImpl Sec) const { 358 // Avoid ternary due to failure to convert the ubig32_t value to a unit64_t 359 // with MSVC. 360 if (is64Bit()) 361 return toSection64(Sec)->SectionSize; 362 363 return toSection32(Sec)->SectionSize; 364 } 365 366 Expected<ArrayRef<uint8_t>> 367 XCOFFObjectFile::getSectionContents(DataRefImpl Sec) const { 368 if (isSectionVirtual(Sec)) 369 return ArrayRef<uint8_t>(); 370 371 uint64_t OffsetToRaw; 372 if (is64Bit()) 373 OffsetToRaw = toSection64(Sec)->FileOffsetToRawData; 374 else 375 OffsetToRaw = toSection32(Sec)->FileOffsetToRawData; 376 377 const uint8_t * ContentStart = base() + OffsetToRaw; 378 uint64_t SectionSize = getSectionSize(Sec); 379 if (Error E = Binary::checkOffset( 380 Data, reinterpret_cast<uintptr_t>(ContentStart), SectionSize)) 381 return createError( 382 toString(std::move(E)) + ": section data with offset 0x" + 383 Twine::utohexstr(OffsetToRaw) + " and size 0x" + 384 Twine::utohexstr(SectionSize) + " goes past the end of the file"); 385 386 return makeArrayRef(ContentStart,SectionSize); 387 } 388 389 uint64_t XCOFFObjectFile::getSectionAlignment(DataRefImpl Sec) const { 390 uint64_t Result = 0; 391 llvm_unreachable("Not yet implemented!"); 392 return Result; 393 } 394 395 Expected<uintptr_t> XCOFFObjectFile::getLoaderSectionAddress() const { 396 uint64_t OffsetToLoaderSection = 0; 397 uint64_t SizeOfLoaderSection = 0; 398 399 if (is64Bit()) { 400 for (const auto &Sec64 : sections64()) 401 if (Sec64.getSectionType() == XCOFF::STYP_LOADER) { 402 OffsetToLoaderSection = Sec64.FileOffsetToRawData; 403 SizeOfLoaderSection = Sec64.SectionSize; 404 break; 405 } 406 } else { 407 for (const auto &Sec32 : sections32()) 408 if (Sec32.getSectionType() == XCOFF::STYP_LOADER) { 409 OffsetToLoaderSection = Sec32.FileOffsetToRawData; 410 SizeOfLoaderSection = Sec32.SectionSize; 411 break; 412 } 413 } 414 415 // No loader section is not an error. 416 if (!SizeOfLoaderSection) 417 return 0; 418 419 uintptr_t LoderSectionStart = 420 reinterpret_cast<uintptr_t>(base() + OffsetToLoaderSection); 421 if (Error E = 422 Binary::checkOffset(Data, LoderSectionStart, SizeOfLoaderSection)) 423 return createError(toString(std::move(E)) + 424 ": loader section with offset 0x" + 425 Twine::utohexstr(OffsetToLoaderSection) + 426 " and size 0x" + Twine::utohexstr(SizeOfLoaderSection) + 427 " goes past the end of the file"); 428 429 return LoderSectionStart; 430 } 431 432 bool XCOFFObjectFile::isSectionCompressed(DataRefImpl Sec) const { 433 return false; 434 } 435 436 bool XCOFFObjectFile::isSectionText(DataRefImpl Sec) const { 437 return getSectionFlags(Sec) & XCOFF::STYP_TEXT; 438 } 439 440 bool XCOFFObjectFile::isSectionData(DataRefImpl Sec) const { 441 uint32_t Flags = getSectionFlags(Sec); 442 return Flags & (XCOFF::STYP_DATA | XCOFF::STYP_TDATA); 443 } 444 445 bool XCOFFObjectFile::isSectionBSS(DataRefImpl Sec) const { 446 uint32_t Flags = getSectionFlags(Sec); 447 return Flags & (XCOFF::STYP_BSS | XCOFF::STYP_TBSS); 448 } 449 450 bool XCOFFObjectFile::isDebugSection(DataRefImpl Sec) const { 451 uint32_t Flags = getSectionFlags(Sec); 452 return Flags & (XCOFF::STYP_DEBUG | XCOFF::STYP_DWARF); 453 } 454 455 bool XCOFFObjectFile::isSectionVirtual(DataRefImpl Sec) const { 456 return is64Bit() ? toSection64(Sec)->FileOffsetToRawData == 0 457 : toSection32(Sec)->FileOffsetToRawData == 0; 458 } 459 460 relocation_iterator XCOFFObjectFile::section_rel_begin(DataRefImpl Sec) const { 461 DataRefImpl Ret; 462 if (is64Bit()) { 463 const XCOFFSectionHeader64 *SectionEntPtr = toSection64(Sec); 464 auto RelocationsOrErr = 465 relocations<XCOFFSectionHeader64, XCOFFRelocation64>(*SectionEntPtr); 466 if (Error E = RelocationsOrErr.takeError()) { 467 // TODO: report the error up the stack. 468 consumeError(std::move(E)); 469 return relocation_iterator(RelocationRef()); 470 } 471 Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().begin()); 472 } else { 473 const XCOFFSectionHeader32 *SectionEntPtr = toSection32(Sec); 474 auto RelocationsOrErr = 475 relocations<XCOFFSectionHeader32, XCOFFRelocation32>(*SectionEntPtr); 476 if (Error E = RelocationsOrErr.takeError()) { 477 // TODO: report the error up the stack. 478 consumeError(std::move(E)); 479 return relocation_iterator(RelocationRef()); 480 } 481 Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().begin()); 482 } 483 return relocation_iterator(RelocationRef(Ret, this)); 484 } 485 486 relocation_iterator XCOFFObjectFile::section_rel_end(DataRefImpl Sec) const { 487 DataRefImpl Ret; 488 if (is64Bit()) { 489 const XCOFFSectionHeader64 *SectionEntPtr = toSection64(Sec); 490 auto RelocationsOrErr = 491 relocations<XCOFFSectionHeader64, XCOFFRelocation64>(*SectionEntPtr); 492 if (Error E = RelocationsOrErr.takeError()) { 493 // TODO: report the error up the stack. 494 consumeError(std::move(E)); 495 return relocation_iterator(RelocationRef()); 496 } 497 Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().end()); 498 } else { 499 const XCOFFSectionHeader32 *SectionEntPtr = toSection32(Sec); 500 auto RelocationsOrErr = 501 relocations<XCOFFSectionHeader32, XCOFFRelocation32>(*SectionEntPtr); 502 if (Error E = RelocationsOrErr.takeError()) { 503 // TODO: report the error up the stack. 504 consumeError(std::move(E)); 505 return relocation_iterator(RelocationRef()); 506 } 507 Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().end()); 508 } 509 return relocation_iterator(RelocationRef(Ret, this)); 510 } 511 512 void XCOFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const { 513 if (is64Bit()) 514 Rel.p = reinterpret_cast<uintptr_t>(viewAs<XCOFFRelocation64>(Rel.p) + 1); 515 else 516 Rel.p = reinterpret_cast<uintptr_t>(viewAs<XCOFFRelocation32>(Rel.p) + 1); 517 } 518 519 uint64_t XCOFFObjectFile::getRelocationOffset(DataRefImpl Rel) const { 520 if (is64Bit()) { 521 const XCOFFRelocation64 *Reloc = viewAs<XCOFFRelocation64>(Rel.p); 522 const XCOFFSectionHeader64 *Sec64 = sectionHeaderTable64(); 523 const uint64_t RelocAddress = Reloc->VirtualAddress; 524 const uint16_t NumberOfSections = getNumberOfSections(); 525 for (uint16_t I = 0; I < NumberOfSections; ++I) { 526 // Find which section this relocation belongs to, and get the 527 // relocation offset relative to the start of the section. 528 if (Sec64->VirtualAddress <= RelocAddress && 529 RelocAddress < Sec64->VirtualAddress + Sec64->SectionSize) { 530 return RelocAddress - Sec64->VirtualAddress; 531 } 532 ++Sec64; 533 } 534 } else { 535 const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(Rel.p); 536 const XCOFFSectionHeader32 *Sec32 = sectionHeaderTable32(); 537 const uint32_t RelocAddress = Reloc->VirtualAddress; 538 const uint16_t NumberOfSections = getNumberOfSections(); 539 for (uint16_t I = 0; I < NumberOfSections; ++I) { 540 // Find which section this relocation belongs to, and get the 541 // relocation offset relative to the start of the section. 542 if (Sec32->VirtualAddress <= RelocAddress && 543 RelocAddress < Sec32->VirtualAddress + Sec32->SectionSize) { 544 return RelocAddress - Sec32->VirtualAddress; 545 } 546 ++Sec32; 547 } 548 } 549 return InvalidRelocOffset; 550 } 551 552 symbol_iterator XCOFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const { 553 uint32_t Index; 554 if (is64Bit()) { 555 const XCOFFRelocation64 *Reloc = viewAs<XCOFFRelocation64>(Rel.p); 556 Index = Reloc->SymbolIndex; 557 558 if (Index >= getNumberOfSymbolTableEntries64()) 559 return symbol_end(); 560 } else { 561 const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(Rel.p); 562 Index = Reloc->SymbolIndex; 563 564 if (Index >= getLogicalNumberOfSymbolTableEntries32()) 565 return symbol_end(); 566 } 567 DataRefImpl SymDRI; 568 SymDRI.p = getSymbolEntryAddressByIndex(Index); 569 return symbol_iterator(SymbolRef(SymDRI, this)); 570 } 571 572 uint64_t XCOFFObjectFile::getRelocationType(DataRefImpl Rel) const { 573 if (is64Bit()) 574 return viewAs<XCOFFRelocation64>(Rel.p)->Type; 575 return viewAs<XCOFFRelocation32>(Rel.p)->Type; 576 } 577 578 void XCOFFObjectFile::getRelocationTypeName( 579 DataRefImpl Rel, SmallVectorImpl<char> &Result) const { 580 StringRef Res; 581 if (is64Bit()) { 582 const XCOFFRelocation64 *Reloc = viewAs<XCOFFRelocation64>(Rel.p); 583 Res = XCOFF::getRelocationTypeString(Reloc->Type); 584 } else { 585 const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(Rel.p); 586 Res = XCOFF::getRelocationTypeString(Reloc->Type); 587 } 588 Result.append(Res.begin(), Res.end()); 589 } 590 591 Expected<uint32_t> XCOFFObjectFile::getSymbolFlags(DataRefImpl Symb) const { 592 XCOFFSymbolRef XCOFFSym = toSymbolRef(Symb); 593 uint32_t Result = SymbolRef::SF_None; 594 595 if (XCOFFSym.getSectionNumber() == XCOFF::N_ABS) 596 Result |= SymbolRef::SF_Absolute; 597 598 XCOFF::StorageClass SC = XCOFFSym.getStorageClass(); 599 if (XCOFF::C_EXT == SC || XCOFF::C_WEAKEXT == SC) 600 Result |= SymbolRef::SF_Global; 601 602 if (XCOFF::C_WEAKEXT == SC) 603 Result |= SymbolRef::SF_Weak; 604 605 if (XCOFFSym.isCsectSymbol()) { 606 Expected<XCOFFCsectAuxRef> CsectAuxEntOrErr = 607 XCOFFSym.getXCOFFCsectAuxRef(); 608 if (CsectAuxEntOrErr) { 609 if (CsectAuxEntOrErr.get().getSymbolType() == XCOFF::XTY_CM) 610 Result |= SymbolRef::SF_Common; 611 } else 612 return CsectAuxEntOrErr.takeError(); 613 } 614 615 if (XCOFFSym.getSectionNumber() == XCOFF::N_UNDEF) 616 Result |= SymbolRef::SF_Undefined; 617 618 return Result; 619 } 620 621 basic_symbol_iterator XCOFFObjectFile::symbol_begin() const { 622 DataRefImpl SymDRI; 623 SymDRI.p = reinterpret_cast<uintptr_t>(SymbolTblPtr); 624 return basic_symbol_iterator(SymbolRef(SymDRI, this)); 625 } 626 627 basic_symbol_iterator XCOFFObjectFile::symbol_end() const { 628 DataRefImpl SymDRI; 629 const uint32_t NumberOfSymbolTableEntries = getNumberOfSymbolTableEntries(); 630 SymDRI.p = getSymbolEntryAddressByIndex(NumberOfSymbolTableEntries); 631 return basic_symbol_iterator(SymbolRef(SymDRI, this)); 632 } 633 634 section_iterator XCOFFObjectFile::section_begin() const { 635 DataRefImpl DRI; 636 DRI.p = getSectionHeaderTableAddress(); 637 return section_iterator(SectionRef(DRI, this)); 638 } 639 640 section_iterator XCOFFObjectFile::section_end() const { 641 DataRefImpl DRI; 642 DRI.p = getWithOffset(getSectionHeaderTableAddress(), 643 getNumberOfSections() * getSectionHeaderSize()); 644 return section_iterator(SectionRef(DRI, this)); 645 } 646 647 uint8_t XCOFFObjectFile::getBytesInAddress() const { return is64Bit() ? 8 : 4; } 648 649 StringRef XCOFFObjectFile::getFileFormatName() const { 650 return is64Bit() ? "aix5coff64-rs6000" : "aixcoff-rs6000"; 651 } 652 653 Triple::ArchType XCOFFObjectFile::getArch() const { 654 return is64Bit() ? Triple::ppc64 : Triple::ppc; 655 } 656 657 SubtargetFeatures XCOFFObjectFile::getFeatures() const { 658 return SubtargetFeatures(); 659 } 660 661 bool XCOFFObjectFile::isRelocatableObject() const { 662 if (is64Bit()) 663 return !(fileHeader64()->Flags & NoRelMask); 664 return !(fileHeader32()->Flags & NoRelMask); 665 } 666 667 Expected<uint64_t> XCOFFObjectFile::getStartAddress() const { 668 // TODO FIXME Should get from auxiliary_header->o_entry when support for the 669 // auxiliary_header is added. 670 return 0; 671 } 672 673 StringRef XCOFFObjectFile::mapDebugSectionName(StringRef Name) const { 674 return StringSwitch<StringRef>(Name) 675 .Case("dwinfo", "debug_info") 676 .Case("dwline", "debug_line") 677 .Case("dwpbnms", "debug_pubnames") 678 .Case("dwpbtyp", "debug_pubtypes") 679 .Case("dwarnge", "debug_aranges") 680 .Case("dwabrev", "debug_abbrev") 681 .Case("dwstr", "debug_str") 682 .Case("dwrnges", "debug_ranges") 683 .Case("dwloc", "debug_loc") 684 .Case("dwframe", "debug_frame") 685 .Case("dwmac", "debug_macinfo") 686 .Default(Name); 687 } 688 689 size_t XCOFFObjectFile::getFileHeaderSize() const { 690 return is64Bit() ? sizeof(XCOFFFileHeader64) : sizeof(XCOFFFileHeader32); 691 } 692 693 size_t XCOFFObjectFile::getSectionHeaderSize() const { 694 return is64Bit() ? sizeof(XCOFFSectionHeader64) : 695 sizeof(XCOFFSectionHeader32); 696 } 697 698 bool XCOFFObjectFile::is64Bit() const { 699 return Binary::ID_XCOFF64 == getType(); 700 } 701 702 uint16_t XCOFFObjectFile::getMagic() const { 703 return is64Bit() ? fileHeader64()->Magic : fileHeader32()->Magic; 704 } 705 706 Expected<DataRefImpl> XCOFFObjectFile::getSectionByNum(int16_t Num) const { 707 if (Num <= 0 || Num > getNumberOfSections()) 708 return createStringError(object_error::invalid_section_index, 709 "the section index (" + Twine(Num) + 710 ") is invalid"); 711 712 DataRefImpl DRI; 713 DRI.p = getWithOffset(getSectionHeaderTableAddress(), 714 getSectionHeaderSize() * (Num - 1)); 715 return DRI; 716 } 717 718 Expected<StringRef> 719 XCOFFObjectFile::getSymbolSectionName(XCOFFSymbolRef SymEntPtr) const { 720 const int16_t SectionNum = SymEntPtr.getSectionNumber(); 721 722 switch (SectionNum) { 723 case XCOFF::N_DEBUG: 724 return "N_DEBUG"; 725 case XCOFF::N_ABS: 726 return "N_ABS"; 727 case XCOFF::N_UNDEF: 728 return "N_UNDEF"; 729 default: 730 Expected<DataRefImpl> SecRef = getSectionByNum(SectionNum); 731 if (SecRef) 732 return generateXCOFFFixedNameStringRef( 733 getSectionNameInternal(SecRef.get())); 734 return SecRef.takeError(); 735 } 736 } 737 738 unsigned XCOFFObjectFile::getSymbolSectionID(SymbolRef Sym) const { 739 XCOFFSymbolRef XCOFFSymRef(Sym.getRawDataRefImpl(), this); 740 return XCOFFSymRef.getSectionNumber(); 741 } 742 743 bool XCOFFObjectFile::isReservedSectionNumber(int16_t SectionNumber) { 744 return (SectionNumber <= 0 && SectionNumber >= -2); 745 } 746 747 uint16_t XCOFFObjectFile::getNumberOfSections() const { 748 return is64Bit() ? fileHeader64()->NumberOfSections 749 : fileHeader32()->NumberOfSections; 750 } 751 752 int32_t XCOFFObjectFile::getTimeStamp() const { 753 return is64Bit() ? fileHeader64()->TimeStamp : fileHeader32()->TimeStamp; 754 } 755 756 uint16_t XCOFFObjectFile::getOptionalHeaderSize() const { 757 return is64Bit() ? fileHeader64()->AuxHeaderSize 758 : fileHeader32()->AuxHeaderSize; 759 } 760 761 uint32_t XCOFFObjectFile::getSymbolTableOffset32() const { 762 return fileHeader32()->SymbolTableOffset; 763 } 764 765 int32_t XCOFFObjectFile::getRawNumberOfSymbolTableEntries32() const { 766 // As far as symbol table size is concerned, if this field is negative it is 767 // to be treated as a 0. However since this field is also used for printing we 768 // don't want to truncate any negative values. 769 return fileHeader32()->NumberOfSymTableEntries; 770 } 771 772 uint32_t XCOFFObjectFile::getLogicalNumberOfSymbolTableEntries32() const { 773 return (fileHeader32()->NumberOfSymTableEntries >= 0 774 ? fileHeader32()->NumberOfSymTableEntries 775 : 0); 776 } 777 778 uint64_t XCOFFObjectFile::getSymbolTableOffset64() const { 779 return fileHeader64()->SymbolTableOffset; 780 } 781 782 uint32_t XCOFFObjectFile::getNumberOfSymbolTableEntries64() const { 783 return fileHeader64()->NumberOfSymTableEntries; 784 } 785 786 uint32_t XCOFFObjectFile::getNumberOfSymbolTableEntries() const { 787 return is64Bit() ? getNumberOfSymbolTableEntries64() 788 : getLogicalNumberOfSymbolTableEntries32(); 789 } 790 791 uintptr_t XCOFFObjectFile::getEndOfSymbolTableAddress() const { 792 const uint32_t NumberOfSymTableEntries = getNumberOfSymbolTableEntries(); 793 return getWithOffset(reinterpret_cast<uintptr_t>(SymbolTblPtr), 794 XCOFF::SymbolTableEntrySize * NumberOfSymTableEntries); 795 } 796 797 void XCOFFObjectFile::checkSymbolEntryPointer(uintptr_t SymbolEntPtr) const { 798 if (SymbolEntPtr < reinterpret_cast<uintptr_t>(SymbolTblPtr)) 799 report_fatal_error("Symbol table entry is outside of symbol table."); 800 801 if (SymbolEntPtr >= getEndOfSymbolTableAddress()) 802 report_fatal_error("Symbol table entry is outside of symbol table."); 803 804 ptrdiff_t Offset = reinterpret_cast<const char *>(SymbolEntPtr) - 805 reinterpret_cast<const char *>(SymbolTblPtr); 806 807 if (Offset % XCOFF::SymbolTableEntrySize != 0) 808 report_fatal_error( 809 "Symbol table entry position is not valid inside of symbol table."); 810 } 811 812 uint32_t XCOFFObjectFile::getSymbolIndex(uintptr_t SymbolEntPtr) const { 813 return (reinterpret_cast<const char *>(SymbolEntPtr) - 814 reinterpret_cast<const char *>(SymbolTblPtr)) / 815 XCOFF::SymbolTableEntrySize; 816 } 817 818 uint64_t XCOFFObjectFile::getSymbolSize(DataRefImpl Symb) const { 819 uint64_t Result = 0; 820 XCOFFSymbolRef XCOFFSym = toSymbolRef(Symb); 821 if (XCOFFSym.isCsectSymbol()) { 822 Expected<XCOFFCsectAuxRef> CsectAuxRefOrError = 823 XCOFFSym.getXCOFFCsectAuxRef(); 824 if (!CsectAuxRefOrError) 825 // TODO: report the error up the stack. 826 consumeError(CsectAuxRefOrError.takeError()); 827 else { 828 XCOFFCsectAuxRef CsectAuxRef = CsectAuxRefOrError.get(); 829 uint8_t SymType = CsectAuxRef.getSymbolType(); 830 if (SymType == XCOFF::XTY_SD || SymType == XCOFF::XTY_CM) 831 Result = CsectAuxRef.getSectionOrLength(); 832 } 833 } 834 return Result; 835 } 836 837 uintptr_t XCOFFObjectFile::getSymbolEntryAddressByIndex(uint32_t Index) const { 838 return getAdvancedSymbolEntryAddress( 839 reinterpret_cast<uintptr_t>(getPointerToSymbolTable()), Index); 840 } 841 842 Expected<StringRef> 843 XCOFFObjectFile::getSymbolNameByIndex(uint32_t Index) const { 844 const uint32_t NumberOfSymTableEntries = getNumberOfSymbolTableEntries(); 845 846 if (Index >= NumberOfSymTableEntries) 847 return createError("symbol index " + Twine(Index) + 848 " exceeds symbol count " + 849 Twine(NumberOfSymTableEntries)); 850 851 DataRefImpl SymDRI; 852 SymDRI.p = getSymbolEntryAddressByIndex(Index); 853 return getSymbolName(SymDRI); 854 } 855 856 uint16_t XCOFFObjectFile::getFlags() const { 857 return is64Bit() ? fileHeader64()->Flags : fileHeader32()->Flags; 858 } 859 860 const char *XCOFFObjectFile::getSectionNameInternal(DataRefImpl Sec) const { 861 return is64Bit() ? toSection64(Sec)->Name : toSection32(Sec)->Name; 862 } 863 864 uintptr_t XCOFFObjectFile::getSectionHeaderTableAddress() const { 865 return reinterpret_cast<uintptr_t>(SectionHeaderTable); 866 } 867 868 int32_t XCOFFObjectFile::getSectionFlags(DataRefImpl Sec) const { 869 return is64Bit() ? toSection64(Sec)->Flags : toSection32(Sec)->Flags; 870 } 871 872 XCOFFObjectFile::XCOFFObjectFile(unsigned int Type, MemoryBufferRef Object) 873 : ObjectFile(Type, Object) { 874 assert(Type == Binary::ID_XCOFF32 || Type == Binary::ID_XCOFF64); 875 } 876 877 ArrayRef<XCOFFSectionHeader64> XCOFFObjectFile::sections64() const { 878 assert(is64Bit() && "64-bit interface called for non 64-bit file."); 879 const XCOFFSectionHeader64 *TablePtr = sectionHeaderTable64(); 880 return ArrayRef<XCOFFSectionHeader64>(TablePtr, 881 TablePtr + getNumberOfSections()); 882 } 883 884 ArrayRef<XCOFFSectionHeader32> XCOFFObjectFile::sections32() const { 885 assert(!is64Bit() && "32-bit interface called for non 32-bit file."); 886 const XCOFFSectionHeader32 *TablePtr = sectionHeaderTable32(); 887 return ArrayRef<XCOFFSectionHeader32>(TablePtr, 888 TablePtr + getNumberOfSections()); 889 } 890 891 // In an XCOFF32 file, when the field value is 65535, then an STYP_OVRFLO 892 // section header contains the actual count of relocation entries in the s_paddr 893 // field. STYP_OVRFLO headers contain the section index of their corresponding 894 // sections as their raw "NumberOfRelocations" field value. 895 template <typename T> 896 Expected<uint32_t> XCOFFObjectFile::getNumberOfRelocationEntries( 897 const XCOFFSectionHeader<T> &Sec) const { 898 const T &Section = static_cast<const T &>(Sec); 899 if (is64Bit()) 900 return Section.NumberOfRelocations; 901 902 uint16_t SectionIndex = &Section - sectionHeaderTable<T>() + 1; 903 if (Section.NumberOfRelocations < XCOFF::RelocOverflow) 904 return Section.NumberOfRelocations; 905 for (const auto &Sec : sections32()) { 906 if (Sec.Flags == XCOFF::STYP_OVRFLO && 907 Sec.NumberOfRelocations == SectionIndex) 908 return Sec.PhysicalAddress; 909 } 910 return errorCodeToError(object_error::parse_failed); 911 } 912 913 template <typename Shdr, typename Reloc> 914 Expected<ArrayRef<Reloc>> XCOFFObjectFile::relocations(const Shdr &Sec) const { 915 uintptr_t RelocAddr = getWithOffset(reinterpret_cast<uintptr_t>(FileHeader), 916 Sec.FileOffsetToRelocationInfo); 917 auto NumRelocEntriesOrErr = getNumberOfRelocationEntries(Sec); 918 if (Error E = NumRelocEntriesOrErr.takeError()) 919 return std::move(E); 920 921 uint32_t NumRelocEntries = NumRelocEntriesOrErr.get(); 922 static_assert((sizeof(Reloc) == XCOFF::RelocationSerializationSize64 || 923 sizeof(Reloc) == XCOFF::RelocationSerializationSize32), 924 "Relocation structure is incorrect"); 925 auto RelocationOrErr = 926 getObject<Reloc>(Data, reinterpret_cast<void *>(RelocAddr), 927 NumRelocEntries * sizeof(Reloc)); 928 if (!RelocationOrErr) 929 return createError( 930 toString(RelocationOrErr.takeError()) + ": relocations with offset 0x" + 931 Twine::utohexstr(Sec.FileOffsetToRelocationInfo) + " and size 0x" + 932 Twine::utohexstr(NumRelocEntries * sizeof(Reloc)) + 933 " go past the end of the file"); 934 935 const Reloc *StartReloc = RelocationOrErr.get(); 936 937 return ArrayRef<Reloc>(StartReloc, StartReloc + NumRelocEntries); 938 } 939 940 Expected<XCOFFStringTable> 941 XCOFFObjectFile::parseStringTable(const XCOFFObjectFile *Obj, uint64_t Offset) { 942 // If there is a string table, then the buffer must contain at least 4 bytes 943 // for the string table's size. Not having a string table is not an error. 944 if (Error E = Binary::checkOffset( 945 Obj->Data, reinterpret_cast<uintptr_t>(Obj->base() + Offset), 4)) { 946 consumeError(std::move(E)); 947 return XCOFFStringTable{0, nullptr}; 948 } 949 950 // Read the size out of the buffer. 951 uint32_t Size = support::endian::read32be(Obj->base() + Offset); 952 953 // If the size is less then 4, then the string table is just a size and no 954 // string data. 955 if (Size <= 4) 956 return XCOFFStringTable{4, nullptr}; 957 958 auto StringTableOrErr = 959 getObject<char>(Obj->Data, Obj->base() + Offset, Size); 960 if (!StringTableOrErr) 961 return createError(toString(StringTableOrErr.takeError()) + 962 ": string table with offset 0x" + 963 Twine::utohexstr(Offset) + " and size 0x" + 964 Twine::utohexstr(Size) + 965 " goes past the end of the file"); 966 967 const char *StringTablePtr = StringTableOrErr.get(); 968 if (StringTablePtr[Size - 1] != '\0') 969 return errorCodeToError(object_error::string_table_non_null_end); 970 971 return XCOFFStringTable{Size, StringTablePtr}; 972 } 973 974 // This function returns the import file table. Each entry in the import file 975 // table consists of: "path_name\0base_name\0archive_member_name\0". 976 Expected<StringRef> XCOFFObjectFile::getImportFileTable() const { 977 Expected<uintptr_t> LoaderSectionAddrOrError = getLoaderSectionAddress(); 978 if (!LoaderSectionAddrOrError) 979 return LoaderSectionAddrOrError.takeError(); 980 981 uintptr_t LoaderSectionAddr = LoaderSectionAddrOrError.get(); 982 if (!LoaderSectionAddr) 983 return StringRef(); 984 985 uint64_t OffsetToImportFileTable = 0; 986 uint64_t LengthOfImportFileTable = 0; 987 if (is64Bit()) { 988 const LoaderSectionHeader64 *LoaderSec64 = 989 viewAs<LoaderSectionHeader64>(LoaderSectionAddr); 990 OffsetToImportFileTable = LoaderSec64->OffsetToImpid; 991 LengthOfImportFileTable = LoaderSec64->LengthOfImpidStrTbl; 992 } else { 993 const LoaderSectionHeader32 *LoaderSec32 = 994 viewAs<LoaderSectionHeader32>(LoaderSectionAddr); 995 OffsetToImportFileTable = LoaderSec32->OffsetToImpid; 996 LengthOfImportFileTable = LoaderSec32->LengthOfImpidStrTbl; 997 } 998 999 auto ImportTableOrErr = getObject<char>( 1000 Data, 1001 reinterpret_cast<void *>(LoaderSectionAddr + OffsetToImportFileTable), 1002 LengthOfImportFileTable); 1003 if (!ImportTableOrErr) 1004 return createError( 1005 toString(ImportTableOrErr.takeError()) + 1006 ": import file table with offset 0x" + 1007 Twine::utohexstr(LoaderSectionAddr + OffsetToImportFileTable) + 1008 " and size 0x" + Twine::utohexstr(LengthOfImportFileTable) + 1009 " goes past the end of the file"); 1010 1011 const char *ImportTablePtr = ImportTableOrErr.get(); 1012 if (ImportTablePtr[LengthOfImportFileTable - 1] != '\0') 1013 return createError( 1014 ": import file name table with offset 0x" + 1015 Twine::utohexstr(LoaderSectionAddr + OffsetToImportFileTable) + 1016 " and size 0x" + Twine::utohexstr(LengthOfImportFileTable) + 1017 " must end with a null terminator"); 1018 1019 return StringRef(ImportTablePtr, LengthOfImportFileTable); 1020 } 1021 1022 Expected<std::unique_ptr<XCOFFObjectFile>> 1023 XCOFFObjectFile::create(unsigned Type, MemoryBufferRef MBR) { 1024 // Can't use std::make_unique because of the private constructor. 1025 std::unique_ptr<XCOFFObjectFile> Obj; 1026 Obj.reset(new XCOFFObjectFile(Type, MBR)); 1027 1028 uint64_t CurOffset = 0; 1029 const auto *Base = Obj->base(); 1030 MemoryBufferRef Data = Obj->Data; 1031 1032 // Parse file header. 1033 auto FileHeaderOrErr = 1034 getObject<void>(Data, Base + CurOffset, Obj->getFileHeaderSize()); 1035 if (Error E = FileHeaderOrErr.takeError()) 1036 return std::move(E); 1037 Obj->FileHeader = FileHeaderOrErr.get(); 1038 1039 CurOffset += Obj->getFileHeaderSize(); 1040 1041 if (Obj->getOptionalHeaderSize()) { 1042 auto AuxiliaryHeaderOrErr = 1043 getObject<void>(Data, Base + CurOffset, Obj->getOptionalHeaderSize()); 1044 if (Error E = AuxiliaryHeaderOrErr.takeError()) 1045 return std::move(E); 1046 Obj->AuxiliaryHeader = AuxiliaryHeaderOrErr.get(); 1047 } 1048 1049 CurOffset += Obj->getOptionalHeaderSize(); 1050 1051 // Parse the section header table if it is present. 1052 if (Obj->getNumberOfSections()) { 1053 uint64_t SectionHeadersSize = 1054 Obj->getNumberOfSections() * Obj->getSectionHeaderSize(); 1055 auto SecHeadersOrErr = 1056 getObject<void>(Data, Base + CurOffset, SectionHeadersSize); 1057 if (!SecHeadersOrErr) 1058 return createError(toString(SecHeadersOrErr.takeError()) + 1059 ": section headers with offset 0x" + 1060 Twine::utohexstr(CurOffset) + " and size 0x" + 1061 Twine::utohexstr(SectionHeadersSize) + 1062 " go past the end of the file"); 1063 1064 Obj->SectionHeaderTable = SecHeadersOrErr.get(); 1065 } 1066 1067 const uint32_t NumberOfSymbolTableEntries = 1068 Obj->getNumberOfSymbolTableEntries(); 1069 1070 // If there is no symbol table we are done parsing the memory buffer. 1071 if (NumberOfSymbolTableEntries == 0) 1072 return std::move(Obj); 1073 1074 // Parse symbol table. 1075 CurOffset = Obj->is64Bit() ? Obj->getSymbolTableOffset64() 1076 : Obj->getSymbolTableOffset32(); 1077 const uint64_t SymbolTableSize = 1078 static_cast<uint64_t>(XCOFF::SymbolTableEntrySize) * 1079 NumberOfSymbolTableEntries; 1080 auto SymTableOrErr = 1081 getObject<void *>(Data, Base + CurOffset, SymbolTableSize); 1082 if (!SymTableOrErr) 1083 return createError( 1084 toString(SymTableOrErr.takeError()) + ": symbol table with offset 0x" + 1085 Twine::utohexstr(CurOffset) + " and size 0x" + 1086 Twine::utohexstr(SymbolTableSize) + " goes past the end of the file"); 1087 1088 Obj->SymbolTblPtr = SymTableOrErr.get(); 1089 CurOffset += SymbolTableSize; 1090 1091 // Parse String table. 1092 Expected<XCOFFStringTable> StringTableOrErr = 1093 parseStringTable(Obj.get(), CurOffset); 1094 if (Error E = StringTableOrErr.takeError()) 1095 return std::move(E); 1096 Obj->StringTable = StringTableOrErr.get(); 1097 1098 return std::move(Obj); 1099 } 1100 1101 Expected<std::unique_ptr<ObjectFile>> 1102 ObjectFile::createXCOFFObjectFile(MemoryBufferRef MemBufRef, 1103 unsigned FileType) { 1104 return XCOFFObjectFile::create(FileType, MemBufRef); 1105 } 1106 1107 bool XCOFFSymbolRef::isFunction() const { 1108 if (!isCsectSymbol()) 1109 return false; 1110 1111 if (getSymbolType() & FunctionSym) 1112 return true; 1113 1114 Expected<XCOFFCsectAuxRef> ExpCsectAuxEnt = getXCOFFCsectAuxRef(); 1115 if (!ExpCsectAuxEnt) { 1116 // If we could not get the CSECT auxiliary entry, then treat this symbol as 1117 // if it isn't a function. Consume the error and return `false` to move on. 1118 consumeError(ExpCsectAuxEnt.takeError()); 1119 return false; 1120 } 1121 1122 const XCOFFCsectAuxRef CsectAuxRef = ExpCsectAuxEnt.get(); 1123 1124 // A function definition should be a label definition. 1125 // FIXME: This is not necessarily the case when -ffunction-sections is 1126 // enabled. 1127 if (!CsectAuxRef.isLabel()) 1128 return false; 1129 1130 if (CsectAuxRef.getStorageMappingClass() != XCOFF::XMC_PR) 1131 return false; 1132 1133 const int16_t SectNum = getSectionNumber(); 1134 Expected<DataRefImpl> SI = OwningObjectPtr->getSectionByNum(SectNum); 1135 if (!SI) { 1136 // If we could not get the section, then this symbol should not be 1137 // a function. So consume the error and return `false` to move on. 1138 consumeError(SI.takeError()); 1139 return false; 1140 } 1141 1142 return (OwningObjectPtr->getSectionFlags(SI.get()) & XCOFF::STYP_TEXT); 1143 } 1144 1145 bool XCOFFSymbolRef::isCsectSymbol() const { 1146 XCOFF::StorageClass SC = getStorageClass(); 1147 return (SC == XCOFF::C_EXT || SC == XCOFF::C_WEAKEXT || 1148 SC == XCOFF::C_HIDEXT); 1149 } 1150 1151 Expected<XCOFFCsectAuxRef> XCOFFSymbolRef::getXCOFFCsectAuxRef() const { 1152 assert(isCsectSymbol() && 1153 "Calling csect symbol interface with a non-csect symbol."); 1154 1155 uint8_t NumberOfAuxEntries = getNumberOfAuxEntries(); 1156 1157 Expected<StringRef> NameOrErr = getName(); 1158 if (auto Err = NameOrErr.takeError()) 1159 return std::move(Err); 1160 1161 uint32_t SymbolIdx = OwningObjectPtr->getSymbolIndex(getEntryAddress()); 1162 if (!NumberOfAuxEntries) { 1163 return createError("csect symbol \"" + *NameOrErr + "\" with index " + 1164 Twine(SymbolIdx) + " contains no auxiliary entry"); 1165 } 1166 1167 if (!OwningObjectPtr->is64Bit()) { 1168 // In XCOFF32, the csect auxilliary entry is always the last auxiliary 1169 // entry for the symbol. 1170 uintptr_t AuxAddr = XCOFFObjectFile::getAdvancedSymbolEntryAddress( 1171 getEntryAddress(), NumberOfAuxEntries); 1172 return XCOFFCsectAuxRef(viewAs<XCOFFCsectAuxEnt32>(AuxAddr)); 1173 } 1174 1175 // XCOFF64 uses SymbolAuxType to identify the auxiliary entry type. 1176 // We need to iterate through all the auxiliary entries to find it. 1177 for (uint8_t Index = NumberOfAuxEntries; Index > 0; --Index) { 1178 uintptr_t AuxAddr = XCOFFObjectFile::getAdvancedSymbolEntryAddress( 1179 getEntryAddress(), Index); 1180 if (*OwningObjectPtr->getSymbolAuxType(AuxAddr) == 1181 XCOFF::SymbolAuxType::AUX_CSECT) { 1182 #ifndef NDEBUG 1183 OwningObjectPtr->checkSymbolEntryPointer(AuxAddr); 1184 #endif 1185 return XCOFFCsectAuxRef(viewAs<XCOFFCsectAuxEnt64>(AuxAddr)); 1186 } 1187 } 1188 1189 return createError( 1190 "a csect auxiliary entry has not been found for symbol \"" + *NameOrErr + 1191 "\" with index " + Twine(SymbolIdx)); 1192 } 1193 1194 Expected<StringRef> XCOFFSymbolRef::getName() const { 1195 // A storage class value with the high-order bit on indicates that the name is 1196 // a symbolic debugger stabstring. 1197 if (getStorageClass() & 0x80) 1198 return StringRef("Unimplemented Debug Name"); 1199 1200 if (Entry32) { 1201 if (Entry32->NameInStrTbl.Magic != XCOFFSymbolRef::NAME_IN_STR_TBL_MAGIC) 1202 return generateXCOFFFixedNameStringRef(Entry32->SymbolName); 1203 1204 return OwningObjectPtr->getStringTableEntry(Entry32->NameInStrTbl.Offset); 1205 } 1206 1207 return OwningObjectPtr->getStringTableEntry(Entry64->Offset); 1208 } 1209 1210 // Explictly instantiate template classes. 1211 template struct XCOFFSectionHeader<XCOFFSectionHeader32>; 1212 template struct XCOFFSectionHeader<XCOFFSectionHeader64>; 1213 1214 template struct XCOFFRelocation<llvm::support::ubig32_t>; 1215 template struct XCOFFRelocation<llvm::support::ubig64_t>; 1216 1217 template llvm::Expected<llvm::ArrayRef<llvm::object::XCOFFRelocation64>> 1218 llvm::object::XCOFFObjectFile::relocations<llvm::object::XCOFFSectionHeader64, 1219 llvm::object::XCOFFRelocation64>( 1220 llvm::object::XCOFFSectionHeader64 const &) const; 1221 template llvm::Expected<llvm::ArrayRef<llvm::object::XCOFFRelocation32>> 1222 llvm::object::XCOFFObjectFile::relocations<llvm::object::XCOFFSectionHeader32, 1223 llvm::object::XCOFFRelocation32>( 1224 llvm::object::XCOFFSectionHeader32 const &) const; 1225 1226 bool doesXCOFFTracebackTableBegin(ArrayRef<uint8_t> Bytes) { 1227 if (Bytes.size() < 4) 1228 return false; 1229 1230 return support::endian::read32be(Bytes.data()) == 0; 1231 } 1232 1233 #define GETVALUEWITHMASK(X) (Data & (TracebackTable::X)) 1234 #define GETVALUEWITHMASKSHIFT(X, S) \ 1235 ((Data & (TracebackTable::X)) >> (TracebackTable::S)) 1236 1237 Expected<TBVectorExt> TBVectorExt::create(StringRef TBvectorStrRef) { 1238 Error Err = Error::success(); 1239 TBVectorExt TBTVecExt(TBvectorStrRef, Err); 1240 if (Err) 1241 return std::move(Err); 1242 return TBTVecExt; 1243 } 1244 1245 TBVectorExt::TBVectorExt(StringRef TBvectorStrRef, Error &Err) { 1246 const uint8_t *Ptr = reinterpret_cast<const uint8_t *>(TBvectorStrRef.data()); 1247 Data = support::endian::read16be(Ptr); 1248 uint32_t VecParmsTypeValue = support::endian::read32be(Ptr + 2); 1249 unsigned ParmsNum = 1250 GETVALUEWITHMASKSHIFT(NumberOfVectorParmsMask, NumberOfVectorParmsShift); 1251 1252 ErrorAsOutParameter EAO(&Err); 1253 Expected<SmallString<32>> VecParmsTypeOrError = 1254 parseVectorParmsType(VecParmsTypeValue, ParmsNum); 1255 if (!VecParmsTypeOrError) 1256 Err = VecParmsTypeOrError.takeError(); 1257 else 1258 VecParmsInfo = VecParmsTypeOrError.get(); 1259 } 1260 1261 uint8_t TBVectorExt::getNumberOfVRSaved() const { 1262 return GETVALUEWITHMASKSHIFT(NumberOfVRSavedMask, NumberOfVRSavedShift); 1263 } 1264 1265 bool TBVectorExt::isVRSavedOnStack() const { 1266 return GETVALUEWITHMASK(IsVRSavedOnStackMask); 1267 } 1268 1269 bool TBVectorExt::hasVarArgs() const { 1270 return GETVALUEWITHMASK(HasVarArgsMask); 1271 } 1272 1273 uint8_t TBVectorExt::getNumberOfVectorParms() const { 1274 return GETVALUEWITHMASKSHIFT(NumberOfVectorParmsMask, 1275 NumberOfVectorParmsShift); 1276 } 1277 1278 bool TBVectorExt::hasVMXInstruction() const { 1279 return GETVALUEWITHMASK(HasVMXInstructionMask); 1280 } 1281 #undef GETVALUEWITHMASK 1282 #undef GETVALUEWITHMASKSHIFT 1283 1284 Expected<XCOFFTracebackTable> XCOFFTracebackTable::create(const uint8_t *Ptr, 1285 uint64_t &Size) { 1286 Error Err = Error::success(); 1287 XCOFFTracebackTable TBT(Ptr, Size, Err); 1288 if (Err) 1289 return std::move(Err); 1290 return TBT; 1291 } 1292 1293 XCOFFTracebackTable::XCOFFTracebackTable(const uint8_t *Ptr, uint64_t &Size, 1294 Error &Err) 1295 : TBPtr(Ptr) { 1296 ErrorAsOutParameter EAO(&Err); 1297 DataExtractor DE(ArrayRef<uint8_t>(Ptr, Size), /*IsLittleEndian=*/false, 1298 /*AddressSize=*/0); 1299 DataExtractor::Cursor Cur(/*Offset=*/0); 1300 1301 // Skip 8 bytes of mandatory fields. 1302 DE.getU64(Cur); 1303 1304 unsigned FixedParmsNum = getNumberOfFixedParms(); 1305 unsigned FloatingParmsNum = getNumberOfFPParms(); 1306 uint32_t ParamsTypeValue = 0; 1307 1308 // Begin to parse optional fields. 1309 if (Cur && (FixedParmsNum + FloatingParmsNum) > 0) 1310 ParamsTypeValue = DE.getU32(Cur); 1311 1312 if (Cur && hasTraceBackTableOffset()) 1313 TraceBackTableOffset = DE.getU32(Cur); 1314 1315 if (Cur && isInterruptHandler()) 1316 HandlerMask = DE.getU32(Cur); 1317 1318 if (Cur && hasControlledStorage()) { 1319 NumOfCtlAnchors = DE.getU32(Cur); 1320 if (Cur && NumOfCtlAnchors) { 1321 SmallVector<uint32_t, 8> Disp; 1322 Disp.reserve(NumOfCtlAnchors.getValue()); 1323 for (uint32_t I = 0; I < NumOfCtlAnchors && Cur; ++I) 1324 Disp.push_back(DE.getU32(Cur)); 1325 if (Cur) 1326 ControlledStorageInfoDisp = std::move(Disp); 1327 } 1328 } 1329 1330 if (Cur && isFuncNamePresent()) { 1331 uint16_t FunctionNameLen = DE.getU16(Cur); 1332 if (Cur) 1333 FunctionName = DE.getBytes(Cur, FunctionNameLen); 1334 } 1335 1336 if (Cur && isAllocaUsed()) 1337 AllocaRegister = DE.getU8(Cur); 1338 1339 unsigned VectorParmsNum = 0; 1340 if (Cur && hasVectorInfo()) { 1341 StringRef VectorExtRef = DE.getBytes(Cur, 6); 1342 if (Cur) { 1343 Expected<TBVectorExt> TBVecExtOrErr = TBVectorExt::create(VectorExtRef); 1344 if (!TBVecExtOrErr) { 1345 Err = TBVecExtOrErr.takeError(); 1346 return; 1347 } 1348 VecExt = TBVecExtOrErr.get(); 1349 VectorParmsNum = VecExt.getValue().getNumberOfVectorParms(); 1350 } 1351 } 1352 1353 // As long as there is no fixed-point or floating-point parameter, this 1354 // field remains not present even when hasVectorInfo gives true and 1355 // indicates the presence of vector parameters. 1356 if (Cur && (FixedParmsNum + FloatingParmsNum) > 0) { 1357 Expected<SmallString<32>> ParmsTypeOrError = 1358 hasVectorInfo() 1359 ? parseParmsTypeWithVecInfo(ParamsTypeValue, FixedParmsNum, 1360 FloatingParmsNum, VectorParmsNum) 1361 : parseParmsType(ParamsTypeValue, FixedParmsNum, FloatingParmsNum); 1362 1363 if (!ParmsTypeOrError) { 1364 Err = ParmsTypeOrError.takeError(); 1365 return; 1366 } 1367 ParmsType = ParmsTypeOrError.get(); 1368 } 1369 1370 if (Cur && hasExtensionTable()) 1371 ExtensionTable = DE.getU8(Cur); 1372 1373 if (!Cur) 1374 Err = Cur.takeError(); 1375 1376 Size = Cur.tell(); 1377 } 1378 1379 #define GETBITWITHMASK(P, X) \ 1380 (support::endian::read32be(TBPtr + (P)) & (TracebackTable::X)) 1381 #define GETBITWITHMASKSHIFT(P, X, S) \ 1382 ((support::endian::read32be(TBPtr + (P)) & (TracebackTable::X)) >> \ 1383 (TracebackTable::S)) 1384 1385 uint8_t XCOFFTracebackTable::getVersion() const { 1386 return GETBITWITHMASKSHIFT(0, VersionMask, VersionShift); 1387 } 1388 1389 uint8_t XCOFFTracebackTable::getLanguageID() const { 1390 return GETBITWITHMASKSHIFT(0, LanguageIdMask, LanguageIdShift); 1391 } 1392 1393 bool XCOFFTracebackTable::isGlobalLinkage() const { 1394 return GETBITWITHMASK(0, IsGlobaLinkageMask); 1395 } 1396 1397 bool XCOFFTracebackTable::isOutOfLineEpilogOrPrologue() const { 1398 return GETBITWITHMASK(0, IsOutOfLineEpilogOrPrologueMask); 1399 } 1400 1401 bool XCOFFTracebackTable::hasTraceBackTableOffset() const { 1402 return GETBITWITHMASK(0, HasTraceBackTableOffsetMask); 1403 } 1404 1405 bool XCOFFTracebackTable::isInternalProcedure() const { 1406 return GETBITWITHMASK(0, IsInternalProcedureMask); 1407 } 1408 1409 bool XCOFFTracebackTable::hasControlledStorage() const { 1410 return GETBITWITHMASK(0, HasControlledStorageMask); 1411 } 1412 1413 bool XCOFFTracebackTable::isTOCless() const { 1414 return GETBITWITHMASK(0, IsTOClessMask); 1415 } 1416 1417 bool XCOFFTracebackTable::isFloatingPointPresent() const { 1418 return GETBITWITHMASK(0, IsFloatingPointPresentMask); 1419 } 1420 1421 bool XCOFFTracebackTable::isFloatingPointOperationLogOrAbortEnabled() const { 1422 return GETBITWITHMASK(0, IsFloatingPointOperationLogOrAbortEnabledMask); 1423 } 1424 1425 bool XCOFFTracebackTable::isInterruptHandler() const { 1426 return GETBITWITHMASK(0, IsInterruptHandlerMask); 1427 } 1428 1429 bool XCOFFTracebackTable::isFuncNamePresent() const { 1430 return GETBITWITHMASK(0, IsFunctionNamePresentMask); 1431 } 1432 1433 bool XCOFFTracebackTable::isAllocaUsed() const { 1434 return GETBITWITHMASK(0, IsAllocaUsedMask); 1435 } 1436 1437 uint8_t XCOFFTracebackTable::getOnConditionDirective() const { 1438 return GETBITWITHMASKSHIFT(0, OnConditionDirectiveMask, 1439 OnConditionDirectiveShift); 1440 } 1441 1442 bool XCOFFTracebackTable::isCRSaved() const { 1443 return GETBITWITHMASK(0, IsCRSavedMask); 1444 } 1445 1446 bool XCOFFTracebackTable::isLRSaved() const { 1447 return GETBITWITHMASK(0, IsLRSavedMask); 1448 } 1449 1450 bool XCOFFTracebackTable::isBackChainStored() const { 1451 return GETBITWITHMASK(4, IsBackChainStoredMask); 1452 } 1453 1454 bool XCOFFTracebackTable::isFixup() const { 1455 return GETBITWITHMASK(4, IsFixupMask); 1456 } 1457 1458 uint8_t XCOFFTracebackTable::getNumOfFPRsSaved() const { 1459 return GETBITWITHMASKSHIFT(4, FPRSavedMask, FPRSavedShift); 1460 } 1461 1462 bool XCOFFTracebackTable::hasExtensionTable() const { 1463 return GETBITWITHMASK(4, HasExtensionTableMask); 1464 } 1465 1466 bool XCOFFTracebackTable::hasVectorInfo() const { 1467 return GETBITWITHMASK(4, HasVectorInfoMask); 1468 } 1469 1470 uint8_t XCOFFTracebackTable::getNumOfGPRsSaved() const { 1471 return GETBITWITHMASKSHIFT(4, GPRSavedMask, GPRSavedShift); 1472 } 1473 1474 uint8_t XCOFFTracebackTable::getNumberOfFixedParms() const { 1475 return GETBITWITHMASKSHIFT(4, NumberOfFixedParmsMask, 1476 NumberOfFixedParmsShift); 1477 } 1478 1479 uint8_t XCOFFTracebackTable::getNumberOfFPParms() const { 1480 return GETBITWITHMASKSHIFT(4, NumberOfFloatingPointParmsMask, 1481 NumberOfFloatingPointParmsShift); 1482 } 1483 1484 bool XCOFFTracebackTable::hasParmsOnStack() const { 1485 return GETBITWITHMASK(4, HasParmsOnStackMask); 1486 } 1487 1488 #undef GETBITWITHMASK 1489 #undef GETBITWITHMASKSHIFT 1490 } // namespace object 1491 } // namespace llvm 1492