1 //===- XCOFFObjectFile.h - XCOFF object file implementation -----*- C++ -*-===//
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 declares the XCOFFObjectFile class.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_OBJECT_XCOFFOBJECTFILE_H
14 #define LLVM_OBJECT_XCOFFOBJECTFILE_H
15 
16 #include "llvm/ADT/SmallString.h"
17 #include "llvm/ADT/SmallVector.h"
18 #include "llvm/BinaryFormat/XCOFF.h"
19 #include "llvm/Object/ObjectFile.h"
20 #include "llvm/Support/Endian.h"
21 #include <limits>
22 
23 namespace llvm {
24 namespace object {
25 
26 struct XCOFFFileHeader32 {
27   support::ubig16_t Magic;
28   support::ubig16_t NumberOfSections;
29 
30   // Unix time value, value of 0 indicates no timestamp.
31   // Negative values are reserved.
32   support::big32_t TimeStamp;
33 
34   support::ubig32_t SymbolTableOffset; // File offset to symbol table.
35   support::big32_t NumberOfSymTableEntries;
36   support::ubig16_t AuxHeaderSize;
37   support::ubig16_t Flags;
38 };
39 
40 struct XCOFFFileHeader64 {
41   support::ubig16_t Magic;
42   support::ubig16_t NumberOfSections;
43 
44   // Unix time value, value of 0 indicates no timestamp.
45   // Negative values are reserved.
46   support::big32_t TimeStamp;
47 
48   support::ubig64_t SymbolTableOffset; // File offset to symbol table.
49   support::ubig16_t AuxHeaderSize;
50   support::ubig16_t Flags;
51   support::ubig32_t NumberOfSymTableEntries;
52 };
53 
54 template <typename T> struct XCOFFAuxiliaryHeader {
55   static constexpr uint8_t AuxiHeaderFlagMask = 0xF0;
56   static constexpr uint8_t AuxiHeaderTDataAlignmentMask = 0x0F;
57 
58 public:
59   uint8_t getFlag() const {
60     return static_cast<const T *>(this)->FlagAndTDataAlignment &
61            AuxiHeaderFlagMask;
62   }
63 
64   uint8_t getTDataAlignment() const {
65     return static_cast<const T *>(this)->FlagAndTDataAlignment &
66            AuxiHeaderTDataAlignmentMask;
67   }
68 
69   uint16_t getVersion() const { return static_cast<const T *>(this)->Version; }
70 };
71 
72 struct XCOFFAuxiliaryHeader32 : XCOFFAuxiliaryHeader<XCOFFAuxiliaryHeader32> {
73   support::ubig16_t
74       AuxMagic; ///< If the value of the o_vstamp field is greater than 1, the
75                 ///< o_mflags field is reserved for future use and it should
76                 ///< contain 0. Otherwise, this field is not used.
77   support::ubig16_t
78       Version; ///< The valid values are 1 and 2. When the o_vstamp field is 2
79                ///< in an XCOFF32 file, the new interpretation of the n_type
80                ///< field in the symbol table entry is used.
81   support::ubig32_t TextSize;
82   support::ubig32_t InitDataSize;
83   support::ubig32_t BssDataSize;
84   support::ubig32_t EntryPointAddr;
85   support::ubig32_t TextStartAddr;
86   support::ubig32_t DataStartAddr;
87   support::ubig32_t TOCAnchorAddr;
88   support::ubig16_t SecNumOfEntryPoint;
89   support::ubig16_t SecNumOfText;
90   support::ubig16_t SecNumOfData;
91   support::ubig16_t SecNumOfTOC;
92   support::ubig16_t SecNumOfLoader;
93   support::ubig16_t SecNumOfBSS;
94   support::ubig16_t MaxAlignOfText;
95   support::ubig16_t MaxAlignOfData;
96   support::ubig16_t ModuleType;
97   uint8_t CpuFlag;
98   uint8_t CpuType;
99   support::ubig32_t MaxStackSize; ///< If the value is 0, the system default
100                                   ///< maximum stack size is used.
101   support::ubig32_t MaxDataSize;  ///< If the value is 0, the system default
102                                   ///< maximum data size is used.
103   support::ubig32_t
104       ReservedForDebugger; ///< This field should contain 0. When a loaded
105                            ///< program is being debugged, the memory image of
106                            ///< this field may be modified by a debugger to
107                            ///< insert a trap instruction.
108   uint8_t TextPageSize;  ///< Specifies the size of pages for the exec text. The
109                          ///< default value is 0 (system-selected page size).
110   uint8_t DataPageSize;  ///< Specifies the size of pages for the exec data. The
111                          ///< default value is 0 (system-selected page size).
112   uint8_t StackPageSize; ///< Specifies the size of pages for the stack. The
113                          ///< default value is 0 (system-selected page size).
114   uint8_t FlagAndTDataAlignment;
115   support::ubig16_t SecNumOfTData;
116   support::ubig16_t SecNumOfTBSS;
117 };
118 
119 struct XCOFFAuxiliaryHeader64 : XCOFFAuxiliaryHeader<XCOFFAuxiliaryHeader64> {
120   support::ubig16_t AuxMagic;
121   support::ubig16_t Version;
122   support::ubig32_t ReservedForDebugger;
123   support::ubig64_t TextStartAddr;
124   support::ubig64_t DataStartAddr;
125   support::ubig64_t TOCAnchorAddr;
126   support::ubig16_t SecNumOfEntryPoint;
127   support::ubig16_t SecNumOfText;
128   support::ubig16_t SecNumOfData;
129   support::ubig16_t SecNumOfTOC;
130   support::ubig16_t SecNumOfLoader;
131   support::ubig16_t SecNumOfBSS;
132   support::ubig16_t MaxAlignOfText;
133   support::ubig16_t MaxAlignOfData;
134   support::ubig16_t ModuleType;
135   uint8_t CpuFlag;
136   uint8_t CpuType;
137   uint8_t TextPageSize;
138   uint8_t DataPageSize;
139   uint8_t StackPageSize;
140   uint8_t FlagAndTDataAlignment;
141   support::ubig64_t TextSize;
142   support::ubig64_t InitDataSize;
143   support::ubig64_t BssDataSize;
144   support::ubig64_t EntryPointAddr;
145   support::ubig64_t MaxStackSize;
146   support::ubig64_t MaxDataSize;
147   support::ubig16_t SecNumOfTData;
148   support::ubig16_t SecNumOfTBSS;
149   support::ubig16_t XCOFF64Flag;
150 };
151 
152 template <typename T> struct XCOFFSectionHeader {
153   // Least significant 3 bits are reserved.
154   static constexpr unsigned SectionFlagsReservedMask = 0x7;
155 
156   // The low order 16 bits of section flags denotes the section type.
157   static constexpr unsigned SectionFlagsTypeMask = 0xffffu;
158 
159 public:
160   StringRef getName() const;
161   uint16_t getSectionType() const;
162   bool isReservedSectionType() const;
163 };
164 
165 // Explicit extern template declarations.
166 struct XCOFFSectionHeader32;
167 struct XCOFFSectionHeader64;
168 extern template struct XCOFFSectionHeader<XCOFFSectionHeader32>;
169 extern template struct XCOFFSectionHeader<XCOFFSectionHeader64>;
170 
171 struct XCOFFSectionHeader32 : XCOFFSectionHeader<XCOFFSectionHeader32> {
172   char Name[XCOFF::NameSize];
173   support::ubig32_t PhysicalAddress;
174   support::ubig32_t VirtualAddress;
175   support::ubig32_t SectionSize;
176   support::ubig32_t FileOffsetToRawData;
177   support::ubig32_t FileOffsetToRelocationInfo;
178   support::ubig32_t FileOffsetToLineNumberInfo;
179   support::ubig16_t NumberOfRelocations;
180   support::ubig16_t NumberOfLineNumbers;
181   support::big32_t Flags;
182 };
183 
184 struct XCOFFSectionHeader64 : XCOFFSectionHeader<XCOFFSectionHeader64> {
185   char Name[XCOFF::NameSize];
186   support::ubig64_t PhysicalAddress;
187   support::ubig64_t VirtualAddress;
188   support::ubig64_t SectionSize;
189   support::big64_t FileOffsetToRawData;
190   support::big64_t FileOffsetToRelocationInfo;
191   support::big64_t FileOffsetToLineNumberInfo;
192   support::ubig32_t NumberOfRelocations;
193   support::ubig32_t NumberOfLineNumbers;
194   support::big32_t Flags;
195   char Padding[4];
196 };
197 
198 struct LoaderSectionHeader32;
199 struct LoaderSectionHeader64;
200 struct LoaderSectionSymbolEntry32 {
201   struct NameOffsetInStrTbl {
202     support::big32_t IsNameInStrTbl; // Zero indicates name in string table.
203     support::ubig32_t Offset;
204   };
205 
206   char SymbolName[XCOFF::NameSize];
207   support::ubig32_t Value; // The virtual address of the symbol.
208   support::big16_t SectionNumber;
209   uint8_t SymbolType;
210   XCOFF::StorageClass StorageClass;
211   support::ubig32_t ImportFileID;
212   support::ubig32_t ParameterTypeCheck;
213 
214   Expected<StringRef>
215   getSymbolName(const LoaderSectionHeader32 *LoaderSecHeader) const;
216 };
217 
218 struct LoaderSectionSymbolEntry64 {
219   support::ubig64_t Value; // The virtual address of the symbol.
220   support::ubig32_t Offset;
221   support::big16_t SectionNumber;
222   uint8_t SymbolType;
223   XCOFF::StorageClass StorageClass;
224   support::ubig32_t ImportFileID;
225   support::ubig32_t ParameterTypeCheck;
226 
227   Expected<StringRef>
228   getSymbolName(const LoaderSectionHeader64 *LoaderSecHeader) const;
229 };
230 
231 struct LoaderSectionRelocationEntry32 {
232   support::ubig32_t VirtualAddr;
233   support::big32_t SymbolIndex;
234   support::ubig16_t Type;
235   support::big16_t SectionNum;
236 };
237 
238 struct LoaderSectionRelocationEntry64 {
239   support::ubig64_t VirtualAddr;
240   support::ubig16_t Type;
241   support::big16_t SectionNum;
242   support::big32_t SymbolIndex;
243 };
244 
245 struct LoaderSectionHeader32 {
246   support::ubig32_t Version;
247   support::ubig32_t NumberOfSymTabEnt;
248   support::ubig32_t NumberOfRelTabEnt;
249   support::ubig32_t LengthOfImpidStrTbl;
250   support::ubig32_t NumberOfImpid;
251   support::big32_t OffsetToImpid;
252   support::ubig32_t LengthOfStrTbl;
253   support::big32_t OffsetToStrTbl;
254 
255   uint64_t getOffsetToSymTbl() const {
256     return NumberOfSymTabEnt == 0 ? 0 : sizeof(LoaderSectionHeader32);
257   }
258 
259   uint64_t getOffsetToRelEnt() const {
260     // Relocation table is after Symbol table.
261     return NumberOfRelTabEnt == 0
262                ? 0
263                : sizeof(LoaderSectionHeader32) +
264                      sizeof(LoaderSectionSymbolEntry32) * NumberOfSymTabEnt;
265   }
266 };
267 
268 struct LoaderSectionHeader64 {
269   support::ubig32_t Version;
270   support::ubig32_t NumberOfSymTabEnt;
271   support::ubig32_t NumberOfRelTabEnt;
272   support::ubig32_t LengthOfImpidStrTbl;
273   support::ubig32_t NumberOfImpid;
274   support::ubig32_t LengthOfStrTbl;
275   support::big64_t OffsetToImpid;
276   support::big64_t OffsetToStrTbl;
277   support::big64_t OffsetToSymTbl;
278   support::big64_t OffsetToRelEnt;
279 
280   uint64_t getOffsetToSymTbl() const { return OffsetToSymTbl; }
281   uint64_t getOffsetToRelEnt() const { return OffsetToRelEnt; }
282 };
283 
284 template <typename AddressType> struct ExceptionSectionEntry {
285   union {
286     support::ubig32_t SymbolIdx;
287     AddressType TrapInstAddr;
288   };
289   uint8_t LangId;
290   uint8_t Reason;
291 
292   uint32_t getSymbolIndex() const {
293     assert(Reason == 0 && "Get symbol table index of the function only when "
294                           "the e_reason field is 0.");
295     return SymbolIdx;
296   }
297 
298   uint64_t getTrapInstAddr() const {
299     assert(Reason != 0 && "Zero is not a valid trap exception reason code.");
300     return TrapInstAddr;
301   }
302   uint8_t getLangID() const { return LangId; }
303   uint8_t getReason() const { return Reason; }
304 };
305 
306 typedef ExceptionSectionEntry<support::ubig32_t> ExceptionSectionEntry32;
307 typedef ExceptionSectionEntry<support::ubig64_t> ExceptionSectionEntry64;
308 
309 // Explicit extern template declarations.
310 extern template struct ExceptionSectionEntry<support::ubig32_t>;
311 extern template struct ExceptionSectionEntry<support::ubig64_t>;
312 
313 struct XCOFFStringTable {
314   uint32_t Size;
315   const char *Data;
316 };
317 
318 struct XCOFFCsectAuxEnt32 {
319   support::ubig32_t SectionOrLength;
320   support::ubig32_t ParameterHashIndex;
321   support::ubig16_t TypeChkSectNum;
322   uint8_t SymbolAlignmentAndType;
323   XCOFF::StorageMappingClass StorageMappingClass;
324   support::ubig32_t StabInfoIndex;
325   support::ubig16_t StabSectNum;
326 };
327 
328 struct XCOFFCsectAuxEnt64 {
329   support::ubig32_t SectionOrLengthLowByte;
330   support::ubig32_t ParameterHashIndex;
331   support::ubig16_t TypeChkSectNum;
332   uint8_t SymbolAlignmentAndType;
333   XCOFF::StorageMappingClass StorageMappingClass;
334   support::ubig32_t SectionOrLengthHighByte;
335   uint8_t Pad;
336   XCOFF::SymbolAuxType AuxType;
337 };
338 
339 class XCOFFCsectAuxRef {
340 public:
341   static constexpr uint8_t SymbolTypeMask = 0x07;
342   static constexpr uint8_t SymbolAlignmentMask = 0xF8;
343   static constexpr size_t SymbolAlignmentBitOffset = 3;
344 
345   XCOFFCsectAuxRef(const XCOFFCsectAuxEnt32 *Entry32) : Entry32(Entry32) {}
346   XCOFFCsectAuxRef(const XCOFFCsectAuxEnt64 *Entry64) : Entry64(Entry64) {}
347 
348   // For getSectionOrLength(),
349   // If the symbol type is XTY_SD or XTY_CM, the csect length.
350   // If the symbol type is XTY_LD, the symbol table
351   // index of the containing csect.
352   // If the symbol type is XTY_ER, 0.
353   uint64_t getSectionOrLength() const {
354     return Entry32 ? getSectionOrLength32() : getSectionOrLength64();
355   }
356 
357   uint32_t getSectionOrLength32() const {
358     assert(Entry32 && "32-bit interface called on 64-bit object file.");
359     return Entry32->SectionOrLength;
360   }
361 
362   uint64_t getSectionOrLength64() const {
363     assert(Entry64 && "64-bit interface called on 32-bit object file.");
364     return (static_cast<uint64_t>(Entry64->SectionOrLengthHighByte) << 32) |
365            Entry64->SectionOrLengthLowByte;
366   }
367 
368 #define GETVALUE(X) Entry32 ? Entry32->X : Entry64->X
369 
370   uint32_t getParameterHashIndex() const {
371     return GETVALUE(ParameterHashIndex);
372   }
373 
374   uint16_t getTypeChkSectNum() const { return GETVALUE(TypeChkSectNum); }
375 
376   XCOFF::StorageMappingClass getStorageMappingClass() const {
377     return GETVALUE(StorageMappingClass);
378   }
379 
380   uintptr_t getEntryAddress() const {
381     return Entry32 ? reinterpret_cast<uintptr_t>(Entry32)
382                    : reinterpret_cast<uintptr_t>(Entry64);
383   }
384 
385   uint16_t getAlignmentLog2() const {
386     return (getSymbolAlignmentAndType() & SymbolAlignmentMask) >>
387            SymbolAlignmentBitOffset;
388   }
389 
390   uint8_t getSymbolType() const {
391     return getSymbolAlignmentAndType() & SymbolTypeMask;
392   }
393 
394   bool isLabel() const { return getSymbolType() == XCOFF::XTY_LD; }
395 
396   uint32_t getStabInfoIndex32() const {
397     assert(Entry32 && "32-bit interface called on 64-bit object file.");
398     return Entry32->StabInfoIndex;
399   }
400 
401   uint16_t getStabSectNum32() const {
402     assert(Entry32 && "32-bit interface called on 64-bit object file.");
403     return Entry32->StabSectNum;
404   }
405 
406   XCOFF::SymbolAuxType getAuxType64() const {
407     assert(Entry64 && "64-bit interface called on 32-bit object file.");
408     return Entry64->AuxType;
409   }
410 
411 private:
412   uint8_t getSymbolAlignmentAndType() const {
413     return GETVALUE(SymbolAlignmentAndType);
414   }
415 
416 #undef GETVALUE
417 
418   const XCOFFCsectAuxEnt32 *Entry32 = nullptr;
419   const XCOFFCsectAuxEnt64 *Entry64 = nullptr;
420 };
421 
422 struct XCOFFFileAuxEnt {
423   typedef struct {
424     support::big32_t Magic; // Zero indicates name in string table.
425     support::ubig32_t Offset;
426     char NamePad[XCOFF::FileNamePadSize];
427   } NameInStrTblType;
428   union {
429     char Name[XCOFF::NameSize + XCOFF::FileNamePadSize];
430     NameInStrTblType NameInStrTbl;
431   };
432   XCOFF::CFileStringType Type;
433   uint8_t ReservedZeros[2];
434   XCOFF::SymbolAuxType AuxType; // 64-bit XCOFF file only.
435 };
436 
437 struct XCOFFSectAuxEntForStat {
438   support::ubig32_t SectionLength;
439   support::ubig16_t NumberOfRelocEnt;
440   support::ubig16_t NumberOfLineNum;
441   uint8_t Pad[10];
442 }; // 32-bit XCOFF file only.
443 
444 struct XCOFFFunctionAuxEnt32 {
445   support::ubig32_t OffsetToExceptionTbl;
446   support::ubig32_t SizeOfFunction;
447   support::ubig32_t PtrToLineNum;
448   support::big32_t SymIdxOfNextBeyond;
449   uint8_t Pad[2];
450 };
451 
452 struct XCOFFFunctionAuxEnt64 {
453   support::ubig64_t PtrToLineNum;
454   support::ubig32_t SizeOfFunction;
455   support::big32_t SymIdxOfNextBeyond;
456   uint8_t Pad;
457   XCOFF::SymbolAuxType AuxType; // Contains _AUX_FCN; Type of auxiliary entry
458 };
459 
460 struct XCOFFExceptionAuxEnt {
461   support::ubig64_t OffsetToExceptionTbl;
462   support::ubig32_t SizeOfFunction;
463   support::big32_t SymIdxOfNextBeyond;
464   uint8_t Pad;
465   XCOFF::SymbolAuxType AuxType; // Contains _AUX_EXCEPT; Type of auxiliary entry
466 };
467 
468 struct XCOFFBlockAuxEnt32 {
469   uint8_t ReservedZeros1[2];
470   support::ubig16_t LineNumHi;
471   support::ubig16_t LineNumLo;
472   uint8_t ReservedZeros2[12];
473 };
474 
475 struct XCOFFBlockAuxEnt64 {
476   support::ubig32_t LineNum;
477   uint8_t Pad[13];
478   XCOFF::SymbolAuxType AuxType; // Contains _AUX_SYM; Type of auxiliary entry
479 };
480 
481 struct XCOFFSectAuxEntForDWARF32 {
482   support::ubig32_t LengthOfSectionPortion;
483   uint8_t Pad1[4];
484   support::ubig32_t NumberOfRelocEnt;
485   uint8_t Pad2[6];
486 };
487 
488 struct XCOFFSectAuxEntForDWARF64 {
489   support::ubig64_t LengthOfSectionPortion;
490   support::ubig64_t NumberOfRelocEnt;
491   uint8_t Pad;
492   XCOFF::SymbolAuxType AuxType; // Contains _AUX_SECT; Type of Auxillary entry
493 };
494 
495 template <typename AddressType> struct XCOFFRelocation {
496 public:
497   AddressType VirtualAddress;
498   support::ubig32_t SymbolIndex;
499 
500   // Packed field, see XR_* masks for details of packing.
501   uint8_t Info;
502 
503   XCOFF::RelocationType Type;
504 
505 public:
506   bool isRelocationSigned() const;
507   bool isFixupIndicated() const;
508 
509   // Returns the number of bits being relocated.
510   uint8_t getRelocatedLength() const;
511 };
512 
513 extern template struct XCOFFRelocation<llvm::support::ubig32_t>;
514 extern template struct XCOFFRelocation<llvm::support::ubig64_t>;
515 
516 struct XCOFFRelocation32 : XCOFFRelocation<llvm::support::ubig32_t> {};
517 struct XCOFFRelocation64 : XCOFFRelocation<llvm::support::ubig64_t> {};
518 
519 class XCOFFSymbolRef;
520 
521 class XCOFFObjectFile : public ObjectFile {
522 private:
523   const void *FileHeader = nullptr;
524   const void *AuxiliaryHeader = nullptr;
525   const void *SectionHeaderTable = nullptr;
526 
527   const void *SymbolTblPtr = nullptr;
528   XCOFFStringTable StringTable = {0, nullptr};
529 
530   const XCOFFSectionHeader32 *sectionHeaderTable32() const;
531   const XCOFFSectionHeader64 *sectionHeaderTable64() const;
532   template <typename T> const T *sectionHeaderTable() const;
533 
534   size_t getFileHeaderSize() const;
535   size_t getSectionHeaderSize() const;
536 
537   const XCOFFSectionHeader32 *toSection32(DataRefImpl Ref) const;
538   const XCOFFSectionHeader64 *toSection64(DataRefImpl Ref) const;
539   uintptr_t getSectionHeaderTableAddress() const;
540   uintptr_t getEndOfSymbolTableAddress() const;
541 
542   DataRefImpl getSectionByType(XCOFF::SectionTypeFlags SectType) const;
543   uint64_t getSectionFileOffsetToRawData(DataRefImpl Sec) const;
544 
545   // This returns a pointer to the start of the storage for the name field of
546   // the 32-bit or 64-bit SectionHeader struct. This string is *not* necessarily
547   // null-terminated.
548   const char *getSectionNameInternal(DataRefImpl Sec) const;
549 
550   static bool isReservedSectionNumber(int16_t SectionNumber);
551 
552   // Constructor and "create" factory function. The constructor is only a thin
553   // wrapper around the base constructor. The "create" function fills out the
554   // XCOFF-specific information and performs the error checking along the way.
555   XCOFFObjectFile(unsigned Type, MemoryBufferRef Object);
556   static Expected<std::unique_ptr<XCOFFObjectFile>> create(unsigned Type,
557                                                            MemoryBufferRef MBR);
558 
559   // Helper for parsing the StringTable. Returns an 'Error' if parsing failed
560   // and an XCOFFStringTable if parsing succeeded.
561   static Expected<XCOFFStringTable> parseStringTable(const XCOFFObjectFile *Obj,
562                                                      uint64_t Offset);
563 
564   // Make a friend so it can call the private 'create' function.
565   friend Expected<std::unique_ptr<ObjectFile>>
566   ObjectFile::createXCOFFObjectFile(MemoryBufferRef Object, unsigned FileType);
567 
568   void checkSectionAddress(uintptr_t Addr, uintptr_t TableAddr) const;
569 
570 public:
571   static constexpr uint64_t InvalidRelocOffset =
572       std::numeric_limits<uint64_t>::max();
573 
574   // Interface inherited from base classes.
575   void moveSymbolNext(DataRefImpl &Symb) const override;
576   Expected<uint32_t> getSymbolFlags(DataRefImpl Symb) const override;
577   basic_symbol_iterator symbol_begin() const override;
578   basic_symbol_iterator symbol_end() const override;
579   bool is64Bit() const override;
580   Expected<StringRef> getSymbolName(DataRefImpl Symb) const override;
581   Expected<uint64_t> getSymbolAddress(DataRefImpl Symb) const override;
582   uint64_t getSymbolValueImpl(DataRefImpl Symb) const override;
583   uint32_t getSymbolAlignment(DataRefImpl Symb) const override;
584   uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const override;
585   Expected<SymbolRef::Type> getSymbolType(DataRefImpl Symb) const override;
586   Expected<section_iterator> getSymbolSection(DataRefImpl Symb) const override;
587 
588   void moveSectionNext(DataRefImpl &Sec) const override;
589   Expected<StringRef> getSectionName(DataRefImpl Sec) const override;
590   uint64_t getSectionAddress(DataRefImpl Sec) const override;
591   uint64_t getSectionIndex(DataRefImpl Sec) const override;
592   uint64_t getSectionSize(DataRefImpl Sec) const override;
593   Expected<ArrayRef<uint8_t>>
594   getSectionContents(DataRefImpl Sec) const override;
595   uint64_t getSectionAlignment(DataRefImpl Sec) const override;
596   bool isSectionCompressed(DataRefImpl Sec) const override;
597   bool isSectionText(DataRefImpl Sec) const override;
598   bool isSectionData(DataRefImpl Sec) const override;
599   bool isSectionBSS(DataRefImpl Sec) const override;
600   bool isDebugSection(DataRefImpl Sec) const override;
601 
602   bool isSectionVirtual(DataRefImpl Sec) const override;
603   relocation_iterator section_rel_begin(DataRefImpl Sec) const override;
604   relocation_iterator section_rel_end(DataRefImpl Sec) const override;
605 
606   void moveRelocationNext(DataRefImpl &Rel) const override;
607 
608   /// \returns the relocation offset with the base address of the containing
609   /// section as zero, or InvalidRelocOffset on errors (such as a relocation
610   /// that does not refer to an address in any section).
611   uint64_t getRelocationOffset(DataRefImpl Rel) const override;
612   symbol_iterator getRelocationSymbol(DataRefImpl Rel) const override;
613   uint64_t getRelocationType(DataRefImpl Rel) const override;
614   void getRelocationTypeName(DataRefImpl Rel,
615                              SmallVectorImpl<char> &Result) const override;
616 
617   section_iterator section_begin() const override;
618   section_iterator section_end() const override;
619   uint8_t getBytesInAddress() const override;
620   StringRef getFileFormatName() const override;
621   Triple::ArchType getArch() const override;
622   Expected<SubtargetFeatures> getFeatures() const override;
623   Expected<uint64_t> getStartAddress() const override;
624   StringRef mapDebugSectionName(StringRef Name) const override;
625   bool isRelocatableObject() const override;
626 
627   // Below here is the non-inherited interface.
628 
629   Expected<StringRef> getRawData(const char *Start, uint64_t Size,
630                                  StringRef Name) const;
631 
632   const XCOFFAuxiliaryHeader32 *auxiliaryHeader32() const;
633   const XCOFFAuxiliaryHeader64 *auxiliaryHeader64() const;
634 
635   const void *getPointerToSymbolTable() const { return SymbolTblPtr; }
636 
637   Expected<StringRef> getSymbolSectionName(XCOFFSymbolRef Ref) const;
638   unsigned getSymbolSectionID(SymbolRef Sym) const;
639   XCOFFSymbolRef toSymbolRef(DataRefImpl Ref) const;
640 
641   // File header related interfaces.
642   const XCOFFFileHeader32 *fileHeader32() const;
643   const XCOFFFileHeader64 *fileHeader64() const;
644   uint16_t getMagic() const;
645   uint16_t getNumberOfSections() const;
646   int32_t getTimeStamp() const;
647 
648   // Symbol table offset and entry count are handled differently between
649   // XCOFF32 and XCOFF64.
650   uint32_t getSymbolTableOffset32() const;
651   uint64_t getSymbolTableOffset64() const;
652 
653   // Note that this value is signed and might return a negative value. Negative
654   // values are reserved for future use.
655   int32_t getRawNumberOfSymbolTableEntries32() const;
656 
657   // The sanitized value appropriate to use as an index into the symbol table.
658   uint32_t getLogicalNumberOfSymbolTableEntries32() const;
659 
660   uint32_t getNumberOfSymbolTableEntries64() const;
661 
662   // Return getLogicalNumberOfSymbolTableEntries32 or
663   // getNumberOfSymbolTableEntries64 depending on the object mode.
664   uint32_t getNumberOfSymbolTableEntries() const;
665 
666   uint32_t getSymbolIndex(uintptr_t SymEntPtr) const;
667   uint64_t getSymbolSize(DataRefImpl Symb) const;
668   uintptr_t getSymbolByIndex(uint32_t Idx) const {
669     return reinterpret_cast<uintptr_t>(SymbolTblPtr) +
670            XCOFF::SymbolTableEntrySize * Idx;
671   }
672   uintptr_t getSymbolEntryAddressByIndex(uint32_t SymbolTableIndex) const;
673   Expected<StringRef> getSymbolNameByIndex(uint32_t SymbolTableIndex) const;
674 
675   Expected<StringRef> getCFileName(const XCOFFFileAuxEnt *CFileEntPtr) const;
676   uint16_t getOptionalHeaderSize() const;
677   uint16_t getFlags() const;
678 
679   // Section header table related interfaces.
680   ArrayRef<XCOFFSectionHeader32> sections32() const;
681   ArrayRef<XCOFFSectionHeader64> sections64() const;
682 
683   int32_t getSectionFlags(DataRefImpl Sec) const;
684   Expected<DataRefImpl> getSectionByNum(int16_t Num) const;
685 
686   Expected<uintptr_t>
687   getSectionFileOffsetToRawData(XCOFF::SectionTypeFlags SectType) const;
688 
689   void checkSymbolEntryPointer(uintptr_t SymbolEntPtr) const;
690 
691   // Relocation-related interfaces.
692   template <typename T>
693   Expected<uint32_t>
694   getNumberOfRelocationEntries(const XCOFFSectionHeader<T> &Sec) const;
695 
696   template <typename Shdr, typename Reloc>
697   Expected<ArrayRef<Reloc>> relocations(const Shdr &Sec) const;
698 
699   // Loader section related interfaces.
700   Expected<StringRef> getImportFileTable() const;
701 
702   // Exception-related interface.
703   template <typename ExceptEnt>
704   Expected<ArrayRef<ExceptEnt>> getExceptionEntries() const;
705 
706   // This function returns string table entry.
707   Expected<StringRef> getStringTableEntry(uint32_t Offset) const;
708 
709   // This function returns the string table.
710   StringRef getStringTable() const;
711 
712   const XCOFF::SymbolAuxType *getSymbolAuxType(uintptr_t AuxEntryAddress) const;
713 
714   static uintptr_t getAdvancedSymbolEntryAddress(uintptr_t CurrentAddress,
715                                                  uint32_t Distance);
716 
717   static bool classof(const Binary *B) { return B->isXCOFF(); }
718 
719   std::optional<StringRef> tryGetCPUName() const override;
720 }; // XCOFFObjectFile
721 
722 typedef struct {
723   uint8_t LanguageId;
724   uint8_t CpuTypeId;
725 } CFileLanguageIdAndTypeIdType;
726 
727 struct XCOFFSymbolEntry32 {
728   typedef struct {
729     support::big32_t Magic; // Zero indicates name in string table.
730     support::ubig32_t Offset;
731   } NameInStrTblType;
732 
733   union {
734     char SymbolName[XCOFF::NameSize];
735     NameInStrTblType NameInStrTbl;
736   };
737 
738   support::ubig32_t Value; // Symbol value; storage class-dependent.
739   support::big16_t SectionNumber;
740 
741   union {
742     support::ubig16_t SymbolType;
743     CFileLanguageIdAndTypeIdType CFileLanguageIdAndTypeId;
744   };
745 
746   XCOFF::StorageClass StorageClass;
747   uint8_t NumberOfAuxEntries;
748 };
749 
750 struct XCOFFSymbolEntry64 {
751   support::ubig64_t Value; // Symbol value; storage class-dependent.
752   support::ubig32_t Offset;
753   support::big16_t SectionNumber;
754 
755   union {
756     support::ubig16_t SymbolType;
757     CFileLanguageIdAndTypeIdType CFileLanguageIdAndTypeId;
758   };
759 
760   XCOFF::StorageClass StorageClass;
761   uint8_t NumberOfAuxEntries;
762 };
763 
764 class XCOFFSymbolRef {
765 public:
766   enum { NAME_IN_STR_TBL_MAGIC = 0x0 };
767 
768   XCOFFSymbolRef(DataRefImpl SymEntDataRef,
769                  const XCOFFObjectFile *OwningObjectPtr)
770       : OwningObjectPtr(OwningObjectPtr) {
771     assert(OwningObjectPtr && "OwningObjectPtr cannot be nullptr!");
772     assert(SymEntDataRef.p != 0 &&
773            "Symbol table entry pointer cannot be nullptr!");
774 
775     if (OwningObjectPtr->is64Bit())
776       Entry64 = reinterpret_cast<const XCOFFSymbolEntry64 *>(SymEntDataRef.p);
777     else
778       Entry32 = reinterpret_cast<const XCOFFSymbolEntry32 *>(SymEntDataRef.p);
779   }
780 
781   const XCOFFSymbolEntry32 *getSymbol32() { return Entry32; }
782   const XCOFFSymbolEntry64 *getSymbol64() { return Entry64; }
783 
784   uint64_t getValue() const { return Entry32 ? getValue32() : getValue64(); }
785 
786   uint32_t getValue32() const { return Entry32->Value; }
787 
788   uint64_t getValue64() const { return Entry64->Value; }
789 
790 #define GETVALUE(X) Entry32 ? Entry32->X : Entry64->X
791 
792   int16_t getSectionNumber() const { return GETVALUE(SectionNumber); }
793 
794   uint16_t getSymbolType() const { return GETVALUE(SymbolType); }
795 
796   uint8_t getLanguageIdForCFile() const {
797     assert(getStorageClass() == XCOFF::C_FILE &&
798            "This interface is for C_FILE only.");
799     return GETVALUE(CFileLanguageIdAndTypeId.LanguageId);
800   }
801 
802   uint8_t getCPUTypeIddForCFile() const {
803     assert(getStorageClass() == XCOFF::C_FILE &&
804            "This interface is for C_FILE only.");
805     return GETVALUE(CFileLanguageIdAndTypeId.CpuTypeId);
806   }
807 
808   XCOFF::StorageClass getStorageClass() const { return GETVALUE(StorageClass); }
809 
810   uint8_t getNumberOfAuxEntries() const { return GETVALUE(NumberOfAuxEntries); }
811 
812 #undef GETVALUE
813 
814   uintptr_t getEntryAddress() const {
815     return Entry32 ? reinterpret_cast<uintptr_t>(Entry32)
816                    : reinterpret_cast<uintptr_t>(Entry64);
817   }
818 
819   Expected<StringRef> getName() const;
820   bool isFunction() const;
821   bool isCsectSymbol() const;
822   Expected<XCOFFCsectAuxRef> getXCOFFCsectAuxRef() const;
823 
824 private:
825   const XCOFFObjectFile *OwningObjectPtr;
826   const XCOFFSymbolEntry32 *Entry32 = nullptr;
827   const XCOFFSymbolEntry64 *Entry64 = nullptr;
828 };
829 
830 class TBVectorExt {
831   uint16_t Data;
832   SmallString<32> VecParmsInfo;
833 
834   TBVectorExt(StringRef TBvectorStrRef, Error &Err);
835 
836 public:
837   static Expected<TBVectorExt> create(StringRef TBvectorStrRef);
838   uint8_t getNumberOfVRSaved() const;
839   bool isVRSavedOnStack() const;
840   bool hasVarArgs() const;
841   uint8_t getNumberOfVectorParms() const;
842   bool hasVMXInstruction() const;
843   SmallString<32> getVectorParmsInfo() const { return VecParmsInfo; };
844 };
845 
846 /// This class provides methods to extract traceback table data from a buffer.
847 /// The various accessors may reference the buffer provided via the constructor.
848 
849 class XCOFFTracebackTable {
850   const uint8_t *const TBPtr;
851   bool Is64BitObj;
852   std::optional<SmallString<32>> ParmsType;
853   std::optional<uint32_t> TraceBackTableOffset;
854   std::optional<uint32_t> HandlerMask;
855   std::optional<uint32_t> NumOfCtlAnchors;
856   std::optional<SmallVector<uint32_t, 8>> ControlledStorageInfoDisp;
857   std::optional<StringRef> FunctionName;
858   std::optional<uint8_t> AllocaRegister;
859   std::optional<TBVectorExt> VecExt;
860   std::optional<uint8_t> ExtensionTable;
861   std::optional<uint64_t> EhInfoDisp;
862 
863   XCOFFTracebackTable(const uint8_t *Ptr, uint64_t &Size, Error &Err,
864                       bool Is64Bit = false);
865 
866 public:
867   /// Parse an XCOFF Traceback Table from \a Ptr with \a Size bytes.
868   /// Returns an XCOFFTracebackTable upon successful parsing, otherwise an
869   /// Error is returned.
870   ///
871   /// \param[in] Ptr
872   ///   A pointer that points just past the initial 4 bytes of zeros at the
873   ///   beginning of an XCOFF Traceback Table.
874   ///
875   /// \param[in, out] Size
876   ///    A pointer that points to the length of the XCOFF Traceback Table.
877   ///    If the XCOFF Traceback Table is not parsed successfully or there are
878   ///    extra bytes that are not recognized, \a Size will be updated to be the
879   ///    size up to the end of the last successfully parsed field of the table.
880   static Expected<XCOFFTracebackTable>
881   create(const uint8_t *Ptr, uint64_t &Size, bool Is64Bits = false);
882   uint8_t getVersion() const;
883   uint8_t getLanguageID() const;
884 
885   bool isGlobalLinkage() const;
886   bool isOutOfLineEpilogOrPrologue() const;
887   bool hasTraceBackTableOffset() const;
888   bool isInternalProcedure() const;
889   bool hasControlledStorage() const;
890   bool isTOCless() const;
891   bool isFloatingPointPresent() const;
892   bool isFloatingPointOperationLogOrAbortEnabled() const;
893 
894   bool isInterruptHandler() const;
895   bool isFuncNamePresent() const;
896   bool isAllocaUsed() const;
897   uint8_t getOnConditionDirective() const;
898   bool isCRSaved() const;
899   bool isLRSaved() const;
900 
901   bool isBackChainStored() const;
902   bool isFixup() const;
903   uint8_t getNumOfFPRsSaved() const;
904 
905   bool hasVectorInfo() const;
906   bool hasExtensionTable() const;
907   uint8_t getNumOfGPRsSaved() const;
908 
909   uint8_t getNumberOfFixedParms() const;
910 
911   uint8_t getNumberOfFPParms() const;
912   bool hasParmsOnStack() const;
913 
914   const std::optional<SmallString<32>> &getParmsType() const {
915     return ParmsType;
916   }
917   const std::optional<uint32_t> &getTraceBackTableOffset() const {
918     return TraceBackTableOffset;
919   }
920   const std::optional<uint32_t> &getHandlerMask() const { return HandlerMask; }
921   const std::optional<uint32_t> &getNumOfCtlAnchors() {
922     return NumOfCtlAnchors;
923   }
924   const std::optional<SmallVector<uint32_t, 8>> &
925   getControlledStorageInfoDisp() {
926     return ControlledStorageInfoDisp;
927   }
928   const std::optional<StringRef> &getFunctionName() const {
929     return FunctionName;
930   }
931   const std::optional<uint8_t> &getAllocaRegister() const {
932     return AllocaRegister;
933   }
934   const std::optional<TBVectorExt> &getVectorExt() const { return VecExt; }
935   const std::optional<uint8_t> &getExtensionTable() const {
936     return ExtensionTable;
937   }
938   const std::optional<uint64_t> &getEhInfoDisp() const { return EhInfoDisp; }
939 };
940 
941 bool doesXCOFFTracebackTableBegin(ArrayRef<uint8_t> Bytes);
942 } // namespace object
943 } // namespace llvm
944 
945 #endif // LLVM_OBJECT_XCOFFOBJECTFILE_H
946