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