File: | llvm/include/llvm/Object/XCOFFObjectFile.h |
Warning: | line 560, column 50 Dereference of null pointer |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===--- XCOFFObjectFile.cpp - XCOFF object file implementation -----------===// | |||
2 | // | |||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||
4 | // See https://llvm.org/LICENSE.txt for license information. | |||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||
6 | // | |||
7 | //===----------------------------------------------------------------------===// | |||
8 | // | |||
9 | // This file defines the XCOFFObjectFile class. | |||
10 | // | |||
11 | //===----------------------------------------------------------------------===// | |||
12 | ||||
13 | #include "llvm/Object/XCOFFObjectFile.h" | |||
14 | #include "llvm/ADT/StringSwitch.h" | |||
15 | #include "llvm/MC/SubtargetFeature.h" | |||
16 | #include "llvm/Support/DataExtractor.h" | |||
17 | #include <cstddef> | |||
18 | #include <cstring> | |||
19 | ||||
20 | namespace llvm { | |||
21 | ||||
22 | using namespace XCOFF; | |||
23 | ||||
24 | namespace object { | |||
25 | ||||
26 | static const uint8_t FunctionSym = 0x20; | |||
27 | static const uint16_t NoRelMask = 0x0001; | |||
28 | static const size_t SymbolAuxTypeOffset = 17; | |||
29 | ||||
30 | // Checks that [Ptr, Ptr + Size) bytes fall inside the memory buffer | |||
31 | // 'M'. Returns a pointer to the underlying object on success. | |||
32 | template <typename T> | |||
33 | static Expected<const T *> getObject(MemoryBufferRef M, const void *Ptr, | |||
34 | const uint64_t Size = sizeof(T)) { | |||
35 | uintptr_t Addr = reinterpret_cast<uintptr_t>(Ptr); | |||
36 | if (Error E = Binary::checkOffset(M, Addr, Size)) | |||
37 | return std::move(E); | |||
38 | return reinterpret_cast<const T *>(Addr); | |||
39 | } | |||
40 | ||||
41 | static uintptr_t getWithOffset(uintptr_t Base, ptrdiff_t Offset) { | |||
42 | return reinterpret_cast<uintptr_t>(reinterpret_cast<const char *>(Base) + | |||
43 | Offset); | |||
44 | } | |||
45 | ||||
46 | template <typename T> static const T *viewAs(uintptr_t in) { | |||
47 | return reinterpret_cast<const T *>(in); | |||
48 | } | |||
49 | ||||
50 | static StringRef generateXCOFFFixedNameStringRef(const char *Name) { | |||
51 | auto NulCharPtr = | |||
52 | static_cast<const char *>(memchr(Name, '\0', XCOFF::NameSize)); | |||
53 | return NulCharPtr ? StringRef(Name, NulCharPtr - Name) | |||
54 | : StringRef(Name, XCOFF::NameSize); | |||
55 | } | |||
56 | ||||
57 | template <typename T> StringRef XCOFFSectionHeader<T>::getName() const { | |||
58 | const T &DerivedXCOFFSectionHeader = static_cast<const T &>(*this); | |||
59 | return generateXCOFFFixedNameStringRef(DerivedXCOFFSectionHeader.Name); | |||
60 | } | |||
61 | ||||
62 | template <typename T> uint16_t XCOFFSectionHeader<T>::getSectionType() const { | |||
63 | const T &DerivedXCOFFSectionHeader = static_cast<const T &>(*this); | |||
64 | return DerivedXCOFFSectionHeader.Flags & SectionFlagsTypeMask; | |||
65 | } | |||
66 | ||||
67 | template <typename T> | |||
68 | bool XCOFFSectionHeader<T>::isReservedSectionType() const { | |||
69 | return getSectionType() & SectionFlagsReservedMask; | |||
70 | } | |||
71 | ||||
72 | template <typename AddressType> | |||
73 | bool XCOFFRelocation<AddressType>::isRelocationSigned() const { | |||
74 | return Info & XR_SIGN_INDICATOR_MASK; | |||
75 | } | |||
76 | ||||
77 | template <typename AddressType> | |||
78 | bool XCOFFRelocation<AddressType>::isFixupIndicated() const { | |||
79 | return Info & XR_FIXUP_INDICATOR_MASK; | |||
80 | } | |||
81 | ||||
82 | template <typename AddressType> | |||
83 | uint8_t XCOFFRelocation<AddressType>::getRelocatedLength() const { | |||
84 | // The relocation encodes the bit length being relocated minus 1. Add back | |||
85 | // the 1 to get the actual length being relocated. | |||
86 | return (Info & XR_BIASED_LENGTH_MASK) + 1; | |||
87 | } | |||
88 | ||||
89 | uintptr_t | |||
90 | XCOFFObjectFile::getAdvancedSymbolEntryAddress(uintptr_t CurrentAddress, | |||
91 | uint32_t Distance) { | |||
92 | return getWithOffset(CurrentAddress, Distance * XCOFF::SymbolTableEntrySize); | |||
93 | } | |||
94 | ||||
95 | const XCOFF::SymbolAuxType * | |||
96 | XCOFFObjectFile::getSymbolAuxType(uintptr_t AuxEntryAddress) const { | |||
97 | assert(is64Bit() && "64-bit interface called on a 32-bit object file.")(static_cast <bool> (is64Bit() && "64-bit interface called on a 32-bit object file." ) ? void (0) : __assert_fail ("is64Bit() && \"64-bit interface called on a 32-bit object file.\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/lib/Object/XCOFFObjectFile.cpp" , 97, __extension__ __PRETTY_FUNCTION__)); | |||
98 | return viewAs<XCOFF::SymbolAuxType>( | |||
99 | getWithOffset(AuxEntryAddress, SymbolAuxTypeOffset)); | |||
100 | } | |||
101 | ||||
102 | void XCOFFObjectFile::checkSectionAddress(uintptr_t Addr, | |||
103 | uintptr_t TableAddress) const { | |||
104 | if (Addr < TableAddress) | |||
105 | report_fatal_error("Section header outside of section header table."); | |||
106 | ||||
107 | uintptr_t Offset = Addr - TableAddress; | |||
108 | if (Offset >= getSectionHeaderSize() * getNumberOfSections()) | |||
109 | report_fatal_error("Section header outside of section header table."); | |||
110 | ||||
111 | if (Offset % getSectionHeaderSize() != 0) | |||
112 | report_fatal_error( | |||
113 | "Section header pointer does not point to a valid section header."); | |||
114 | } | |||
115 | ||||
116 | const XCOFFSectionHeader32 * | |||
117 | XCOFFObjectFile::toSection32(DataRefImpl Ref) const { | |||
118 | assert(!is64Bit() && "32-bit interface called on 64-bit object file.")(static_cast <bool> (!is64Bit() && "32-bit interface called on 64-bit object file." ) ? void (0) : __assert_fail ("!is64Bit() && \"32-bit interface called on 64-bit object file.\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/lib/Object/XCOFFObjectFile.cpp" , 118, __extension__ __PRETTY_FUNCTION__)); | |||
119 | #ifndef NDEBUG | |||
120 | checkSectionAddress(Ref.p, getSectionHeaderTableAddress()); | |||
121 | #endif | |||
122 | return viewAs<XCOFFSectionHeader32>(Ref.p); | |||
123 | } | |||
124 | ||||
125 | const XCOFFSectionHeader64 * | |||
126 | XCOFFObjectFile::toSection64(DataRefImpl Ref) const { | |||
127 | assert(is64Bit() && "64-bit interface called on a 32-bit object file.")(static_cast <bool> (is64Bit() && "64-bit interface called on a 32-bit object file." ) ? void (0) : __assert_fail ("is64Bit() && \"64-bit interface called on a 32-bit object file.\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/lib/Object/XCOFFObjectFile.cpp" , 127, __extension__ __PRETTY_FUNCTION__)); | |||
128 | #ifndef NDEBUG | |||
129 | checkSectionAddress(Ref.p, getSectionHeaderTableAddress()); | |||
130 | #endif | |||
131 | return viewAs<XCOFFSectionHeader64>(Ref.p); | |||
132 | } | |||
133 | ||||
134 | XCOFFSymbolRef XCOFFObjectFile::toSymbolRef(DataRefImpl Ref) const { | |||
135 | assert(Ref.p != 0 && "Symbol table pointer can not be nullptr!")(static_cast <bool> (Ref.p != 0 && "Symbol table pointer can not be nullptr!" ) ? void (0) : __assert_fail ("Ref.p != 0 && \"Symbol table pointer can not be nullptr!\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/lib/Object/XCOFFObjectFile.cpp" , 135, __extension__ __PRETTY_FUNCTION__)); | |||
136 | #ifndef NDEBUG | |||
137 | checkSymbolEntryPointer(Ref.p); | |||
138 | #endif | |||
139 | return XCOFFSymbolRef(Ref, this); | |||
140 | } | |||
141 | ||||
142 | const XCOFFFileHeader32 *XCOFFObjectFile::fileHeader32() const { | |||
143 | assert(!is64Bit() && "32-bit interface called on 64-bit object file.")(static_cast <bool> (!is64Bit() && "32-bit interface called on 64-bit object file." ) ? void (0) : __assert_fail ("!is64Bit() && \"32-bit interface called on 64-bit object file.\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/lib/Object/XCOFFObjectFile.cpp" , 143, __extension__ __PRETTY_FUNCTION__)); | |||
144 | return static_cast<const XCOFFFileHeader32 *>(FileHeader); | |||
145 | } | |||
146 | ||||
147 | const XCOFFFileHeader64 *XCOFFObjectFile::fileHeader64() const { | |||
148 | assert(is64Bit() && "64-bit interface called on a 32-bit object file.")(static_cast <bool> (is64Bit() && "64-bit interface called on a 32-bit object file." ) ? void (0) : __assert_fail ("is64Bit() && \"64-bit interface called on a 32-bit object file.\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/lib/Object/XCOFFObjectFile.cpp" , 148, __extension__ __PRETTY_FUNCTION__)); | |||
149 | return static_cast<const XCOFFFileHeader64 *>(FileHeader); | |||
150 | } | |||
151 | ||||
152 | template <typename T> const T *XCOFFObjectFile::sectionHeaderTable() const { | |||
153 | return static_cast<const T *>(SectionHeaderTable); | |||
154 | } | |||
155 | ||||
156 | const XCOFFSectionHeader32 * | |||
157 | XCOFFObjectFile::sectionHeaderTable32() const { | |||
158 | assert(!is64Bit() && "32-bit interface called on 64-bit object file.")(static_cast <bool> (!is64Bit() && "32-bit interface called on 64-bit object file." ) ? void (0) : __assert_fail ("!is64Bit() && \"32-bit interface called on 64-bit object file.\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/lib/Object/XCOFFObjectFile.cpp" , 158, __extension__ __PRETTY_FUNCTION__)); | |||
159 | return static_cast<const XCOFFSectionHeader32 *>(SectionHeaderTable); | |||
160 | } | |||
161 | ||||
162 | const XCOFFSectionHeader64 * | |||
163 | XCOFFObjectFile::sectionHeaderTable64() const { | |||
164 | assert(is64Bit() && "64-bit interface called on a 32-bit object file.")(static_cast <bool> (is64Bit() && "64-bit interface called on a 32-bit object file." ) ? void (0) : __assert_fail ("is64Bit() && \"64-bit interface called on a 32-bit object file.\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/lib/Object/XCOFFObjectFile.cpp" , 164, __extension__ __PRETTY_FUNCTION__)); | |||
165 | return static_cast<const XCOFFSectionHeader64 *>(SectionHeaderTable); | |||
166 | } | |||
167 | ||||
168 | void XCOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const { | |||
169 | uintptr_t NextSymbolAddr = getAdvancedSymbolEntryAddress( | |||
170 | Symb.p, toSymbolRef(Symb).getNumberOfAuxEntries() + 1); | |||
| ||||
171 | #ifndef NDEBUG | |||
172 | // This function is used by basic_symbol_iterator, which allows to | |||
173 | // point to the end-of-symbol-table address. | |||
174 | if (NextSymbolAddr != getEndOfSymbolTableAddress()) | |||
175 | checkSymbolEntryPointer(NextSymbolAddr); | |||
176 | #endif | |||
177 | Symb.p = NextSymbolAddr; | |||
178 | } | |||
179 | ||||
180 | Expected<StringRef> | |||
181 | XCOFFObjectFile::getStringTableEntry(uint32_t Offset) const { | |||
182 | // The byte offset is relative to the start of the string table. | |||
183 | // A byte offset value of 0 is a null or zero-length symbol | |||
184 | // name. A byte offset in the range 1 to 3 (inclusive) points into the length | |||
185 | // field; as a soft-error recovery mechanism, we treat such cases as having an | |||
186 | // offset of 0. | |||
187 | if (Offset < 4) | |||
188 | return StringRef(nullptr, 0); | |||
189 | ||||
190 | if (StringTable.Data != nullptr && StringTable.Size > Offset) | |||
191 | return (StringTable.Data + Offset); | |||
192 | ||||
193 | return make_error<GenericBinaryError>("Bad offset for string table entry", | |||
194 | object_error::parse_failed); | |||
195 | } | |||
196 | ||||
197 | StringRef XCOFFObjectFile::getStringTable() const { | |||
198 | // If the size is less than or equal to 4, then the string table contains no | |||
199 | // string data. | |||
200 | return StringRef(StringTable.Data, | |||
201 | StringTable.Size <= 4 ? 0 : StringTable.Size); | |||
202 | } | |||
203 | ||||
204 | Expected<StringRef> | |||
205 | XCOFFObjectFile::getCFileName(const XCOFFFileAuxEnt *CFileEntPtr) const { | |||
206 | if (CFileEntPtr->NameInStrTbl.Magic != XCOFFSymbolRef::NAME_IN_STR_TBL_MAGIC) | |||
207 | return generateXCOFFFixedNameStringRef(CFileEntPtr->Name); | |||
208 | return getStringTableEntry(CFileEntPtr->NameInStrTbl.Offset); | |||
209 | } | |||
210 | ||||
211 | Expected<StringRef> XCOFFObjectFile::getSymbolName(DataRefImpl Symb) const { | |||
212 | return toSymbolRef(Symb).getName(); | |||
213 | } | |||
214 | ||||
215 | Expected<uint64_t> XCOFFObjectFile::getSymbolAddress(DataRefImpl Symb) const { | |||
216 | return toSymbolRef(Symb).getValue(); | |||
217 | } | |||
218 | ||||
219 | uint64_t XCOFFObjectFile::getSymbolValueImpl(DataRefImpl Symb) const { | |||
220 | return toSymbolRef(Symb).getValue(); | |||
221 | } | |||
222 | ||||
223 | uint64_t XCOFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const { | |||
224 | uint64_t Result = 0; | |||
225 | llvm_unreachable("Not yet implemented!")::llvm::llvm_unreachable_internal("Not yet implemented!", "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/lib/Object/XCOFFObjectFile.cpp" , 225); | |||
226 | return Result; | |||
227 | } | |||
228 | ||||
229 | Expected<SymbolRef::Type> | |||
230 | XCOFFObjectFile::getSymbolType(DataRefImpl Symb) const { | |||
231 | // TODO: Return the correct symbol type. | |||
232 | return SymbolRef::ST_Other; | |||
233 | } | |||
234 | ||||
235 | Expected<section_iterator> | |||
236 | XCOFFObjectFile::getSymbolSection(DataRefImpl Symb) const { | |||
237 | const int16_t SectNum = toSymbolRef(Symb).getSectionNumber(); | |||
238 | ||||
239 | if (isReservedSectionNumber(SectNum)) | |||
240 | return section_end(); | |||
241 | ||||
242 | Expected<DataRefImpl> ExpSec = getSectionByNum(SectNum); | |||
243 | if (!ExpSec) | |||
244 | return ExpSec.takeError(); | |||
245 | ||||
246 | return section_iterator(SectionRef(ExpSec.get(), this)); | |||
247 | } | |||
248 | ||||
249 | void XCOFFObjectFile::moveSectionNext(DataRefImpl &Sec) const { | |||
250 | const char *Ptr = reinterpret_cast<const char *>(Sec.p); | |||
251 | Sec.p = reinterpret_cast<uintptr_t>(Ptr + getSectionHeaderSize()); | |||
252 | } | |||
253 | ||||
254 | Expected<StringRef> XCOFFObjectFile::getSectionName(DataRefImpl Sec) const { | |||
255 | return generateXCOFFFixedNameStringRef(getSectionNameInternal(Sec)); | |||
256 | } | |||
257 | ||||
258 | uint64_t XCOFFObjectFile::getSectionAddress(DataRefImpl Sec) const { | |||
259 | // Avoid ternary due to failure to convert the ubig32_t value to a unit64_t | |||
260 | // with MSVC. | |||
261 | if (is64Bit()) | |||
262 | return toSection64(Sec)->VirtualAddress; | |||
263 | ||||
264 | return toSection32(Sec)->VirtualAddress; | |||
265 | } | |||
266 | ||||
267 | uint64_t XCOFFObjectFile::getSectionIndex(DataRefImpl Sec) const { | |||
268 | // Section numbers in XCOFF are numbered beginning at 1. A section number of | |||
269 | // zero is used to indicate that a symbol is being imported or is undefined. | |||
270 | if (is64Bit()) | |||
271 | return toSection64(Sec) - sectionHeaderTable64() + 1; | |||
272 | else | |||
273 | return toSection32(Sec) - sectionHeaderTable32() + 1; | |||
274 | } | |||
275 | ||||
276 | uint64_t XCOFFObjectFile::getSectionSize(DataRefImpl Sec) const { | |||
277 | // Avoid ternary due to failure to convert the ubig32_t value to a unit64_t | |||
278 | // with MSVC. | |||
279 | if (is64Bit()) | |||
280 | return toSection64(Sec)->SectionSize; | |||
281 | ||||
282 | return toSection32(Sec)->SectionSize; | |||
283 | } | |||
284 | ||||
285 | Expected<ArrayRef<uint8_t>> | |||
286 | XCOFFObjectFile::getSectionContents(DataRefImpl Sec) const { | |||
287 | if (isSectionVirtual(Sec)) | |||
288 | return ArrayRef<uint8_t>(); | |||
289 | ||||
290 | uint64_t OffsetToRaw; | |||
291 | if (is64Bit()) | |||
292 | OffsetToRaw = toSection64(Sec)->FileOffsetToRawData; | |||
293 | else | |||
294 | OffsetToRaw = toSection32(Sec)->FileOffsetToRawData; | |||
295 | ||||
296 | const uint8_t * ContentStart = base() + OffsetToRaw; | |||
297 | uint64_t SectionSize = getSectionSize(Sec); | |||
298 | if (checkOffset(Data, reinterpret_cast<uintptr_t>(ContentStart), SectionSize)) | |||
299 | return make_error<BinaryError>(); | |||
300 | ||||
301 | return makeArrayRef(ContentStart,SectionSize); | |||
302 | } | |||
303 | ||||
304 | uint64_t XCOFFObjectFile::getSectionAlignment(DataRefImpl Sec) const { | |||
305 | uint64_t Result = 0; | |||
306 | llvm_unreachable("Not yet implemented!")::llvm::llvm_unreachable_internal("Not yet implemented!", "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/lib/Object/XCOFFObjectFile.cpp" , 306); | |||
307 | return Result; | |||
308 | } | |||
309 | ||||
310 | Expected<uintptr_t> XCOFFObjectFile::getLoaderSectionAddress() const { | |||
311 | uint64_t OffsetToLoaderSection = 0; | |||
312 | uint64_t SizeOfLoaderSection = 0; | |||
313 | ||||
314 | if (is64Bit()) { | |||
315 | for (const auto &Sec64 : sections64()) | |||
316 | if (Sec64.getSectionType() == XCOFF::STYP_LOADER) { | |||
317 | OffsetToLoaderSection = Sec64.FileOffsetToRawData; | |||
318 | SizeOfLoaderSection = Sec64.SectionSize; | |||
319 | break; | |||
320 | } | |||
321 | } else { | |||
322 | for (const auto &Sec32 : sections32()) | |||
323 | if (Sec32.getSectionType() == XCOFF::STYP_LOADER) { | |||
324 | OffsetToLoaderSection = Sec32.FileOffsetToRawData; | |||
325 | SizeOfLoaderSection = Sec32.SectionSize; | |||
326 | break; | |||
327 | } | |||
328 | } | |||
329 | ||||
330 | // No loader section is not an error. | |||
331 | if (!SizeOfLoaderSection) | |||
332 | return 0; | |||
333 | ||||
334 | uintptr_t LoderSectionStart = | |||
335 | reinterpret_cast<uintptr_t>(base() + OffsetToLoaderSection); | |||
336 | if (Error E = | |||
337 | Binary::checkOffset(Data, LoderSectionStart, SizeOfLoaderSection)) | |||
338 | return std::move(E); | |||
339 | return LoderSectionStart; | |||
340 | } | |||
341 | ||||
342 | bool XCOFFObjectFile::isSectionCompressed(DataRefImpl Sec) const { | |||
343 | return false; | |||
344 | } | |||
345 | ||||
346 | bool XCOFFObjectFile::isSectionText(DataRefImpl Sec) const { | |||
347 | return getSectionFlags(Sec) & XCOFF::STYP_TEXT; | |||
348 | } | |||
349 | ||||
350 | bool XCOFFObjectFile::isSectionData(DataRefImpl Sec) const { | |||
351 | uint32_t Flags = getSectionFlags(Sec); | |||
352 | return Flags & (XCOFF::STYP_DATA | XCOFF::STYP_TDATA); | |||
353 | } | |||
354 | ||||
355 | bool XCOFFObjectFile::isSectionBSS(DataRefImpl Sec) const { | |||
356 | uint32_t Flags = getSectionFlags(Sec); | |||
357 | return Flags & (XCOFF::STYP_BSS | XCOFF::STYP_TBSS); | |||
358 | } | |||
359 | ||||
360 | bool XCOFFObjectFile::isDebugSection(DataRefImpl Sec) const { | |||
361 | uint32_t Flags = getSectionFlags(Sec); | |||
362 | return Flags & (XCOFF::STYP_DEBUG | XCOFF::STYP_DWARF); | |||
363 | } | |||
364 | ||||
365 | bool XCOFFObjectFile::isSectionVirtual(DataRefImpl Sec) const { | |||
366 | return is64Bit() ? toSection64(Sec)->FileOffsetToRawData == 0 | |||
367 | : toSection32(Sec)->FileOffsetToRawData == 0; | |||
368 | } | |||
369 | ||||
370 | relocation_iterator XCOFFObjectFile::section_rel_begin(DataRefImpl Sec) const { | |||
371 | DataRefImpl Ret; | |||
372 | if (is64Bit()) { | |||
373 | const XCOFFSectionHeader64 *SectionEntPtr = toSection64(Sec); | |||
374 | auto RelocationsOrErr = | |||
375 | relocations<XCOFFSectionHeader64, XCOFFRelocation64>(*SectionEntPtr); | |||
376 | if (Error E = RelocationsOrErr.takeError()) { | |||
377 | // TODO: report the error up the stack. | |||
378 | consumeError(std::move(E)); | |||
379 | return relocation_iterator(RelocationRef()); | |||
380 | } | |||
381 | Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().begin()); | |||
382 | } else { | |||
383 | const XCOFFSectionHeader32 *SectionEntPtr = toSection32(Sec); | |||
384 | auto RelocationsOrErr = | |||
385 | relocations<XCOFFSectionHeader32, XCOFFRelocation32>(*SectionEntPtr); | |||
386 | if (Error E = RelocationsOrErr.takeError()) { | |||
387 | // TODO: report the error up the stack. | |||
388 | consumeError(std::move(E)); | |||
389 | return relocation_iterator(RelocationRef()); | |||
390 | } | |||
391 | Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().begin()); | |||
392 | } | |||
393 | return relocation_iterator(RelocationRef(Ret, this)); | |||
394 | } | |||
395 | ||||
396 | relocation_iterator XCOFFObjectFile::section_rel_end(DataRefImpl Sec) const { | |||
397 | DataRefImpl Ret; | |||
398 | if (is64Bit()) { | |||
399 | const XCOFFSectionHeader64 *SectionEntPtr = toSection64(Sec); | |||
400 | auto RelocationsOrErr = | |||
401 | relocations<XCOFFSectionHeader64, XCOFFRelocation64>(*SectionEntPtr); | |||
402 | if (Error E = RelocationsOrErr.takeError()) { | |||
403 | // TODO: report the error up the stack. | |||
404 | consumeError(std::move(E)); | |||
405 | return relocation_iterator(RelocationRef()); | |||
406 | } | |||
407 | Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().end()); | |||
408 | } else { | |||
409 | const XCOFFSectionHeader32 *SectionEntPtr = toSection32(Sec); | |||
410 | auto RelocationsOrErr = | |||
411 | relocations<XCOFFSectionHeader32, XCOFFRelocation32>(*SectionEntPtr); | |||
412 | if (Error E = RelocationsOrErr.takeError()) { | |||
413 | // TODO: report the error up the stack. | |||
414 | consumeError(std::move(E)); | |||
415 | return relocation_iterator(RelocationRef()); | |||
416 | } | |||
417 | Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().end()); | |||
418 | } | |||
419 | return relocation_iterator(RelocationRef(Ret, this)); | |||
420 | } | |||
421 | ||||
422 | void XCOFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const { | |||
423 | if (is64Bit()) | |||
424 | Rel.p = reinterpret_cast<uintptr_t>(viewAs<XCOFFRelocation64>(Rel.p) + 1); | |||
425 | else | |||
426 | Rel.p = reinterpret_cast<uintptr_t>(viewAs<XCOFFRelocation32>(Rel.p) + 1); | |||
427 | } | |||
428 | ||||
429 | uint64_t XCOFFObjectFile::getRelocationOffset(DataRefImpl Rel) const { | |||
430 | if (is64Bit()) { | |||
431 | const XCOFFRelocation64 *Reloc = viewAs<XCOFFRelocation64>(Rel.p); | |||
432 | const XCOFFSectionHeader64 *Sec64 = sectionHeaderTable64(); | |||
433 | const uint64_t RelocAddress = Reloc->VirtualAddress; | |||
434 | const uint16_t NumberOfSections = getNumberOfSections(); | |||
435 | for (uint16_t I = 0; I < NumberOfSections; ++I) { | |||
436 | // Find which section this relocation belongs to, and get the | |||
437 | // relocation offset relative to the start of the section. | |||
438 | if (Sec64->VirtualAddress <= RelocAddress && | |||
439 | RelocAddress < Sec64->VirtualAddress + Sec64->SectionSize) { | |||
440 | return RelocAddress - Sec64->VirtualAddress; | |||
441 | } | |||
442 | ++Sec64; | |||
443 | } | |||
444 | } else { | |||
445 | const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(Rel.p); | |||
446 | const XCOFFSectionHeader32 *Sec32 = sectionHeaderTable32(); | |||
447 | const uint32_t RelocAddress = Reloc->VirtualAddress; | |||
448 | const uint16_t NumberOfSections = getNumberOfSections(); | |||
449 | for (uint16_t I = 0; I < NumberOfSections; ++I) { | |||
450 | // Find which section this relocation belongs to, and get the | |||
451 | // relocation offset relative to the start of the section. | |||
452 | if (Sec32->VirtualAddress <= RelocAddress && | |||
453 | RelocAddress < Sec32->VirtualAddress + Sec32->SectionSize) { | |||
454 | return RelocAddress - Sec32->VirtualAddress; | |||
455 | } | |||
456 | ++Sec32; | |||
457 | } | |||
458 | } | |||
459 | return InvalidRelocOffset; | |||
460 | } | |||
461 | ||||
462 | symbol_iterator XCOFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const { | |||
463 | uint32_t Index; | |||
464 | if (is64Bit()) { | |||
465 | const XCOFFRelocation64 *Reloc = viewAs<XCOFFRelocation64>(Rel.p); | |||
466 | Index = Reloc->SymbolIndex; | |||
467 | ||||
468 | if (Index >= getNumberOfSymbolTableEntries64()) | |||
469 | return symbol_end(); | |||
470 | } else { | |||
471 | const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(Rel.p); | |||
472 | Index = Reloc->SymbolIndex; | |||
473 | ||||
474 | if (Index >= getLogicalNumberOfSymbolTableEntries32()) | |||
475 | return symbol_end(); | |||
476 | } | |||
477 | DataRefImpl SymDRI; | |||
478 | SymDRI.p = getSymbolEntryAddressByIndex(Index); | |||
479 | return symbol_iterator(SymbolRef(SymDRI, this)); | |||
480 | } | |||
481 | ||||
482 | uint64_t XCOFFObjectFile::getRelocationType(DataRefImpl Rel) const { | |||
483 | if (is64Bit()) | |||
484 | return viewAs<XCOFFRelocation64>(Rel.p)->Type; | |||
485 | return viewAs<XCOFFRelocation32>(Rel.p)->Type; | |||
486 | } | |||
487 | ||||
488 | void XCOFFObjectFile::getRelocationTypeName( | |||
489 | DataRefImpl Rel, SmallVectorImpl<char> &Result) const { | |||
490 | StringRef Res; | |||
491 | if (is64Bit()) { | |||
492 | const XCOFFRelocation64 *Reloc = viewAs<XCOFFRelocation64>(Rel.p); | |||
493 | Res = XCOFF::getRelocationTypeString(Reloc->Type); | |||
494 | } else { | |||
495 | const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(Rel.p); | |||
496 | Res = XCOFF::getRelocationTypeString(Reloc->Type); | |||
497 | } | |||
498 | Result.append(Res.begin(), Res.end()); | |||
499 | } | |||
500 | ||||
501 | Expected<uint32_t> XCOFFObjectFile::getSymbolFlags(DataRefImpl Symb) const { | |||
502 | uint32_t Result = 0; | |||
503 | // TODO: Return correct symbol flags. | |||
504 | return Result; | |||
505 | } | |||
506 | ||||
507 | basic_symbol_iterator XCOFFObjectFile::symbol_begin() const { | |||
508 | DataRefImpl SymDRI; | |||
509 | SymDRI.p = reinterpret_cast<uintptr_t>(SymbolTblPtr); | |||
510 | return basic_symbol_iterator(SymbolRef(SymDRI, this)); | |||
511 | } | |||
512 | ||||
513 | basic_symbol_iterator XCOFFObjectFile::symbol_end() const { | |||
514 | DataRefImpl SymDRI; | |||
515 | const uint32_t NumberOfSymbolTableEntries = getNumberOfSymbolTableEntries(); | |||
516 | SymDRI.p = getSymbolEntryAddressByIndex(NumberOfSymbolTableEntries); | |||
517 | return basic_symbol_iterator(SymbolRef(SymDRI, this)); | |||
518 | } | |||
519 | ||||
520 | section_iterator XCOFFObjectFile::section_begin() const { | |||
521 | DataRefImpl DRI; | |||
522 | DRI.p = getSectionHeaderTableAddress(); | |||
523 | return section_iterator(SectionRef(DRI, this)); | |||
524 | } | |||
525 | ||||
526 | section_iterator XCOFFObjectFile::section_end() const { | |||
527 | DataRefImpl DRI; | |||
528 | DRI.p = getWithOffset(getSectionHeaderTableAddress(), | |||
529 | getNumberOfSections() * getSectionHeaderSize()); | |||
530 | return section_iterator(SectionRef(DRI, this)); | |||
531 | } | |||
532 | ||||
533 | uint8_t XCOFFObjectFile::getBytesInAddress() const { return is64Bit() ? 8 : 4; } | |||
534 | ||||
535 | StringRef XCOFFObjectFile::getFileFormatName() const { | |||
536 | return is64Bit() ? "aix5coff64-rs6000" : "aixcoff-rs6000"; | |||
537 | } | |||
538 | ||||
539 | Triple::ArchType XCOFFObjectFile::getArch() const { | |||
540 | return is64Bit() ? Triple::ppc64 : Triple::ppc; | |||
541 | } | |||
542 | ||||
543 | SubtargetFeatures XCOFFObjectFile::getFeatures() const { | |||
544 | return SubtargetFeatures(); | |||
545 | } | |||
546 | ||||
547 | bool XCOFFObjectFile::isRelocatableObject() const { | |||
548 | if (is64Bit()) | |||
549 | return !(fileHeader64()->Flags & NoRelMask); | |||
550 | return !(fileHeader32()->Flags & NoRelMask); | |||
551 | } | |||
552 | ||||
553 | Expected<uint64_t> XCOFFObjectFile::getStartAddress() const { | |||
554 | // TODO FIXME Should get from auxiliary_header->o_entry when support for the | |||
555 | // auxiliary_header is added. | |||
556 | return 0; | |||
557 | } | |||
558 | ||||
559 | StringRef XCOFFObjectFile::mapDebugSectionName(StringRef Name) const { | |||
560 | return StringSwitch<StringRef>(Name) | |||
561 | .Case("dwinfo", "debug_info") | |||
562 | .Case("dwline", "debug_line") | |||
563 | .Case("dwpbnms", "debug_pubnames") | |||
564 | .Case("dwpbtyp", "debug_pubtypes") | |||
565 | .Case("dwarnge", "debug_aranges") | |||
566 | .Case("dwabrev", "debug_abbrev") | |||
567 | .Case("dwstr", "debug_str") | |||
568 | .Case("dwrnges", "debug_ranges") | |||
569 | .Case("dwloc", "debug_loc") | |||
570 | .Case("dwframe", "debug_frame") | |||
571 | .Case("dwmac", "debug_macinfo") | |||
572 | .Default(Name); | |||
573 | } | |||
574 | ||||
575 | size_t XCOFFObjectFile::getFileHeaderSize() const { | |||
576 | return is64Bit() ? sizeof(XCOFFFileHeader64) : sizeof(XCOFFFileHeader32); | |||
577 | } | |||
578 | ||||
579 | size_t XCOFFObjectFile::getSectionHeaderSize() const { | |||
580 | return is64Bit() ? sizeof(XCOFFSectionHeader64) : | |||
581 | sizeof(XCOFFSectionHeader32); | |||
582 | } | |||
583 | ||||
584 | bool XCOFFObjectFile::is64Bit() const { | |||
585 | return Binary::ID_XCOFF64 == getType(); | |||
586 | } | |||
587 | ||||
588 | uint16_t XCOFFObjectFile::getMagic() const { | |||
589 | return is64Bit() ? fileHeader64()->Magic : fileHeader32()->Magic; | |||
590 | } | |||
591 | ||||
592 | Expected<DataRefImpl> XCOFFObjectFile::getSectionByNum(int16_t Num) const { | |||
593 | if (Num <= 0 || Num > getNumberOfSections()) | |||
594 | return errorCodeToError(object_error::invalid_section_index); | |||
595 | ||||
596 | DataRefImpl DRI; | |||
597 | DRI.p = getWithOffset(getSectionHeaderTableAddress(), | |||
598 | getSectionHeaderSize() * (Num - 1)); | |||
599 | return DRI; | |||
600 | } | |||
601 | ||||
602 | Expected<StringRef> | |||
603 | XCOFFObjectFile::getSymbolSectionName(XCOFFSymbolRef SymEntPtr) const { | |||
604 | const int16_t SectionNum = SymEntPtr.getSectionNumber(); | |||
605 | ||||
606 | switch (SectionNum) { | |||
607 | case XCOFF::N_DEBUG: | |||
608 | return "N_DEBUG"; | |||
609 | case XCOFF::N_ABS: | |||
610 | return "N_ABS"; | |||
611 | case XCOFF::N_UNDEF: | |||
612 | return "N_UNDEF"; | |||
613 | default: | |||
614 | Expected<DataRefImpl> SecRef = getSectionByNum(SectionNum); | |||
615 | if (SecRef) | |||
616 | return generateXCOFFFixedNameStringRef( | |||
617 | getSectionNameInternal(SecRef.get())); | |||
618 | return SecRef.takeError(); | |||
619 | } | |||
620 | } | |||
621 | ||||
622 | unsigned XCOFFObjectFile::getSymbolSectionID(SymbolRef Sym) const { | |||
623 | XCOFFSymbolRef XCOFFSymRef(Sym.getRawDataRefImpl(), this); | |||
624 | return XCOFFSymRef.getSectionNumber(); | |||
625 | } | |||
626 | ||||
627 | bool XCOFFObjectFile::isReservedSectionNumber(int16_t SectionNumber) { | |||
628 | return (SectionNumber <= 0 && SectionNumber >= -2); | |||
629 | } | |||
630 | ||||
631 | uint16_t XCOFFObjectFile::getNumberOfSections() const { | |||
632 | return is64Bit() ? fileHeader64()->NumberOfSections | |||
633 | : fileHeader32()->NumberOfSections; | |||
634 | } | |||
635 | ||||
636 | int32_t XCOFFObjectFile::getTimeStamp() const { | |||
637 | return is64Bit() ? fileHeader64()->TimeStamp : fileHeader32()->TimeStamp; | |||
638 | } | |||
639 | ||||
640 | uint16_t XCOFFObjectFile::getOptionalHeaderSize() const { | |||
641 | return is64Bit() ? fileHeader64()->AuxHeaderSize | |||
642 | : fileHeader32()->AuxHeaderSize; | |||
643 | } | |||
644 | ||||
645 | uint32_t XCOFFObjectFile::getSymbolTableOffset32() const { | |||
646 | return fileHeader32()->SymbolTableOffset; | |||
647 | } | |||
648 | ||||
649 | int32_t XCOFFObjectFile::getRawNumberOfSymbolTableEntries32() const { | |||
650 | // As far as symbol table size is concerned, if this field is negative it is | |||
651 | // to be treated as a 0. However since this field is also used for printing we | |||
652 | // don't want to truncate any negative values. | |||
653 | return fileHeader32()->NumberOfSymTableEntries; | |||
654 | } | |||
655 | ||||
656 | uint32_t XCOFFObjectFile::getLogicalNumberOfSymbolTableEntries32() const { | |||
657 | return (fileHeader32()->NumberOfSymTableEntries >= 0 | |||
658 | ? fileHeader32()->NumberOfSymTableEntries | |||
659 | : 0); | |||
660 | } | |||
661 | ||||
662 | uint64_t XCOFFObjectFile::getSymbolTableOffset64() const { | |||
663 | return fileHeader64()->SymbolTableOffset; | |||
664 | } | |||
665 | ||||
666 | uint32_t XCOFFObjectFile::getNumberOfSymbolTableEntries64() const { | |||
667 | return fileHeader64()->NumberOfSymTableEntries; | |||
668 | } | |||
669 | ||||
670 | uint32_t XCOFFObjectFile::getNumberOfSymbolTableEntries() const { | |||
671 | return is64Bit() ? getNumberOfSymbolTableEntries64() | |||
672 | : getLogicalNumberOfSymbolTableEntries32(); | |||
673 | } | |||
674 | ||||
675 | uintptr_t XCOFFObjectFile::getEndOfSymbolTableAddress() const { | |||
676 | const uint32_t NumberOfSymTableEntries = getNumberOfSymbolTableEntries(); | |||
677 | return getWithOffset(reinterpret_cast<uintptr_t>(SymbolTblPtr), | |||
678 | XCOFF::SymbolTableEntrySize * NumberOfSymTableEntries); | |||
679 | } | |||
680 | ||||
681 | void XCOFFObjectFile::checkSymbolEntryPointer(uintptr_t SymbolEntPtr) const { | |||
682 | if (SymbolEntPtr < reinterpret_cast<uintptr_t>(SymbolTblPtr)) | |||
683 | report_fatal_error("Symbol table entry is outside of symbol table."); | |||
684 | ||||
685 | if (SymbolEntPtr >= getEndOfSymbolTableAddress()) | |||
686 | report_fatal_error("Symbol table entry is outside of symbol table."); | |||
687 | ||||
688 | ptrdiff_t Offset = reinterpret_cast<const char *>(SymbolEntPtr) - | |||
689 | reinterpret_cast<const char *>(SymbolTblPtr); | |||
690 | ||||
691 | if (Offset % XCOFF::SymbolTableEntrySize != 0) | |||
692 | report_fatal_error( | |||
693 | "Symbol table entry position is not valid inside of symbol table."); | |||
694 | } | |||
695 | ||||
696 | uint32_t XCOFFObjectFile::getSymbolIndex(uintptr_t SymbolEntPtr) const { | |||
697 | return (reinterpret_cast<const char *>(SymbolEntPtr) - | |||
698 | reinterpret_cast<const char *>(SymbolTblPtr)) / | |||
699 | XCOFF::SymbolTableEntrySize; | |||
700 | } | |||
701 | ||||
702 | uintptr_t XCOFFObjectFile::getSymbolEntryAddressByIndex(uint32_t Index) const { | |||
703 | return getAdvancedSymbolEntryAddress( | |||
704 | reinterpret_cast<uintptr_t>(getPointerToSymbolTable()), Index); | |||
705 | } | |||
706 | ||||
707 | Expected<StringRef> | |||
708 | XCOFFObjectFile::getSymbolNameByIndex(uint32_t Index) const { | |||
709 | const uint32_t NumberOfSymTableEntries = getNumberOfSymbolTableEntries(); | |||
710 | ||||
711 | if (Index >= NumberOfSymTableEntries) | |||
712 | return errorCodeToError(object_error::invalid_symbol_index); | |||
713 | ||||
714 | DataRefImpl SymDRI; | |||
715 | SymDRI.p = getSymbolEntryAddressByIndex(Index); | |||
716 | return getSymbolName(SymDRI); | |||
717 | } | |||
718 | ||||
719 | uint16_t XCOFFObjectFile::getFlags() const { | |||
720 | return is64Bit() ? fileHeader64()->Flags : fileHeader32()->Flags; | |||
721 | } | |||
722 | ||||
723 | const char *XCOFFObjectFile::getSectionNameInternal(DataRefImpl Sec) const { | |||
724 | return is64Bit() ? toSection64(Sec)->Name : toSection32(Sec)->Name; | |||
725 | } | |||
726 | ||||
727 | uintptr_t XCOFFObjectFile::getSectionHeaderTableAddress() const { | |||
728 | return reinterpret_cast<uintptr_t>(SectionHeaderTable); | |||
729 | } | |||
730 | ||||
731 | int32_t XCOFFObjectFile::getSectionFlags(DataRefImpl Sec) const { | |||
732 | return is64Bit() ? toSection64(Sec)->Flags : toSection32(Sec)->Flags; | |||
733 | } | |||
734 | ||||
735 | XCOFFObjectFile::XCOFFObjectFile(unsigned int Type, MemoryBufferRef Object) | |||
736 | : ObjectFile(Type, Object) { | |||
737 | assert(Type == Binary::ID_XCOFF32 || Type == Binary::ID_XCOFF64)(static_cast <bool> (Type == Binary::ID_XCOFF32 || Type == Binary::ID_XCOFF64) ? void (0) : __assert_fail ("Type == Binary::ID_XCOFF32 || Type == Binary::ID_XCOFF64" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/lib/Object/XCOFFObjectFile.cpp" , 737, __extension__ __PRETTY_FUNCTION__)); | |||
738 | } | |||
739 | ||||
740 | ArrayRef<XCOFFSectionHeader64> XCOFFObjectFile::sections64() const { | |||
741 | assert(is64Bit() && "64-bit interface called for non 64-bit file.")(static_cast <bool> (is64Bit() && "64-bit interface called for non 64-bit file." ) ? void (0) : __assert_fail ("is64Bit() && \"64-bit interface called for non 64-bit file.\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/lib/Object/XCOFFObjectFile.cpp" , 741, __extension__ __PRETTY_FUNCTION__)); | |||
742 | const XCOFFSectionHeader64 *TablePtr = sectionHeaderTable64(); | |||
743 | return ArrayRef<XCOFFSectionHeader64>(TablePtr, | |||
744 | TablePtr + getNumberOfSections()); | |||
745 | } | |||
746 | ||||
747 | ArrayRef<XCOFFSectionHeader32> XCOFFObjectFile::sections32() const { | |||
748 | assert(!is64Bit() && "32-bit interface called for non 32-bit file.")(static_cast <bool> (!is64Bit() && "32-bit interface called for non 32-bit file." ) ? void (0) : __assert_fail ("!is64Bit() && \"32-bit interface called for non 32-bit file.\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/lib/Object/XCOFFObjectFile.cpp" , 748, __extension__ __PRETTY_FUNCTION__)); | |||
749 | const XCOFFSectionHeader32 *TablePtr = sectionHeaderTable32(); | |||
750 | return ArrayRef<XCOFFSectionHeader32>(TablePtr, | |||
751 | TablePtr + getNumberOfSections()); | |||
752 | } | |||
753 | ||||
754 | // In an XCOFF32 file, when the field value is 65535, then an STYP_OVRFLO | |||
755 | // section header contains the actual count of relocation entries in the s_paddr | |||
756 | // field. STYP_OVRFLO headers contain the section index of their corresponding | |||
757 | // sections as their raw "NumberOfRelocations" field value. | |||
758 | template <typename T> | |||
759 | Expected<uint32_t> XCOFFObjectFile::getNumberOfRelocationEntries( | |||
760 | const XCOFFSectionHeader<T> &Sec) const { | |||
761 | const T &Section = static_cast<const T &>(Sec); | |||
762 | if (is64Bit()) | |||
763 | return Section.NumberOfRelocations; | |||
764 | ||||
765 | uint16_t SectionIndex = &Section - sectionHeaderTable<T>() + 1; | |||
766 | if (Section.NumberOfRelocations < XCOFF::RelocOverflow) | |||
767 | return Section.NumberOfRelocations; | |||
768 | for (const auto &Sec : sections32()) { | |||
769 | if (Sec.Flags == XCOFF::STYP_OVRFLO && | |||
770 | Sec.NumberOfRelocations == SectionIndex) | |||
771 | return Sec.PhysicalAddress; | |||
772 | } | |||
773 | return errorCodeToError(object_error::parse_failed); | |||
774 | } | |||
775 | ||||
776 | template <typename Shdr, typename Reloc> | |||
777 | Expected<ArrayRef<Reloc>> XCOFFObjectFile::relocations(const Shdr &Sec) const { | |||
778 | uintptr_t RelocAddr = getWithOffset(reinterpret_cast<uintptr_t>(FileHeader), | |||
779 | Sec.FileOffsetToRelocationInfo); | |||
780 | auto NumRelocEntriesOrErr = getNumberOfRelocationEntries(Sec); | |||
781 | if (Error E = NumRelocEntriesOrErr.takeError()) | |||
782 | return std::move(E); | |||
783 | ||||
784 | uint32_t NumRelocEntries = NumRelocEntriesOrErr.get(); | |||
785 | static_assert((sizeof(Reloc) == XCOFF::RelocationSerializationSize64 || | |||
786 | sizeof(Reloc) == XCOFF::RelocationSerializationSize32), | |||
787 | "Relocation structure is incorrect"); | |||
788 | auto RelocationOrErr = | |||
789 | getObject<Reloc>(Data, reinterpret_cast<void *>(RelocAddr), | |||
790 | NumRelocEntries * sizeof(Reloc)); | |||
791 | if (Error E = RelocationOrErr.takeError()) | |||
792 | return std::move(E); | |||
793 | ||||
794 | const Reloc *StartReloc = RelocationOrErr.get(); | |||
795 | ||||
796 | return ArrayRef<Reloc>(StartReloc, StartReloc + NumRelocEntries); | |||
797 | } | |||
798 | ||||
799 | Expected<XCOFFStringTable> | |||
800 | XCOFFObjectFile::parseStringTable(const XCOFFObjectFile *Obj, uint64_t Offset) { | |||
801 | // If there is a string table, then the buffer must contain at least 4 bytes | |||
802 | // for the string table's size. Not having a string table is not an error. | |||
803 | if (Error E = Binary::checkOffset( | |||
804 | Obj->Data, reinterpret_cast<uintptr_t>(Obj->base() + Offset), 4)) { | |||
805 | consumeError(std::move(E)); | |||
806 | return XCOFFStringTable{0, nullptr}; | |||
807 | } | |||
808 | ||||
809 | // Read the size out of the buffer. | |||
810 | uint32_t Size = support::endian::read32be(Obj->base() + Offset); | |||
811 | ||||
812 | // If the size is less then 4, then the string table is just a size and no | |||
813 | // string data. | |||
814 | if (Size <= 4) | |||
815 | return XCOFFStringTable{4, nullptr}; | |||
816 | ||||
817 | auto StringTableOrErr = | |||
818 | getObject<char>(Obj->Data, Obj->base() + Offset, Size); | |||
819 | if (Error E = StringTableOrErr.takeError()) | |||
820 | return std::move(E); | |||
821 | ||||
822 | const char *StringTablePtr = StringTableOrErr.get(); | |||
823 | if (StringTablePtr[Size - 1] != '\0') | |||
824 | return errorCodeToError(object_error::string_table_non_null_end); | |||
825 | ||||
826 | return XCOFFStringTable{Size, StringTablePtr}; | |||
827 | } | |||
828 | ||||
829 | // This function returns the import file table. Each entry in the import file | |||
830 | // table consists of: "path_name\0base_name\0archive_member_name\0". | |||
831 | Expected<StringRef> XCOFFObjectFile::getImportFileTable() const { | |||
832 | Expected<uintptr_t> LoaderSectionAddrOrError = getLoaderSectionAddress(); | |||
833 | if (!LoaderSectionAddrOrError) | |||
834 | return LoaderSectionAddrOrError.takeError(); | |||
835 | ||||
836 | uintptr_t LoaderSectionAddr = LoaderSectionAddrOrError.get(); | |||
837 | if (!LoaderSectionAddr) | |||
838 | return StringRef(); | |||
839 | ||||
840 | uint64_t OffsetToImportFileTable = 0; | |||
841 | uint64_t LengthOfImportFileTable = 0; | |||
842 | if (is64Bit()) { | |||
843 | const LoaderSectionHeader64 *LoaderSec64 = | |||
844 | viewAs<LoaderSectionHeader64>(LoaderSectionAddr); | |||
845 | OffsetToImportFileTable = LoaderSec64->OffsetToImpid; | |||
846 | LengthOfImportFileTable = LoaderSec64->LengthOfImpidStrTbl; | |||
847 | } else { | |||
848 | const LoaderSectionHeader32 *LoaderSec32 = | |||
849 | viewAs<LoaderSectionHeader32>(LoaderSectionAddr); | |||
850 | OffsetToImportFileTable = LoaderSec32->OffsetToImpid; | |||
851 | LengthOfImportFileTable = LoaderSec32->LengthOfImpidStrTbl; | |||
852 | } | |||
853 | ||||
854 | auto ImportTableOrErr = getObject<char>( | |||
855 | Data, | |||
856 | reinterpret_cast<void *>(LoaderSectionAddr + OffsetToImportFileTable), | |||
857 | LengthOfImportFileTable); | |||
858 | if (Error E = ImportTableOrErr.takeError()) | |||
859 | return std::move(E); | |||
860 | ||||
861 | const char *ImportTablePtr = ImportTableOrErr.get(); | |||
862 | if (ImportTablePtr[LengthOfImportFileTable - 1] != '\0') | |||
863 | return createStringError( | |||
864 | object_error::parse_failed, | |||
865 | "the import file table must end with a null terminator"); | |||
866 | ||||
867 | return StringRef(ImportTablePtr, LengthOfImportFileTable); | |||
868 | } | |||
869 | ||||
870 | Expected<std::unique_ptr<XCOFFObjectFile>> | |||
871 | XCOFFObjectFile::create(unsigned Type, MemoryBufferRef MBR) { | |||
872 | // Can't use std::make_unique because of the private constructor. | |||
873 | std::unique_ptr<XCOFFObjectFile> Obj; | |||
874 | Obj.reset(new XCOFFObjectFile(Type, MBR)); | |||
875 | ||||
876 | uint64_t CurOffset = 0; | |||
877 | const auto *Base = Obj->base(); | |||
878 | MemoryBufferRef Data = Obj->Data; | |||
879 | ||||
880 | // Parse file header. | |||
881 | auto FileHeaderOrErr = | |||
882 | getObject<void>(Data, Base + CurOffset, Obj->getFileHeaderSize()); | |||
883 | if (Error E = FileHeaderOrErr.takeError()) | |||
884 | return std::move(E); | |||
885 | Obj->FileHeader = FileHeaderOrErr.get(); | |||
886 | ||||
887 | CurOffset += Obj->getFileHeaderSize(); | |||
888 | // TODO FIXME we don't have support for an optional header yet, so just skip | |||
889 | // past it. | |||
890 | CurOffset += Obj->getOptionalHeaderSize(); | |||
891 | ||||
892 | // Parse the section header table if it is present. | |||
893 | if (Obj->getNumberOfSections()) { | |||
894 | auto SecHeadersOrErr = getObject<void>(Data, Base + CurOffset, | |||
895 | Obj->getNumberOfSections() * | |||
896 | Obj->getSectionHeaderSize()); | |||
897 | if (Error E = SecHeadersOrErr.takeError()) | |||
898 | return std::move(E); | |||
899 | Obj->SectionHeaderTable = SecHeadersOrErr.get(); | |||
900 | } | |||
901 | ||||
902 | const uint32_t NumberOfSymbolTableEntries = | |||
903 | Obj->getNumberOfSymbolTableEntries(); | |||
904 | ||||
905 | // If there is no symbol table we are done parsing the memory buffer. | |||
906 | if (NumberOfSymbolTableEntries == 0) | |||
907 | return std::move(Obj); | |||
908 | ||||
909 | // Parse symbol table. | |||
910 | CurOffset = Obj->is64Bit() ? Obj->getSymbolTableOffset64() | |||
911 | : Obj->getSymbolTableOffset32(); | |||
912 | const uint64_t SymbolTableSize = | |||
913 | static_cast<uint64_t>(XCOFF::SymbolTableEntrySize) * | |||
914 | NumberOfSymbolTableEntries; | |||
915 | auto SymTableOrErr = | |||
916 | getObject<void *>(Data, Base + CurOffset, SymbolTableSize); | |||
917 | if (Error E = SymTableOrErr.takeError()) | |||
918 | return std::move(E); | |||
919 | Obj->SymbolTblPtr = SymTableOrErr.get(); | |||
920 | CurOffset += SymbolTableSize; | |||
921 | ||||
922 | // Parse String table. | |||
923 | Expected<XCOFFStringTable> StringTableOrErr = | |||
924 | parseStringTable(Obj.get(), CurOffset); | |||
925 | if (Error E = StringTableOrErr.takeError()) | |||
926 | return std::move(E); | |||
927 | Obj->StringTable = StringTableOrErr.get(); | |||
928 | ||||
929 | return std::move(Obj); | |||
930 | } | |||
931 | ||||
932 | Expected<std::unique_ptr<ObjectFile>> | |||
933 | ObjectFile::createXCOFFObjectFile(MemoryBufferRef MemBufRef, | |||
934 | unsigned FileType) { | |||
935 | return XCOFFObjectFile::create(FileType, MemBufRef); | |||
936 | } | |||
937 | ||||
938 | bool XCOFFSymbolRef::isFunction() const { | |||
939 | if (!isCsectSymbol()) | |||
940 | return false; | |||
941 | ||||
942 | if (getSymbolType() & FunctionSym) | |||
943 | return true; | |||
944 | ||||
945 | Expected<XCOFFCsectAuxRef> ExpCsectAuxEnt = getXCOFFCsectAuxRef(); | |||
946 | if (!ExpCsectAuxEnt) | |||
947 | return false; | |||
948 | ||||
949 | const XCOFFCsectAuxRef CsectAuxRef = ExpCsectAuxEnt.get(); | |||
950 | ||||
951 | // A function definition should be a label definition. | |||
952 | // FIXME: This is not necessarily the case when -ffunction-sections is | |||
953 | // enabled. | |||
954 | if (!CsectAuxRef.isLabel()) | |||
955 | return false; | |||
956 | ||||
957 | if (CsectAuxRef.getStorageMappingClass() != XCOFF::XMC_PR) | |||
958 | return false; | |||
959 | ||||
960 | const int16_t SectNum = getSectionNumber(); | |||
961 | Expected<DataRefImpl> SI = OwningObjectPtr->getSectionByNum(SectNum); | |||
962 | if (!SI) { | |||
963 | // If we could not get the section, then this symbol should not be | |||
964 | // a function. So consume the error and return `false` to move on. | |||
965 | consumeError(SI.takeError()); | |||
966 | return false; | |||
967 | } | |||
968 | ||||
969 | return (OwningObjectPtr->getSectionFlags(SI.get()) & XCOFF::STYP_TEXT); | |||
970 | } | |||
971 | ||||
972 | bool XCOFFSymbolRef::isCsectSymbol() const { | |||
973 | XCOFF::StorageClass SC = getStorageClass(); | |||
974 | return (SC == XCOFF::C_EXT || SC == XCOFF::C_WEAKEXT || | |||
975 | SC == XCOFF::C_HIDEXT); | |||
976 | } | |||
977 | ||||
978 | Expected<XCOFFCsectAuxRef> XCOFFSymbolRef::getXCOFFCsectAuxRef() const { | |||
979 | assert(isCsectSymbol() &&(static_cast <bool> (isCsectSymbol() && "Calling csect symbol interface with a non-csect symbol." ) ? void (0) : __assert_fail ("isCsectSymbol() && \"Calling csect symbol interface with a non-csect symbol.\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/lib/Object/XCOFFObjectFile.cpp" , 980, __extension__ __PRETTY_FUNCTION__)) | |||
980 | "Calling csect symbol interface with a non-csect symbol.")(static_cast <bool> (isCsectSymbol() && "Calling csect symbol interface with a non-csect symbol." ) ? void (0) : __assert_fail ("isCsectSymbol() && \"Calling csect symbol interface with a non-csect symbol.\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/lib/Object/XCOFFObjectFile.cpp" , 980, __extension__ __PRETTY_FUNCTION__)); | |||
981 | ||||
982 | uint8_t NumberOfAuxEntries = getNumberOfAuxEntries(); | |||
983 | ||||
984 | Expected<StringRef> NameOrErr = getName(); | |||
985 | if (auto Err = NameOrErr.takeError()) | |||
986 | return std::move(Err); | |||
987 | ||||
988 | if (!NumberOfAuxEntries) { | |||
989 | return createStringError(object_error::parse_failed, | |||
990 | "csect symbol \"" + *NameOrErr + | |||
991 | "\" contains no auxiliary entry"); | |||
992 | } | |||
993 | ||||
994 | if (!OwningObjectPtr->is64Bit()) { | |||
995 | // In XCOFF32, the csect auxilliary entry is always the last auxiliary | |||
996 | // entry for the symbol. | |||
997 | uintptr_t AuxAddr = XCOFFObjectFile::getAdvancedSymbolEntryAddress( | |||
998 | getEntryAddress(), NumberOfAuxEntries); | |||
999 | return XCOFFCsectAuxRef(viewAs<XCOFFCsectAuxEnt32>(AuxAddr)); | |||
1000 | } | |||
1001 | ||||
1002 | // XCOFF64 uses SymbolAuxType to identify the auxiliary entry type. | |||
1003 | // We need to iterate through all the auxiliary entries to find it. | |||
1004 | for (uint8_t Index = NumberOfAuxEntries; Index > 0; --Index) { | |||
1005 | uintptr_t AuxAddr = XCOFFObjectFile::getAdvancedSymbolEntryAddress( | |||
1006 | getEntryAddress(), Index); | |||
1007 | if (*OwningObjectPtr->getSymbolAuxType(AuxAddr) == | |||
1008 | XCOFF::SymbolAuxType::AUX_CSECT) { | |||
1009 | #ifndef NDEBUG | |||
1010 | OwningObjectPtr->checkSymbolEntryPointer(AuxAddr); | |||
1011 | #endif | |||
1012 | return XCOFFCsectAuxRef(viewAs<XCOFFCsectAuxEnt64>(AuxAddr)); | |||
1013 | } | |||
1014 | } | |||
1015 | ||||
1016 | return createStringError( | |||
1017 | object_error::parse_failed, | |||
1018 | "a csect auxiliary entry is not found for symbol \"" + *NameOrErr + "\""); | |||
1019 | } | |||
1020 | ||||
1021 | Expected<StringRef> XCOFFSymbolRef::getName() const { | |||
1022 | // A storage class value with the high-order bit on indicates that the name is | |||
1023 | // a symbolic debugger stabstring. | |||
1024 | if (getStorageClass() & 0x80) | |||
1025 | return StringRef("Unimplemented Debug Name"); | |||
1026 | ||||
1027 | if (Entry32) { | |||
1028 | if (Entry32->NameInStrTbl.Magic != XCOFFSymbolRef::NAME_IN_STR_TBL_MAGIC) | |||
1029 | return generateXCOFFFixedNameStringRef(Entry32->SymbolName); | |||
1030 | ||||
1031 | return OwningObjectPtr->getStringTableEntry(Entry32->NameInStrTbl.Offset); | |||
1032 | } | |||
1033 | ||||
1034 | return OwningObjectPtr->getStringTableEntry(Entry64->Offset); | |||
1035 | } | |||
1036 | ||||
1037 | // Explictly instantiate template classes. | |||
1038 | template struct XCOFFSectionHeader<XCOFFSectionHeader32>; | |||
1039 | template struct XCOFFSectionHeader<XCOFFSectionHeader64>; | |||
1040 | ||||
1041 | template struct XCOFFRelocation<llvm::support::ubig32_t>; | |||
1042 | template struct XCOFFRelocation<llvm::support::ubig64_t>; | |||
1043 | ||||
1044 | template llvm::Expected<llvm::ArrayRef<llvm::object::XCOFFRelocation64>> | |||
1045 | llvm::object::XCOFFObjectFile::relocations<llvm::object::XCOFFSectionHeader64, | |||
1046 | llvm::object::XCOFFRelocation64>( | |||
1047 | llvm::object::XCOFFSectionHeader64 const &) const; | |||
1048 | template llvm::Expected<llvm::ArrayRef<llvm::object::XCOFFRelocation32>> | |||
1049 | llvm::object::XCOFFObjectFile::relocations<llvm::object::XCOFFSectionHeader32, | |||
1050 | llvm::object::XCOFFRelocation32>( | |||
1051 | llvm::object::XCOFFSectionHeader32 const &) const; | |||
1052 | ||||
1053 | bool doesXCOFFTracebackTableBegin(ArrayRef<uint8_t> Bytes) { | |||
1054 | if (Bytes.size() < 4) | |||
1055 | return false; | |||
1056 | ||||
1057 | return support::endian::read32be(Bytes.data()) == 0; | |||
1058 | } | |||
1059 | ||||
1060 | #define GETVALUEWITHMASK(X) (Data & (TracebackTable::X)) | |||
1061 | #define GETVALUEWITHMASKSHIFT(X, S) \ | |||
1062 | ((Data & (TracebackTable::X)) >> (TracebackTable::S)) | |||
1063 | ||||
1064 | Expected<TBVectorExt> TBVectorExt::create(StringRef TBvectorStrRef) { | |||
1065 | Error Err = Error::success(); | |||
1066 | TBVectorExt TBTVecExt(TBvectorStrRef, Err); | |||
1067 | if (Err) | |||
1068 | return std::move(Err); | |||
1069 | return TBTVecExt; | |||
1070 | } | |||
1071 | ||||
1072 | TBVectorExt::TBVectorExt(StringRef TBvectorStrRef, Error &Err) { | |||
1073 | const uint8_t *Ptr = reinterpret_cast<const uint8_t *>(TBvectorStrRef.data()); | |||
1074 | Data = support::endian::read16be(Ptr); | |||
1075 | uint32_t VecParmsTypeValue = support::endian::read32be(Ptr + 2); | |||
1076 | unsigned ParmsNum = | |||
1077 | GETVALUEWITHMASKSHIFT(NumberOfVectorParmsMask, NumberOfVectorParmsShift); | |||
1078 | ||||
1079 | ErrorAsOutParameter EAO(&Err); | |||
1080 | Expected<SmallString<32>> VecParmsTypeOrError = | |||
1081 | parseVectorParmsType(VecParmsTypeValue, ParmsNum); | |||
1082 | if (!VecParmsTypeOrError) | |||
1083 | Err = VecParmsTypeOrError.takeError(); | |||
1084 | else | |||
1085 | VecParmsInfo = VecParmsTypeOrError.get(); | |||
1086 | } | |||
1087 | ||||
1088 | uint8_t TBVectorExt::getNumberOfVRSaved() const { | |||
1089 | return GETVALUEWITHMASKSHIFT(NumberOfVRSavedMask, NumberOfVRSavedShift); | |||
1090 | } | |||
1091 | ||||
1092 | bool TBVectorExt::isVRSavedOnStack() const { | |||
1093 | return GETVALUEWITHMASK(IsVRSavedOnStackMask); | |||
1094 | } | |||
1095 | ||||
1096 | bool TBVectorExt::hasVarArgs() const { | |||
1097 | return GETVALUEWITHMASK(HasVarArgsMask); | |||
1098 | } | |||
1099 | ||||
1100 | uint8_t TBVectorExt::getNumberOfVectorParms() const { | |||
1101 | return GETVALUEWITHMASKSHIFT(NumberOfVectorParmsMask, | |||
1102 | NumberOfVectorParmsShift); | |||
1103 | } | |||
1104 | ||||
1105 | bool TBVectorExt::hasVMXInstruction() const { | |||
1106 | return GETVALUEWITHMASK(HasVMXInstructionMask); | |||
1107 | } | |||
1108 | #undef GETVALUEWITHMASK | |||
1109 | #undef GETVALUEWITHMASKSHIFT | |||
1110 | ||||
1111 | Expected<XCOFFTracebackTable> XCOFFTracebackTable::create(const uint8_t *Ptr, | |||
1112 | uint64_t &Size) { | |||
1113 | Error Err = Error::success(); | |||
1114 | XCOFFTracebackTable TBT(Ptr, Size, Err); | |||
1115 | if (Err) | |||
1116 | return std::move(Err); | |||
1117 | return TBT; | |||
1118 | } | |||
1119 | ||||
1120 | XCOFFTracebackTable::XCOFFTracebackTable(const uint8_t *Ptr, uint64_t &Size, | |||
1121 | Error &Err) | |||
1122 | : TBPtr(Ptr) { | |||
1123 | ErrorAsOutParameter EAO(&Err); | |||
1124 | DataExtractor DE(ArrayRef<uint8_t>(Ptr, Size), /*IsLittleEndian=*/false, | |||
1125 | /*AddressSize=*/0); | |||
1126 | DataExtractor::Cursor Cur(/*Offset=*/0); | |||
1127 | ||||
1128 | // Skip 8 bytes of mandatory fields. | |||
1129 | DE.getU64(Cur); | |||
1130 | ||||
1131 | unsigned FixedParmsNum = getNumberOfFixedParms(); | |||
1132 | unsigned FloatingParmsNum = getNumberOfFPParms(); | |||
1133 | uint32_t ParamsTypeValue = 0; | |||
1134 | ||||
1135 | // Begin to parse optional fields. | |||
1136 | if (Cur && (FixedParmsNum + FloatingParmsNum) > 0) | |||
1137 | ParamsTypeValue = DE.getU32(Cur); | |||
1138 | ||||
1139 | if (Cur && hasTraceBackTableOffset()) | |||
1140 | TraceBackTableOffset = DE.getU32(Cur); | |||
1141 | ||||
1142 | if (Cur && isInterruptHandler()) | |||
1143 | HandlerMask = DE.getU32(Cur); | |||
1144 | ||||
1145 | if (Cur && hasControlledStorage()) { | |||
1146 | NumOfCtlAnchors = DE.getU32(Cur); | |||
1147 | if (Cur && NumOfCtlAnchors) { | |||
1148 | SmallVector<uint32_t, 8> Disp; | |||
1149 | Disp.reserve(NumOfCtlAnchors.getValue()); | |||
1150 | for (uint32_t I = 0; I < NumOfCtlAnchors && Cur; ++I) | |||
1151 | Disp.push_back(DE.getU32(Cur)); | |||
1152 | if (Cur) | |||
1153 | ControlledStorageInfoDisp = std::move(Disp); | |||
1154 | } | |||
1155 | } | |||
1156 | ||||
1157 | if (Cur && isFuncNamePresent()) { | |||
1158 | uint16_t FunctionNameLen = DE.getU16(Cur); | |||
1159 | if (Cur) | |||
1160 | FunctionName = DE.getBytes(Cur, FunctionNameLen); | |||
1161 | } | |||
1162 | ||||
1163 | if (Cur && isAllocaUsed()) | |||
1164 | AllocaRegister = DE.getU8(Cur); | |||
1165 | ||||
1166 | unsigned VectorParmsNum = 0; | |||
1167 | if (Cur && hasVectorInfo()) { | |||
1168 | StringRef VectorExtRef = DE.getBytes(Cur, 6); | |||
1169 | if (Cur) { | |||
1170 | Expected<TBVectorExt> TBVecExtOrErr = TBVectorExt::create(VectorExtRef); | |||
1171 | if (!TBVecExtOrErr) { | |||
1172 | Err = TBVecExtOrErr.takeError(); | |||
1173 | return; | |||
1174 | } | |||
1175 | VecExt = TBVecExtOrErr.get(); | |||
1176 | VectorParmsNum = VecExt.getValue().getNumberOfVectorParms(); | |||
1177 | } | |||
1178 | } | |||
1179 | ||||
1180 | // As long as there is no fixed-point or floating-point parameter, this | |||
1181 | // field remains not present even when hasVectorInfo gives true and | |||
1182 | // indicates the presence of vector parameters. | |||
1183 | if (Cur && (FixedParmsNum + FloatingParmsNum) > 0) { | |||
1184 | Expected<SmallString<32>> ParmsTypeOrError = | |||
1185 | hasVectorInfo() | |||
1186 | ? parseParmsTypeWithVecInfo(ParamsTypeValue, FixedParmsNum, | |||
1187 | FloatingParmsNum, VectorParmsNum) | |||
1188 | : parseParmsType(ParamsTypeValue, FixedParmsNum, FloatingParmsNum); | |||
1189 | ||||
1190 | if (!ParmsTypeOrError) { | |||
1191 | Err = ParmsTypeOrError.takeError(); | |||
1192 | return; | |||
1193 | } | |||
1194 | ParmsType = ParmsTypeOrError.get(); | |||
1195 | } | |||
1196 | ||||
1197 | if (Cur && hasExtensionTable()) | |||
1198 | ExtensionTable = DE.getU8(Cur); | |||
1199 | ||||
1200 | if (!Cur) | |||
1201 | Err = Cur.takeError(); | |||
1202 | ||||
1203 | Size = Cur.tell(); | |||
1204 | } | |||
1205 | ||||
1206 | #define GETBITWITHMASK(P, X) \ | |||
1207 | (support::endian::read32be(TBPtr + (P)) & (TracebackTable::X)) | |||
1208 | #define GETBITWITHMASKSHIFT(P, X, S) \ | |||
1209 | ((support::endian::read32be(TBPtr + (P)) & (TracebackTable::X)) >> \ | |||
1210 | (TracebackTable::S)) | |||
1211 | ||||
1212 | uint8_t XCOFFTracebackTable::getVersion() const { | |||
1213 | return GETBITWITHMASKSHIFT(0, VersionMask, VersionShift); | |||
1214 | } | |||
1215 | ||||
1216 | uint8_t XCOFFTracebackTable::getLanguageID() const { | |||
1217 | return GETBITWITHMASKSHIFT(0, LanguageIdMask, LanguageIdShift); | |||
1218 | } | |||
1219 | ||||
1220 | bool XCOFFTracebackTable::isGlobalLinkage() const { | |||
1221 | return GETBITWITHMASK(0, IsGlobaLinkageMask); | |||
1222 | } | |||
1223 | ||||
1224 | bool XCOFFTracebackTable::isOutOfLineEpilogOrPrologue() const { | |||
1225 | return GETBITWITHMASK(0, IsOutOfLineEpilogOrPrologueMask); | |||
1226 | } | |||
1227 | ||||
1228 | bool XCOFFTracebackTable::hasTraceBackTableOffset() const { | |||
1229 | return GETBITWITHMASK(0, HasTraceBackTableOffsetMask); | |||
1230 | } | |||
1231 | ||||
1232 | bool XCOFFTracebackTable::isInternalProcedure() const { | |||
1233 | return GETBITWITHMASK(0, IsInternalProcedureMask); | |||
1234 | } | |||
1235 | ||||
1236 | bool XCOFFTracebackTable::hasControlledStorage() const { | |||
1237 | return GETBITWITHMASK(0, HasControlledStorageMask); | |||
1238 | } | |||
1239 | ||||
1240 | bool XCOFFTracebackTable::isTOCless() const { | |||
1241 | return GETBITWITHMASK(0, IsTOClessMask); | |||
1242 | } | |||
1243 | ||||
1244 | bool XCOFFTracebackTable::isFloatingPointPresent() const { | |||
1245 | return GETBITWITHMASK(0, IsFloatingPointPresentMask); | |||
1246 | } | |||
1247 | ||||
1248 | bool XCOFFTracebackTable::isFloatingPointOperationLogOrAbortEnabled() const { | |||
1249 | return GETBITWITHMASK(0, IsFloatingPointOperationLogOrAbortEnabledMask); | |||
1250 | } | |||
1251 | ||||
1252 | bool XCOFFTracebackTable::isInterruptHandler() const { | |||
1253 | return GETBITWITHMASK(0, IsInterruptHandlerMask); | |||
1254 | } | |||
1255 | ||||
1256 | bool XCOFFTracebackTable::isFuncNamePresent() const { | |||
1257 | return GETBITWITHMASK(0, IsFunctionNamePresentMask); | |||
1258 | } | |||
1259 | ||||
1260 | bool XCOFFTracebackTable::isAllocaUsed() const { | |||
1261 | return GETBITWITHMASK(0, IsAllocaUsedMask); | |||
1262 | } | |||
1263 | ||||
1264 | uint8_t XCOFFTracebackTable::getOnConditionDirective() const { | |||
1265 | return GETBITWITHMASKSHIFT(0, OnConditionDirectiveMask, | |||
1266 | OnConditionDirectiveShift); | |||
1267 | } | |||
1268 | ||||
1269 | bool XCOFFTracebackTable::isCRSaved() const { | |||
1270 | return GETBITWITHMASK(0, IsCRSavedMask); | |||
1271 | } | |||
1272 | ||||
1273 | bool XCOFFTracebackTable::isLRSaved() const { | |||
1274 | return GETBITWITHMASK(0, IsLRSavedMask); | |||
1275 | } | |||
1276 | ||||
1277 | bool XCOFFTracebackTable::isBackChainStored() const { | |||
1278 | return GETBITWITHMASK(4, IsBackChainStoredMask); | |||
1279 | } | |||
1280 | ||||
1281 | bool XCOFFTracebackTable::isFixup() const { | |||
1282 | return GETBITWITHMASK(4, IsFixupMask); | |||
1283 | } | |||
1284 | ||||
1285 | uint8_t XCOFFTracebackTable::getNumOfFPRsSaved() const { | |||
1286 | return GETBITWITHMASKSHIFT(4, FPRSavedMask, FPRSavedShift); | |||
1287 | } | |||
1288 | ||||
1289 | bool XCOFFTracebackTable::hasExtensionTable() const { | |||
1290 | return GETBITWITHMASK(4, HasExtensionTableMask); | |||
1291 | } | |||
1292 | ||||
1293 | bool XCOFFTracebackTable::hasVectorInfo() const { | |||
1294 | return GETBITWITHMASK(4, HasVectorInfoMask); | |||
1295 | } | |||
1296 | ||||
1297 | uint8_t XCOFFTracebackTable::getNumOfGPRsSaved() const { | |||
1298 | return GETBITWITHMASKSHIFT(4, GPRSavedMask, GPRSavedShift); | |||
1299 | } | |||
1300 | ||||
1301 | uint8_t XCOFFTracebackTable::getNumberOfFixedParms() const { | |||
1302 | return GETBITWITHMASKSHIFT(4, NumberOfFixedParmsMask, | |||
1303 | NumberOfFixedParmsShift); | |||
1304 | } | |||
1305 | ||||
1306 | uint8_t XCOFFTracebackTable::getNumberOfFPParms() const { | |||
1307 | return GETBITWITHMASKSHIFT(4, NumberOfFloatingPointParmsMask, | |||
1308 | NumberOfFloatingPointParmsShift); | |||
1309 | } | |||
1310 | ||||
1311 | bool XCOFFTracebackTable::hasParmsOnStack() const { | |||
1312 | return GETBITWITHMASK(4, HasParmsOnStackMask); | |||
1313 | } | |||
1314 | ||||
1315 | #undef GETBITWITHMASK | |||
1316 | #undef GETBITWITHMASKSHIFT | |||
1317 | } // namespace object | |||
1318 | } // namespace llvm |
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 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 | ||||
61 | public: | |||
62 | StringRef getName() const; | |||
63 | uint16_t getSectionType() const; | |||
64 | bool isReservedSectionType() const; | |||
65 | }; | |||
66 | ||||
67 | // Explicit extern template declarations. | |||
68 | struct XCOFFSectionHeader32; | |||
69 | struct XCOFFSectionHeader64; | |||
70 | extern template struct XCOFFSectionHeader<XCOFFSectionHeader32>; | |||
71 | extern template struct XCOFFSectionHeader<XCOFFSectionHeader64>; | |||
72 | ||||
73 | struct XCOFFSectionHeader32 : XCOFFSectionHeader<XCOFFSectionHeader32> { | |||
74 | char Name[XCOFF::NameSize]; | |||
75 | 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; | |||
84 | }; | |||
85 | ||||
86 | struct XCOFFSectionHeader64 : XCOFFSectionHeader<XCOFFSectionHeader64> { | |||
87 | char Name[XCOFF::NameSize]; | |||
88 | 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]; | |||
98 | }; | |||
99 | ||||
100 | struct LoaderSectionHeader32 { | |||
101 | support::ubig32_t Version; | |||
102 | support::ubig32_t NumberOfSymTabEnt; | |||
103 | support::ubig32_t NumberOfRelTabEnt; | |||
104 | support::ubig32_t LengthOfImpidStrTbl; | |||
105 | support::ubig32_t NumberOfImpid; | |||
106 | support::big32_t OffsetToImpid; | |||
107 | support::ubig32_t LengthOfStrTbl; | |||
108 | support::big32_t OffsetToStrTbl; | |||
109 | }; | |||
110 | ||||
111 | struct LoaderSectionHeader64 { | |||
112 | support::ubig32_t Version; | |||
113 | support::ubig32_t NumberOfSymTabEnt; | |||
114 | support::ubig32_t NumberOfRelTabEnt; | |||
115 | support::ubig32_t LengthOfImpidStrTbl; | |||
116 | support::ubig32_t NumberOfImpid; | |||
117 | support::ubig32_t LengthOfStrTbl; | |||
118 | support::big64_t OffsetToImpid; | |||
119 | support::big64_t OffsetToStrTbl; | |||
120 | support::big64_t OffsetToSymTbl; | |||
121 | char Padding[16]; | |||
122 | support::big32_t OffsetToRelEnt; | |||
123 | }; | |||
124 | ||||
125 | struct XCOFFStringTable { | |||
126 | uint32_t Size; | |||
127 | const char *Data; | |||
128 | }; | |||
129 | ||||
130 | struct XCOFFCsectAuxEnt32 { | |||
131 | support::ubig32_t SectionOrLength; | |||
132 | support::ubig32_t ParameterHashIndex; | |||
133 | support::ubig16_t TypeChkSectNum; | |||
134 | uint8_t SymbolAlignmentAndType; | |||
135 | XCOFF::StorageMappingClass StorageMappingClass; | |||
136 | support::ubig32_t StabInfoIndex; | |||
137 | support::ubig16_t StabSectNum; | |||
138 | }; | |||
139 | ||||
140 | struct XCOFFCsectAuxEnt64 { | |||
141 | support::ubig32_t SectionOrLengthLowByte; | |||
142 | support::ubig32_t ParameterHashIndex; | |||
143 | support::ubig16_t TypeChkSectNum; | |||
144 | uint8_t SymbolAlignmentAndType; | |||
145 | XCOFF::StorageMappingClass StorageMappingClass; | |||
146 | support::ubig32_t SectionOrLengthHighByte; | |||
147 | uint8_t Pad; | |||
148 | XCOFF::SymbolAuxType AuxType; | |||
149 | }; | |||
150 | ||||
151 | class XCOFFCsectAuxRef { | |||
152 | public: | |||
153 | static constexpr uint8_t SymbolTypeMask = 0x07; | |||
154 | static constexpr uint8_t SymbolAlignmentMask = 0xF8; | |||
155 | static constexpr size_t SymbolAlignmentBitOffset = 3; | |||
156 | ||||
157 | XCOFFCsectAuxRef(const XCOFFCsectAuxEnt32 *Entry32) : Entry32(Entry32) {} | |||
158 | XCOFFCsectAuxRef(const XCOFFCsectAuxEnt64 *Entry64) : Entry64(Entry64) {} | |||
159 | ||||
160 | // For getSectionOrLength(), | |||
161 | // If the symbol type is XTY_SD or XTY_CM, the csect length. | |||
162 | // If the symbol type is XTY_LD, the symbol table | |||
163 | // index of the containing csect. | |||
164 | // If the symbol type is XTY_ER, 0. | |||
165 | uint64_t getSectionOrLength() const { | |||
166 | return Entry32 ? getSectionOrLength32() : getSectionOrLength64(); | |||
167 | } | |||
168 | ||||
169 | uint32_t getSectionOrLength32() const { | |||
170 | assert(Entry32 && "32-bit interface called on 64-bit object file.")(static_cast <bool> (Entry32 && "32-bit interface called on 64-bit object file." ) ? void (0) : __assert_fail ("Entry32 && \"32-bit interface called on 64-bit object file.\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/Object/XCOFFObjectFile.h" , 170, __extension__ __PRETTY_FUNCTION__)); | |||
171 | return Entry32->SectionOrLength; | |||
172 | } | |||
173 | ||||
174 | uint64_t getSectionOrLength64() const { | |||
175 | assert(Entry64 && "64-bit interface called on 32-bit object file.")(static_cast <bool> (Entry64 && "64-bit interface called on 32-bit object file." ) ? void (0) : __assert_fail ("Entry64 && \"64-bit interface called on 32-bit object file.\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/Object/XCOFFObjectFile.h" , 175, __extension__ __PRETTY_FUNCTION__)); | |||
176 | return (static_cast<uint64_t>(Entry64->SectionOrLengthHighByte) << 32) | | |||
177 | Entry64->SectionOrLengthLowByte; | |||
178 | } | |||
179 | ||||
180 | #define GETVALUE(X) Entry32 ? Entry32->X : Entry64->X | |||
181 | ||||
182 | uint32_t getParameterHashIndex() const { | |||
183 | return GETVALUE(ParameterHashIndex); | |||
184 | } | |||
185 | ||||
186 | uint16_t getTypeChkSectNum() const { return GETVALUE(TypeChkSectNum); } | |||
187 | ||||
188 | XCOFF::StorageMappingClass getStorageMappingClass() const { | |||
189 | return GETVALUE(StorageMappingClass); | |||
190 | } | |||
191 | ||||
192 | uintptr_t getEntryAddress() const { | |||
193 | return Entry32 ? reinterpret_cast<uintptr_t>(Entry32) | |||
194 | : reinterpret_cast<uintptr_t>(Entry64); | |||
195 | } | |||
196 | ||||
197 | uint16_t getAlignmentLog2() const { | |||
198 | return (getSymbolAlignmentAndType() & SymbolAlignmentMask) >> | |||
199 | SymbolAlignmentBitOffset; | |||
200 | } | |||
201 | ||||
202 | uint8_t getSymbolType() const { | |||
203 | return getSymbolAlignmentAndType() & SymbolTypeMask; | |||
204 | } | |||
205 | ||||
206 | bool isLabel() const { return getSymbolType() == XCOFF::XTY_LD; } | |||
207 | ||||
208 | uint32_t getStabInfoIndex32() const { | |||
209 | assert(Entry32 && "32-bit interface called on 64-bit object file.")(static_cast <bool> (Entry32 && "32-bit interface called on 64-bit object file." ) ? void (0) : __assert_fail ("Entry32 && \"32-bit interface called on 64-bit object file.\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/Object/XCOFFObjectFile.h" , 209, __extension__ __PRETTY_FUNCTION__)); | |||
210 | return Entry32->StabInfoIndex; | |||
211 | } | |||
212 | ||||
213 | uint16_t getStabSectNum32() const { | |||
214 | assert(Entry32 && "32-bit interface called on 64-bit object file.")(static_cast <bool> (Entry32 && "32-bit interface called on 64-bit object file." ) ? void (0) : __assert_fail ("Entry32 && \"32-bit interface called on 64-bit object file.\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/Object/XCOFFObjectFile.h" , 214, __extension__ __PRETTY_FUNCTION__)); | |||
215 | return Entry32->StabSectNum; | |||
216 | } | |||
217 | ||||
218 | XCOFF::SymbolAuxType getAuxType64() const { | |||
219 | assert(Entry64 && "64-bit interface called on 32-bit object file.")(static_cast <bool> (Entry64 && "64-bit interface called on 32-bit object file." ) ? void (0) : __assert_fail ("Entry64 && \"64-bit interface called on 32-bit object file.\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/Object/XCOFFObjectFile.h" , 219, __extension__ __PRETTY_FUNCTION__)); | |||
220 | return Entry64->AuxType; | |||
221 | } | |||
222 | ||||
223 | private: | |||
224 | uint8_t getSymbolAlignmentAndType() const { | |||
225 | return GETVALUE(SymbolAlignmentAndType); | |||
226 | } | |||
227 | ||||
228 | #undef GETVALUE | |||
229 | ||||
230 | const XCOFFCsectAuxEnt32 *Entry32 = nullptr; | |||
231 | const XCOFFCsectAuxEnt64 *Entry64 = nullptr; | |||
232 | }; | |||
233 | ||||
234 | struct XCOFFFileAuxEnt { | |||
235 | typedef struct { | |||
236 | support::big32_t Magic; // Zero indicates name in string table. | |||
237 | support::ubig32_t Offset; | |||
238 | char NamePad[XCOFF::FileNamePadSize]; | |||
239 | } NameInStrTblType; | |||
240 | union { | |||
241 | char Name[XCOFF::NameSize + XCOFF::FileNamePadSize]; | |||
242 | NameInStrTblType NameInStrTbl; | |||
243 | }; | |||
244 | XCOFF::CFileStringType Type; | |||
245 | uint8_t ReservedZeros[2]; | |||
246 | XCOFF::SymbolAuxType AuxType; // 64-bit XCOFF file only. | |||
247 | }; | |||
248 | ||||
249 | struct XCOFFSectAuxEntForStat { | |||
250 | support::ubig32_t SectionLength; | |||
251 | support::ubig16_t NumberOfRelocEnt; | |||
252 | support::ubig16_t NumberOfLineNum; | |||
253 | uint8_t Pad[10]; | |||
254 | }; // 32-bit XCOFF file only. | |||
255 | ||||
256 | template <typename AddressType> struct XCOFFRelocation { | |||
257 | // Masks for packing/unpacking the r_rsize field of relocations. | |||
258 | ||||
259 | // The msb is used to indicate if the bits being relocated are signed or | |||
260 | // unsigned. | |||
261 | static constexpr uint8_t XR_SIGN_INDICATOR_MASK = 0x80; | |||
262 | ||||
263 | // The 2nd msb is used to indicate that the binder has replaced/modified the | |||
264 | // original instruction. | |||
265 | static constexpr uint8_t XR_FIXUP_INDICATOR_MASK = 0x40; | |||
266 | ||||
267 | // The remaining bits specify the bit length of the relocatable reference | |||
268 | // minus one. | |||
269 | static constexpr uint8_t XR_BIASED_LENGTH_MASK = 0x3f; | |||
270 | ||||
271 | public: | |||
272 | AddressType VirtualAddress; | |||
273 | support::ubig32_t SymbolIndex; | |||
274 | ||||
275 | // Packed field, see XR_* masks for details of packing. | |||
276 | uint8_t Info; | |||
277 | ||||
278 | XCOFF::RelocationType Type; | |||
279 | ||||
280 | public: | |||
281 | bool isRelocationSigned() const; | |||
282 | bool isFixupIndicated() const; | |||
283 | ||||
284 | // Returns the number of bits being relocated. | |||
285 | uint8_t getRelocatedLength() const; | |||
286 | }; | |||
287 | ||||
288 | extern template struct XCOFFRelocation<llvm::support::ubig32_t>; | |||
289 | extern template struct XCOFFRelocation<llvm::support::ubig64_t>; | |||
290 | ||||
291 | struct XCOFFRelocation32 : XCOFFRelocation<llvm::support::ubig32_t> {}; | |||
292 | struct XCOFFRelocation64 : XCOFFRelocation<llvm::support::ubig64_t> {}; | |||
293 | ||||
294 | class XCOFFSymbolRef; | |||
295 | ||||
296 | class XCOFFObjectFile : public ObjectFile { | |||
297 | private: | |||
298 | const void *FileHeader = nullptr; | |||
299 | const void *SectionHeaderTable = nullptr; | |||
300 | ||||
301 | const void *SymbolTblPtr = nullptr; | |||
302 | XCOFFStringTable StringTable = {0, nullptr}; | |||
303 | ||||
304 | const XCOFFFileHeader32 *fileHeader32() const; | |||
305 | const XCOFFFileHeader64 *fileHeader64() const; | |||
306 | ||||
307 | const XCOFFSectionHeader32 *sectionHeaderTable32() const; | |||
308 | const XCOFFSectionHeader64 *sectionHeaderTable64() const; | |||
309 | template <typename T> const T *sectionHeaderTable() const; | |||
310 | ||||
311 | size_t getFileHeaderSize() const; | |||
312 | size_t getSectionHeaderSize() const; | |||
313 | ||||
314 | const XCOFFSectionHeader32 *toSection32(DataRefImpl Ref) const; | |||
315 | const XCOFFSectionHeader64 *toSection64(DataRefImpl Ref) const; | |||
316 | uintptr_t getSectionHeaderTableAddress() const; | |||
317 | uintptr_t getEndOfSymbolTableAddress() const; | |||
318 | Expected<uintptr_t> getLoaderSectionAddress() const; | |||
319 | ||||
320 | // This returns a pointer to the start of the storage for the name field of | |||
321 | // the 32-bit or 64-bit SectionHeader struct. This string is *not* necessarily | |||
322 | // null-terminated. | |||
323 | const char *getSectionNameInternal(DataRefImpl Sec) const; | |||
324 | ||||
325 | static bool isReservedSectionNumber(int16_t SectionNumber); | |||
326 | ||||
327 | // Constructor and "create" factory function. The constructor is only a thin | |||
328 | // wrapper around the base constructor. The "create" function fills out the | |||
329 | // XCOFF-specific information and performs the error checking along the way. | |||
330 | XCOFFObjectFile(unsigned Type, MemoryBufferRef Object); | |||
331 | static Expected<std::unique_ptr<XCOFFObjectFile>> create(unsigned Type, | |||
332 | MemoryBufferRef MBR); | |||
333 | ||||
334 | // Helper for parsing the StringTable. Returns an 'Error' if parsing failed | |||
335 | // and an XCOFFStringTable if parsing succeeded. | |||
336 | static Expected<XCOFFStringTable> parseStringTable(const XCOFFObjectFile *Obj, | |||
337 | uint64_t Offset); | |||
338 | ||||
339 | // Make a friend so it can call the private 'create' function. | |||
340 | friend Expected<std::unique_ptr<ObjectFile>> | |||
341 | ObjectFile::createXCOFFObjectFile(MemoryBufferRef Object, unsigned FileType); | |||
342 | ||||
343 | void checkSectionAddress(uintptr_t Addr, uintptr_t TableAddr) const; | |||
344 | ||||
345 | public: | |||
346 | static constexpr uint64_t InvalidRelocOffset = | |||
347 | std::numeric_limits<uint64_t>::max(); | |||
348 | ||||
349 | // Interface inherited from base classes. | |||
350 | void moveSymbolNext(DataRefImpl &Symb) const override; | |||
351 | Expected<uint32_t> getSymbolFlags(DataRefImpl Symb) const override; | |||
352 | basic_symbol_iterator symbol_begin() const override; | |||
353 | basic_symbol_iterator symbol_end() const override; | |||
354 | ||||
355 | Expected<StringRef> getSymbolName(DataRefImpl Symb) const override; | |||
356 | Expected<uint64_t> getSymbolAddress(DataRefImpl Symb) const override; | |||
357 | uint64_t getSymbolValueImpl(DataRefImpl Symb) const override; | |||
358 | uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const override; | |||
359 | Expected<SymbolRef::Type> getSymbolType(DataRefImpl Symb) const override; | |||
360 | Expected<section_iterator> getSymbolSection(DataRefImpl Symb) const override; | |||
361 | ||||
362 | void moveSectionNext(DataRefImpl &Sec) const override; | |||
363 | Expected<StringRef> getSectionName(DataRefImpl Sec) const override; | |||
364 | uint64_t getSectionAddress(DataRefImpl Sec) const override; | |||
365 | uint64_t getSectionIndex(DataRefImpl Sec) const override; | |||
366 | uint64_t getSectionSize(DataRefImpl Sec) const override; | |||
367 | Expected<ArrayRef<uint8_t>> | |||
368 | getSectionContents(DataRefImpl Sec) const override; | |||
369 | uint64_t getSectionAlignment(DataRefImpl Sec) const override; | |||
370 | bool isSectionCompressed(DataRefImpl Sec) const override; | |||
371 | bool isSectionText(DataRefImpl Sec) const override; | |||
372 | bool isSectionData(DataRefImpl Sec) const override; | |||
373 | bool isSectionBSS(DataRefImpl Sec) const override; | |||
374 | bool isDebugSection(DataRefImpl Sec) const override; | |||
375 | ||||
376 | bool isSectionVirtual(DataRefImpl Sec) const override; | |||
377 | relocation_iterator section_rel_begin(DataRefImpl Sec) const override; | |||
378 | relocation_iterator section_rel_end(DataRefImpl Sec) const override; | |||
379 | ||||
380 | void moveRelocationNext(DataRefImpl &Rel) const override; | |||
381 | ||||
382 | /// \returns the relocation offset with the base address of the containing | |||
383 | /// section as zero, or InvalidRelocOffset on errors (such as a relocation | |||
384 | /// that does not refer to an address in any section). | |||
385 | uint64_t getRelocationOffset(DataRefImpl Rel) const override; | |||
386 | symbol_iterator getRelocationSymbol(DataRefImpl Rel) const override; | |||
387 | uint64_t getRelocationType(DataRefImpl Rel) const override; | |||
388 | void getRelocationTypeName(DataRefImpl Rel, | |||
389 | SmallVectorImpl<char> &Result) const override; | |||
390 | ||||
391 | section_iterator section_begin() const override; | |||
392 | section_iterator section_end() const override; | |||
393 | uint8_t getBytesInAddress() const override; | |||
394 | StringRef getFileFormatName() const override; | |||
395 | Triple::ArchType getArch() const override; | |||
396 | SubtargetFeatures getFeatures() const override; | |||
397 | Expected<uint64_t> getStartAddress() const override; | |||
398 | StringRef mapDebugSectionName(StringRef Name) const override; | |||
399 | bool isRelocatableObject() const override; | |||
400 | ||||
401 | // Below here is the non-inherited interface. | |||
402 | bool is64Bit() const; | |||
403 | ||||
404 | const void *getPointerToSymbolTable() const { return SymbolTblPtr; } | |||
405 | ||||
406 | Expected<StringRef> getSymbolSectionName(XCOFFSymbolRef Ref) const; | |||
407 | unsigned getSymbolSectionID(SymbolRef Sym) const; | |||
408 | XCOFFSymbolRef toSymbolRef(DataRefImpl Ref) const; | |||
409 | ||||
410 | // File header related interfaces. | |||
411 | uint16_t getMagic() const; | |||
412 | uint16_t getNumberOfSections() const; | |||
413 | int32_t getTimeStamp() const; | |||
414 | ||||
415 | // Symbol table offset and entry count are handled differently between | |||
416 | // XCOFF32 and XCOFF64. | |||
417 | uint32_t getSymbolTableOffset32() const; | |||
418 | uint64_t getSymbolTableOffset64() const; | |||
419 | ||||
420 | // Note that this value is signed and might return a negative value. Negative | |||
421 | // values are reserved for future use. | |||
422 | int32_t getRawNumberOfSymbolTableEntries32() const; | |||
423 | ||||
424 | // The sanitized value appropriate to use as an index into the symbol table. | |||
425 | uint32_t getLogicalNumberOfSymbolTableEntries32() const; | |||
426 | ||||
427 | uint32_t getNumberOfSymbolTableEntries64() const; | |||
428 | ||||
429 | // Return getLogicalNumberOfSymbolTableEntries32 or | |||
430 | // getNumberOfSymbolTableEntries64 depending on the object mode. | |||
431 | uint32_t getNumberOfSymbolTableEntries() const; | |||
432 | ||||
433 | uint32_t getSymbolIndex(uintptr_t SymEntPtr) const; | |||
434 | uintptr_t getSymbolEntryAddressByIndex(uint32_t SymbolTableIndex) const; | |||
435 | Expected<StringRef> getSymbolNameByIndex(uint32_t SymbolTableIndex) const; | |||
436 | ||||
437 | Expected<StringRef> getCFileName(const XCOFFFileAuxEnt *CFileEntPtr) const; | |||
438 | uint16_t getOptionalHeaderSize() const; | |||
439 | uint16_t getFlags() const; | |||
440 | ||||
441 | // Section header table related interfaces. | |||
442 | ArrayRef<XCOFFSectionHeader32> sections32() const; | |||
443 | ArrayRef<XCOFFSectionHeader64> sections64() const; | |||
444 | ||||
445 | int32_t getSectionFlags(DataRefImpl Sec) const; | |||
446 | Expected<DataRefImpl> getSectionByNum(int16_t Num) const; | |||
447 | ||||
448 | void checkSymbolEntryPointer(uintptr_t SymbolEntPtr) const; | |||
449 | ||||
450 | // Relocation-related interfaces. | |||
451 | template <typename T> | |||
452 | Expected<uint32_t> | |||
453 | getNumberOfRelocationEntries(const XCOFFSectionHeader<T> &Sec) const; | |||
454 | ||||
455 | template <typename Shdr, typename Reloc> | |||
456 | Expected<ArrayRef<Reloc>> relocations(const Shdr &Sec) const; | |||
457 | ||||
458 | // Loader section related interfaces. | |||
459 | Expected<StringRef> getImportFileTable() const; | |||
460 | ||||
461 | // This function returns string table entry. | |||
462 | Expected<StringRef> getStringTableEntry(uint32_t Offset) const; | |||
463 | ||||
464 | // This function returns the string table. | |||
465 | StringRef getStringTable() const; | |||
466 | ||||
467 | const XCOFF::SymbolAuxType *getSymbolAuxType(uintptr_t AuxEntryAddress) const; | |||
468 | ||||
469 | static uintptr_t getAdvancedSymbolEntryAddress(uintptr_t CurrentAddress, | |||
470 | uint32_t Distance); | |||
471 | ||||
472 | static bool classof(const Binary *B) { return B->isXCOFF(); } | |||
473 | }; // XCOFFObjectFile | |||
474 | ||||
475 | typedef struct { | |||
476 | uint8_t LanguageId; | |||
477 | uint8_t CpuTypeId; | |||
478 | } CFileLanguageIdAndTypeIdType; | |||
479 | ||||
480 | struct XCOFFSymbolEntry32 { | |||
481 | typedef struct { | |||
482 | support::big32_t Magic; // Zero indicates name in string table. | |||
483 | support::ubig32_t Offset; | |||
484 | } NameInStrTblType; | |||
485 | ||||
486 | union { | |||
487 | char SymbolName[XCOFF::NameSize]; | |||
488 | NameInStrTblType NameInStrTbl; | |||
489 | }; | |||
490 | ||||
491 | support::ubig32_t Value; // Symbol value; storage class-dependent. | |||
492 | support::big16_t SectionNumber; | |||
493 | ||||
494 | union { | |||
495 | support::ubig16_t SymbolType; | |||
496 | CFileLanguageIdAndTypeIdType CFileLanguageIdAndTypeId; | |||
497 | }; | |||
498 | ||||
499 | XCOFF::StorageClass StorageClass; | |||
500 | uint8_t NumberOfAuxEntries; | |||
501 | }; | |||
502 | ||||
503 | struct XCOFFSymbolEntry64 { | |||
504 | support::ubig64_t Value; // Symbol value; storage class-dependent. | |||
505 | support::ubig32_t Offset; | |||
506 | support::big16_t SectionNumber; | |||
507 | ||||
508 | union { | |||
509 | support::ubig16_t SymbolType; | |||
510 | CFileLanguageIdAndTypeIdType CFileLanguageIdAndTypeId; | |||
511 | }; | |||
512 | ||||
513 | XCOFF::StorageClass StorageClass; | |||
514 | uint8_t NumberOfAuxEntries; | |||
515 | }; | |||
516 | ||||
517 | class XCOFFSymbolRef { | |||
518 | public: | |||
519 | enum { NAME_IN_STR_TBL_MAGIC = 0x0 }; | |||
520 | ||||
521 | XCOFFSymbolRef(DataRefImpl SymEntDataRef, | |||
522 | const XCOFFObjectFile *OwningObjectPtr) | |||
523 | : OwningObjectPtr(OwningObjectPtr) { | |||
524 | assert(OwningObjectPtr && "OwningObjectPtr cannot be nullptr!")(static_cast <bool> (OwningObjectPtr && "OwningObjectPtr cannot be nullptr!" ) ? void (0) : __assert_fail ("OwningObjectPtr && \"OwningObjectPtr cannot be nullptr!\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/Object/XCOFFObjectFile.h" , 524, __extension__ __PRETTY_FUNCTION__)); | |||
525 | assert(SymEntDataRef.p != 0 &&(static_cast <bool> (SymEntDataRef.p != 0 && "Symbol table entry pointer cannot be nullptr!" ) ? void (0) : __assert_fail ("SymEntDataRef.p != 0 && \"Symbol table entry pointer cannot be nullptr!\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/Object/XCOFFObjectFile.h" , 526, __extension__ __PRETTY_FUNCTION__)) | |||
526 | "Symbol table entry pointer cannot be nullptr!")(static_cast <bool> (SymEntDataRef.p != 0 && "Symbol table entry pointer cannot be nullptr!" ) ? void (0) : __assert_fail ("SymEntDataRef.p != 0 && \"Symbol table entry pointer cannot be nullptr!\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/Object/XCOFFObjectFile.h" , 526, __extension__ __PRETTY_FUNCTION__)); | |||
527 | ||||
528 | if (OwningObjectPtr->is64Bit()) | |||
529 | Entry64 = reinterpret_cast<const XCOFFSymbolEntry64 *>(SymEntDataRef.p); | |||
530 | else | |||
531 | Entry32 = reinterpret_cast<const XCOFFSymbolEntry32 *>(SymEntDataRef.p); | |||
532 | } | |||
533 | ||||
534 | uint64_t getValue() const { return Entry32 ? getValue32() : getValue64(); } | |||
535 | ||||
536 | uint32_t getValue32() const { return Entry32->Value; } | |||
537 | ||||
538 | uint64_t getValue64() const { return Entry64->Value; } | |||
539 | ||||
540 | #define GETVALUE(X) Entry32 ? Entry32->X : Entry64->X | |||
541 | ||||
542 | int16_t getSectionNumber() const { return GETVALUE(SectionNumber); } | |||
543 | ||||
544 | uint16_t getSymbolType() const { return GETVALUE(SymbolType); } | |||
545 | ||||
546 | uint8_t getLanguageIdForCFile() const { | |||
547 | assert(getStorageClass() == XCOFF::C_FILE &&(static_cast <bool> (getStorageClass() == XCOFF::C_FILE && "This interface is for C_FILE only.") ? void (0) : __assert_fail ("getStorageClass() == XCOFF::C_FILE && \"This interface is for C_FILE only.\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/Object/XCOFFObjectFile.h" , 548, __extension__ __PRETTY_FUNCTION__)) | |||
548 | "This interface is for C_FILE only.")(static_cast <bool> (getStorageClass() == XCOFF::C_FILE && "This interface is for C_FILE only.") ? void (0) : __assert_fail ("getStorageClass() == XCOFF::C_FILE && \"This interface is for C_FILE only.\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/Object/XCOFFObjectFile.h" , 548, __extension__ __PRETTY_FUNCTION__)); | |||
549 | return GETVALUE(CFileLanguageIdAndTypeId.LanguageId); | |||
550 | } | |||
551 | ||||
552 | uint8_t getCPUTypeIddForCFile() const { | |||
553 | assert(getStorageClass() == XCOFF::C_FILE &&(static_cast <bool> (getStorageClass() == XCOFF::C_FILE && "This interface is for C_FILE only.") ? void (0) : __assert_fail ("getStorageClass() == XCOFF::C_FILE && \"This interface is for C_FILE only.\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/Object/XCOFFObjectFile.h" , 554, __extension__ __PRETTY_FUNCTION__)) | |||
554 | "This interface is for C_FILE only.")(static_cast <bool> (getStorageClass() == XCOFF::C_FILE && "This interface is for C_FILE only.") ? void (0) : __assert_fail ("getStorageClass() == XCOFF::C_FILE && \"This interface is for C_FILE only.\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/Object/XCOFFObjectFile.h" , 554, __extension__ __PRETTY_FUNCTION__)); | |||
555 | return GETVALUE(CFileLanguageIdAndTypeId.CpuTypeId); | |||
556 | } | |||
557 | ||||
558 | XCOFF::StorageClass getStorageClass() const { return GETVALUE(StorageClass); } | |||
559 | ||||
560 | uint8_t getNumberOfAuxEntries() const { return GETVALUE(NumberOfAuxEntries); } | |||
| ||||
561 | ||||
562 | #undef GETVALUE | |||
563 | ||||
564 | uintptr_t getEntryAddress() const { | |||
565 | return Entry32 ? reinterpret_cast<uintptr_t>(Entry32) | |||
566 | : reinterpret_cast<uintptr_t>(Entry64); | |||
567 | } | |||
568 | ||||
569 | Expected<StringRef> getName() const; | |||
570 | bool isFunction() const; | |||
571 | bool isCsectSymbol() const; | |||
572 | Expected<XCOFFCsectAuxRef> getXCOFFCsectAuxRef() const; | |||
573 | ||||
574 | private: | |||
575 | const XCOFFObjectFile *OwningObjectPtr; | |||
576 | const XCOFFSymbolEntry32 *Entry32 = nullptr; | |||
577 | const XCOFFSymbolEntry64 *Entry64 = nullptr; | |||
578 | }; | |||
579 | ||||
580 | class TBVectorExt { | |||
581 | uint16_t Data; | |||
582 | SmallString<32> VecParmsInfo; | |||
583 | ||||
584 | TBVectorExt(StringRef TBvectorStrRef, Error &Err); | |||
585 | ||||
586 | public: | |||
587 | static Expected<TBVectorExt> create(StringRef TBvectorStrRef); | |||
588 | uint8_t getNumberOfVRSaved() const; | |||
589 | bool isVRSavedOnStack() const; | |||
590 | bool hasVarArgs() const; | |||
591 | uint8_t getNumberOfVectorParms() const; | |||
592 | bool hasVMXInstruction() const; | |||
593 | SmallString<32> getVectorParmsInfo() const { return VecParmsInfo; }; | |||
594 | }; | |||
595 | ||||
596 | /// This class provides methods to extract traceback table data from a buffer. | |||
597 | /// The various accessors may reference the buffer provided via the constructor. | |||
598 | ||||
599 | class XCOFFTracebackTable { | |||
600 | const uint8_t *const TBPtr; | |||
601 | Optional<SmallString<32>> ParmsType; | |||
602 | Optional<uint32_t> TraceBackTableOffset; | |||
603 | Optional<uint32_t> HandlerMask; | |||
604 | Optional<uint32_t> NumOfCtlAnchors; | |||
605 | Optional<SmallVector<uint32_t, 8>> ControlledStorageInfoDisp; | |||
606 | Optional<StringRef> FunctionName; | |||
607 | Optional<uint8_t> AllocaRegister; | |||
608 | Optional<TBVectorExt> VecExt; | |||
609 | Optional<uint8_t> ExtensionTable; | |||
610 | ||||
611 | XCOFFTracebackTable(const uint8_t *Ptr, uint64_t &Size, Error &Err); | |||
612 | ||||
613 | public: | |||
614 | /// Parse an XCOFF Traceback Table from \a Ptr with \a Size bytes. | |||
615 | /// Returns an XCOFFTracebackTable upon successful parsing, otherwise an | |||
616 | /// Error is returned. | |||
617 | /// | |||
618 | /// \param[in] Ptr | |||
619 | /// A pointer that points just past the initial 4 bytes of zeros at the | |||
620 | /// beginning of an XCOFF Traceback Table. | |||
621 | /// | |||
622 | /// \param[in, out] Size | |||
623 | /// A pointer that points to the length of the XCOFF Traceback Table. | |||
624 | /// If the XCOFF Traceback Table is not parsed successfully or there are | |||
625 | /// extra bytes that are not recognized, \a Size will be updated to be the | |||
626 | /// size up to the end of the last successfully parsed field of the table. | |||
627 | static Expected<XCOFFTracebackTable> create(const uint8_t *Ptr, | |||
628 | uint64_t &Size); | |||
629 | uint8_t getVersion() const; | |||
630 | uint8_t getLanguageID() const; | |||
631 | ||||
632 | bool isGlobalLinkage() const; | |||
633 | bool isOutOfLineEpilogOrPrologue() const; | |||
634 | bool hasTraceBackTableOffset() const; | |||
635 | bool isInternalProcedure() const; | |||
636 | bool hasControlledStorage() const; | |||
637 | bool isTOCless() const; | |||
638 | bool isFloatingPointPresent() const; | |||
639 | bool isFloatingPointOperationLogOrAbortEnabled() const; | |||
640 | ||||
641 | bool isInterruptHandler() const; | |||
642 | bool isFuncNamePresent() const; | |||
643 | bool isAllocaUsed() const; | |||
644 | uint8_t getOnConditionDirective() const; | |||
645 | bool isCRSaved() const; | |||
646 | bool isLRSaved() const; | |||
647 | ||||
648 | bool isBackChainStored() const; | |||
649 | bool isFixup() const; | |||
650 | uint8_t getNumOfFPRsSaved() const; | |||
651 | ||||
652 | bool hasVectorInfo() const; | |||
653 | bool hasExtensionTable() const; | |||
654 | uint8_t getNumOfGPRsSaved() const; | |||
655 | ||||
656 | uint8_t getNumberOfFixedParms() const; | |||
657 | ||||
658 | uint8_t getNumberOfFPParms() const; | |||
659 | bool hasParmsOnStack() const; | |||
660 | ||||
661 | const Optional<SmallString<32>> &getParmsType() const { return ParmsType; } | |||
662 | const Optional<uint32_t> &getTraceBackTableOffset() const { | |||
663 | return TraceBackTableOffset; | |||
664 | } | |||
665 | const Optional<uint32_t> &getHandlerMask() const { return HandlerMask; } | |||
666 | const Optional<uint32_t> &getNumOfCtlAnchors() { return NumOfCtlAnchors; } | |||
667 | const Optional<SmallVector<uint32_t, 8>> &getControlledStorageInfoDisp() { | |||
668 | return ControlledStorageInfoDisp; | |||
669 | } | |||
670 | const Optional<StringRef> &getFunctionName() const { return FunctionName; } | |||
671 | const Optional<uint8_t> &getAllocaRegister() const { return AllocaRegister; } | |||
672 | const Optional<TBVectorExt> &getVectorExt() const { return VecExt; } | |||
673 | const Optional<uint8_t> &getExtensionTable() const { return ExtensionTable; } | |||
674 | }; | |||
675 | ||||
676 | bool doesXCOFFTracebackTableBegin(ArrayRef<uint8_t> Bytes); | |||
677 | } // namespace object | |||
678 | } // namespace llvm | |||
679 | ||||
680 | #endif // LLVM_OBJECT_XCOFFOBJECTFILE_H |