blob: 1ac00ed5e2c757276c8d9d5fff5f4f5d6c7d7fca [file] [log] [blame]
Andrew Walbran3d2c1972020-04-07 12:24:26 +01001//===- 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
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020016#include "llvm/ADT/SmallString.h"
17#include "llvm/ADT/SmallVector.h"
Andrew Walbran3d2c1972020-04-07 12:24:26 +010018#include "llvm/BinaryFormat/XCOFF.h"
Andrew Walbran3d2c1972020-04-07 12:24:26 +010019#include "llvm/Object/ObjectFile.h"
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020020#include "llvm/Support/Endian.h"
21#include <limits>
Andrew Walbran3d2c1972020-04-07 12:24:26 +010022
23namespace llvm {
24namespace object {
25
26struct 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
40struct 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
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020054template <typename T> struct XCOFFSectionHeader {
55 // Least significant 3 bits are reserved.
56 static constexpr unsigned SectionFlagsReservedMask = 0x7;
57
58 // The low order 16 bits of section flags denotes the section type.
59 static constexpr unsigned SectionFlagsTypeMask = 0xffffu;
60
61public:
62 StringRef getName() const;
63 uint16_t getSectionType() const;
64 bool isReservedSectionType() const;
65};
66
67// Explicit extern template declarations.
68struct XCOFFSectionHeader32;
69struct XCOFFSectionHeader64;
70extern template struct XCOFFSectionHeader<XCOFFSectionHeader32>;
71extern template struct XCOFFSectionHeader<XCOFFSectionHeader64>;
72
73struct XCOFFSectionHeader32 : XCOFFSectionHeader<XCOFFSectionHeader32> {
74 char Name[XCOFF::NameSize];
Andrew Walbran3d2c1972020-04-07 12:24:26 +010075 support::ubig32_t PhysicalAddress;
76 support::ubig32_t VirtualAddress;
77 support::ubig32_t SectionSize;
78 support::ubig32_t FileOffsetToRawData;
79 support::ubig32_t FileOffsetToRelocationInfo;
80 support::ubig32_t FileOffsetToLineNumberInfo;
81 support::ubig16_t NumberOfRelocations;
82 support::ubig16_t NumberOfLineNumbers;
83 support::big32_t Flags;
Andrew Walbran3d2c1972020-04-07 12:24:26 +010084};
85
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020086struct XCOFFSectionHeader64 : XCOFFSectionHeader<XCOFFSectionHeader64> {
87 char Name[XCOFF::NameSize];
Andrew Walbran3d2c1972020-04-07 12:24:26 +010088 support::ubig64_t PhysicalAddress;
89 support::ubig64_t VirtualAddress;
90 support::ubig64_t SectionSize;
91 support::big64_t FileOffsetToRawData;
92 support::big64_t FileOffsetToRelocationInfo;
93 support::big64_t FileOffsetToLineNumberInfo;
94 support::ubig32_t NumberOfRelocations;
95 support::ubig32_t NumberOfLineNumbers;
96 support::big32_t Flags;
97 char Padding[4];
Andrew Walbran3d2c1972020-04-07 12:24:26 +010098};
99
100struct XCOFFSymbolEntry {
101 enum { NAME_IN_STR_TBL_MAGIC = 0x0 };
102 typedef struct {
103 support::big32_t Magic; // Zero indicates name in string table.
104 support::ubig32_t Offset;
105 } NameInStrTblType;
106
107 typedef struct {
108 uint8_t LanguageId;
109 uint8_t CpuTypeId;
110 } CFileLanguageIdAndTypeIdType;
111
112 union {
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200113 char SymbolName[XCOFF::NameSize];
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100114 NameInStrTblType NameInStrTbl;
115 };
116
117 support::ubig32_t Value; // Symbol value; storage class-dependent.
118 support::big16_t SectionNumber;
119
120 union {
121 support::ubig16_t SymbolType;
122 CFileLanguageIdAndTypeIdType CFileLanguageIdAndTypeId;
123 };
124
125 XCOFF::StorageClass StorageClass;
126 uint8_t NumberOfAuxEntries;
127};
128
129struct XCOFFStringTable {
130 uint32_t Size;
131 const char *Data;
132};
133
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200134struct XCOFFCsectAuxEnt32 {
135 static constexpr uint8_t SymbolTypeMask = 0x07;
136 static constexpr uint8_t SymbolAlignmentMask = 0xF8;
137 static constexpr size_t SymbolAlignmentBitOffset = 3;
138
139 support::ubig32_t
140 SectionOrLength; // If the symbol type is XTY_SD or XTY_CM, the csect
141 // length.
142 // If the symbol type is XTY_LD, the symbol table
143 // index of the containing csect.
144 // If the symbol type is XTY_ER, 0.
145 support::ubig32_t ParameterHashIndex;
146 support::ubig16_t TypeChkSectNum;
147 uint8_t SymbolAlignmentAndType;
148 XCOFF::StorageMappingClass StorageMappingClass;
149 support::ubig32_t StabInfoIndex;
150 support::ubig16_t StabSectNum;
151
152 uint16_t getAlignmentLog2() const {
153 return (SymbolAlignmentAndType & SymbolAlignmentMask) >>
154 SymbolAlignmentBitOffset;
155 }
156
157 uint8_t getSymbolType() const {
158 return SymbolAlignmentAndType & SymbolTypeMask;
159 }
160
161 bool isLabel() const { return getSymbolType() == XCOFF::XTY_LD; }
162};
163
164struct XCOFFFileAuxEnt {
165 typedef struct {
166 support::big32_t Magic; // Zero indicates name in string table.
167 support::ubig32_t Offset;
168 char NamePad[XCOFF::FileNamePadSize];
169 } NameInStrTblType;
170 union {
171 char Name[XCOFF::NameSize + XCOFF::FileNamePadSize];
172 NameInStrTblType NameInStrTbl;
173 };
174 XCOFF::CFileStringType Type;
175 uint8_t ReservedZeros[2];
176 uint8_t AuxType; // 64-bit XCOFF file only.
177};
178
179struct XCOFFSectAuxEntForStat {
180 support::ubig32_t SectionLength;
181 support::ubig16_t NumberOfRelocEnt;
182 support::ubig16_t NumberOfLineNum;
183 uint8_t Pad[10];
184};
185
186struct XCOFFRelocation32 {
187 // Masks for packing/unpacking the r_rsize field of relocations.
188
189 // The msb is used to indicate if the bits being relocated are signed or
190 // unsigned.
191 static constexpr uint8_t XR_SIGN_INDICATOR_MASK = 0x80;
192
193 // The 2nd msb is used to indicate that the binder has replaced/modified the
194 // original instruction.
195 static constexpr uint8_t XR_FIXUP_INDICATOR_MASK = 0x40;
196
197 // The remaining bits specify the bit length of the relocatable reference
198 // minus one.
199 static constexpr uint8_t XR_BIASED_LENGTH_MASK = 0x3f;
200
201public:
202 support::ubig32_t VirtualAddress;
203 support::ubig32_t SymbolIndex;
204
205 // Packed field, see XR_* masks for details of packing.
206 uint8_t Info;
207
208 XCOFF::RelocationType Type;
209
210public:
211 bool isRelocationSigned() const;
212 bool isFixupIndicated() const;
213
214 // Returns the number of bits being relocated.
215 uint8_t getRelocatedLength() const;
216};
217
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100218class XCOFFObjectFile : public ObjectFile {
219private:
220 const void *FileHeader = nullptr;
221 const void *SectionHeaderTable = nullptr;
222
223 const XCOFFSymbolEntry *SymbolTblPtr = nullptr;
224 XCOFFStringTable StringTable = {0, nullptr};
225
226 const XCOFFFileHeader32 *fileHeader32() const;
227 const XCOFFFileHeader64 *fileHeader64() const;
228
229 const XCOFFSectionHeader32 *sectionHeaderTable32() const;
230 const XCOFFSectionHeader64 *sectionHeaderTable64() const;
231
232 size_t getFileHeaderSize() const;
233 size_t getSectionHeaderSize() const;
234
235 const XCOFFSectionHeader32 *toSection32(DataRefImpl Ref) const;
236 const XCOFFSectionHeader64 *toSection64(DataRefImpl Ref) const;
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100237 uintptr_t getSectionHeaderTableAddress() const;
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200238 uintptr_t getEndOfSymbolTableAddress() const;
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100239
240 // This returns a pointer to the start of the storage for the name field of
241 // the 32-bit or 64-bit SectionHeader struct. This string is *not* necessarily
242 // null-terminated.
243 const char *getSectionNameInternal(DataRefImpl Sec) const;
244
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200245 // This function returns string table entry.
246 Expected<StringRef> getStringTableEntry(uint32_t Offset) const;
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100247
248 static bool isReservedSectionNumber(int16_t SectionNumber);
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100249
250 // Constructor and "create" factory function. The constructor is only a thin
251 // wrapper around the base constructor. The "create" function fills out the
252 // XCOFF-specific information and performs the error checking along the way.
253 XCOFFObjectFile(unsigned Type, MemoryBufferRef Object);
254 static Expected<std::unique_ptr<XCOFFObjectFile>> create(unsigned Type,
255 MemoryBufferRef MBR);
256
257 // Helper for parsing the StringTable. Returns an 'Error' if parsing failed
258 // and an XCOFFStringTable if parsing succeeded.
259 static Expected<XCOFFStringTable> parseStringTable(const XCOFFObjectFile *Obj,
260 uint64_t Offset);
261
262 // Make a friend so it can call the private 'create' function.
263 friend Expected<std::unique_ptr<ObjectFile>>
264 ObjectFile::createXCOFFObjectFile(MemoryBufferRef Object, unsigned FileType);
265
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200266 void checkSectionAddress(uintptr_t Addr, uintptr_t TableAddr) const;
267
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100268public:
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200269 static constexpr uint64_t InvalidRelocOffset =
270 std::numeric_limits<uint64_t>::max();
271
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100272 // Interface inherited from base classes.
273 void moveSymbolNext(DataRefImpl &Symb) const override;
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200274 Expected<uint32_t> getSymbolFlags(DataRefImpl Symb) const override;
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100275 basic_symbol_iterator symbol_begin() const override;
276 basic_symbol_iterator symbol_end() const override;
277
278 Expected<StringRef> getSymbolName(DataRefImpl Symb) const override;
279 Expected<uint64_t> getSymbolAddress(DataRefImpl Symb) const override;
280 uint64_t getSymbolValueImpl(DataRefImpl Symb) const override;
281 uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const override;
282 Expected<SymbolRef::Type> getSymbolType(DataRefImpl Symb) const override;
283 Expected<section_iterator> getSymbolSection(DataRefImpl Symb) const override;
284
285 void moveSectionNext(DataRefImpl &Sec) const override;
286 Expected<StringRef> getSectionName(DataRefImpl Sec) const override;
287 uint64_t getSectionAddress(DataRefImpl Sec) const override;
288 uint64_t getSectionIndex(DataRefImpl Sec) const override;
289 uint64_t getSectionSize(DataRefImpl Sec) const override;
290 Expected<ArrayRef<uint8_t>>
291 getSectionContents(DataRefImpl Sec) const override;
292 uint64_t getSectionAlignment(DataRefImpl Sec) const override;
293 bool isSectionCompressed(DataRefImpl Sec) const override;
294 bool isSectionText(DataRefImpl Sec) const override;
295 bool isSectionData(DataRefImpl Sec) const override;
296 bool isSectionBSS(DataRefImpl Sec) const override;
297
298 bool isSectionVirtual(DataRefImpl Sec) const override;
299 relocation_iterator section_rel_begin(DataRefImpl Sec) const override;
300 relocation_iterator section_rel_end(DataRefImpl Sec) const override;
301
302 void moveRelocationNext(DataRefImpl &Rel) const override;
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200303
304 /// \returns the relocation offset with the base address of the containing
305 /// section as zero, or InvalidRelocOffset on errors (such as a relocation
306 /// that does not refer to an address in any section).
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100307 uint64_t getRelocationOffset(DataRefImpl Rel) const override;
308 symbol_iterator getRelocationSymbol(DataRefImpl Rel) const override;
309 uint64_t getRelocationType(DataRefImpl Rel) const override;
310 void getRelocationTypeName(DataRefImpl Rel,
311 SmallVectorImpl<char> &Result) const override;
312
313 section_iterator section_begin() const override;
314 section_iterator section_end() const override;
315 uint8_t getBytesInAddress() const override;
316 StringRef getFileFormatName() const override;
317 Triple::ArchType getArch() const override;
318 SubtargetFeatures getFeatures() const override;
319 Expected<uint64_t> getStartAddress() const override;
320 bool isRelocatableObject() const override;
321
322 // Below here is the non-inherited interface.
323 bool is64Bit() const;
324
325 const XCOFFSymbolEntry *getPointerToSymbolTable() const {
326 assert(!is64Bit() && "Symbol table handling not supported yet.");
327 return SymbolTblPtr;
328 }
329
330 Expected<StringRef>
331 getSymbolSectionName(const XCOFFSymbolEntry *SymEntPtr) const;
332
333 const XCOFFSymbolEntry *toSymbolEntry(DataRefImpl Ref) const;
334
335 // File header related interfaces.
336 uint16_t getMagic() const;
337 uint16_t getNumberOfSections() const;
338 int32_t getTimeStamp() const;
339
340 // Symbol table offset and entry count are handled differently between
341 // XCOFF32 and XCOFF64.
342 uint32_t getSymbolTableOffset32() const;
343 uint64_t getSymbolTableOffset64() const;
344
345 // Note that this value is signed and might return a negative value. Negative
346 // values are reserved for future use.
347 int32_t getRawNumberOfSymbolTableEntries32() const;
348
349 // The sanitized value appropriate to use as an index into the symbol table.
350 uint32_t getLogicalNumberOfSymbolTableEntries32() const;
351
352 uint32_t getNumberOfSymbolTableEntries64() const;
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200353 uint32_t getSymbolIndex(uintptr_t SymEntPtr) const;
354 Expected<StringRef> getSymbolNameByIndex(uint32_t SymbolTableIndex) const;
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100355
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200356 Expected<StringRef> getCFileName(const XCOFFFileAuxEnt *CFileEntPtr) const;
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100357 uint16_t getOptionalHeaderSize() const;
358 uint16_t getFlags() const;
359
360 // Section header table related interfaces.
361 ArrayRef<XCOFFSectionHeader32> sections32() const;
362 ArrayRef<XCOFFSectionHeader64> sections64() const;
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200363
364 int32_t getSectionFlags(DataRefImpl Sec) const;
365 Expected<DataRefImpl> getSectionByNum(int16_t Num) const;
366
367 void checkSymbolEntryPointer(uintptr_t SymbolEntPtr) const;
368
369 // Relocation-related interfaces.
370 Expected<uint32_t>
371 getLogicalNumberOfRelocationEntries(const XCOFFSectionHeader32 &Sec) const;
372
373 Expected<ArrayRef<XCOFFRelocation32>>
374 relocations(const XCOFFSectionHeader32 &) const;
375
376 static bool classof(const Binary *B) { return B->isXCOFF(); }
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100377}; // XCOFFObjectFile
378
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200379class XCOFFSymbolRef {
380 const DataRefImpl SymEntDataRef;
381 const XCOFFObjectFile *const OwningObjectPtr;
382
383public:
384 XCOFFSymbolRef(DataRefImpl SymEntDataRef,
385 const XCOFFObjectFile *OwningObjectPtr)
386 : SymEntDataRef(SymEntDataRef), OwningObjectPtr(OwningObjectPtr){};
387
388 XCOFF::StorageClass getStorageClass() const;
389 uint8_t getNumberOfAuxEntries() const;
390 const XCOFFCsectAuxEnt32 *getXCOFFCsectAuxEnt32() const;
391 uint16_t getType() const;
392 int16_t getSectionNumber() const;
393
394 bool hasCsectAuxEnt() const;
395 bool isFunction() const;
396};
397
398class TBVectorExt {
399 friend class XCOFFTracebackTable;
400
401 uint16_t Data;
402 uint32_t VecParmsInfo;
403
404 TBVectorExt(StringRef TBvectorStrRef);
405
406public:
407 uint8_t getNumberOfVRSaved() const;
408 bool isVRSavedOnStack() const;
409 bool hasVarArgs() const;
410 uint8_t getNumberOfVectorParms() const;
411 bool hasVMXInstruction() const;
412 SmallString<32> getVectorParmsInfoString() const;
413};
414
415/// This class provides methods to extract traceback table data from a buffer.
416/// The various accessors may reference the buffer provided via the constructor.
417
418class XCOFFTracebackTable {
419 const uint8_t *const TBPtr;
420 Optional<SmallString<32>> ParmsType;
421 Optional<uint32_t> TraceBackTableOffset;
422 Optional<uint32_t> HandlerMask;
423 Optional<uint32_t> NumOfCtlAnchors;
424 Optional<SmallVector<uint32_t, 8>> ControlledStorageInfoDisp;
425 Optional<StringRef> FunctionName;
426 Optional<uint8_t> AllocaRegister;
427 Optional<TBVectorExt> VecExt;
428 Optional<uint8_t> ExtensionTable;
429
430 XCOFFTracebackTable(const uint8_t *Ptr, uint64_t &Size, Error &Err);
431public:
432 /// Parse an XCOFF Traceback Table from \a Ptr with \a Size bytes.
433 /// Returns an XCOFFTracebackTable upon successful parsing, otherwise an
434 /// Error is returned.
435 ///
436 /// \param[in] Ptr
437 /// A pointer that points just past the initial 4 bytes of zeros at the
438 /// beginning of an XCOFF Traceback Table.
439 ///
440 /// \param[in, out] Size
441 /// A pointer that points to the length of the XCOFF Traceback Table.
442 /// If the XCOFF Traceback Table is not parsed successfully or there are
443 /// extra bytes that are not recognized, \a Size will be updated to be the
444 /// size up to the end of the last successfully parsed field of the table.
445 static Expected<XCOFFTracebackTable> create(const uint8_t *Ptr,
446 uint64_t &Size);
447 uint8_t getVersion() const;
448 uint8_t getLanguageID() const;
449
450 bool isGlobalLinkage() const;
451 bool isOutOfLineEpilogOrPrologue() const;
452 bool hasTraceBackTableOffset() const;
453 bool isInternalProcedure() const;
454 bool hasControlledStorage() const;
455 bool isTOCless() const;
456 bool isFloatingPointPresent() const;
457 bool isFloatingPointOperationLogOrAbortEnabled() const;
458
459 bool isInterruptHandler() const;
460 bool isFuncNamePresent() const;
461 bool isAllocaUsed() const;
462 uint8_t getOnConditionDirective() const;
463 bool isCRSaved() const;
464 bool isLRSaved() const;
465
466 bool isBackChainStored() const;
467 bool isFixup() const;
468 uint8_t getNumOfFPRsSaved() const;
469
470 bool hasVectorInfo() const;
471 bool hasExtensionTable() const;
472 uint8_t getNumOfGPRsSaved() const;
473
474 uint8_t getNumberOfFixedParms() const;
475
476 uint8_t getNumberOfFPParms() const;
477 bool hasParmsOnStack() const;
478
479 const Optional<SmallString<32>> &getParmsType() const { return ParmsType; }
480 const Optional<uint32_t> &getTraceBackTableOffset() const {
481 return TraceBackTableOffset;
482 }
483 const Optional<uint32_t> &getHandlerMask() const { return HandlerMask; }
484 const Optional<uint32_t> &getNumOfCtlAnchors() { return NumOfCtlAnchors; }
485 const Optional<SmallVector<uint32_t, 8>> &getControlledStorageInfoDisp() {
486 return ControlledStorageInfoDisp;
487 }
488 const Optional<StringRef> &getFunctionName() const { return FunctionName; }
489 const Optional<uint8_t> &getAllocaRegister() const { return AllocaRegister; }
490 const Optional<TBVectorExt> &getVectorExt() const { return VecExt; }
491 const Optional<uint8_t> &getExtensionTable() const { return ExtensionTable; }
492};
493
494bool doesXCOFFTracebackTableBegin(ArrayRef<uint8_t> Bytes);
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100495} // namespace object
496} // namespace llvm
497
498#endif // LLVM_OBJECT_XCOFFOBJECTFILE_H