1 //===--- XCOFFObjectFile.cpp - XCOFF object file implementation -----------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines the XCOFFObjectFile class.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/Object/XCOFFObjectFile.h"
14 #include "llvm/ADT/StringSwitch.h"
15 #include "llvm/Support/DataExtractor.h"
16 #include "llvm/TargetParser/SubtargetFeature.h"
22 using namespace XCOFF
;
26 static const uint8_t FunctionSym
= 0x20;
27 static const uint16_t NoRelMask
= 0x0001;
28 static const size_t SymbolAuxTypeOffset
= 17;
30 // Checks that [Ptr, Ptr + Size) bytes fall inside the memory buffer
31 // 'M'. Returns a pointer to the underlying object on success.
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
))
38 return reinterpret_cast<const T
*>(Addr
);
41 static uintptr_t getWithOffset(uintptr_t Base
, ptrdiff_t Offset
) {
42 return reinterpret_cast<uintptr_t>(reinterpret_cast<const char *>(Base
) +
46 template <typename T
> static const T
*viewAs(uintptr_t in
) {
47 return reinterpret_cast<const T
*>(in
);
50 static StringRef
generateXCOFFFixedNameStringRef(const char *Name
) {
52 static_cast<const char *>(memchr(Name
, '\0', XCOFF::NameSize
));
53 return NulCharPtr
? StringRef(Name
, NulCharPtr
- Name
)
54 : StringRef(Name
, XCOFF::NameSize
);
57 template <typename T
> StringRef XCOFFSectionHeader
<T
>::getName() const {
58 const T
&DerivedXCOFFSectionHeader
= static_cast<const T
&>(*this);
59 return generateXCOFFFixedNameStringRef(DerivedXCOFFSectionHeader
.Name
);
62 template <typename T
> uint16_t XCOFFSectionHeader
<T
>::getSectionType() const {
63 const T
&DerivedXCOFFSectionHeader
= static_cast<const T
&>(*this);
64 return DerivedXCOFFSectionHeader
.Flags
& SectionFlagsTypeMask
;
68 bool XCOFFSectionHeader
<T
>::isReservedSectionType() const {
69 return getSectionType() & SectionFlagsReservedMask
;
72 template <typename AddressType
>
73 bool XCOFFRelocation
<AddressType
>::isRelocationSigned() const {
74 return Info
& XR_SIGN_INDICATOR_MASK
;
77 template <typename AddressType
>
78 bool XCOFFRelocation
<AddressType
>::isFixupIndicated() const {
79 return Info
& XR_FIXUP_INDICATOR_MASK
;
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;
89 template struct ExceptionSectionEntry
<support::ubig32_t
>;
90 template struct ExceptionSectionEntry
<support::ubig64_t
>;
93 Expected
<StringRef
> getLoaderSecSymNameInStrTbl(const T
*LoaderSecHeader
,
95 if (LoaderSecHeader
->LengthOfStrTbl
> Offset
)
96 return (reinterpret_cast<const char *>(LoaderSecHeader
) +
97 LoaderSecHeader
->OffsetToStrTbl
+ Offset
);
99 return createError("entry with offset 0x" + Twine::utohexstr(Offset
) +
100 " in the loader section's string table with size 0x" +
101 Twine::utohexstr(LoaderSecHeader
->LengthOfStrTbl
) +
105 Expected
<StringRef
> LoaderSectionSymbolEntry32::getSymbolName(
106 const LoaderSectionHeader32
*LoaderSecHeader32
) const {
107 const NameOffsetInStrTbl
*NameInStrTbl
=
108 reinterpret_cast<const NameOffsetInStrTbl
*>(SymbolName
);
109 if (NameInStrTbl
->IsNameInStrTbl
!= XCOFFSymbolRef::NAME_IN_STR_TBL_MAGIC
)
110 return generateXCOFFFixedNameStringRef(SymbolName
);
112 return getLoaderSecSymNameInStrTbl(LoaderSecHeader32
, NameInStrTbl
->Offset
);
115 Expected
<StringRef
> LoaderSectionSymbolEntry64::getSymbolName(
116 const LoaderSectionHeader64
*LoaderSecHeader64
) const {
117 return getLoaderSecSymNameInStrTbl(LoaderSecHeader64
, Offset
);
121 XCOFFObjectFile::getAdvancedSymbolEntryAddress(uintptr_t CurrentAddress
,
123 return getWithOffset(CurrentAddress
, Distance
* XCOFF::SymbolTableEntrySize
);
126 const XCOFF::SymbolAuxType
*
127 XCOFFObjectFile::getSymbolAuxType(uintptr_t AuxEntryAddress
) const {
128 assert(is64Bit() && "64-bit interface called on a 32-bit object file.");
129 return viewAs
<XCOFF::SymbolAuxType
>(
130 getWithOffset(AuxEntryAddress
, SymbolAuxTypeOffset
));
133 void XCOFFObjectFile::checkSectionAddress(uintptr_t Addr
,
134 uintptr_t TableAddress
) const {
135 if (Addr
< TableAddress
)
136 report_fatal_error("Section header outside of section header table.");
138 uintptr_t Offset
= Addr
- TableAddress
;
139 if (Offset
>= getSectionHeaderSize() * getNumberOfSections())
140 report_fatal_error("Section header outside of section header table.");
142 if (Offset
% getSectionHeaderSize() != 0)
144 "Section header pointer does not point to a valid section header.");
147 const XCOFFSectionHeader32
*
148 XCOFFObjectFile::toSection32(DataRefImpl Ref
) const {
149 assert(!is64Bit() && "32-bit interface called on 64-bit object file.");
151 checkSectionAddress(Ref
.p
, getSectionHeaderTableAddress());
153 return viewAs
<XCOFFSectionHeader32
>(Ref
.p
);
156 const XCOFFSectionHeader64
*
157 XCOFFObjectFile::toSection64(DataRefImpl Ref
) const {
158 assert(is64Bit() && "64-bit interface called on a 32-bit object file.");
160 checkSectionAddress(Ref
.p
, getSectionHeaderTableAddress());
162 return viewAs
<XCOFFSectionHeader64
>(Ref
.p
);
165 XCOFFSymbolRef
XCOFFObjectFile::toSymbolRef(DataRefImpl Ref
) const {
166 assert(Ref
.p
!= 0 && "Symbol table pointer can not be nullptr!");
168 checkSymbolEntryPointer(Ref
.p
);
170 return XCOFFSymbolRef(Ref
, this);
173 const XCOFFFileHeader32
*XCOFFObjectFile::fileHeader32() const {
174 assert(!is64Bit() && "32-bit interface called on 64-bit object file.");
175 return static_cast<const XCOFFFileHeader32
*>(FileHeader
);
178 const XCOFFFileHeader64
*XCOFFObjectFile::fileHeader64() const {
179 assert(is64Bit() && "64-bit interface called on a 32-bit object file.");
180 return static_cast<const XCOFFFileHeader64
*>(FileHeader
);
183 const XCOFFAuxiliaryHeader32
*XCOFFObjectFile::auxiliaryHeader32() const {
184 assert(!is64Bit() && "32-bit interface called on 64-bit object file.");
185 return static_cast<const XCOFFAuxiliaryHeader32
*>(AuxiliaryHeader
);
188 const XCOFFAuxiliaryHeader64
*XCOFFObjectFile::auxiliaryHeader64() const {
189 assert(is64Bit() && "64-bit interface called on a 32-bit object file.");
190 return static_cast<const XCOFFAuxiliaryHeader64
*>(AuxiliaryHeader
);
193 template <typename T
> const T
*XCOFFObjectFile::sectionHeaderTable() const {
194 return static_cast<const T
*>(SectionHeaderTable
);
197 const XCOFFSectionHeader32
*
198 XCOFFObjectFile::sectionHeaderTable32() const {
199 assert(!is64Bit() && "32-bit interface called on 64-bit object file.");
200 return static_cast<const XCOFFSectionHeader32
*>(SectionHeaderTable
);
203 const XCOFFSectionHeader64
*
204 XCOFFObjectFile::sectionHeaderTable64() const {
205 assert(is64Bit() && "64-bit interface called on a 32-bit object file.");
206 return static_cast<const XCOFFSectionHeader64
*>(SectionHeaderTable
);
209 void XCOFFObjectFile::moveSymbolNext(DataRefImpl
&Symb
) const {
210 uintptr_t NextSymbolAddr
= getAdvancedSymbolEntryAddress(
211 Symb
.p
, toSymbolRef(Symb
).getNumberOfAuxEntries() + 1);
213 // This function is used by basic_symbol_iterator, which allows to
214 // point to the end-of-symbol-table address.
215 if (NextSymbolAddr
!= getEndOfSymbolTableAddress())
216 checkSymbolEntryPointer(NextSymbolAddr
);
218 Symb
.p
= NextSymbolAddr
;
222 XCOFFObjectFile::getStringTableEntry(uint32_t Offset
) const {
223 // The byte offset is relative to the start of the string table.
224 // A byte offset value of 0 is a null or zero-length symbol
225 // name. A byte offset in the range 1 to 3 (inclusive) points into the length
226 // field; as a soft-error recovery mechanism, we treat such cases as having an
229 return StringRef(nullptr, 0);
231 if (StringTable
.Data
!= nullptr && StringTable
.Size
> Offset
)
232 return (StringTable
.Data
+ Offset
);
234 return createError("entry with offset 0x" + Twine::utohexstr(Offset
) +
235 " in a string table with size 0x" +
236 Twine::utohexstr(StringTable
.Size
) + " is invalid");
239 StringRef
XCOFFObjectFile::getStringTable() const {
240 // If the size is less than or equal to 4, then the string table contains no
242 return StringRef(StringTable
.Data
,
243 StringTable
.Size
<= 4 ? 0 : StringTable
.Size
);
247 XCOFFObjectFile::getCFileName(const XCOFFFileAuxEnt
*CFileEntPtr
) const {
248 if (CFileEntPtr
->NameInStrTbl
.Magic
!= XCOFFSymbolRef::NAME_IN_STR_TBL_MAGIC
)
249 return generateXCOFFFixedNameStringRef(CFileEntPtr
->Name
);
250 return getStringTableEntry(CFileEntPtr
->NameInStrTbl
.Offset
);
253 Expected
<StringRef
> XCOFFObjectFile::getSymbolName(DataRefImpl Symb
) const {
254 return toSymbolRef(Symb
).getName();
257 Expected
<uint64_t> XCOFFObjectFile::getSymbolAddress(DataRefImpl Symb
) const {
258 return toSymbolRef(Symb
).getValue();
261 uint64_t XCOFFObjectFile::getSymbolValueImpl(DataRefImpl Symb
) const {
262 return toSymbolRef(Symb
).getValue();
265 uint32_t XCOFFObjectFile::getSymbolAlignment(DataRefImpl Symb
) const {
267 XCOFFSymbolRef XCOFFSym
= toSymbolRef(Symb
);
268 if (XCOFFSym
.isCsectSymbol()) {
269 Expected
<XCOFFCsectAuxRef
> CsectAuxRefOrError
=
270 XCOFFSym
.getXCOFFCsectAuxRef();
271 if (!CsectAuxRefOrError
)
272 // TODO: report the error up the stack.
273 consumeError(CsectAuxRefOrError
.takeError());
275 Result
= 1ULL << CsectAuxRefOrError
.get().getAlignmentLog2();
280 uint64_t XCOFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb
) const {
282 XCOFFSymbolRef XCOFFSym
= toSymbolRef(Symb
);
283 if (XCOFFSym
.isCsectSymbol()) {
284 Expected
<XCOFFCsectAuxRef
> CsectAuxRefOrError
=
285 XCOFFSym
.getXCOFFCsectAuxRef();
286 if (!CsectAuxRefOrError
)
287 // TODO: report the error up the stack.
288 consumeError(CsectAuxRefOrError
.takeError());
290 XCOFFCsectAuxRef CsectAuxRef
= CsectAuxRefOrError
.get();
291 assert(CsectAuxRef
.getSymbolType() == XCOFF::XTY_CM
);
292 Result
= CsectAuxRef
.getSectionOrLength();
298 Expected
<SymbolRef::Type
>
299 XCOFFObjectFile::getSymbolType(DataRefImpl Symb
) const {
300 XCOFFSymbolRef XCOFFSym
= toSymbolRef(Symb
);
302 if (XCOFFSym
.isFunction())
303 return SymbolRef::ST_Function
;
305 if (XCOFF::C_FILE
== XCOFFSym
.getStorageClass())
306 return SymbolRef::ST_File
;
308 int16_t SecNum
= XCOFFSym
.getSectionNumber();
310 return SymbolRef::ST_Other
;
312 Expected
<DataRefImpl
> SecDRIOrErr
=
313 getSectionByNum(XCOFFSym
.getSectionNumber());
316 return SecDRIOrErr
.takeError();
318 DataRefImpl SecDRI
= SecDRIOrErr
.get();
320 Expected
<StringRef
> SymNameOrError
= XCOFFSym
.getName();
321 if (SymNameOrError
) {
322 // The "TOC" symbol is treated as SymbolRef::ST_Other.
323 if (SymNameOrError
.get() == "TOC")
324 return SymbolRef::ST_Other
;
326 // The symbol for a section name is treated as SymbolRef::ST_Other.
329 SecName
= XCOFFObjectFile::toSection64(SecDRIOrErr
.get())->getName();
331 SecName
= XCOFFObjectFile::toSection32(SecDRIOrErr
.get())->getName();
333 if (SecName
== SymNameOrError
.get())
334 return SymbolRef::ST_Other
;
336 return SymNameOrError
.takeError();
338 if (isSectionData(SecDRI
) || isSectionBSS(SecDRI
))
339 return SymbolRef::ST_Data
;
341 if (isDebugSection(SecDRI
))
342 return SymbolRef::ST_Debug
;
344 return SymbolRef::ST_Other
;
347 Expected
<section_iterator
>
348 XCOFFObjectFile::getSymbolSection(DataRefImpl Symb
) const {
349 const int16_t SectNum
= toSymbolRef(Symb
).getSectionNumber();
351 if (isReservedSectionNumber(SectNum
))
352 return section_end();
354 Expected
<DataRefImpl
> ExpSec
= getSectionByNum(SectNum
);
356 return ExpSec
.takeError();
358 return section_iterator(SectionRef(ExpSec
.get(), this));
361 void XCOFFObjectFile::moveSectionNext(DataRefImpl
&Sec
) const {
362 const char *Ptr
= reinterpret_cast<const char *>(Sec
.p
);
363 Sec
.p
= reinterpret_cast<uintptr_t>(Ptr
+ getSectionHeaderSize());
366 Expected
<StringRef
> XCOFFObjectFile::getSectionName(DataRefImpl Sec
) const {
367 return generateXCOFFFixedNameStringRef(getSectionNameInternal(Sec
));
370 uint64_t XCOFFObjectFile::getSectionAddress(DataRefImpl Sec
) const {
371 // Avoid ternary due to failure to convert the ubig32_t value to a unit64_t
374 return toSection64(Sec
)->VirtualAddress
;
376 return toSection32(Sec
)->VirtualAddress
;
379 uint64_t XCOFFObjectFile::getSectionIndex(DataRefImpl Sec
) const {
380 // Section numbers in XCOFF are numbered beginning at 1. A section number of
381 // zero is used to indicate that a symbol is being imported or is undefined.
383 return toSection64(Sec
) - sectionHeaderTable64() + 1;
385 return toSection32(Sec
) - sectionHeaderTable32() + 1;
388 uint64_t XCOFFObjectFile::getSectionSize(DataRefImpl Sec
) const {
389 // Avoid ternary due to failure to convert the ubig32_t value to a unit64_t
392 return toSection64(Sec
)->SectionSize
;
394 return toSection32(Sec
)->SectionSize
;
397 Expected
<ArrayRef
<uint8_t>>
398 XCOFFObjectFile::getSectionContents(DataRefImpl Sec
) const {
399 if (isSectionVirtual(Sec
))
400 return ArrayRef
<uint8_t>();
402 uint64_t OffsetToRaw
;
404 OffsetToRaw
= toSection64(Sec
)->FileOffsetToRawData
;
406 OffsetToRaw
= toSection32(Sec
)->FileOffsetToRawData
;
408 const uint8_t * ContentStart
= base() + OffsetToRaw
;
409 uint64_t SectionSize
= getSectionSize(Sec
);
410 if (Error E
= Binary::checkOffset(
411 Data
, reinterpret_cast<uintptr_t>(ContentStart
), SectionSize
))
413 toString(std::move(E
)) + ": section data with offset 0x" +
414 Twine::utohexstr(OffsetToRaw
) + " and size 0x" +
415 Twine::utohexstr(SectionSize
) + " goes past the end of the file");
417 return ArrayRef(ContentStart
, SectionSize
);
420 uint64_t XCOFFObjectFile::getSectionAlignment(DataRefImpl Sec
) const {
422 llvm_unreachable("Not yet implemented!");
426 uint64_t XCOFFObjectFile::getSectionFileOffsetToRawData(DataRefImpl Sec
) const {
428 return toSection64(Sec
)->FileOffsetToRawData
;
430 return toSection32(Sec
)->FileOffsetToRawData
;
433 Expected
<uintptr_t> XCOFFObjectFile::getSectionFileOffsetToRawData(
434 XCOFF::SectionTypeFlags SectType
) const {
435 DataRefImpl DRI
= getSectionByType(SectType
);
437 if (DRI
.p
== 0) // No section is not an error.
440 uint64_t SectionOffset
= getSectionFileOffsetToRawData(DRI
);
441 uint64_t SizeOfSection
= getSectionSize(DRI
);
443 uintptr_t SectionStart
= reinterpret_cast<uintptr_t>(base() + SectionOffset
);
444 if (Error E
= Binary::checkOffset(Data
, SectionStart
, SizeOfSection
)) {
445 SmallString
<32> UnknownType
;
446 Twine(("<Unknown:") + Twine::utohexstr(SectType
) + ">")
447 .toVector(UnknownType
);
448 const char *SectionName
= UnknownType
.c_str();
451 #define ECASE(Value, String) \
453 SectionName = String; \
456 ECASE(STYP_PAD
, "pad");
457 ECASE(STYP_DWARF
, "dwarf");
458 ECASE(STYP_TEXT
, "text");
459 ECASE(STYP_DATA
, "data");
460 ECASE(STYP_BSS
, "bss");
461 ECASE(STYP_EXCEPT
, "expect");
462 ECASE(STYP_INFO
, "info");
463 ECASE(STYP_TDATA
, "tdata");
464 ECASE(STYP_TBSS
, "tbss");
465 ECASE(STYP_LOADER
, "loader");
466 ECASE(STYP_DEBUG
, "debug");
467 ECASE(STYP_TYPCHK
, "typchk");
468 ECASE(STYP_OVRFLO
, "ovrflo");
471 return createError(toString(std::move(E
)) + ": " + SectionName
+
472 " section with offset 0x" +
473 Twine::utohexstr(SectionOffset
) + " and size 0x" +
474 Twine::utohexstr(SizeOfSection
) +
475 " goes past the end of the file");
480 bool XCOFFObjectFile::isSectionCompressed(DataRefImpl Sec
) const {
484 bool XCOFFObjectFile::isSectionText(DataRefImpl Sec
) const {
485 return getSectionFlags(Sec
) & XCOFF::STYP_TEXT
;
488 bool XCOFFObjectFile::isSectionData(DataRefImpl Sec
) const {
489 uint32_t Flags
= getSectionFlags(Sec
);
490 return Flags
& (XCOFF::STYP_DATA
| XCOFF::STYP_TDATA
);
493 bool XCOFFObjectFile::isSectionBSS(DataRefImpl Sec
) const {
494 uint32_t Flags
= getSectionFlags(Sec
);
495 return Flags
& (XCOFF::STYP_BSS
| XCOFF::STYP_TBSS
);
498 bool XCOFFObjectFile::isDebugSection(DataRefImpl Sec
) const {
499 uint32_t Flags
= getSectionFlags(Sec
);
500 return Flags
& (XCOFF::STYP_DEBUG
| XCOFF::STYP_DWARF
);
503 bool XCOFFObjectFile::isSectionVirtual(DataRefImpl Sec
) const {
504 return is64Bit() ? toSection64(Sec
)->FileOffsetToRawData
== 0
505 : toSection32(Sec
)->FileOffsetToRawData
== 0;
508 relocation_iterator
XCOFFObjectFile::section_rel_begin(DataRefImpl Sec
) const {
511 const XCOFFSectionHeader64
*SectionEntPtr
= toSection64(Sec
);
512 auto RelocationsOrErr
=
513 relocations
<XCOFFSectionHeader64
, XCOFFRelocation64
>(*SectionEntPtr
);
514 if (Error E
= RelocationsOrErr
.takeError()) {
515 // TODO: report the error up the stack.
516 consumeError(std::move(E
));
517 return relocation_iterator(RelocationRef());
519 Ret
.p
= reinterpret_cast<uintptr_t>(&*RelocationsOrErr
.get().begin());
521 const XCOFFSectionHeader32
*SectionEntPtr
= toSection32(Sec
);
522 auto RelocationsOrErr
=
523 relocations
<XCOFFSectionHeader32
, XCOFFRelocation32
>(*SectionEntPtr
);
524 if (Error E
= RelocationsOrErr
.takeError()) {
525 // TODO: report the error up the stack.
526 consumeError(std::move(E
));
527 return relocation_iterator(RelocationRef());
529 Ret
.p
= reinterpret_cast<uintptr_t>(&*RelocationsOrErr
.get().begin());
531 return relocation_iterator(RelocationRef(Ret
, this));
534 relocation_iterator
XCOFFObjectFile::section_rel_end(DataRefImpl Sec
) const {
537 const XCOFFSectionHeader64
*SectionEntPtr
= toSection64(Sec
);
538 auto RelocationsOrErr
=
539 relocations
<XCOFFSectionHeader64
, XCOFFRelocation64
>(*SectionEntPtr
);
540 if (Error E
= RelocationsOrErr
.takeError()) {
541 // TODO: report the error up the stack.
542 consumeError(std::move(E
));
543 return relocation_iterator(RelocationRef());
545 Ret
.p
= reinterpret_cast<uintptr_t>(&*RelocationsOrErr
.get().end());
547 const XCOFFSectionHeader32
*SectionEntPtr
= toSection32(Sec
);
548 auto RelocationsOrErr
=
549 relocations
<XCOFFSectionHeader32
, XCOFFRelocation32
>(*SectionEntPtr
);
550 if (Error E
= RelocationsOrErr
.takeError()) {
551 // TODO: report the error up the stack.
552 consumeError(std::move(E
));
553 return relocation_iterator(RelocationRef());
555 Ret
.p
= reinterpret_cast<uintptr_t>(&*RelocationsOrErr
.get().end());
557 return relocation_iterator(RelocationRef(Ret
, this));
560 void XCOFFObjectFile::moveRelocationNext(DataRefImpl
&Rel
) const {
562 Rel
.p
= reinterpret_cast<uintptr_t>(viewAs
<XCOFFRelocation64
>(Rel
.p
) + 1);
564 Rel
.p
= reinterpret_cast<uintptr_t>(viewAs
<XCOFFRelocation32
>(Rel
.p
) + 1);
567 uint64_t XCOFFObjectFile::getRelocationOffset(DataRefImpl Rel
) const {
569 const XCOFFRelocation64
*Reloc
= viewAs
<XCOFFRelocation64
>(Rel
.p
);
570 const XCOFFSectionHeader64
*Sec64
= sectionHeaderTable64();
571 const uint64_t RelocAddress
= Reloc
->VirtualAddress
;
572 const uint16_t NumberOfSections
= getNumberOfSections();
573 for (uint16_t I
= 0; I
< NumberOfSections
; ++I
) {
574 // Find which section this relocation belongs to, and get the
575 // relocation offset relative to the start of the section.
576 if (Sec64
->VirtualAddress
<= RelocAddress
&&
577 RelocAddress
< Sec64
->VirtualAddress
+ Sec64
->SectionSize
) {
578 return RelocAddress
- Sec64
->VirtualAddress
;
583 const XCOFFRelocation32
*Reloc
= viewAs
<XCOFFRelocation32
>(Rel
.p
);
584 const XCOFFSectionHeader32
*Sec32
= sectionHeaderTable32();
585 const uint32_t RelocAddress
= Reloc
->VirtualAddress
;
586 const uint16_t NumberOfSections
= getNumberOfSections();
587 for (uint16_t I
= 0; I
< NumberOfSections
; ++I
) {
588 // Find which section this relocation belongs to, and get the
589 // relocation offset relative to the start of the section.
590 if (Sec32
->VirtualAddress
<= RelocAddress
&&
591 RelocAddress
< Sec32
->VirtualAddress
+ Sec32
->SectionSize
) {
592 return RelocAddress
- Sec32
->VirtualAddress
;
597 return InvalidRelocOffset
;
600 symbol_iterator
XCOFFObjectFile::getRelocationSymbol(DataRefImpl Rel
) const {
603 const XCOFFRelocation64
*Reloc
= viewAs
<XCOFFRelocation64
>(Rel
.p
);
604 Index
= Reloc
->SymbolIndex
;
606 if (Index
>= getNumberOfSymbolTableEntries64())
609 const XCOFFRelocation32
*Reloc
= viewAs
<XCOFFRelocation32
>(Rel
.p
);
610 Index
= Reloc
->SymbolIndex
;
612 if (Index
>= getLogicalNumberOfSymbolTableEntries32())
616 SymDRI
.p
= getSymbolEntryAddressByIndex(Index
);
617 return symbol_iterator(SymbolRef(SymDRI
, this));
620 uint64_t XCOFFObjectFile::getRelocationType(DataRefImpl Rel
) const {
622 return viewAs
<XCOFFRelocation64
>(Rel
.p
)->Type
;
623 return viewAs
<XCOFFRelocation32
>(Rel
.p
)->Type
;
626 void XCOFFObjectFile::getRelocationTypeName(
627 DataRefImpl Rel
, SmallVectorImpl
<char> &Result
) const {
630 const XCOFFRelocation64
*Reloc
= viewAs
<XCOFFRelocation64
>(Rel
.p
);
631 Res
= XCOFF::getRelocationTypeString(Reloc
->Type
);
633 const XCOFFRelocation32
*Reloc
= viewAs
<XCOFFRelocation32
>(Rel
.p
);
634 Res
= XCOFF::getRelocationTypeString(Reloc
->Type
);
636 Result
.append(Res
.begin(), Res
.end());
639 Expected
<uint32_t> XCOFFObjectFile::getSymbolFlags(DataRefImpl Symb
) const {
640 XCOFFSymbolRef XCOFFSym
= toSymbolRef(Symb
);
641 uint32_t Result
= SymbolRef::SF_None
;
643 if (XCOFFSym
.getSectionNumber() == XCOFF::N_ABS
)
644 Result
|= SymbolRef::SF_Absolute
;
646 XCOFF::StorageClass SC
= XCOFFSym
.getStorageClass();
647 if (XCOFF::C_EXT
== SC
|| XCOFF::C_WEAKEXT
== SC
)
648 Result
|= SymbolRef::SF_Global
;
650 if (XCOFF::C_WEAKEXT
== SC
)
651 Result
|= SymbolRef::SF_Weak
;
653 if (XCOFFSym
.isCsectSymbol()) {
654 Expected
<XCOFFCsectAuxRef
> CsectAuxEntOrErr
=
655 XCOFFSym
.getXCOFFCsectAuxRef();
656 if (CsectAuxEntOrErr
) {
657 if (CsectAuxEntOrErr
.get().getSymbolType() == XCOFF::XTY_CM
)
658 Result
|= SymbolRef::SF_Common
;
660 return CsectAuxEntOrErr
.takeError();
663 if (XCOFFSym
.getSectionNumber() == XCOFF::N_UNDEF
)
664 Result
|= SymbolRef::SF_Undefined
;
666 // There is no visibility in old 32 bit XCOFF object file interpret.
667 if (is64Bit() || (auxiliaryHeader32() && (auxiliaryHeader32()->getVersion() ==
668 NEW_XCOFF_INTERPRET
))) {
669 uint16_t SymType
= XCOFFSym
.getSymbolType();
670 if ((SymType
& VISIBILITY_MASK
) == SYM_V_HIDDEN
)
671 Result
|= SymbolRef::SF_Hidden
;
673 if ((SymType
& VISIBILITY_MASK
) == SYM_V_EXPORTED
)
674 Result
|= SymbolRef::SF_Exported
;
679 basic_symbol_iterator
XCOFFObjectFile::symbol_begin() const {
681 SymDRI
.p
= reinterpret_cast<uintptr_t>(SymbolTblPtr
);
682 return basic_symbol_iterator(SymbolRef(SymDRI
, this));
685 basic_symbol_iterator
XCOFFObjectFile::symbol_end() const {
687 const uint32_t NumberOfSymbolTableEntries
= getNumberOfSymbolTableEntries();
688 SymDRI
.p
= getSymbolEntryAddressByIndex(NumberOfSymbolTableEntries
);
689 return basic_symbol_iterator(SymbolRef(SymDRI
, this));
692 XCOFFObjectFile::xcoff_symbol_iterator_range
XCOFFObjectFile::symbols() const {
693 return xcoff_symbol_iterator_range(symbol_begin(), symbol_end());
696 section_iterator
XCOFFObjectFile::section_begin() const {
698 DRI
.p
= getSectionHeaderTableAddress();
699 return section_iterator(SectionRef(DRI
, this));
702 section_iterator
XCOFFObjectFile::section_end() const {
704 DRI
.p
= getWithOffset(getSectionHeaderTableAddress(),
705 getNumberOfSections() * getSectionHeaderSize());
706 return section_iterator(SectionRef(DRI
, this));
709 uint8_t XCOFFObjectFile::getBytesInAddress() const { return is64Bit() ? 8 : 4; }
711 StringRef
XCOFFObjectFile::getFileFormatName() const {
712 return is64Bit() ? "aix5coff64-rs6000" : "aixcoff-rs6000";
715 Triple::ArchType
XCOFFObjectFile::getArch() const {
716 return is64Bit() ? Triple::ppc64
: Triple::ppc
;
719 Expected
<SubtargetFeatures
> XCOFFObjectFile::getFeatures() const {
720 return SubtargetFeatures();
723 bool XCOFFObjectFile::isRelocatableObject() const {
725 return !(fileHeader64()->Flags
& NoRelMask
);
726 return !(fileHeader32()->Flags
& NoRelMask
);
729 Expected
<uint64_t> XCOFFObjectFile::getStartAddress() const {
730 // TODO FIXME Should get from auxiliary_header->o_entry when support for the
731 // auxiliary_header is added.
735 StringRef
XCOFFObjectFile::mapDebugSectionName(StringRef Name
) const {
736 return StringSwitch
<StringRef
>(Name
)
737 .Case("dwinfo", "debug_info")
738 .Case("dwline", "debug_line")
739 .Case("dwpbnms", "debug_pubnames")
740 .Case("dwpbtyp", "debug_pubtypes")
741 .Case("dwarnge", "debug_aranges")
742 .Case("dwabrev", "debug_abbrev")
743 .Case("dwstr", "debug_str")
744 .Case("dwrnges", "debug_ranges")
745 .Case("dwloc", "debug_loc")
746 .Case("dwframe", "debug_frame")
747 .Case("dwmac", "debug_macinfo")
751 size_t XCOFFObjectFile::getFileHeaderSize() const {
752 return is64Bit() ? sizeof(XCOFFFileHeader64
) : sizeof(XCOFFFileHeader32
);
755 size_t XCOFFObjectFile::getSectionHeaderSize() const {
756 return is64Bit() ? sizeof(XCOFFSectionHeader64
) :
757 sizeof(XCOFFSectionHeader32
);
760 bool XCOFFObjectFile::is64Bit() const {
761 return Binary::ID_XCOFF64
== getType();
764 Expected
<StringRef
> XCOFFObjectFile::getRawData(const char *Start
,
766 StringRef Name
) const {
767 uintptr_t StartPtr
= reinterpret_cast<uintptr_t>(Start
);
768 // TODO: this path is untested.
769 if (Error E
= Binary::checkOffset(Data
, StartPtr
, Size
))
770 return createError(toString(std::move(E
)) + ": " + Name
.data() +
771 " data with offset 0x" + Twine::utohexstr(StartPtr
) +
772 " and size 0x" + Twine::utohexstr(Size
) +
773 " goes past the end of the file");
774 return StringRef(Start
, Size
);
777 uint16_t XCOFFObjectFile::getMagic() const {
778 return is64Bit() ? fileHeader64()->Magic
: fileHeader32()->Magic
;
781 Expected
<DataRefImpl
> XCOFFObjectFile::getSectionByNum(int16_t Num
) const {
782 if (Num
<= 0 || Num
> getNumberOfSections())
783 return createStringError(object_error::invalid_section_index
,
784 "the section index (" + Twine(Num
) +
788 DRI
.p
= getWithOffset(getSectionHeaderTableAddress(),
789 getSectionHeaderSize() * (Num
- 1));
794 XCOFFObjectFile::getSectionByType(XCOFF::SectionTypeFlags SectType
) const {
796 auto GetSectionAddr
= [&](const auto &Sections
) -> uintptr_t {
797 for (const auto &Sec
: Sections
)
798 if (Sec
.getSectionType() == SectType
)
799 return reinterpret_cast<uintptr_t>(&Sec
);
803 DRI
.p
= GetSectionAddr(sections64());
805 DRI
.p
= GetSectionAddr(sections32());
810 XCOFFObjectFile::getSymbolSectionName(XCOFFSymbolRef SymEntPtr
) const {
811 const int16_t SectionNum
= SymEntPtr
.getSectionNumber();
813 switch (SectionNum
) {
821 Expected
<DataRefImpl
> SecRef
= getSectionByNum(SectionNum
);
823 return generateXCOFFFixedNameStringRef(
824 getSectionNameInternal(SecRef
.get()));
825 return SecRef
.takeError();
829 unsigned XCOFFObjectFile::getSymbolSectionID(SymbolRef Sym
) const {
830 XCOFFSymbolRef
XCOFFSymRef(Sym
.getRawDataRefImpl(), this);
831 return XCOFFSymRef
.getSectionNumber();
834 bool XCOFFObjectFile::isReservedSectionNumber(int16_t SectionNumber
) {
835 return (SectionNumber
<= 0 && SectionNumber
>= -2);
838 uint16_t XCOFFObjectFile::getNumberOfSections() const {
839 return is64Bit() ? fileHeader64()->NumberOfSections
840 : fileHeader32()->NumberOfSections
;
843 int32_t XCOFFObjectFile::getTimeStamp() const {
844 return is64Bit() ? fileHeader64()->TimeStamp
: fileHeader32()->TimeStamp
;
847 uint16_t XCOFFObjectFile::getOptionalHeaderSize() const {
848 return is64Bit() ? fileHeader64()->AuxHeaderSize
849 : fileHeader32()->AuxHeaderSize
;
852 uint32_t XCOFFObjectFile::getSymbolTableOffset32() const {
853 return fileHeader32()->SymbolTableOffset
;
856 int32_t XCOFFObjectFile::getRawNumberOfSymbolTableEntries32() const {
857 // As far as symbol table size is concerned, if this field is negative it is
858 // to be treated as a 0. However since this field is also used for printing we
859 // don't want to truncate any negative values.
860 return fileHeader32()->NumberOfSymTableEntries
;
863 uint32_t XCOFFObjectFile::getLogicalNumberOfSymbolTableEntries32() const {
864 return (fileHeader32()->NumberOfSymTableEntries
>= 0
865 ? fileHeader32()->NumberOfSymTableEntries
869 uint64_t XCOFFObjectFile::getSymbolTableOffset64() const {
870 return fileHeader64()->SymbolTableOffset
;
873 uint32_t XCOFFObjectFile::getNumberOfSymbolTableEntries64() const {
874 return fileHeader64()->NumberOfSymTableEntries
;
877 uint32_t XCOFFObjectFile::getNumberOfSymbolTableEntries() const {
878 return is64Bit() ? getNumberOfSymbolTableEntries64()
879 : getLogicalNumberOfSymbolTableEntries32();
882 uintptr_t XCOFFObjectFile::getEndOfSymbolTableAddress() const {
883 const uint32_t NumberOfSymTableEntries
= getNumberOfSymbolTableEntries();
884 return getWithOffset(reinterpret_cast<uintptr_t>(SymbolTblPtr
),
885 XCOFF::SymbolTableEntrySize
* NumberOfSymTableEntries
);
888 void XCOFFObjectFile::checkSymbolEntryPointer(uintptr_t SymbolEntPtr
) const {
889 if (SymbolEntPtr
< reinterpret_cast<uintptr_t>(SymbolTblPtr
))
890 report_fatal_error("Symbol table entry is outside of symbol table.");
892 if (SymbolEntPtr
>= getEndOfSymbolTableAddress())
893 report_fatal_error("Symbol table entry is outside of symbol table.");
895 ptrdiff_t Offset
= reinterpret_cast<const char *>(SymbolEntPtr
) -
896 reinterpret_cast<const char *>(SymbolTblPtr
);
898 if (Offset
% XCOFF::SymbolTableEntrySize
!= 0)
900 "Symbol table entry position is not valid inside of symbol table.");
903 uint32_t XCOFFObjectFile::getSymbolIndex(uintptr_t SymbolEntPtr
) const {
904 return (reinterpret_cast<const char *>(SymbolEntPtr
) -
905 reinterpret_cast<const char *>(SymbolTblPtr
)) /
906 XCOFF::SymbolTableEntrySize
;
909 uint64_t XCOFFObjectFile::getSymbolSize(DataRefImpl Symb
) const {
911 XCOFFSymbolRef XCOFFSym
= toSymbolRef(Symb
);
912 if (XCOFFSym
.isCsectSymbol()) {
913 Expected
<XCOFFCsectAuxRef
> CsectAuxRefOrError
=
914 XCOFFSym
.getXCOFFCsectAuxRef();
915 if (!CsectAuxRefOrError
)
916 // TODO: report the error up the stack.
917 consumeError(CsectAuxRefOrError
.takeError());
919 XCOFFCsectAuxRef CsectAuxRef
= CsectAuxRefOrError
.get();
920 uint8_t SymType
= CsectAuxRef
.getSymbolType();
921 if (SymType
== XCOFF::XTY_SD
|| SymType
== XCOFF::XTY_CM
)
922 Result
= CsectAuxRef
.getSectionOrLength();
928 uintptr_t XCOFFObjectFile::getSymbolEntryAddressByIndex(uint32_t Index
) const {
929 return getAdvancedSymbolEntryAddress(
930 reinterpret_cast<uintptr_t>(getPointerToSymbolTable()), Index
);
934 XCOFFObjectFile::getSymbolNameByIndex(uint32_t Index
) const {
935 const uint32_t NumberOfSymTableEntries
= getNumberOfSymbolTableEntries();
937 if (Index
>= NumberOfSymTableEntries
)
938 return createError("symbol index " + Twine(Index
) +
939 " exceeds symbol count " +
940 Twine(NumberOfSymTableEntries
));
943 SymDRI
.p
= getSymbolEntryAddressByIndex(Index
);
944 return getSymbolName(SymDRI
);
947 uint16_t XCOFFObjectFile::getFlags() const {
948 return is64Bit() ? fileHeader64()->Flags
: fileHeader32()->Flags
;
951 const char *XCOFFObjectFile::getSectionNameInternal(DataRefImpl Sec
) const {
952 return is64Bit() ? toSection64(Sec
)->Name
: toSection32(Sec
)->Name
;
955 uintptr_t XCOFFObjectFile::getSectionHeaderTableAddress() const {
956 return reinterpret_cast<uintptr_t>(SectionHeaderTable
);
959 int32_t XCOFFObjectFile::getSectionFlags(DataRefImpl Sec
) const {
960 return is64Bit() ? toSection64(Sec
)->Flags
: toSection32(Sec
)->Flags
;
963 XCOFFObjectFile::XCOFFObjectFile(unsigned int Type
, MemoryBufferRef Object
)
964 : ObjectFile(Type
, Object
) {
965 assert(Type
== Binary::ID_XCOFF32
|| Type
== Binary::ID_XCOFF64
);
968 ArrayRef
<XCOFFSectionHeader64
> XCOFFObjectFile::sections64() const {
969 assert(is64Bit() && "64-bit interface called for non 64-bit file.");
970 const XCOFFSectionHeader64
*TablePtr
= sectionHeaderTable64();
971 return ArrayRef
<XCOFFSectionHeader64
>(TablePtr
,
972 TablePtr
+ getNumberOfSections());
975 ArrayRef
<XCOFFSectionHeader32
> XCOFFObjectFile::sections32() const {
976 assert(!is64Bit() && "32-bit interface called for non 32-bit file.");
977 const XCOFFSectionHeader32
*TablePtr
= sectionHeaderTable32();
978 return ArrayRef
<XCOFFSectionHeader32
>(TablePtr
,
979 TablePtr
+ getNumberOfSections());
982 // In an XCOFF32 file, when the field value is 65535, then an STYP_OVRFLO
983 // section header contains the actual count of relocation entries in the s_paddr
984 // field. STYP_OVRFLO headers contain the section index of their corresponding
985 // sections as their raw "NumberOfRelocations" field value.
986 template <typename T
>
987 Expected
<uint32_t> XCOFFObjectFile::getNumberOfRelocationEntries(
988 const XCOFFSectionHeader
<T
> &Sec
) const {
989 const T
&Section
= static_cast<const T
&>(Sec
);
991 return Section
.NumberOfRelocations
;
993 uint16_t SectionIndex
= &Section
- sectionHeaderTable
<T
>() + 1;
994 if (Section
.NumberOfRelocations
< XCOFF::RelocOverflow
)
995 return Section
.NumberOfRelocations
;
996 for (const auto &Sec
: sections32()) {
997 if (Sec
.Flags
== XCOFF::STYP_OVRFLO
&&
998 Sec
.NumberOfRelocations
== SectionIndex
)
999 return Sec
.PhysicalAddress
;
1001 return errorCodeToError(object_error::parse_failed
);
1004 template <typename Shdr
, typename Reloc
>
1005 Expected
<ArrayRef
<Reloc
>> XCOFFObjectFile::relocations(const Shdr
&Sec
) const {
1006 uintptr_t RelocAddr
= getWithOffset(reinterpret_cast<uintptr_t>(FileHeader
),
1007 Sec
.FileOffsetToRelocationInfo
);
1008 auto NumRelocEntriesOrErr
= getNumberOfRelocationEntries(Sec
);
1009 if (Error E
= NumRelocEntriesOrErr
.takeError())
1010 return std::move(E
);
1012 uint32_t NumRelocEntries
= NumRelocEntriesOrErr
.get();
1013 static_assert((sizeof(Reloc
) == XCOFF::RelocationSerializationSize64
||
1014 sizeof(Reloc
) == XCOFF::RelocationSerializationSize32
),
1015 "Relocation structure is incorrect");
1016 auto RelocationOrErr
=
1017 getObject
<Reloc
>(Data
, reinterpret_cast<void *>(RelocAddr
),
1018 NumRelocEntries
* sizeof(Reloc
));
1019 if (!RelocationOrErr
)
1021 toString(RelocationOrErr
.takeError()) + ": relocations with offset 0x" +
1022 Twine::utohexstr(Sec
.FileOffsetToRelocationInfo
) + " and size 0x" +
1023 Twine::utohexstr(NumRelocEntries
* sizeof(Reloc
)) +
1024 " go past the end of the file");
1026 const Reloc
*StartReloc
= RelocationOrErr
.get();
1028 return ArrayRef
<Reloc
>(StartReloc
, StartReloc
+ NumRelocEntries
);
1031 template <typename ExceptEnt
>
1032 Expected
<ArrayRef
<ExceptEnt
>> XCOFFObjectFile::getExceptionEntries() const {
1033 assert((is64Bit() && sizeof(ExceptEnt
) == sizeof(ExceptionSectionEntry64
)) ||
1034 (!is64Bit() && sizeof(ExceptEnt
) == sizeof(ExceptionSectionEntry32
)));
1036 Expected
<uintptr_t> ExceptionSectOrErr
=
1037 getSectionFileOffsetToRawData(XCOFF::STYP_EXCEPT
);
1038 if (!ExceptionSectOrErr
)
1039 return ExceptionSectOrErr
.takeError();
1041 DataRefImpl DRI
= getSectionByType(XCOFF::STYP_EXCEPT
);
1043 return ArrayRef
<ExceptEnt
>();
1045 ExceptEnt
*ExceptEntStart
=
1046 reinterpret_cast<ExceptEnt
*>(*ExceptionSectOrErr
);
1047 return ArrayRef
<ExceptEnt
>(
1048 ExceptEntStart
, ExceptEntStart
+ getSectionSize(DRI
) / sizeof(ExceptEnt
));
1051 template Expected
<ArrayRef
<ExceptionSectionEntry32
>>
1052 XCOFFObjectFile::getExceptionEntries() const;
1053 template Expected
<ArrayRef
<ExceptionSectionEntry64
>>
1054 XCOFFObjectFile::getExceptionEntries() const;
1056 Expected
<XCOFFStringTable
>
1057 XCOFFObjectFile::parseStringTable(const XCOFFObjectFile
*Obj
, uint64_t Offset
) {
1058 // If there is a string table, then the buffer must contain at least 4 bytes
1059 // for the string table's size. Not having a string table is not an error.
1060 if (Error E
= Binary::checkOffset(
1061 Obj
->Data
, reinterpret_cast<uintptr_t>(Obj
->base() + Offset
), 4)) {
1062 consumeError(std::move(E
));
1063 return XCOFFStringTable
{0, nullptr};
1066 // Read the size out of the buffer.
1067 uint32_t Size
= support::endian::read32be(Obj
->base() + Offset
);
1069 // If the size is less then 4, then the string table is just a size and no
1072 return XCOFFStringTable
{4, nullptr};
1074 auto StringTableOrErr
=
1075 getObject
<char>(Obj
->Data
, Obj
->base() + Offset
, Size
);
1076 if (!StringTableOrErr
)
1077 return createError(toString(StringTableOrErr
.takeError()) +
1078 ": string table with offset 0x" +
1079 Twine::utohexstr(Offset
) + " and size 0x" +
1080 Twine::utohexstr(Size
) +
1081 " goes past the end of the file");
1083 const char *StringTablePtr
= StringTableOrErr
.get();
1084 if (StringTablePtr
[Size
- 1] != '\0')
1085 return errorCodeToError(object_error::string_table_non_null_end
);
1087 return XCOFFStringTable
{Size
, StringTablePtr
};
1090 // This function returns the import file table. Each entry in the import file
1091 // table consists of: "path_name\0base_name\0archive_member_name\0".
1092 Expected
<StringRef
> XCOFFObjectFile::getImportFileTable() const {
1093 Expected
<uintptr_t> LoaderSectionAddrOrError
=
1094 getSectionFileOffsetToRawData(XCOFF::STYP_LOADER
);
1095 if (!LoaderSectionAddrOrError
)
1096 return LoaderSectionAddrOrError
.takeError();
1098 uintptr_t LoaderSectionAddr
= LoaderSectionAddrOrError
.get();
1099 if (!LoaderSectionAddr
)
1102 uint64_t OffsetToImportFileTable
= 0;
1103 uint64_t LengthOfImportFileTable
= 0;
1105 const LoaderSectionHeader64
*LoaderSec64
=
1106 viewAs
<LoaderSectionHeader64
>(LoaderSectionAddr
);
1107 OffsetToImportFileTable
= LoaderSec64
->OffsetToImpid
;
1108 LengthOfImportFileTable
= LoaderSec64
->LengthOfImpidStrTbl
;
1110 const LoaderSectionHeader32
*LoaderSec32
=
1111 viewAs
<LoaderSectionHeader32
>(LoaderSectionAddr
);
1112 OffsetToImportFileTable
= LoaderSec32
->OffsetToImpid
;
1113 LengthOfImportFileTable
= LoaderSec32
->LengthOfImpidStrTbl
;
1116 auto ImportTableOrErr
= getObject
<char>(
1118 reinterpret_cast<void *>(LoaderSectionAddr
+ OffsetToImportFileTable
),
1119 LengthOfImportFileTable
);
1120 if (!ImportTableOrErr
)
1122 toString(ImportTableOrErr
.takeError()) +
1123 ": import file table with offset 0x" +
1124 Twine::utohexstr(LoaderSectionAddr
+ OffsetToImportFileTable
) +
1125 " and size 0x" + Twine::utohexstr(LengthOfImportFileTable
) +
1126 " goes past the end of the file");
1128 const char *ImportTablePtr
= ImportTableOrErr
.get();
1129 if (ImportTablePtr
[LengthOfImportFileTable
- 1] != '\0')
1131 ": import file name table with offset 0x" +
1132 Twine::utohexstr(LoaderSectionAddr
+ OffsetToImportFileTable
) +
1133 " and size 0x" + Twine::utohexstr(LengthOfImportFileTable
) +
1134 " must end with a null terminator");
1136 return StringRef(ImportTablePtr
, LengthOfImportFileTable
);
1139 Expected
<std::unique_ptr
<XCOFFObjectFile
>>
1140 XCOFFObjectFile::create(unsigned Type
, MemoryBufferRef MBR
) {
1141 // Can't use std::make_unique because of the private constructor.
1142 std::unique_ptr
<XCOFFObjectFile
> Obj
;
1143 Obj
.reset(new XCOFFObjectFile(Type
, MBR
));
1145 uint64_t CurOffset
= 0;
1146 const auto *Base
= Obj
->base();
1147 MemoryBufferRef Data
= Obj
->Data
;
1149 // Parse file header.
1150 auto FileHeaderOrErr
=
1151 getObject
<void>(Data
, Base
+ CurOffset
, Obj
->getFileHeaderSize());
1152 if (Error E
= FileHeaderOrErr
.takeError())
1153 return std::move(E
);
1154 Obj
->FileHeader
= FileHeaderOrErr
.get();
1156 CurOffset
+= Obj
->getFileHeaderSize();
1158 if (Obj
->getOptionalHeaderSize()) {
1159 auto AuxiliaryHeaderOrErr
=
1160 getObject
<void>(Data
, Base
+ CurOffset
, Obj
->getOptionalHeaderSize());
1161 if (Error E
= AuxiliaryHeaderOrErr
.takeError())
1162 return std::move(E
);
1163 Obj
->AuxiliaryHeader
= AuxiliaryHeaderOrErr
.get();
1166 CurOffset
+= Obj
->getOptionalHeaderSize();
1168 // Parse the section header table if it is present.
1169 if (Obj
->getNumberOfSections()) {
1170 uint64_t SectionHeadersSize
=
1171 Obj
->getNumberOfSections() * Obj
->getSectionHeaderSize();
1172 auto SecHeadersOrErr
=
1173 getObject
<void>(Data
, Base
+ CurOffset
, SectionHeadersSize
);
1174 if (!SecHeadersOrErr
)
1175 return createError(toString(SecHeadersOrErr
.takeError()) +
1176 ": section headers with offset 0x" +
1177 Twine::utohexstr(CurOffset
) + " and size 0x" +
1178 Twine::utohexstr(SectionHeadersSize
) +
1179 " go past the end of the file");
1181 Obj
->SectionHeaderTable
= SecHeadersOrErr
.get();
1184 const uint32_t NumberOfSymbolTableEntries
=
1185 Obj
->getNumberOfSymbolTableEntries();
1187 // If there is no symbol table we are done parsing the memory buffer.
1188 if (NumberOfSymbolTableEntries
== 0)
1189 return std::move(Obj
);
1191 // Parse symbol table.
1192 CurOffset
= Obj
->is64Bit() ? Obj
->getSymbolTableOffset64()
1193 : Obj
->getSymbolTableOffset32();
1194 const uint64_t SymbolTableSize
=
1195 static_cast<uint64_t>(XCOFF::SymbolTableEntrySize
) *
1196 NumberOfSymbolTableEntries
;
1197 auto SymTableOrErr
=
1198 getObject
<void *>(Data
, Base
+ CurOffset
, SymbolTableSize
);
1201 toString(SymTableOrErr
.takeError()) + ": symbol table with offset 0x" +
1202 Twine::utohexstr(CurOffset
) + " and size 0x" +
1203 Twine::utohexstr(SymbolTableSize
) + " goes past the end of the file");
1205 Obj
->SymbolTblPtr
= SymTableOrErr
.get();
1206 CurOffset
+= SymbolTableSize
;
1208 // Parse String table.
1209 Expected
<XCOFFStringTable
> StringTableOrErr
=
1210 parseStringTable(Obj
.get(), CurOffset
);
1211 if (Error E
= StringTableOrErr
.takeError())
1212 return std::move(E
);
1213 Obj
->StringTable
= StringTableOrErr
.get();
1215 return std::move(Obj
);
1218 Expected
<std::unique_ptr
<ObjectFile
>>
1219 ObjectFile::createXCOFFObjectFile(MemoryBufferRef MemBufRef
,
1220 unsigned FileType
) {
1221 return XCOFFObjectFile::create(FileType
, MemBufRef
);
1224 std::optional
<StringRef
> XCOFFObjectFile::tryGetCPUName() const {
1225 return StringRef("future");
1228 bool XCOFFSymbolRef::isFunction() const {
1229 if (!isCsectSymbol())
1232 if (getSymbolType() & FunctionSym
)
1235 Expected
<XCOFFCsectAuxRef
> ExpCsectAuxEnt
= getXCOFFCsectAuxRef();
1236 if (!ExpCsectAuxEnt
) {
1237 // If we could not get the CSECT auxiliary entry, then treat this symbol as
1238 // if it isn't a function. Consume the error and return `false` to move on.
1239 consumeError(ExpCsectAuxEnt
.takeError());
1243 const XCOFFCsectAuxRef CsectAuxRef
= ExpCsectAuxEnt
.get();
1245 // A function definition should be a label definition.
1246 // FIXME: This is not necessarily the case when -ffunction-sections is
1248 if (!CsectAuxRef
.isLabel())
1251 if (CsectAuxRef
.getStorageMappingClass() != XCOFF::XMC_PR
)
1254 const int16_t SectNum
= getSectionNumber();
1255 Expected
<DataRefImpl
> SI
= getObject()->getSectionByNum(SectNum
);
1257 // If we could not get the section, then this symbol should not be
1258 // a function. So consume the error and return `false` to move on.
1259 consumeError(SI
.takeError());
1263 return (getObject()->getSectionFlags(SI
.get()) & XCOFF::STYP_TEXT
);
1266 bool XCOFFSymbolRef::isCsectSymbol() const {
1267 XCOFF::StorageClass SC
= getStorageClass();
1268 return (SC
== XCOFF::C_EXT
|| SC
== XCOFF::C_WEAKEXT
||
1269 SC
== XCOFF::C_HIDEXT
);
1272 Expected
<XCOFFCsectAuxRef
> XCOFFSymbolRef::getXCOFFCsectAuxRef() const {
1273 assert(isCsectSymbol() &&
1274 "Calling csect symbol interface with a non-csect symbol.");
1276 uint8_t NumberOfAuxEntries
= getNumberOfAuxEntries();
1278 Expected
<StringRef
> NameOrErr
= getName();
1279 if (auto Err
= NameOrErr
.takeError())
1280 return std::move(Err
);
1282 uint32_t SymbolIdx
= getObject()->getSymbolIndex(getEntryAddress());
1283 if (!NumberOfAuxEntries
) {
1284 return createError("csect symbol \"" + *NameOrErr
+ "\" with index " +
1285 Twine(SymbolIdx
) + " contains no auxiliary entry");
1288 if (!getObject()->is64Bit()) {
1289 // In XCOFF32, the csect auxilliary entry is always the last auxiliary
1290 // entry for the symbol.
1291 uintptr_t AuxAddr
= XCOFFObjectFile::getAdvancedSymbolEntryAddress(
1292 getEntryAddress(), NumberOfAuxEntries
);
1293 return XCOFFCsectAuxRef(viewAs
<XCOFFCsectAuxEnt32
>(AuxAddr
));
1296 // XCOFF64 uses SymbolAuxType to identify the auxiliary entry type.
1297 // We need to iterate through all the auxiliary entries to find it.
1298 for (uint8_t Index
= NumberOfAuxEntries
; Index
> 0; --Index
) {
1299 uintptr_t AuxAddr
= XCOFFObjectFile::getAdvancedSymbolEntryAddress(
1300 getEntryAddress(), Index
);
1301 if (*getObject()->getSymbolAuxType(AuxAddr
) ==
1302 XCOFF::SymbolAuxType::AUX_CSECT
) {
1304 getObject()->checkSymbolEntryPointer(AuxAddr
);
1306 return XCOFFCsectAuxRef(viewAs
<XCOFFCsectAuxEnt64
>(AuxAddr
));
1311 "a csect auxiliary entry has not been found for symbol \"" + *NameOrErr
+
1312 "\" with index " + Twine(SymbolIdx
));
1315 Expected
<StringRef
> XCOFFSymbolRef::getName() const {
1316 // A storage class value with the high-order bit on indicates that the name is
1317 // a symbolic debugger stabstring.
1318 if (getStorageClass() & 0x80)
1319 return StringRef("Unimplemented Debug Name");
1321 if (!getObject()->is64Bit()) {
1322 if (getSymbol32()->NameInStrTbl
.Magic
!=
1323 XCOFFSymbolRef::NAME_IN_STR_TBL_MAGIC
)
1324 return generateXCOFFFixedNameStringRef(getSymbol32()->SymbolName
);
1326 return getObject()->getStringTableEntry(getSymbol32()->NameInStrTbl
.Offset
);
1329 return getObject()->getStringTableEntry(getSymbol64()->Offset
);
1332 // Explictly instantiate template classes.
1333 template struct XCOFFSectionHeader
<XCOFFSectionHeader32
>;
1334 template struct XCOFFSectionHeader
<XCOFFSectionHeader64
>;
1336 template struct XCOFFRelocation
<llvm::support::ubig32_t
>;
1337 template struct XCOFFRelocation
<llvm::support::ubig64_t
>;
1339 template llvm::Expected
<llvm::ArrayRef
<llvm::object::XCOFFRelocation64
>>
1340 llvm::object::XCOFFObjectFile::relocations
<llvm::object::XCOFFSectionHeader64
,
1341 llvm::object::XCOFFRelocation64
>(
1342 llvm::object::XCOFFSectionHeader64
const &) const;
1343 template llvm::Expected
<llvm::ArrayRef
<llvm::object::XCOFFRelocation32
>>
1344 llvm::object::XCOFFObjectFile::relocations
<llvm::object::XCOFFSectionHeader32
,
1345 llvm::object::XCOFFRelocation32
>(
1346 llvm::object::XCOFFSectionHeader32
const &) const;
1348 bool doesXCOFFTracebackTableBegin(ArrayRef
<uint8_t> Bytes
) {
1349 if (Bytes
.size() < 4)
1352 return support::endian::read32be(Bytes
.data()) == 0;
1355 #define GETVALUEWITHMASK(X) (Data & (TracebackTable::X))
1356 #define GETVALUEWITHMASKSHIFT(X, S) \
1357 ((Data & (TracebackTable::X)) >> (TracebackTable::S))
1359 Expected
<TBVectorExt
> TBVectorExt::create(StringRef TBvectorStrRef
) {
1360 Error Err
= Error::success();
1361 TBVectorExt
TBTVecExt(TBvectorStrRef
, Err
);
1363 return std::move(Err
);
1367 TBVectorExt::TBVectorExt(StringRef TBvectorStrRef
, Error
&Err
) {
1368 const uint8_t *Ptr
= reinterpret_cast<const uint8_t *>(TBvectorStrRef
.data());
1369 Data
= support::endian::read16be(Ptr
);
1370 uint32_t VecParmsTypeValue
= support::endian::read32be(Ptr
+ 2);
1372 GETVALUEWITHMASKSHIFT(NumberOfVectorParmsMask
, NumberOfVectorParmsShift
);
1374 ErrorAsOutParameter
EAO(&Err
);
1375 Expected
<SmallString
<32>> VecParmsTypeOrError
=
1376 parseVectorParmsType(VecParmsTypeValue
, ParmsNum
);
1377 if (!VecParmsTypeOrError
)
1378 Err
= VecParmsTypeOrError
.takeError();
1380 VecParmsInfo
= VecParmsTypeOrError
.get();
1383 uint8_t TBVectorExt::getNumberOfVRSaved() const {
1384 return GETVALUEWITHMASKSHIFT(NumberOfVRSavedMask
, NumberOfVRSavedShift
);
1387 bool TBVectorExt::isVRSavedOnStack() const {
1388 return GETVALUEWITHMASK(IsVRSavedOnStackMask
);
1391 bool TBVectorExt::hasVarArgs() const {
1392 return GETVALUEWITHMASK(HasVarArgsMask
);
1395 uint8_t TBVectorExt::getNumberOfVectorParms() const {
1396 return GETVALUEWITHMASKSHIFT(NumberOfVectorParmsMask
,
1397 NumberOfVectorParmsShift
);
1400 bool TBVectorExt::hasVMXInstruction() const {
1401 return GETVALUEWITHMASK(HasVMXInstructionMask
);
1403 #undef GETVALUEWITHMASK
1404 #undef GETVALUEWITHMASKSHIFT
1406 Expected
<XCOFFTracebackTable
>
1407 XCOFFTracebackTable::create(const uint8_t *Ptr
, uint64_t &Size
, bool Is64Bit
) {
1408 Error Err
= Error::success();
1409 XCOFFTracebackTable
TBT(Ptr
, Size
, Err
, Is64Bit
);
1411 return std::move(Err
);
1415 XCOFFTracebackTable::XCOFFTracebackTable(const uint8_t *Ptr
, uint64_t &Size
,
1416 Error
&Err
, bool Is64Bit
)
1417 : TBPtr(Ptr
), Is64BitObj(Is64Bit
) {
1418 ErrorAsOutParameter
EAO(&Err
);
1419 DataExtractor
DE(ArrayRef
<uint8_t>(Ptr
, Size
), /*IsLittleEndian=*/false,
1421 DataExtractor::Cursor
Cur(/*Offset=*/0);
1423 // Skip 8 bytes of mandatory fields.
1426 unsigned FixedParmsNum
= getNumberOfFixedParms();
1427 unsigned FloatingParmsNum
= getNumberOfFPParms();
1428 uint32_t ParamsTypeValue
= 0;
1430 // Begin to parse optional fields.
1431 if (Cur
&& (FixedParmsNum
+ FloatingParmsNum
) > 0)
1432 ParamsTypeValue
= DE
.getU32(Cur
);
1434 if (Cur
&& hasTraceBackTableOffset())
1435 TraceBackTableOffset
= DE
.getU32(Cur
);
1437 if (Cur
&& isInterruptHandler())
1438 HandlerMask
= DE
.getU32(Cur
);
1440 if (Cur
&& hasControlledStorage()) {
1441 NumOfCtlAnchors
= DE
.getU32(Cur
);
1442 if (Cur
&& NumOfCtlAnchors
) {
1443 SmallVector
<uint32_t, 8> Disp
;
1444 Disp
.reserve(*NumOfCtlAnchors
);
1445 for (uint32_t I
= 0; I
< NumOfCtlAnchors
&& Cur
; ++I
)
1446 Disp
.push_back(DE
.getU32(Cur
));
1448 ControlledStorageInfoDisp
= std::move(Disp
);
1452 if (Cur
&& isFuncNamePresent()) {
1453 uint16_t FunctionNameLen
= DE
.getU16(Cur
);
1455 FunctionName
= DE
.getBytes(Cur
, FunctionNameLen
);
1458 if (Cur
&& isAllocaUsed())
1459 AllocaRegister
= DE
.getU8(Cur
);
1461 unsigned VectorParmsNum
= 0;
1462 if (Cur
&& hasVectorInfo()) {
1463 StringRef VectorExtRef
= DE
.getBytes(Cur
, 6);
1465 Expected
<TBVectorExt
> TBVecExtOrErr
= TBVectorExt::create(VectorExtRef
);
1466 if (!TBVecExtOrErr
) {
1467 Err
= TBVecExtOrErr
.takeError();
1470 VecExt
= TBVecExtOrErr
.get();
1471 VectorParmsNum
= VecExt
->getNumberOfVectorParms();
1472 // Skip two bytes of padding after vector info.
1477 // As long as there is no fixed-point or floating-point parameter, this
1478 // field remains not present even when hasVectorInfo gives true and
1479 // indicates the presence of vector parameters.
1480 if (Cur
&& (FixedParmsNum
+ FloatingParmsNum
) > 0) {
1481 Expected
<SmallString
<32>> ParmsTypeOrError
=
1483 ? parseParmsTypeWithVecInfo(ParamsTypeValue
, FixedParmsNum
,
1484 FloatingParmsNum
, VectorParmsNum
)
1485 : parseParmsType(ParamsTypeValue
, FixedParmsNum
, FloatingParmsNum
);
1487 if (!ParmsTypeOrError
) {
1488 Err
= ParmsTypeOrError
.takeError();
1491 ParmsType
= ParmsTypeOrError
.get();
1494 if (Cur
&& hasExtensionTable()) {
1495 ExtensionTable
= DE
.getU8(Cur
);
1497 if (*ExtensionTable
& ExtendedTBTableFlag::TB_EH_INFO
) {
1498 // eh_info displacement must be 4-byte aligned.
1499 Cur
.seek(alignTo(Cur
.tell(), 4));
1500 EhInfoDisp
= Is64BitObj
? DE
.getU64(Cur
) : DE
.getU32(Cur
);
1504 Err
= Cur
.takeError();
1509 #define GETBITWITHMASK(P, X) \
1510 (support::endian::read32be(TBPtr + (P)) & (TracebackTable::X))
1511 #define GETBITWITHMASKSHIFT(P, X, S) \
1512 ((support::endian::read32be(TBPtr + (P)) & (TracebackTable::X)) >> \
1513 (TracebackTable::S))
1515 uint8_t XCOFFTracebackTable::getVersion() const {
1516 return GETBITWITHMASKSHIFT(0, VersionMask
, VersionShift
);
1519 uint8_t XCOFFTracebackTable::getLanguageID() const {
1520 return GETBITWITHMASKSHIFT(0, LanguageIdMask
, LanguageIdShift
);
1523 bool XCOFFTracebackTable::isGlobalLinkage() const {
1524 return GETBITWITHMASK(0, IsGlobaLinkageMask
);
1527 bool XCOFFTracebackTable::isOutOfLineEpilogOrPrologue() const {
1528 return GETBITWITHMASK(0, IsOutOfLineEpilogOrPrologueMask
);
1531 bool XCOFFTracebackTable::hasTraceBackTableOffset() const {
1532 return GETBITWITHMASK(0, HasTraceBackTableOffsetMask
);
1535 bool XCOFFTracebackTable::isInternalProcedure() const {
1536 return GETBITWITHMASK(0, IsInternalProcedureMask
);
1539 bool XCOFFTracebackTable::hasControlledStorage() const {
1540 return GETBITWITHMASK(0, HasControlledStorageMask
);
1543 bool XCOFFTracebackTable::isTOCless() const {
1544 return GETBITWITHMASK(0, IsTOClessMask
);
1547 bool XCOFFTracebackTable::isFloatingPointPresent() const {
1548 return GETBITWITHMASK(0, IsFloatingPointPresentMask
);
1551 bool XCOFFTracebackTable::isFloatingPointOperationLogOrAbortEnabled() const {
1552 return GETBITWITHMASK(0, IsFloatingPointOperationLogOrAbortEnabledMask
);
1555 bool XCOFFTracebackTable::isInterruptHandler() const {
1556 return GETBITWITHMASK(0, IsInterruptHandlerMask
);
1559 bool XCOFFTracebackTable::isFuncNamePresent() const {
1560 return GETBITWITHMASK(0, IsFunctionNamePresentMask
);
1563 bool XCOFFTracebackTable::isAllocaUsed() const {
1564 return GETBITWITHMASK(0, IsAllocaUsedMask
);
1567 uint8_t XCOFFTracebackTable::getOnConditionDirective() const {
1568 return GETBITWITHMASKSHIFT(0, OnConditionDirectiveMask
,
1569 OnConditionDirectiveShift
);
1572 bool XCOFFTracebackTable::isCRSaved() const {
1573 return GETBITWITHMASK(0, IsCRSavedMask
);
1576 bool XCOFFTracebackTable::isLRSaved() const {
1577 return GETBITWITHMASK(0, IsLRSavedMask
);
1580 bool XCOFFTracebackTable::isBackChainStored() const {
1581 return GETBITWITHMASK(4, IsBackChainStoredMask
);
1584 bool XCOFFTracebackTable::isFixup() const {
1585 return GETBITWITHMASK(4, IsFixupMask
);
1588 uint8_t XCOFFTracebackTable::getNumOfFPRsSaved() const {
1589 return GETBITWITHMASKSHIFT(4, FPRSavedMask
, FPRSavedShift
);
1592 bool XCOFFTracebackTable::hasExtensionTable() const {
1593 return GETBITWITHMASK(4, HasExtensionTableMask
);
1596 bool XCOFFTracebackTable::hasVectorInfo() const {
1597 return GETBITWITHMASK(4, HasVectorInfoMask
);
1600 uint8_t XCOFFTracebackTable::getNumOfGPRsSaved() const {
1601 return GETBITWITHMASKSHIFT(4, GPRSavedMask
, GPRSavedShift
);
1604 uint8_t XCOFFTracebackTable::getNumberOfFixedParms() const {
1605 return GETBITWITHMASKSHIFT(4, NumberOfFixedParmsMask
,
1606 NumberOfFixedParmsShift
);
1609 uint8_t XCOFFTracebackTable::getNumberOfFPParms() const {
1610 return GETBITWITHMASKSHIFT(4, NumberOfFloatingPointParmsMask
,
1611 NumberOfFloatingPointParmsShift
);
1614 bool XCOFFTracebackTable::hasParmsOnStack() const {
1615 return GETBITWITHMASK(4, HasParmsOnStackMask
);
1618 #undef GETBITWITHMASK
1619 #undef GETBITWITHMASKSHIFT
1620 } // namespace object