XCOFFObjectFile.cpp revision 360784
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 <cstddef>
15#include <cstring>
16
17namespace llvm {
18namespace object {
19
20enum { FUNCTION_SYM = 0x20, SYM_TYPE_MASK = 0x07, RELOC_OVERFLOW = 65535 };
21
22// Checks that [Ptr, Ptr + Size) bytes fall inside the memory buffer
23// 'M'. Returns a pointer to the underlying object on success.
24template <typename T>
25static Expected<const T *> getObject(MemoryBufferRef M, const void *Ptr,
26                                     const uint64_t Size = sizeof(T)) {
27  uintptr_t Addr = uintptr_t(Ptr);
28  if (std::error_code EC = Binary::checkOffset(M, Addr, Size))
29    return errorCodeToError(EC);
30  return reinterpret_cast<const T *>(Addr);
31}
32
33static uintptr_t getWithOffset(uintptr_t Base, ptrdiff_t Offset) {
34  return reinterpret_cast<uintptr_t>(reinterpret_cast<const char *>(Base) +
35                                     Offset);
36}
37
38template <typename T> static const T *viewAs(uintptr_t in) {
39  return reinterpret_cast<const T *>(in);
40}
41
42static StringRef generateXCOFFFixedNameStringRef(const char *Name) {
43  auto NulCharPtr =
44      static_cast<const char *>(memchr(Name, '\0', XCOFF::NameSize));
45  return NulCharPtr ? StringRef(Name, NulCharPtr - Name)
46                    : StringRef(Name, XCOFF::NameSize);
47}
48
49template <typename T> StringRef XCOFFSectionHeader<T>::getName() const {
50  const T &DerivedXCOFFSectionHeader = static_cast<const T &>(*this);
51  return generateXCOFFFixedNameStringRef(DerivedXCOFFSectionHeader.Name);
52}
53
54template <typename T> uint16_t XCOFFSectionHeader<T>::getSectionType() const {
55  const T &DerivedXCOFFSectionHeader = static_cast<const T &>(*this);
56  return DerivedXCOFFSectionHeader.Flags & SectionFlagsTypeMask;
57}
58
59template <typename T>
60bool XCOFFSectionHeader<T>::isReservedSectionType() const {
61  return getSectionType() & SectionFlagsReservedMask;
62}
63
64bool XCOFFRelocation32::isRelocationSigned() const {
65  return Info & XR_SIGN_INDICATOR_MASK;
66}
67
68bool XCOFFRelocation32::isFixupIndicated() const {
69  return Info & XR_FIXUP_INDICATOR_MASK;
70}
71
72uint8_t XCOFFRelocation32::getRelocatedLength() const {
73  // The relocation encodes the bit length being relocated minus 1. Add back
74  // the 1 to get the actual length being relocated.
75  return (Info & XR_BIASED_LENGTH_MASK) + 1;
76}
77
78void XCOFFObjectFile::checkSectionAddress(uintptr_t Addr,
79                                          uintptr_t TableAddress) const {
80  if (Addr < TableAddress)
81    report_fatal_error("Section header outside of section header table.");
82
83  uintptr_t Offset = Addr - TableAddress;
84  if (Offset >= getSectionHeaderSize() * getNumberOfSections())
85    report_fatal_error("Section header outside of section header table.");
86
87  if (Offset % getSectionHeaderSize() != 0)
88    report_fatal_error(
89        "Section header pointer does not point to a valid section header.");
90}
91
92const XCOFFSectionHeader32 *
93XCOFFObjectFile::toSection32(DataRefImpl Ref) const {
94  assert(!is64Bit() && "32-bit interface called on 64-bit object file.");
95#ifndef NDEBUG
96  checkSectionAddress(Ref.p, getSectionHeaderTableAddress());
97#endif
98  return viewAs<XCOFFSectionHeader32>(Ref.p);
99}
100
101const XCOFFSectionHeader64 *
102XCOFFObjectFile::toSection64(DataRefImpl Ref) const {
103  assert(is64Bit() && "64-bit interface called on a 32-bit object file.");
104#ifndef NDEBUG
105  checkSectionAddress(Ref.p, getSectionHeaderTableAddress());
106#endif
107  return viewAs<XCOFFSectionHeader64>(Ref.p);
108}
109
110const XCOFFSymbolEntry *XCOFFObjectFile::toSymbolEntry(DataRefImpl Ref) const {
111  assert(!is64Bit() && "Symbol table support not implemented for 64-bit.");
112  assert(Ref.p != 0 && "Symbol table pointer can not be nullptr!");
113#ifndef NDEBUG
114  checkSymbolEntryPointer(Ref.p);
115#endif
116  auto SymEntPtr = viewAs<XCOFFSymbolEntry>(Ref.p);
117  return SymEntPtr;
118}
119
120const XCOFFFileHeader32 *XCOFFObjectFile::fileHeader32() const {
121  assert(!is64Bit() && "32-bit interface called on 64-bit object file.");
122  return static_cast<const XCOFFFileHeader32 *>(FileHeader);
123}
124
125const XCOFFFileHeader64 *XCOFFObjectFile::fileHeader64() const {
126  assert(is64Bit() && "64-bit interface called on a 32-bit object file.");
127  return static_cast<const XCOFFFileHeader64 *>(FileHeader);
128}
129
130const XCOFFSectionHeader32 *
131XCOFFObjectFile::sectionHeaderTable32() const {
132  assert(!is64Bit() && "32-bit interface called on 64-bit object file.");
133  return static_cast<const XCOFFSectionHeader32 *>(SectionHeaderTable);
134}
135
136const XCOFFSectionHeader64 *
137XCOFFObjectFile::sectionHeaderTable64() const {
138  assert(is64Bit() && "64-bit interface called on a 32-bit object file.");
139  return static_cast<const XCOFFSectionHeader64 *>(SectionHeaderTable);
140}
141
142void XCOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const {
143  const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb);
144  SymEntPtr += SymEntPtr->NumberOfAuxEntries + 1;
145#ifndef NDEBUG
146  // This function is used by basic_symbol_iterator, which allows to
147  // point to the end-of-symbol-table address.
148  if (reinterpret_cast<uintptr_t>(SymEntPtr) != getEndOfSymbolTableAddress())
149    checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(SymEntPtr));
150#endif
151  Symb.p = reinterpret_cast<uintptr_t>(SymEntPtr);
152}
153
154Expected<StringRef>
155XCOFFObjectFile::getStringTableEntry(uint32_t Offset) const {
156  // The byte offset is relative to the start of the string table.
157  // A byte offset value of 0 is a null or zero-length symbol
158  // name. A byte offset in the range 1 to 3 (inclusive) points into the length
159  // field; as a soft-error recovery mechanism, we treat such cases as having an
160  // offset of 0.
161  if (Offset < 4)
162    return StringRef(nullptr, 0);
163
164  if (StringTable.Data != nullptr && StringTable.Size > Offset)
165    return (StringTable.Data + Offset);
166
167  return make_error<GenericBinaryError>("Bad offset for string table entry",
168                                        object_error::parse_failed);
169}
170
171Expected<StringRef>
172XCOFFObjectFile::getCFileName(const XCOFFFileAuxEnt *CFileEntPtr) const {
173  if (CFileEntPtr->NameInStrTbl.Magic !=
174      XCOFFSymbolEntry::NAME_IN_STR_TBL_MAGIC)
175    return generateXCOFFFixedNameStringRef(CFileEntPtr->Name);
176  return getStringTableEntry(CFileEntPtr->NameInStrTbl.Offset);
177}
178
179Expected<StringRef> XCOFFObjectFile::getSymbolName(DataRefImpl Symb) const {
180  const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb);
181
182  // A storage class value with the high-order bit on indicates that the name is
183  // a symbolic debugger stabstring.
184  if (SymEntPtr->StorageClass & 0x80)
185    return StringRef("Unimplemented Debug Name");
186
187  if (SymEntPtr->NameInStrTbl.Magic != XCOFFSymbolEntry::NAME_IN_STR_TBL_MAGIC)
188    return generateXCOFFFixedNameStringRef(SymEntPtr->SymbolName);
189
190  return getStringTableEntry(SymEntPtr->NameInStrTbl.Offset);
191}
192
193Expected<uint64_t> XCOFFObjectFile::getSymbolAddress(DataRefImpl Symb) const {
194  assert(!is64Bit() && "Symbol table support not implemented for 64-bit.");
195  return toSymbolEntry(Symb)->Value;
196}
197
198uint64_t XCOFFObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
199  assert(!is64Bit() && "Symbol table support not implemented for 64-bit.");
200  return toSymbolEntry(Symb)->Value;
201}
202
203uint64_t XCOFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
204  uint64_t Result = 0;
205  llvm_unreachable("Not yet implemented!");
206  return Result;
207}
208
209Expected<SymbolRef::Type>
210XCOFFObjectFile::getSymbolType(DataRefImpl Symb) const {
211  llvm_unreachable("Not yet implemented!");
212  return SymbolRef::ST_Other;
213}
214
215Expected<section_iterator>
216XCOFFObjectFile::getSymbolSection(DataRefImpl Symb) const {
217  const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb);
218  int16_t SectNum = SymEntPtr->SectionNumber;
219
220  if (isReservedSectionNumber(SectNum))
221    return section_end();
222
223  Expected<DataRefImpl> ExpSec = getSectionByNum(SectNum);
224  if (!ExpSec)
225    return ExpSec.takeError();
226
227  return section_iterator(SectionRef(ExpSec.get(), this));
228}
229
230void XCOFFObjectFile::moveSectionNext(DataRefImpl &Sec) const {
231  const char *Ptr = reinterpret_cast<const char *>(Sec.p);
232  Sec.p = reinterpret_cast<uintptr_t>(Ptr + getSectionHeaderSize());
233}
234
235Expected<StringRef> XCOFFObjectFile::getSectionName(DataRefImpl Sec) const {
236  return generateXCOFFFixedNameStringRef(getSectionNameInternal(Sec));
237}
238
239uint64_t XCOFFObjectFile::getSectionAddress(DataRefImpl Sec) const {
240  // Avoid ternary due to failure to convert the ubig32_t value to a unit64_t
241  // with MSVC.
242  if (is64Bit())
243    return toSection64(Sec)->VirtualAddress;
244
245  return toSection32(Sec)->VirtualAddress;
246}
247
248uint64_t XCOFFObjectFile::getSectionIndex(DataRefImpl Sec) const {
249  // Section numbers in XCOFF are numbered beginning at 1. A section number of
250  // zero is used to indicate that a symbol is being imported or is undefined.
251  if (is64Bit())
252    return toSection64(Sec) - sectionHeaderTable64() + 1;
253  else
254    return toSection32(Sec) - sectionHeaderTable32() + 1;
255}
256
257uint64_t XCOFFObjectFile::getSectionSize(DataRefImpl Sec) const {
258  // Avoid ternary due to failure to convert the ubig32_t value to a unit64_t
259  // with MSVC.
260  if (is64Bit())
261    return toSection64(Sec)->SectionSize;
262
263  return toSection32(Sec)->SectionSize;
264}
265
266Expected<ArrayRef<uint8_t>>
267XCOFFObjectFile::getSectionContents(DataRefImpl Sec) const {
268  if (isSectionVirtual(Sec))
269    return ArrayRef<uint8_t>();
270
271  uint64_t OffsetToRaw;
272  if (is64Bit())
273    OffsetToRaw = toSection64(Sec)->FileOffsetToRawData;
274  else
275    OffsetToRaw = toSection32(Sec)->FileOffsetToRawData;
276
277  const uint8_t * ContentStart = base() + OffsetToRaw;
278  uint64_t SectionSize = getSectionSize(Sec);
279  if (checkOffset(Data, uintptr_t(ContentStart), SectionSize))
280    return make_error<BinaryError>();
281
282  return makeArrayRef(ContentStart,SectionSize);
283}
284
285uint64_t XCOFFObjectFile::getSectionAlignment(DataRefImpl Sec) const {
286  uint64_t Result = 0;
287  llvm_unreachable("Not yet implemented!");
288  return Result;
289}
290
291bool XCOFFObjectFile::isSectionCompressed(DataRefImpl Sec) const {
292  bool Result = false;
293  llvm_unreachable("Not yet implemented!");
294  return Result;
295}
296
297bool XCOFFObjectFile::isSectionText(DataRefImpl Sec) const {
298  return getSectionFlags(Sec) & XCOFF::STYP_TEXT;
299}
300
301bool XCOFFObjectFile::isSectionData(DataRefImpl Sec) const {
302  uint32_t Flags = getSectionFlags(Sec);
303  return Flags & (XCOFF::STYP_DATA | XCOFF::STYP_TDATA);
304}
305
306bool XCOFFObjectFile::isSectionBSS(DataRefImpl Sec) const {
307  uint32_t Flags = getSectionFlags(Sec);
308  return Flags & (XCOFF::STYP_BSS | XCOFF::STYP_TBSS);
309}
310
311bool XCOFFObjectFile::isSectionVirtual(DataRefImpl Sec) const {
312  return is64Bit() ? toSection64(Sec)->FileOffsetToRawData == 0
313                   : toSection32(Sec)->FileOffsetToRawData == 0;
314}
315
316relocation_iterator XCOFFObjectFile::section_rel_begin(DataRefImpl Sec) const {
317  llvm_unreachable("Not yet implemented!");
318  return relocation_iterator(RelocationRef());
319}
320
321relocation_iterator XCOFFObjectFile::section_rel_end(DataRefImpl Sec) const {
322  llvm_unreachable("Not yet implemented!");
323  return relocation_iterator(RelocationRef());
324}
325
326void XCOFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const {
327  llvm_unreachable("Not yet implemented!");
328  return;
329}
330
331uint64_t XCOFFObjectFile::getRelocationOffset(DataRefImpl Rel) const {
332  llvm_unreachable("Not yet implemented!");
333  uint64_t Result = 0;
334  return Result;
335}
336
337symbol_iterator XCOFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
338  llvm_unreachable("Not yet implemented!");
339  return symbol_iterator(SymbolRef());
340}
341
342uint64_t XCOFFObjectFile::getRelocationType(DataRefImpl Rel) const {
343  llvm_unreachable("Not yet implemented!");
344  uint64_t Result = 0;
345  return Result;
346}
347
348void XCOFFObjectFile::getRelocationTypeName(
349    DataRefImpl Rel, SmallVectorImpl<char> &Result) const {
350  llvm_unreachable("Not yet implemented!");
351  return;
352}
353
354uint32_t XCOFFObjectFile::getSymbolFlags(DataRefImpl Symb) const {
355  uint32_t Result = 0;
356  llvm_unreachable("Not yet implemented!");
357  return Result;
358}
359
360basic_symbol_iterator XCOFFObjectFile::symbol_begin() const {
361  assert(!is64Bit() && "64-bit support not implemented yet.");
362  DataRefImpl SymDRI;
363  SymDRI.p = reinterpret_cast<uintptr_t>(SymbolTblPtr);
364  return basic_symbol_iterator(SymbolRef(SymDRI, this));
365}
366
367basic_symbol_iterator XCOFFObjectFile::symbol_end() const {
368  assert(!is64Bit() && "64-bit support not implemented yet.");
369  DataRefImpl SymDRI;
370  SymDRI.p = reinterpret_cast<uintptr_t>(
371      SymbolTblPtr + getLogicalNumberOfSymbolTableEntries32());
372  return basic_symbol_iterator(SymbolRef(SymDRI, this));
373}
374
375section_iterator XCOFFObjectFile::section_begin() const {
376  DataRefImpl DRI;
377  DRI.p = getSectionHeaderTableAddress();
378  return section_iterator(SectionRef(DRI, this));
379}
380
381section_iterator XCOFFObjectFile::section_end() const {
382  DataRefImpl DRI;
383  DRI.p = getWithOffset(getSectionHeaderTableAddress(),
384                        getNumberOfSections() * getSectionHeaderSize());
385  return section_iterator(SectionRef(DRI, this));
386}
387
388uint8_t XCOFFObjectFile::getBytesInAddress() const { return is64Bit() ? 8 : 4; }
389
390StringRef XCOFFObjectFile::getFileFormatName() const {
391  return is64Bit() ? "aix5coff64-rs6000" : "aixcoff-rs6000";
392}
393
394Triple::ArchType XCOFFObjectFile::getArch() const {
395  return is64Bit() ? Triple::ppc64 : Triple::ppc;
396}
397
398SubtargetFeatures XCOFFObjectFile::getFeatures() const {
399  return SubtargetFeatures();
400}
401
402bool XCOFFObjectFile::isRelocatableObject() const {
403  bool Result = false;
404  llvm_unreachable("Not yet implemented!");
405  return Result;
406}
407
408Expected<uint64_t> XCOFFObjectFile::getStartAddress() const {
409  // TODO FIXME Should get from auxiliary_header->o_entry when support for the
410  // auxiliary_header is added.
411  return 0;
412}
413
414size_t XCOFFObjectFile::getFileHeaderSize() const {
415  return is64Bit() ? sizeof(XCOFFFileHeader64) : sizeof(XCOFFFileHeader32);
416}
417
418size_t XCOFFObjectFile::getSectionHeaderSize() const {
419  return is64Bit() ? sizeof(XCOFFSectionHeader64) :
420                     sizeof(XCOFFSectionHeader32);
421}
422
423bool XCOFFObjectFile::is64Bit() const {
424  return Binary::ID_XCOFF64 == getType();
425}
426
427uint16_t XCOFFObjectFile::getMagic() const {
428  return is64Bit() ? fileHeader64()->Magic : fileHeader32()->Magic;
429}
430
431Expected<DataRefImpl> XCOFFObjectFile::getSectionByNum(int16_t Num) const {
432  if (Num <= 0 || Num > getNumberOfSections())
433    return errorCodeToError(object_error::invalid_section_index);
434
435  DataRefImpl DRI;
436  DRI.p = getWithOffset(getSectionHeaderTableAddress(),
437                        getSectionHeaderSize() * (Num - 1));
438  return DRI;
439}
440
441Expected<StringRef>
442XCOFFObjectFile::getSymbolSectionName(const XCOFFSymbolEntry *SymEntPtr) const {
443  assert(!is64Bit() && "Symbol table support not implemented for 64-bit.");
444  int16_t SectionNum = SymEntPtr->SectionNumber;
445
446  switch (SectionNum) {
447  case XCOFF::N_DEBUG:
448    return "N_DEBUG";
449  case XCOFF::N_ABS:
450    return "N_ABS";
451  case XCOFF::N_UNDEF:
452    return "N_UNDEF";
453  default:
454    Expected<DataRefImpl> SecRef = getSectionByNum(SectionNum);
455    if (SecRef)
456      return generateXCOFFFixedNameStringRef(
457          getSectionNameInternal(SecRef.get()));
458    return SecRef.takeError();
459  }
460}
461
462bool XCOFFObjectFile::isReservedSectionNumber(int16_t SectionNumber) {
463  return (SectionNumber <= 0 && SectionNumber >= -2);
464}
465
466uint16_t XCOFFObjectFile::getNumberOfSections() const {
467  return is64Bit() ? fileHeader64()->NumberOfSections
468                   : fileHeader32()->NumberOfSections;
469}
470
471int32_t XCOFFObjectFile::getTimeStamp() const {
472  return is64Bit() ? fileHeader64()->TimeStamp : fileHeader32()->TimeStamp;
473}
474
475uint16_t XCOFFObjectFile::getOptionalHeaderSize() const {
476  return is64Bit() ? fileHeader64()->AuxHeaderSize
477                   : fileHeader32()->AuxHeaderSize;
478}
479
480uint32_t XCOFFObjectFile::getSymbolTableOffset32() const {
481  return fileHeader32()->SymbolTableOffset;
482}
483
484int32_t XCOFFObjectFile::getRawNumberOfSymbolTableEntries32() const {
485  // As far as symbol table size is concerned, if this field is negative it is
486  // to be treated as a 0. However since this field is also used for printing we
487  // don't want to truncate any negative values.
488  return fileHeader32()->NumberOfSymTableEntries;
489}
490
491uint32_t XCOFFObjectFile::getLogicalNumberOfSymbolTableEntries32() const {
492  return (fileHeader32()->NumberOfSymTableEntries >= 0
493              ? fileHeader32()->NumberOfSymTableEntries
494              : 0);
495}
496
497uint64_t XCOFFObjectFile::getSymbolTableOffset64() const {
498  return fileHeader64()->SymbolTableOffset;
499}
500
501uint32_t XCOFFObjectFile::getNumberOfSymbolTableEntries64() const {
502  return fileHeader64()->NumberOfSymTableEntries;
503}
504
505uintptr_t XCOFFObjectFile::getEndOfSymbolTableAddress() const {
506  uint32_t NumberOfSymTableEntries =
507      is64Bit() ? getNumberOfSymbolTableEntries64()
508                : getLogicalNumberOfSymbolTableEntries32();
509  return getWithOffset(reinterpret_cast<uintptr_t>(SymbolTblPtr),
510                       XCOFF::SymbolTableEntrySize * NumberOfSymTableEntries);
511}
512
513void XCOFFObjectFile::checkSymbolEntryPointer(uintptr_t SymbolEntPtr) const {
514  if (SymbolEntPtr < reinterpret_cast<uintptr_t>(SymbolTblPtr))
515    report_fatal_error("Symbol table entry is outside of symbol table.");
516
517  if (SymbolEntPtr >= getEndOfSymbolTableAddress())
518    report_fatal_error("Symbol table entry is outside of symbol table.");
519
520  ptrdiff_t Offset = reinterpret_cast<const char *>(SymbolEntPtr) -
521                     reinterpret_cast<const char *>(SymbolTblPtr);
522
523  if (Offset % XCOFF::SymbolTableEntrySize != 0)
524    report_fatal_error(
525        "Symbol table entry position is not valid inside of symbol table.");
526}
527
528uint32_t XCOFFObjectFile::getSymbolIndex(uintptr_t SymbolEntPtr) const {
529  return (reinterpret_cast<const char *>(SymbolEntPtr) -
530          reinterpret_cast<const char *>(SymbolTblPtr)) /
531         XCOFF::SymbolTableEntrySize;
532}
533
534Expected<StringRef>
535XCOFFObjectFile::getSymbolNameByIndex(uint32_t Index) const {
536  if (is64Bit())
537    report_fatal_error("64-bit symbol table support not implemented yet.");
538
539  if (Index >= getLogicalNumberOfSymbolTableEntries32())
540    return errorCodeToError(object_error::invalid_symbol_index);
541
542  DataRefImpl SymDRI;
543  SymDRI.p = reinterpret_cast<uintptr_t>(getPointerToSymbolTable() + Index);
544  return getSymbolName(SymDRI);
545}
546
547uint16_t XCOFFObjectFile::getFlags() const {
548  return is64Bit() ? fileHeader64()->Flags : fileHeader32()->Flags;
549}
550
551const char *XCOFFObjectFile::getSectionNameInternal(DataRefImpl Sec) const {
552  return is64Bit() ? toSection64(Sec)->Name : toSection32(Sec)->Name;
553}
554
555uintptr_t XCOFFObjectFile::getSectionHeaderTableAddress() const {
556  return reinterpret_cast<uintptr_t>(SectionHeaderTable);
557}
558
559int32_t XCOFFObjectFile::getSectionFlags(DataRefImpl Sec) const {
560  return is64Bit() ? toSection64(Sec)->Flags : toSection32(Sec)->Flags;
561}
562
563XCOFFObjectFile::XCOFFObjectFile(unsigned int Type, MemoryBufferRef Object)
564    : ObjectFile(Type, Object) {
565  assert(Type == Binary::ID_XCOFF32 || Type == Binary::ID_XCOFF64);
566}
567
568ArrayRef<XCOFFSectionHeader64> XCOFFObjectFile::sections64() const {
569  assert(is64Bit() && "64-bit interface called for non 64-bit file.");
570  const XCOFFSectionHeader64 *TablePtr = sectionHeaderTable64();
571  return ArrayRef<XCOFFSectionHeader64>(TablePtr,
572                                        TablePtr + getNumberOfSections());
573}
574
575ArrayRef<XCOFFSectionHeader32> XCOFFObjectFile::sections32() const {
576  assert(!is64Bit() && "32-bit interface called for non 32-bit file.");
577  const XCOFFSectionHeader32 *TablePtr = sectionHeaderTable32();
578  return ArrayRef<XCOFFSectionHeader32>(TablePtr,
579                                        TablePtr + getNumberOfSections());
580}
581
582// In an XCOFF32 file, when the field value is 65535, then an STYP_OVRFLO
583// section header contains the actual count of relocation entries in the s_paddr
584// field. STYP_OVRFLO headers contain the section index of their corresponding
585// sections as their raw "NumberOfRelocations" field value.
586Expected<uint32_t> XCOFFObjectFile::getLogicalNumberOfRelocationEntries(
587    const XCOFFSectionHeader32 &Sec) const {
588
589  uint16_t SectionIndex = &Sec - sectionHeaderTable32() + 1;
590
591  if (Sec.NumberOfRelocations < RELOC_OVERFLOW)
592    return Sec.NumberOfRelocations;
593  for (const auto &Sec : sections32()) {
594    if (Sec.Flags == XCOFF::STYP_OVRFLO &&
595        Sec.NumberOfRelocations == SectionIndex)
596      return Sec.PhysicalAddress;
597  }
598  return errorCodeToError(object_error::parse_failed);
599}
600
601Expected<ArrayRef<XCOFFRelocation32>>
602XCOFFObjectFile::relocations(const XCOFFSectionHeader32 &Sec) const {
603  uintptr_t RelocAddr = getWithOffset(reinterpret_cast<uintptr_t>(FileHeader),
604                                      Sec.FileOffsetToRelocationInfo);
605  auto NumRelocEntriesOrErr = getLogicalNumberOfRelocationEntries(Sec);
606  if (Error E = NumRelocEntriesOrErr.takeError())
607    return std::move(E);
608
609  uint32_t NumRelocEntries = NumRelocEntriesOrErr.get();
610
611  auto RelocationOrErr =
612      getObject<XCOFFRelocation32>(Data, reinterpret_cast<void *>(RelocAddr),
613                                   NumRelocEntries * sizeof(XCOFFRelocation32));
614  if (Error E = RelocationOrErr.takeError())
615    return std::move(E);
616
617  const XCOFFRelocation32 *StartReloc = RelocationOrErr.get();
618
619  return ArrayRef<XCOFFRelocation32>(StartReloc, StartReloc + NumRelocEntries);
620}
621
622Expected<XCOFFStringTable>
623XCOFFObjectFile::parseStringTable(const XCOFFObjectFile *Obj, uint64_t Offset) {
624  // If there is a string table, then the buffer must contain at least 4 bytes
625  // for the string table's size. Not having a string table is not an error.
626  if (auto EC = Binary::checkOffset(
627          Obj->Data, reinterpret_cast<uintptr_t>(Obj->base() + Offset), 4))
628    return XCOFFStringTable{0, nullptr};
629
630  // Read the size out of the buffer.
631  uint32_t Size = support::endian::read32be(Obj->base() + Offset);
632
633  // If the size is less then 4, then the string table is just a size and no
634  // string data.
635  if (Size <= 4)
636    return XCOFFStringTable{4, nullptr};
637
638  auto StringTableOrErr =
639      getObject<char>(Obj->Data, Obj->base() + Offset, Size);
640  if (Error E = StringTableOrErr.takeError())
641    return std::move(E);
642
643  const char *StringTablePtr = StringTableOrErr.get();
644  if (StringTablePtr[Size - 1] != '\0')
645    return errorCodeToError(object_error::string_table_non_null_end);
646
647  return XCOFFStringTable{Size, StringTablePtr};
648}
649
650Expected<std::unique_ptr<XCOFFObjectFile>>
651XCOFFObjectFile::create(unsigned Type, MemoryBufferRef MBR) {
652  // Can't use std::make_unique because of the private constructor.
653  std::unique_ptr<XCOFFObjectFile> Obj;
654  Obj.reset(new XCOFFObjectFile(Type, MBR));
655
656  uint64_t CurOffset = 0;
657  const auto *Base = Obj->base();
658  MemoryBufferRef Data = Obj->Data;
659
660  // Parse file header.
661  auto FileHeaderOrErr =
662      getObject<void>(Data, Base + CurOffset, Obj->getFileHeaderSize());
663  if (Error E = FileHeaderOrErr.takeError())
664    return std::move(E);
665  Obj->FileHeader = FileHeaderOrErr.get();
666
667  CurOffset += Obj->getFileHeaderSize();
668  // TODO FIXME we don't have support for an optional header yet, so just skip
669  // past it.
670  CurOffset += Obj->getOptionalHeaderSize();
671
672  // Parse the section header table if it is present.
673  if (Obj->getNumberOfSections()) {
674    auto SecHeadersOrErr = getObject<void>(Data, Base + CurOffset,
675                                           Obj->getNumberOfSections() *
676                                               Obj->getSectionHeaderSize());
677    if (Error E = SecHeadersOrErr.takeError())
678      return std::move(E);
679    Obj->SectionHeaderTable = SecHeadersOrErr.get();
680  }
681
682  // 64-bit object supports only file header and section headers for now.
683  if (Obj->is64Bit())
684    return std::move(Obj);
685
686  // If there is no symbol table we are done parsing the memory buffer.
687  if (Obj->getLogicalNumberOfSymbolTableEntries32() == 0)
688    return std::move(Obj);
689
690  // Parse symbol table.
691  CurOffset = Obj->fileHeader32()->SymbolTableOffset;
692  uint64_t SymbolTableSize = (uint64_t)(sizeof(XCOFFSymbolEntry)) *
693                             Obj->getLogicalNumberOfSymbolTableEntries32();
694  auto SymTableOrErr =
695      getObject<XCOFFSymbolEntry>(Data, Base + CurOffset, SymbolTableSize);
696  if (Error E = SymTableOrErr.takeError())
697    return std::move(E);
698  Obj->SymbolTblPtr = SymTableOrErr.get();
699  CurOffset += SymbolTableSize;
700
701  // Parse String table.
702  Expected<XCOFFStringTable> StringTableOrErr =
703      parseStringTable(Obj.get(), CurOffset);
704  if (Error E = StringTableOrErr.takeError())
705    return std::move(E);
706  Obj->StringTable = StringTableOrErr.get();
707
708  return std::move(Obj);
709}
710
711Expected<std::unique_ptr<ObjectFile>>
712ObjectFile::createXCOFFObjectFile(MemoryBufferRef MemBufRef,
713                                  unsigned FileType) {
714  return XCOFFObjectFile::create(FileType, MemBufRef);
715}
716
717XCOFF::StorageClass XCOFFSymbolRef::getStorageClass() const {
718  return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->StorageClass;
719}
720
721uint8_t XCOFFSymbolRef::getNumberOfAuxEntries() const {
722  return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->NumberOfAuxEntries;
723}
724
725const XCOFFCsectAuxEnt32 *XCOFFSymbolRef::getXCOFFCsectAuxEnt32() const {
726  assert(!OwningObjectPtr->is64Bit() &&
727         "32-bit interface called on 64-bit object file.");
728  assert(hasCsectAuxEnt() && "No Csect Auxiliary Entry is found.");
729
730  // In XCOFF32, the csect auxilliary entry is always the last auxiliary
731  // entry for the symbol.
732  uintptr_t AuxAddr = getWithOffset(
733      SymEntDataRef.p, XCOFF::SymbolTableEntrySize * getNumberOfAuxEntries());
734
735#ifndef NDEBUG
736  OwningObjectPtr->checkSymbolEntryPointer(AuxAddr);
737#endif
738
739  return reinterpret_cast<const XCOFFCsectAuxEnt32 *>(AuxAddr);
740}
741
742uint16_t XCOFFSymbolRef::getType() const {
743  return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->SymbolType;
744}
745
746int16_t XCOFFSymbolRef::getSectionNumber() const {
747  return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->SectionNumber;
748}
749
750bool XCOFFSymbolRef::hasCsectAuxEnt() const {
751  XCOFF::StorageClass SC = getStorageClass();
752  return (SC == XCOFF::C_EXT || SC == XCOFF::C_WEAKEXT ||
753          SC == XCOFF::C_HIDEXT);
754}
755
756bool XCOFFSymbolRef::isFunction() const {
757  if (OwningObjectPtr->is64Bit())
758    report_fatal_error("64-bit support is unimplemented yet.");
759
760  if (getType() & FUNCTION_SYM)
761    return true;
762
763  if (!hasCsectAuxEnt())
764    return false;
765
766  const XCOFFCsectAuxEnt32 *CsectAuxEnt = getXCOFFCsectAuxEnt32();
767
768  // A function definition should be a label definition.
769  if ((CsectAuxEnt->SymbolAlignmentAndType & SYM_TYPE_MASK) != XCOFF::XTY_LD)
770    return false;
771
772  if (CsectAuxEnt->StorageMappingClass != XCOFF::XMC_PR)
773    return false;
774
775  int16_t SectNum = getSectionNumber();
776  Expected<DataRefImpl> SI = OwningObjectPtr->getSectionByNum(SectNum);
777  if (!SI)
778    return false;
779
780  return (OwningObjectPtr->getSectionFlags(SI.get()) & XCOFF::STYP_TEXT);
781}
782
783// Explictly instantiate template classes.
784template struct XCOFFSectionHeader<XCOFFSectionHeader32>;
785template struct XCOFFSectionHeader<XCOFFSectionHeader64>;
786
787} // namespace object
788} // namespace llvm
789