1351278Sdim//===--- XCOFFObjectFile.cpp - XCOFF object file implementation -----------===//
2351278Sdim//
3351278Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4351278Sdim// See https://llvm.org/LICENSE.txt for license information.
5351278Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6351278Sdim//
7351278Sdim//===----------------------------------------------------------------------===//
8351278Sdim//
9351278Sdim// This file defines the XCOFFObjectFile class.
10351278Sdim//
11351278Sdim//===----------------------------------------------------------------------===//
12351278Sdim
13351278Sdim#include "llvm/Object/XCOFFObjectFile.h"
14351278Sdim#include <cstddef>
15351278Sdim#include <cstring>
16351278Sdim
17351278Sdimnamespace llvm {
18351278Sdimnamespace object {
19351278Sdim
20360784Sdimenum { FUNCTION_SYM = 0x20, SYM_TYPE_MASK = 0x07, RELOC_OVERFLOW = 65535 };
21360784Sdim
22351278Sdim// Checks that [Ptr, Ptr + Size) bytes fall inside the memory buffer
23351278Sdim// 'M'. Returns a pointer to the underlying object on success.
24351278Sdimtemplate <typename T>
25351278Sdimstatic Expected<const T *> getObject(MemoryBufferRef M, const void *Ptr,
26351278Sdim                                     const uint64_t Size = sizeof(T)) {
27351278Sdim  uintptr_t Addr = uintptr_t(Ptr);
28351278Sdim  if (std::error_code EC = Binary::checkOffset(M, Addr, Size))
29351278Sdim    return errorCodeToError(EC);
30351278Sdim  return reinterpret_cast<const T *>(Addr);
31351278Sdim}
32351278Sdim
33351278Sdimstatic uintptr_t getWithOffset(uintptr_t Base, ptrdiff_t Offset) {
34351278Sdim  return reinterpret_cast<uintptr_t>(reinterpret_cast<const char *>(Base) +
35351278Sdim                                     Offset);
36351278Sdim}
37351278Sdim
38351278Sdimtemplate <typename T> static const T *viewAs(uintptr_t in) {
39351278Sdim  return reinterpret_cast<const T *>(in);
40351278Sdim}
41351278Sdim
42360784Sdimstatic StringRef generateXCOFFFixedNameStringRef(const char *Name) {
43360784Sdim  auto NulCharPtr =
44360784Sdim      static_cast<const char *>(memchr(Name, '\0', XCOFF::NameSize));
45351278Sdim  return NulCharPtr ? StringRef(Name, NulCharPtr - Name)
46360784Sdim                    : StringRef(Name, XCOFF::NameSize);
47351278Sdim}
48351278Sdim
49360784Sdimtemplate <typename T> StringRef XCOFFSectionHeader<T>::getName() const {
50360784Sdim  const T &DerivedXCOFFSectionHeader = static_cast<const T &>(*this);
51360784Sdim  return generateXCOFFFixedNameStringRef(DerivedXCOFFSectionHeader.Name);
52360784Sdim}
53360784Sdim
54360784Sdimtemplate <typename T> uint16_t XCOFFSectionHeader<T>::getSectionType() const {
55360784Sdim  const T &DerivedXCOFFSectionHeader = static_cast<const T &>(*this);
56360784Sdim  return DerivedXCOFFSectionHeader.Flags & SectionFlagsTypeMask;
57360784Sdim}
58360784Sdim
59360784Sdimtemplate <typename T>
60360784Sdimbool XCOFFSectionHeader<T>::isReservedSectionType() const {
61360784Sdim  return getSectionType() & SectionFlagsReservedMask;
62360784Sdim}
63360784Sdim
64360784Sdimbool XCOFFRelocation32::isRelocationSigned() const {
65360784Sdim  return Info & XR_SIGN_INDICATOR_MASK;
66360784Sdim}
67360784Sdim
68360784Sdimbool XCOFFRelocation32::isFixupIndicated() const {
69360784Sdim  return Info & XR_FIXUP_INDICATOR_MASK;
70360784Sdim}
71360784Sdim
72360784Sdimuint8_t XCOFFRelocation32::getRelocatedLength() const {
73360784Sdim  // The relocation encodes the bit length being relocated minus 1. Add back
74360784Sdim  // the 1 to get the actual length being relocated.
75360784Sdim  return (Info & XR_BIASED_LENGTH_MASK) + 1;
76360784Sdim}
77360784Sdim
78351278Sdimvoid XCOFFObjectFile::checkSectionAddress(uintptr_t Addr,
79351278Sdim                                          uintptr_t TableAddress) const {
80351278Sdim  if (Addr < TableAddress)
81351278Sdim    report_fatal_error("Section header outside of section header table.");
82351278Sdim
83351278Sdim  uintptr_t Offset = Addr - TableAddress;
84351278Sdim  if (Offset >= getSectionHeaderSize() * getNumberOfSections())
85351278Sdim    report_fatal_error("Section header outside of section header table.");
86351278Sdim
87351278Sdim  if (Offset % getSectionHeaderSize() != 0)
88351278Sdim    report_fatal_error(
89351278Sdim        "Section header pointer does not point to a valid section header.");
90351278Sdim}
91351278Sdim
92351278Sdimconst XCOFFSectionHeader32 *
93351278SdimXCOFFObjectFile::toSection32(DataRefImpl Ref) const {
94351278Sdim  assert(!is64Bit() && "32-bit interface called on 64-bit object file.");
95351278Sdim#ifndef NDEBUG
96351278Sdim  checkSectionAddress(Ref.p, getSectionHeaderTableAddress());
97351278Sdim#endif
98351278Sdim  return viewAs<XCOFFSectionHeader32>(Ref.p);
99351278Sdim}
100351278Sdim
101351278Sdimconst XCOFFSectionHeader64 *
102351278SdimXCOFFObjectFile::toSection64(DataRefImpl Ref) const {
103351278Sdim  assert(is64Bit() && "64-bit interface called on a 32-bit object file.");
104351278Sdim#ifndef NDEBUG
105351278Sdim  checkSectionAddress(Ref.p, getSectionHeaderTableAddress());
106351278Sdim#endif
107351278Sdim  return viewAs<XCOFFSectionHeader64>(Ref.p);
108351278Sdim}
109351278Sdim
110351278Sdimconst XCOFFSymbolEntry *XCOFFObjectFile::toSymbolEntry(DataRefImpl Ref) const {
111351278Sdim  assert(!is64Bit() && "Symbol table support not implemented for 64-bit.");
112351278Sdim  assert(Ref.p != 0 && "Symbol table pointer can not be nullptr!");
113360784Sdim#ifndef NDEBUG
114360784Sdim  checkSymbolEntryPointer(Ref.p);
115360784Sdim#endif
116351278Sdim  auto SymEntPtr = viewAs<XCOFFSymbolEntry>(Ref.p);
117351278Sdim  return SymEntPtr;
118351278Sdim}
119351278Sdim
120351278Sdimconst XCOFFFileHeader32 *XCOFFObjectFile::fileHeader32() const {
121351278Sdim  assert(!is64Bit() && "32-bit interface called on 64-bit object file.");
122351278Sdim  return static_cast<const XCOFFFileHeader32 *>(FileHeader);
123351278Sdim}
124351278Sdim
125351278Sdimconst XCOFFFileHeader64 *XCOFFObjectFile::fileHeader64() const {
126351278Sdim  assert(is64Bit() && "64-bit interface called on a 32-bit object file.");
127351278Sdim  return static_cast<const XCOFFFileHeader64 *>(FileHeader);
128351278Sdim}
129351278Sdim
130351278Sdimconst XCOFFSectionHeader32 *
131351278SdimXCOFFObjectFile::sectionHeaderTable32() const {
132351278Sdim  assert(!is64Bit() && "32-bit interface called on 64-bit object file.");
133351278Sdim  return static_cast<const XCOFFSectionHeader32 *>(SectionHeaderTable);
134351278Sdim}
135351278Sdim
136351278Sdimconst XCOFFSectionHeader64 *
137351278SdimXCOFFObjectFile::sectionHeaderTable64() const {
138351278Sdim  assert(is64Bit() && "64-bit interface called on a 32-bit object file.");
139351278Sdim  return static_cast<const XCOFFSectionHeader64 *>(SectionHeaderTable);
140351278Sdim}
141351278Sdim
142351278Sdimvoid XCOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const {
143351278Sdim  const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb);
144351278Sdim  SymEntPtr += SymEntPtr->NumberOfAuxEntries + 1;
145360784Sdim#ifndef NDEBUG
146360784Sdim  // This function is used by basic_symbol_iterator, which allows to
147360784Sdim  // point to the end-of-symbol-table address.
148360784Sdim  if (reinterpret_cast<uintptr_t>(SymEntPtr) != getEndOfSymbolTableAddress())
149360784Sdim    checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(SymEntPtr));
150360784Sdim#endif
151351278Sdim  Symb.p = reinterpret_cast<uintptr_t>(SymEntPtr);
152351278Sdim}
153351278Sdim
154360784SdimExpected<StringRef>
155360784SdimXCOFFObjectFile::getStringTableEntry(uint32_t Offset) const {
156360784Sdim  // The byte offset is relative to the start of the string table.
157360784Sdim  // A byte offset value of 0 is a null or zero-length symbol
158351278Sdim  // name. A byte offset in the range 1 to 3 (inclusive) points into the length
159351278Sdim  // field; as a soft-error recovery mechanism, we treat such cases as having an
160351278Sdim  // offset of 0.
161351278Sdim  if (Offset < 4)
162351278Sdim    return StringRef(nullptr, 0);
163351278Sdim
164351278Sdim  if (StringTable.Data != nullptr && StringTable.Size > Offset)
165351278Sdim    return (StringTable.Data + Offset);
166351278Sdim
167360784Sdim  return make_error<GenericBinaryError>("Bad offset for string table entry",
168351278Sdim                                        object_error::parse_failed);
169351278Sdim}
170351278Sdim
171360784SdimExpected<StringRef>
172360784SdimXCOFFObjectFile::getCFileName(const XCOFFFileAuxEnt *CFileEntPtr) const {
173360784Sdim  if (CFileEntPtr->NameInStrTbl.Magic !=
174360784Sdim      XCOFFSymbolEntry::NAME_IN_STR_TBL_MAGIC)
175360784Sdim    return generateXCOFFFixedNameStringRef(CFileEntPtr->Name);
176360784Sdim  return getStringTableEntry(CFileEntPtr->NameInStrTbl.Offset);
177360784Sdim}
178360784Sdim
179360784SdimExpected<StringRef> XCOFFObjectFile::getSymbolName(DataRefImpl Symb) const {
180360784Sdim  const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb);
181360784Sdim
182360784Sdim  // A storage class value with the high-order bit on indicates that the name is
183360784Sdim  // a symbolic debugger stabstring.
184360784Sdim  if (SymEntPtr->StorageClass & 0x80)
185360784Sdim    return StringRef("Unimplemented Debug Name");
186360784Sdim
187360784Sdim  if (SymEntPtr->NameInStrTbl.Magic != XCOFFSymbolEntry::NAME_IN_STR_TBL_MAGIC)
188360784Sdim    return generateXCOFFFixedNameStringRef(SymEntPtr->SymbolName);
189360784Sdim
190360784Sdim  return getStringTableEntry(SymEntPtr->NameInStrTbl.Offset);
191360784Sdim}
192360784Sdim
193351278SdimExpected<uint64_t> XCOFFObjectFile::getSymbolAddress(DataRefImpl Symb) const {
194360784Sdim  assert(!is64Bit() && "Symbol table support not implemented for 64-bit.");
195360784Sdim  return toSymbolEntry(Symb)->Value;
196351278Sdim}
197351278Sdim
198351278Sdimuint64_t XCOFFObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
199360784Sdim  assert(!is64Bit() && "Symbol table support not implemented for 64-bit.");
200351278Sdim  return toSymbolEntry(Symb)->Value;
201351278Sdim}
202351278Sdim
203351278Sdimuint64_t XCOFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
204351278Sdim  uint64_t Result = 0;
205351278Sdim  llvm_unreachable("Not yet implemented!");
206351278Sdim  return Result;
207351278Sdim}
208351278Sdim
209351278SdimExpected<SymbolRef::Type>
210351278SdimXCOFFObjectFile::getSymbolType(DataRefImpl Symb) const {
211351278Sdim  llvm_unreachable("Not yet implemented!");
212351278Sdim  return SymbolRef::ST_Other;
213351278Sdim}
214351278Sdim
215351278SdimExpected<section_iterator>
216351278SdimXCOFFObjectFile::getSymbolSection(DataRefImpl Symb) const {
217351278Sdim  const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb);
218351278Sdim  int16_t SectNum = SymEntPtr->SectionNumber;
219351278Sdim
220351278Sdim  if (isReservedSectionNumber(SectNum))
221351278Sdim    return section_end();
222351278Sdim
223351278Sdim  Expected<DataRefImpl> ExpSec = getSectionByNum(SectNum);
224351278Sdim  if (!ExpSec)
225351278Sdim    return ExpSec.takeError();
226351278Sdim
227351278Sdim  return section_iterator(SectionRef(ExpSec.get(), this));
228351278Sdim}
229351278Sdim
230351278Sdimvoid XCOFFObjectFile::moveSectionNext(DataRefImpl &Sec) const {
231351278Sdim  const char *Ptr = reinterpret_cast<const char *>(Sec.p);
232351278Sdim  Sec.p = reinterpret_cast<uintptr_t>(Ptr + getSectionHeaderSize());
233351278Sdim}
234351278Sdim
235351278SdimExpected<StringRef> XCOFFObjectFile::getSectionName(DataRefImpl Sec) const {
236360784Sdim  return generateXCOFFFixedNameStringRef(getSectionNameInternal(Sec));
237351278Sdim}
238351278Sdim
239351278Sdimuint64_t XCOFFObjectFile::getSectionAddress(DataRefImpl Sec) const {
240351278Sdim  // Avoid ternary due to failure to convert the ubig32_t value to a unit64_t
241351278Sdim  // with MSVC.
242351278Sdim  if (is64Bit())
243351278Sdim    return toSection64(Sec)->VirtualAddress;
244351278Sdim
245351278Sdim  return toSection32(Sec)->VirtualAddress;
246351278Sdim}
247351278Sdim
248351278Sdimuint64_t XCOFFObjectFile::getSectionIndex(DataRefImpl Sec) const {
249351278Sdim  // Section numbers in XCOFF are numbered beginning at 1. A section number of
250351278Sdim  // zero is used to indicate that a symbol is being imported or is undefined.
251351278Sdim  if (is64Bit())
252351278Sdim    return toSection64(Sec) - sectionHeaderTable64() + 1;
253351278Sdim  else
254351278Sdim    return toSection32(Sec) - sectionHeaderTable32() + 1;
255351278Sdim}
256351278Sdim
257351278Sdimuint64_t XCOFFObjectFile::getSectionSize(DataRefImpl Sec) const {
258351278Sdim  // Avoid ternary due to failure to convert the ubig32_t value to a unit64_t
259351278Sdim  // with MSVC.
260351278Sdim  if (is64Bit())
261351278Sdim    return toSection64(Sec)->SectionSize;
262351278Sdim
263351278Sdim  return toSection32(Sec)->SectionSize;
264351278Sdim}
265351278Sdim
266351278SdimExpected<ArrayRef<uint8_t>>
267351278SdimXCOFFObjectFile::getSectionContents(DataRefImpl Sec) const {
268360784Sdim  if (isSectionVirtual(Sec))
269360784Sdim    return ArrayRef<uint8_t>();
270360784Sdim
271360784Sdim  uint64_t OffsetToRaw;
272360784Sdim  if (is64Bit())
273360784Sdim    OffsetToRaw = toSection64(Sec)->FileOffsetToRawData;
274360784Sdim  else
275360784Sdim    OffsetToRaw = toSection32(Sec)->FileOffsetToRawData;
276360784Sdim
277360784Sdim  const uint8_t * ContentStart = base() + OffsetToRaw;
278360784Sdim  uint64_t SectionSize = getSectionSize(Sec);
279360784Sdim  if (checkOffset(Data, uintptr_t(ContentStart), SectionSize))
280360784Sdim    return make_error<BinaryError>();
281360784Sdim
282360784Sdim  return makeArrayRef(ContentStart,SectionSize);
283351278Sdim}
284351278Sdim
285351278Sdimuint64_t XCOFFObjectFile::getSectionAlignment(DataRefImpl Sec) const {
286351278Sdim  uint64_t Result = 0;
287351278Sdim  llvm_unreachable("Not yet implemented!");
288351278Sdim  return Result;
289351278Sdim}
290351278Sdim
291351278Sdimbool XCOFFObjectFile::isSectionCompressed(DataRefImpl Sec) const {
292351278Sdim  bool Result = false;
293351278Sdim  llvm_unreachable("Not yet implemented!");
294351278Sdim  return Result;
295351278Sdim}
296351278Sdim
297351278Sdimbool XCOFFObjectFile::isSectionText(DataRefImpl Sec) const {
298351278Sdim  return getSectionFlags(Sec) & XCOFF::STYP_TEXT;
299351278Sdim}
300351278Sdim
301351278Sdimbool XCOFFObjectFile::isSectionData(DataRefImpl Sec) const {
302351278Sdim  uint32_t Flags = getSectionFlags(Sec);
303351278Sdim  return Flags & (XCOFF::STYP_DATA | XCOFF::STYP_TDATA);
304351278Sdim}
305351278Sdim
306351278Sdimbool XCOFFObjectFile::isSectionBSS(DataRefImpl Sec) const {
307351278Sdim  uint32_t Flags = getSectionFlags(Sec);
308351278Sdim  return Flags & (XCOFF::STYP_BSS | XCOFF::STYP_TBSS);
309351278Sdim}
310351278Sdim
311351278Sdimbool XCOFFObjectFile::isSectionVirtual(DataRefImpl Sec) const {
312360784Sdim  return is64Bit() ? toSection64(Sec)->FileOffsetToRawData == 0
313360784Sdim                   : toSection32(Sec)->FileOffsetToRawData == 0;
314351278Sdim}
315351278Sdim
316351278Sdimrelocation_iterator XCOFFObjectFile::section_rel_begin(DataRefImpl Sec) const {
317351278Sdim  llvm_unreachable("Not yet implemented!");
318351278Sdim  return relocation_iterator(RelocationRef());
319351278Sdim}
320351278Sdim
321351278Sdimrelocation_iterator XCOFFObjectFile::section_rel_end(DataRefImpl Sec) const {
322351278Sdim  llvm_unreachable("Not yet implemented!");
323351278Sdim  return relocation_iterator(RelocationRef());
324351278Sdim}
325351278Sdim
326351278Sdimvoid XCOFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const {
327351278Sdim  llvm_unreachable("Not yet implemented!");
328351278Sdim  return;
329351278Sdim}
330351278Sdim
331351278Sdimuint64_t XCOFFObjectFile::getRelocationOffset(DataRefImpl Rel) const {
332351278Sdim  llvm_unreachable("Not yet implemented!");
333351278Sdim  uint64_t Result = 0;
334351278Sdim  return Result;
335351278Sdim}
336351278Sdim
337351278Sdimsymbol_iterator XCOFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
338351278Sdim  llvm_unreachable("Not yet implemented!");
339351278Sdim  return symbol_iterator(SymbolRef());
340351278Sdim}
341351278Sdim
342351278Sdimuint64_t XCOFFObjectFile::getRelocationType(DataRefImpl Rel) const {
343351278Sdim  llvm_unreachable("Not yet implemented!");
344351278Sdim  uint64_t Result = 0;
345351278Sdim  return Result;
346351278Sdim}
347351278Sdim
348351278Sdimvoid XCOFFObjectFile::getRelocationTypeName(
349351278Sdim    DataRefImpl Rel, SmallVectorImpl<char> &Result) const {
350351278Sdim  llvm_unreachable("Not yet implemented!");
351351278Sdim  return;
352351278Sdim}
353351278Sdim
354351278Sdimuint32_t XCOFFObjectFile::getSymbolFlags(DataRefImpl Symb) const {
355351278Sdim  uint32_t Result = 0;
356351278Sdim  llvm_unreachable("Not yet implemented!");
357351278Sdim  return Result;
358351278Sdim}
359351278Sdim
360351278Sdimbasic_symbol_iterator XCOFFObjectFile::symbol_begin() const {
361351278Sdim  assert(!is64Bit() && "64-bit support not implemented yet.");
362351278Sdim  DataRefImpl SymDRI;
363351278Sdim  SymDRI.p = reinterpret_cast<uintptr_t>(SymbolTblPtr);
364351278Sdim  return basic_symbol_iterator(SymbolRef(SymDRI, this));
365351278Sdim}
366351278Sdim
367351278Sdimbasic_symbol_iterator XCOFFObjectFile::symbol_end() const {
368351278Sdim  assert(!is64Bit() && "64-bit support not implemented yet.");
369351278Sdim  DataRefImpl SymDRI;
370351278Sdim  SymDRI.p = reinterpret_cast<uintptr_t>(
371351278Sdim      SymbolTblPtr + getLogicalNumberOfSymbolTableEntries32());
372351278Sdim  return basic_symbol_iterator(SymbolRef(SymDRI, this));
373351278Sdim}
374351278Sdim
375351278Sdimsection_iterator XCOFFObjectFile::section_begin() const {
376351278Sdim  DataRefImpl DRI;
377351278Sdim  DRI.p = getSectionHeaderTableAddress();
378351278Sdim  return section_iterator(SectionRef(DRI, this));
379351278Sdim}
380351278Sdim
381351278Sdimsection_iterator XCOFFObjectFile::section_end() const {
382351278Sdim  DataRefImpl DRI;
383351278Sdim  DRI.p = getWithOffset(getSectionHeaderTableAddress(),
384351278Sdim                        getNumberOfSections() * getSectionHeaderSize());
385351278Sdim  return section_iterator(SectionRef(DRI, this));
386351278Sdim}
387351278Sdim
388351278Sdimuint8_t XCOFFObjectFile::getBytesInAddress() const { return is64Bit() ? 8 : 4; }
389351278Sdim
390351278SdimStringRef XCOFFObjectFile::getFileFormatName() const {
391351278Sdim  return is64Bit() ? "aix5coff64-rs6000" : "aixcoff-rs6000";
392351278Sdim}
393351278Sdim
394351278SdimTriple::ArchType XCOFFObjectFile::getArch() const {
395351278Sdim  return is64Bit() ? Triple::ppc64 : Triple::ppc;
396351278Sdim}
397351278Sdim
398351278SdimSubtargetFeatures XCOFFObjectFile::getFeatures() const {
399351278Sdim  return SubtargetFeatures();
400351278Sdim}
401351278Sdim
402351278Sdimbool XCOFFObjectFile::isRelocatableObject() const {
403351278Sdim  bool Result = false;
404351278Sdim  llvm_unreachable("Not yet implemented!");
405351278Sdim  return Result;
406351278Sdim}
407351278Sdim
408351278SdimExpected<uint64_t> XCOFFObjectFile::getStartAddress() const {
409351278Sdim  // TODO FIXME Should get from auxiliary_header->o_entry when support for the
410351278Sdim  // auxiliary_header is added.
411351278Sdim  return 0;
412351278Sdim}
413351278Sdim
414351278Sdimsize_t XCOFFObjectFile::getFileHeaderSize() const {
415351278Sdim  return is64Bit() ? sizeof(XCOFFFileHeader64) : sizeof(XCOFFFileHeader32);
416351278Sdim}
417351278Sdim
418351278Sdimsize_t XCOFFObjectFile::getSectionHeaderSize() const {
419351278Sdim  return is64Bit() ? sizeof(XCOFFSectionHeader64) :
420351278Sdim                     sizeof(XCOFFSectionHeader32);
421351278Sdim}
422351278Sdim
423351278Sdimbool XCOFFObjectFile::is64Bit() const {
424351278Sdim  return Binary::ID_XCOFF64 == getType();
425351278Sdim}
426351278Sdim
427351278Sdimuint16_t XCOFFObjectFile::getMagic() const {
428351278Sdim  return is64Bit() ? fileHeader64()->Magic : fileHeader32()->Magic;
429351278Sdim}
430351278Sdim
431351278SdimExpected<DataRefImpl> XCOFFObjectFile::getSectionByNum(int16_t Num) const {
432351278Sdim  if (Num <= 0 || Num > getNumberOfSections())
433351278Sdim    return errorCodeToError(object_error::invalid_section_index);
434351278Sdim
435351278Sdim  DataRefImpl DRI;
436351278Sdim  DRI.p = getWithOffset(getSectionHeaderTableAddress(),
437351278Sdim                        getSectionHeaderSize() * (Num - 1));
438351278Sdim  return DRI;
439351278Sdim}
440351278Sdim
441351278SdimExpected<StringRef>
442351278SdimXCOFFObjectFile::getSymbolSectionName(const XCOFFSymbolEntry *SymEntPtr) const {
443351278Sdim  assert(!is64Bit() && "Symbol table support not implemented for 64-bit.");
444351278Sdim  int16_t SectionNum = SymEntPtr->SectionNumber;
445351278Sdim
446351278Sdim  switch (SectionNum) {
447351278Sdim  case XCOFF::N_DEBUG:
448351278Sdim    return "N_DEBUG";
449351278Sdim  case XCOFF::N_ABS:
450351278Sdim    return "N_ABS";
451351278Sdim  case XCOFF::N_UNDEF:
452351278Sdim    return "N_UNDEF";
453351278Sdim  default:
454351278Sdim    Expected<DataRefImpl> SecRef = getSectionByNum(SectionNum);
455351278Sdim    if (SecRef)
456360784Sdim      return generateXCOFFFixedNameStringRef(
457360784Sdim          getSectionNameInternal(SecRef.get()));
458351278Sdim    return SecRef.takeError();
459351278Sdim  }
460351278Sdim}
461351278Sdim
462351278Sdimbool XCOFFObjectFile::isReservedSectionNumber(int16_t SectionNumber) {
463351278Sdim  return (SectionNumber <= 0 && SectionNumber >= -2);
464351278Sdim}
465351278Sdim
466351278Sdimuint16_t XCOFFObjectFile::getNumberOfSections() const {
467351278Sdim  return is64Bit() ? fileHeader64()->NumberOfSections
468351278Sdim                   : fileHeader32()->NumberOfSections;
469351278Sdim}
470351278Sdim
471351278Sdimint32_t XCOFFObjectFile::getTimeStamp() const {
472351278Sdim  return is64Bit() ? fileHeader64()->TimeStamp : fileHeader32()->TimeStamp;
473351278Sdim}
474351278Sdim
475351278Sdimuint16_t XCOFFObjectFile::getOptionalHeaderSize() const {
476351278Sdim  return is64Bit() ? fileHeader64()->AuxHeaderSize
477351278Sdim                   : fileHeader32()->AuxHeaderSize;
478351278Sdim}
479351278Sdim
480351278Sdimuint32_t XCOFFObjectFile::getSymbolTableOffset32() const {
481351278Sdim  return fileHeader32()->SymbolTableOffset;
482351278Sdim}
483351278Sdim
484351278Sdimint32_t XCOFFObjectFile::getRawNumberOfSymbolTableEntries32() const {
485351278Sdim  // As far as symbol table size is concerned, if this field is negative it is
486351278Sdim  // to be treated as a 0. However since this field is also used for printing we
487351278Sdim  // don't want to truncate any negative values.
488351278Sdim  return fileHeader32()->NumberOfSymTableEntries;
489351278Sdim}
490351278Sdim
491351278Sdimuint32_t XCOFFObjectFile::getLogicalNumberOfSymbolTableEntries32() const {
492351278Sdim  return (fileHeader32()->NumberOfSymTableEntries >= 0
493351278Sdim              ? fileHeader32()->NumberOfSymTableEntries
494351278Sdim              : 0);
495351278Sdim}
496351278Sdim
497351278Sdimuint64_t XCOFFObjectFile::getSymbolTableOffset64() const {
498351278Sdim  return fileHeader64()->SymbolTableOffset;
499351278Sdim}
500351278Sdim
501351278Sdimuint32_t XCOFFObjectFile::getNumberOfSymbolTableEntries64() const {
502351278Sdim  return fileHeader64()->NumberOfSymTableEntries;
503351278Sdim}
504351278Sdim
505360784Sdimuintptr_t XCOFFObjectFile::getEndOfSymbolTableAddress() const {
506360784Sdim  uint32_t NumberOfSymTableEntries =
507360784Sdim      is64Bit() ? getNumberOfSymbolTableEntries64()
508360784Sdim                : getLogicalNumberOfSymbolTableEntries32();
509360784Sdim  return getWithOffset(reinterpret_cast<uintptr_t>(SymbolTblPtr),
510360784Sdim                       XCOFF::SymbolTableEntrySize * NumberOfSymTableEntries);
511360784Sdim}
512360784Sdim
513360784Sdimvoid XCOFFObjectFile::checkSymbolEntryPointer(uintptr_t SymbolEntPtr) const {
514360784Sdim  if (SymbolEntPtr < reinterpret_cast<uintptr_t>(SymbolTblPtr))
515360784Sdim    report_fatal_error("Symbol table entry is outside of symbol table.");
516360784Sdim
517360784Sdim  if (SymbolEntPtr >= getEndOfSymbolTableAddress())
518360784Sdim    report_fatal_error("Symbol table entry is outside of symbol table.");
519360784Sdim
520360784Sdim  ptrdiff_t Offset = reinterpret_cast<const char *>(SymbolEntPtr) -
521360784Sdim                     reinterpret_cast<const char *>(SymbolTblPtr);
522360784Sdim
523360784Sdim  if (Offset % XCOFF::SymbolTableEntrySize != 0)
524360784Sdim    report_fatal_error(
525360784Sdim        "Symbol table entry position is not valid inside of symbol table.");
526360784Sdim}
527360784Sdim
528360784Sdimuint32_t XCOFFObjectFile::getSymbolIndex(uintptr_t SymbolEntPtr) const {
529360784Sdim  return (reinterpret_cast<const char *>(SymbolEntPtr) -
530360784Sdim          reinterpret_cast<const char *>(SymbolTblPtr)) /
531360784Sdim         XCOFF::SymbolTableEntrySize;
532360784Sdim}
533360784Sdim
534360784SdimExpected<StringRef>
535360784SdimXCOFFObjectFile::getSymbolNameByIndex(uint32_t Index) const {
536360784Sdim  if (is64Bit())
537360784Sdim    report_fatal_error("64-bit symbol table support not implemented yet.");
538360784Sdim
539360784Sdim  if (Index >= getLogicalNumberOfSymbolTableEntries32())
540360784Sdim    return errorCodeToError(object_error::invalid_symbol_index);
541360784Sdim
542360784Sdim  DataRefImpl SymDRI;
543360784Sdim  SymDRI.p = reinterpret_cast<uintptr_t>(getPointerToSymbolTable() + Index);
544360784Sdim  return getSymbolName(SymDRI);
545360784Sdim}
546360784Sdim
547351278Sdimuint16_t XCOFFObjectFile::getFlags() const {
548351278Sdim  return is64Bit() ? fileHeader64()->Flags : fileHeader32()->Flags;
549351278Sdim}
550351278Sdim
551351278Sdimconst char *XCOFFObjectFile::getSectionNameInternal(DataRefImpl Sec) const {
552351278Sdim  return is64Bit() ? toSection64(Sec)->Name : toSection32(Sec)->Name;
553351278Sdim}
554351278Sdim
555351278Sdimuintptr_t XCOFFObjectFile::getSectionHeaderTableAddress() const {
556351278Sdim  return reinterpret_cast<uintptr_t>(SectionHeaderTable);
557351278Sdim}
558351278Sdim
559351278Sdimint32_t XCOFFObjectFile::getSectionFlags(DataRefImpl Sec) const {
560351278Sdim  return is64Bit() ? toSection64(Sec)->Flags : toSection32(Sec)->Flags;
561351278Sdim}
562351278Sdim
563351278SdimXCOFFObjectFile::XCOFFObjectFile(unsigned int Type, MemoryBufferRef Object)
564351278Sdim    : ObjectFile(Type, Object) {
565351278Sdim  assert(Type == Binary::ID_XCOFF32 || Type == Binary::ID_XCOFF64);
566351278Sdim}
567351278Sdim
568351278SdimArrayRef<XCOFFSectionHeader64> XCOFFObjectFile::sections64() const {
569351278Sdim  assert(is64Bit() && "64-bit interface called for non 64-bit file.");
570351278Sdim  const XCOFFSectionHeader64 *TablePtr = sectionHeaderTable64();
571351278Sdim  return ArrayRef<XCOFFSectionHeader64>(TablePtr,
572351278Sdim                                        TablePtr + getNumberOfSections());
573351278Sdim}
574351278Sdim
575351278SdimArrayRef<XCOFFSectionHeader32> XCOFFObjectFile::sections32() const {
576351278Sdim  assert(!is64Bit() && "32-bit interface called for non 32-bit file.");
577351278Sdim  const XCOFFSectionHeader32 *TablePtr = sectionHeaderTable32();
578351278Sdim  return ArrayRef<XCOFFSectionHeader32>(TablePtr,
579351278Sdim                                        TablePtr + getNumberOfSections());
580351278Sdim}
581351278Sdim
582360784Sdim// In an XCOFF32 file, when the field value is 65535, then an STYP_OVRFLO
583360784Sdim// section header contains the actual count of relocation entries in the s_paddr
584360784Sdim// field. STYP_OVRFLO headers contain the section index of their corresponding
585360784Sdim// sections as their raw "NumberOfRelocations" field value.
586360784SdimExpected<uint32_t> XCOFFObjectFile::getLogicalNumberOfRelocationEntries(
587360784Sdim    const XCOFFSectionHeader32 &Sec) const {
588360784Sdim
589360784Sdim  uint16_t SectionIndex = &Sec - sectionHeaderTable32() + 1;
590360784Sdim
591360784Sdim  if (Sec.NumberOfRelocations < RELOC_OVERFLOW)
592360784Sdim    return Sec.NumberOfRelocations;
593360784Sdim  for (const auto &Sec : sections32()) {
594360784Sdim    if (Sec.Flags == XCOFF::STYP_OVRFLO &&
595360784Sdim        Sec.NumberOfRelocations == SectionIndex)
596360784Sdim      return Sec.PhysicalAddress;
597360784Sdim  }
598360784Sdim  return errorCodeToError(object_error::parse_failed);
599360784Sdim}
600360784Sdim
601360784SdimExpected<ArrayRef<XCOFFRelocation32>>
602360784SdimXCOFFObjectFile::relocations(const XCOFFSectionHeader32 &Sec) const {
603360784Sdim  uintptr_t RelocAddr = getWithOffset(reinterpret_cast<uintptr_t>(FileHeader),
604360784Sdim                                      Sec.FileOffsetToRelocationInfo);
605360784Sdim  auto NumRelocEntriesOrErr = getLogicalNumberOfRelocationEntries(Sec);
606360784Sdim  if (Error E = NumRelocEntriesOrErr.takeError())
607360784Sdim    return std::move(E);
608360784Sdim
609360784Sdim  uint32_t NumRelocEntries = NumRelocEntriesOrErr.get();
610360784Sdim
611360784Sdim  auto RelocationOrErr =
612360784Sdim      getObject<XCOFFRelocation32>(Data, reinterpret_cast<void *>(RelocAddr),
613360784Sdim                                   NumRelocEntries * sizeof(XCOFFRelocation32));
614360784Sdim  if (Error E = RelocationOrErr.takeError())
615360784Sdim    return std::move(E);
616360784Sdim
617360784Sdim  const XCOFFRelocation32 *StartReloc = RelocationOrErr.get();
618360784Sdim
619360784Sdim  return ArrayRef<XCOFFRelocation32>(StartReloc, StartReloc + NumRelocEntries);
620360784Sdim}
621360784Sdim
622351278SdimExpected<XCOFFStringTable>
623351278SdimXCOFFObjectFile::parseStringTable(const XCOFFObjectFile *Obj, uint64_t Offset) {
624351278Sdim  // If there is a string table, then the buffer must contain at least 4 bytes
625351278Sdim  // for the string table's size. Not having a string table is not an error.
626351278Sdim  if (auto EC = Binary::checkOffset(
627351278Sdim          Obj->Data, reinterpret_cast<uintptr_t>(Obj->base() + Offset), 4))
628351278Sdim    return XCOFFStringTable{0, nullptr};
629351278Sdim
630351278Sdim  // Read the size out of the buffer.
631351278Sdim  uint32_t Size = support::endian::read32be(Obj->base() + Offset);
632351278Sdim
633351278Sdim  // If the size is less then 4, then the string table is just a size and no
634351278Sdim  // string data.
635351278Sdim  if (Size <= 4)
636351278Sdim    return XCOFFStringTable{4, nullptr};
637351278Sdim
638351278Sdim  auto StringTableOrErr =
639351278Sdim      getObject<char>(Obj->Data, Obj->base() + Offset, Size);
640351278Sdim  if (Error E = StringTableOrErr.takeError())
641351278Sdim    return std::move(E);
642351278Sdim
643351278Sdim  const char *StringTablePtr = StringTableOrErr.get();
644351278Sdim  if (StringTablePtr[Size - 1] != '\0')
645351278Sdim    return errorCodeToError(object_error::string_table_non_null_end);
646351278Sdim
647351278Sdim  return XCOFFStringTable{Size, StringTablePtr};
648351278Sdim}
649351278Sdim
650351278SdimExpected<std::unique_ptr<XCOFFObjectFile>>
651351278SdimXCOFFObjectFile::create(unsigned Type, MemoryBufferRef MBR) {
652360784Sdim  // Can't use std::make_unique because of the private constructor.
653351278Sdim  std::unique_ptr<XCOFFObjectFile> Obj;
654351278Sdim  Obj.reset(new XCOFFObjectFile(Type, MBR));
655351278Sdim
656351278Sdim  uint64_t CurOffset = 0;
657351278Sdim  const auto *Base = Obj->base();
658351278Sdim  MemoryBufferRef Data = Obj->Data;
659351278Sdim
660351278Sdim  // Parse file header.
661351278Sdim  auto FileHeaderOrErr =
662351278Sdim      getObject<void>(Data, Base + CurOffset, Obj->getFileHeaderSize());
663351278Sdim  if (Error E = FileHeaderOrErr.takeError())
664351278Sdim    return std::move(E);
665351278Sdim  Obj->FileHeader = FileHeaderOrErr.get();
666351278Sdim
667351278Sdim  CurOffset += Obj->getFileHeaderSize();
668351278Sdim  // TODO FIXME we don't have support for an optional header yet, so just skip
669351278Sdim  // past it.
670351278Sdim  CurOffset += Obj->getOptionalHeaderSize();
671351278Sdim
672351278Sdim  // Parse the section header table if it is present.
673351278Sdim  if (Obj->getNumberOfSections()) {
674351278Sdim    auto SecHeadersOrErr = getObject<void>(Data, Base + CurOffset,
675351278Sdim                                           Obj->getNumberOfSections() *
676351278Sdim                                               Obj->getSectionHeaderSize());
677351278Sdim    if (Error E = SecHeadersOrErr.takeError())
678351278Sdim      return std::move(E);
679351278Sdim    Obj->SectionHeaderTable = SecHeadersOrErr.get();
680351278Sdim  }
681351278Sdim
682351278Sdim  // 64-bit object supports only file header and section headers for now.
683351278Sdim  if (Obj->is64Bit())
684351278Sdim    return std::move(Obj);
685351278Sdim
686351278Sdim  // If there is no symbol table we are done parsing the memory buffer.
687351278Sdim  if (Obj->getLogicalNumberOfSymbolTableEntries32() == 0)
688351278Sdim    return std::move(Obj);
689351278Sdim
690351278Sdim  // Parse symbol table.
691351278Sdim  CurOffset = Obj->fileHeader32()->SymbolTableOffset;
692351278Sdim  uint64_t SymbolTableSize = (uint64_t)(sizeof(XCOFFSymbolEntry)) *
693351278Sdim                             Obj->getLogicalNumberOfSymbolTableEntries32();
694351278Sdim  auto SymTableOrErr =
695351278Sdim      getObject<XCOFFSymbolEntry>(Data, Base + CurOffset, SymbolTableSize);
696351278Sdim  if (Error E = SymTableOrErr.takeError())
697351278Sdim    return std::move(E);
698351278Sdim  Obj->SymbolTblPtr = SymTableOrErr.get();
699351278Sdim  CurOffset += SymbolTableSize;
700351278Sdim
701351278Sdim  // Parse String table.
702351278Sdim  Expected<XCOFFStringTable> StringTableOrErr =
703351278Sdim      parseStringTable(Obj.get(), CurOffset);
704351278Sdim  if (Error E = StringTableOrErr.takeError())
705351278Sdim    return std::move(E);
706351278Sdim  Obj->StringTable = StringTableOrErr.get();
707351278Sdim
708351278Sdim  return std::move(Obj);
709351278Sdim}
710351278Sdim
711351278SdimExpected<std::unique_ptr<ObjectFile>>
712351278SdimObjectFile::createXCOFFObjectFile(MemoryBufferRef MemBufRef,
713351278Sdim                                  unsigned FileType) {
714351278Sdim  return XCOFFObjectFile::create(FileType, MemBufRef);
715351278Sdim}
716351278Sdim
717360784SdimXCOFF::StorageClass XCOFFSymbolRef::getStorageClass() const {
718360784Sdim  return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->StorageClass;
719351278Sdim}
720351278Sdim
721360784Sdimuint8_t XCOFFSymbolRef::getNumberOfAuxEntries() const {
722360784Sdim  return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->NumberOfAuxEntries;
723351278Sdim}
724351278Sdim
725360784Sdimconst XCOFFCsectAuxEnt32 *XCOFFSymbolRef::getXCOFFCsectAuxEnt32() const {
726360784Sdim  assert(!OwningObjectPtr->is64Bit() &&
727360784Sdim         "32-bit interface called on 64-bit object file.");
728360784Sdim  assert(hasCsectAuxEnt() && "No Csect Auxiliary Entry is found.");
729360784Sdim
730360784Sdim  // In XCOFF32, the csect auxilliary entry is always the last auxiliary
731360784Sdim  // entry for the symbol.
732360784Sdim  uintptr_t AuxAddr = getWithOffset(
733360784Sdim      SymEntDataRef.p, XCOFF::SymbolTableEntrySize * getNumberOfAuxEntries());
734360784Sdim
735360784Sdim#ifndef NDEBUG
736360784Sdim  OwningObjectPtr->checkSymbolEntryPointer(AuxAddr);
737360784Sdim#endif
738360784Sdim
739360784Sdim  return reinterpret_cast<const XCOFFCsectAuxEnt32 *>(AuxAddr);
740360784Sdim}
741360784Sdim
742360784Sdimuint16_t XCOFFSymbolRef::getType() const {
743360784Sdim  return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->SymbolType;
744360784Sdim}
745360784Sdim
746360784Sdimint16_t XCOFFSymbolRef::getSectionNumber() const {
747360784Sdim  return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->SectionNumber;
748360784Sdim}
749360784Sdim
750360784Sdimbool XCOFFSymbolRef::hasCsectAuxEnt() const {
751360784Sdim  XCOFF::StorageClass SC = getStorageClass();
752360784Sdim  return (SC == XCOFF::C_EXT || SC == XCOFF::C_WEAKEXT ||
753360784Sdim          SC == XCOFF::C_HIDEXT);
754360784Sdim}
755360784Sdim
756360784Sdimbool XCOFFSymbolRef::isFunction() const {
757360784Sdim  if (OwningObjectPtr->is64Bit())
758360784Sdim    report_fatal_error("64-bit support is unimplemented yet.");
759360784Sdim
760360784Sdim  if (getType() & FUNCTION_SYM)
761360784Sdim    return true;
762360784Sdim
763360784Sdim  if (!hasCsectAuxEnt())
764360784Sdim    return false;
765360784Sdim
766360784Sdim  const XCOFFCsectAuxEnt32 *CsectAuxEnt = getXCOFFCsectAuxEnt32();
767360784Sdim
768360784Sdim  // A function definition should be a label definition.
769360784Sdim  if ((CsectAuxEnt->SymbolAlignmentAndType & SYM_TYPE_MASK) != XCOFF::XTY_LD)
770360784Sdim    return false;
771360784Sdim
772360784Sdim  if (CsectAuxEnt->StorageMappingClass != XCOFF::XMC_PR)
773360784Sdim    return false;
774360784Sdim
775360784Sdim  int16_t SectNum = getSectionNumber();
776360784Sdim  Expected<DataRefImpl> SI = OwningObjectPtr->getSectionByNum(SectNum);
777360784Sdim  if (!SI)
778360784Sdim    return false;
779360784Sdim
780360784Sdim  return (OwningObjectPtr->getSectionFlags(SI.get()) & XCOFF::STYP_TEXT);
781360784Sdim}
782360784Sdim
783360784Sdim// Explictly instantiate template classes.
784360784Sdimtemplate struct XCOFFSectionHeader<XCOFFSectionHeader32>;
785360784Sdimtemplate struct XCOFFSectionHeader<XCOFFSectionHeader64>;
786360784Sdim
787351278Sdim} // namespace object
788351278Sdim} // namespace llvm
789