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