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