Bug Summary

File:llvm/include/llvm/Object/XCOFFObjectFile.h
Warning:line 560, column 50
Dereference of null pointer

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name XCOFFObjectFile.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/lib/Object -resource-dir /usr/lib/llvm-14/lib/clang/14.0.0 -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/lib/Object -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/llvm/lib/Object -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/include -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/llvm/include -D NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -std=c++14 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/lib/Object -fdebug-prefix-map=/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e=. -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2021-09-04-040900-46481-1 -x c++ /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/llvm/lib/Object/XCOFFObjectFile.cpp

/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/llvm/lib/Object/XCOFFObjectFile.cpp

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
20namespace llvm {
21
22using namespace XCOFF;
23
24namespace object {
25
26static const uint8_t FunctionSym = 0x20;
27static const uint16_t NoRelMask = 0x0001;
28static 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.
32template <typename T>
33static 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
41static uintptr_t getWithOffset(uintptr_t Base, ptrdiff_t Offset) {
42 return reinterpret_cast<uintptr_t>(reinterpret_cast<const char *>(Base) +
43 Offset);
44}
45
46template <typename T> static const T *viewAs(uintptr_t in) {
47 return reinterpret_cast<const T *>(in);
48}
49
50static 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
57template <typename T> StringRef XCOFFSectionHeader<T>::getName() const {
58 const T &DerivedXCOFFSectionHeader = static_cast<const T &>(*this);
59 return generateXCOFFFixedNameStringRef(DerivedXCOFFSectionHeader.Name);
60}
61
62template <typename T> uint16_t XCOFFSectionHeader<T>::getSectionType() const {
63 const T &DerivedXCOFFSectionHeader = static_cast<const T &>(*this);
64 return DerivedXCOFFSectionHeader.Flags & SectionFlagsTypeMask;
65}
66
67template <typename T>
68bool XCOFFSectionHeader<T>::isReservedSectionType() const {
69 return getSectionType() & SectionFlagsReservedMask;
70}
71
72template <typename AddressType>
73bool XCOFFRelocation<AddressType>::isRelocationSigned() const {
74 return Info & XR_SIGN_INDICATOR_MASK;
75}
76
77template <typename AddressType>
78bool XCOFFRelocation<AddressType>::isFixupIndicated() const {
79 return Info & XR_FIXUP_INDICATOR_MASK;
80}
81
82template <typename AddressType>
83uint8_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
89uintptr_t
90XCOFFObjectFile::getAdvancedSymbolEntryAddress(uintptr_t CurrentAddress,
91 uint32_t Distance) {
92 return getWithOffset(CurrentAddress, Distance * XCOFF::SymbolTableEntrySize);
93}
94
95const XCOFF::SymbolAuxType *
96XCOFFObjectFile::getSymbolAuxType(uintptr_t AuxEntryAddress) const {
97 assert(is64Bit() && "64-bit interface called on a 32-bit object file.")(static_cast<void> (0));
98 return viewAs<XCOFF::SymbolAuxType>(
99 getWithOffset(AuxEntryAddress, SymbolAuxTypeOffset));
100}
101
102void 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
116const XCOFFSectionHeader32 *
117XCOFFObjectFile::toSection32(DataRefImpl Ref) const {
118 assert(!is64Bit() && "32-bit interface called on 64-bit object file.")(static_cast<void> (0));
119#ifndef NDEBUG1
120 checkSectionAddress(Ref.p, getSectionHeaderTableAddress());
121#endif
122 return viewAs<XCOFFSectionHeader32>(Ref.p);
123}
124
125const XCOFFSectionHeader64 *
126XCOFFObjectFile::toSection64(DataRefImpl Ref) const {
127 assert(is64Bit() && "64-bit interface called on a 32-bit object file.")(static_cast<void> (0));
128#ifndef NDEBUG1
129 checkSectionAddress(Ref.p, getSectionHeaderTableAddress());
130#endif
131 return viewAs<XCOFFSectionHeader64>(Ref.p);
132}
133
134XCOFFSymbolRef XCOFFObjectFile::toSymbolRef(DataRefImpl Ref) const {
135 assert(Ref.p != 0 && "Symbol table pointer can not be nullptr!")(static_cast<void> (0));
136#ifndef NDEBUG1
137 checkSymbolEntryPointer(Ref.p);
138#endif
139 return XCOFFSymbolRef(Ref, this);
140}
141
142const XCOFFFileHeader32 *XCOFFObjectFile::fileHeader32() const {
143 assert(!is64Bit() && "32-bit interface called on 64-bit object file.")(static_cast<void> (0));
144 return static_cast<const XCOFFFileHeader32 *>(FileHeader);
145}
146
147const XCOFFFileHeader64 *XCOFFObjectFile::fileHeader64() const {
148 assert(is64Bit() && "64-bit interface called on a 32-bit object file.")(static_cast<void> (0));
149 return static_cast<const XCOFFFileHeader64 *>(FileHeader);
150}
151
152template <typename T> const T *XCOFFObjectFile::sectionHeaderTable() const {
153 return static_cast<const T *>(SectionHeaderTable);
154}
155
156const XCOFFSectionHeader32 *
157XCOFFObjectFile::sectionHeaderTable32() const {
158 assert(!is64Bit() && "32-bit interface called on 64-bit object file.")(static_cast<void> (0));
159 return static_cast<const XCOFFSectionHeader32 *>(SectionHeaderTable);
160}
161
162const XCOFFSectionHeader64 *
163XCOFFObjectFile::sectionHeaderTable64() const {
164 assert(is64Bit() && "64-bit interface called on a 32-bit object file.")(static_cast<void> (0));
165 return static_cast<const XCOFFSectionHeader64 *>(SectionHeaderTable);
166}
167
168void XCOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const {
169 uintptr_t NextSymbolAddr = getAdvancedSymbolEntryAddress(
170 Symb.p, toSymbolRef(Symb).getNumberOfAuxEntries() + 1);
1
Calling 'XCOFFSymbolRef::getNumberOfAuxEntries'
171#ifndef NDEBUG1
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
180Expected<StringRef>
181XCOFFObjectFile::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
197StringRef 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
204Expected<StringRef>
205XCOFFObjectFile::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
211Expected<StringRef> XCOFFObjectFile::getSymbolName(DataRefImpl Symb) const {
212 return toSymbolRef(Symb).getName();
213}
214
215Expected<uint64_t> XCOFFObjectFile::getSymbolAddress(DataRefImpl Symb) const {
216 return toSymbolRef(Symb).getValue();
217}
218
219uint64_t XCOFFObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
220 return toSymbolRef(Symb).getValue();
221}
222
223uint64_t XCOFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
224 uint64_t Result = 0;
225 llvm_unreachable("Not yet implemented!")__builtin_unreachable();
226 return Result;
227}
228
229Expected<SymbolRef::Type>
230XCOFFObjectFile::getSymbolType(DataRefImpl Symb) const {
231 // TODO: Return the correct symbol type.
232 return SymbolRef::ST_Other;
233}
234
235Expected<section_iterator>
236XCOFFObjectFile::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
249void 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
254Expected<StringRef> XCOFFObjectFile::getSectionName(DataRefImpl Sec) const {
255 return generateXCOFFFixedNameStringRef(getSectionNameInternal(Sec));
256}
257
258uint64_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
267uint64_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
276uint64_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
285Expected<ArrayRef<uint8_t>>
286XCOFFObjectFile::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
304uint64_t XCOFFObjectFile::getSectionAlignment(DataRefImpl Sec) const {
305 uint64_t Result = 0;
306 llvm_unreachable("Not yet implemented!")__builtin_unreachable();
307 return Result;
308}
309
310Expected<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
342bool XCOFFObjectFile::isSectionCompressed(DataRefImpl Sec) const {
343 return false;
344}
345
346bool XCOFFObjectFile::isSectionText(DataRefImpl Sec) const {
347 return getSectionFlags(Sec) & XCOFF::STYP_TEXT;
348}
349
350bool XCOFFObjectFile::isSectionData(DataRefImpl Sec) const {
351 uint32_t Flags = getSectionFlags(Sec);
352 return Flags & (XCOFF::STYP_DATA | XCOFF::STYP_TDATA);
353}
354
355bool XCOFFObjectFile::isSectionBSS(DataRefImpl Sec) const {
356 uint32_t Flags = getSectionFlags(Sec);
357 return Flags & (XCOFF::STYP_BSS | XCOFF::STYP_TBSS);
358}
359
360bool XCOFFObjectFile::isDebugSection(DataRefImpl Sec) const {
361 uint32_t Flags = getSectionFlags(Sec);
362 return Flags & (XCOFF::STYP_DEBUG | XCOFF::STYP_DWARF);
363}
364
365bool XCOFFObjectFile::isSectionVirtual(DataRefImpl Sec) const {
366 return is64Bit() ? toSection64(Sec)->FileOffsetToRawData == 0
367 : toSection32(Sec)->FileOffsetToRawData == 0;
368}
369
370relocation_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
396relocation_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
422void 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
429uint64_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
462symbol_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
482uint64_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
488void 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
501Expected<uint32_t> XCOFFObjectFile::getSymbolFlags(DataRefImpl Symb) const {
502 uint32_t Result = 0;
503 // TODO: Return correct symbol flags.
504 return Result;
505}
506
507basic_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
513basic_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
520section_iterator XCOFFObjectFile::section_begin() const {
521 DataRefImpl DRI;
522 DRI.p = getSectionHeaderTableAddress();
523 return section_iterator(SectionRef(DRI, this));
524}
525
526section_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
533uint8_t XCOFFObjectFile::getBytesInAddress() const { return is64Bit() ? 8 : 4; }
534
535StringRef XCOFFObjectFile::getFileFormatName() const {
536 return is64Bit() ? "aix5coff64-rs6000" : "aixcoff-rs6000";
537}
538
539Triple::ArchType XCOFFObjectFile::getArch() const {
540 return is64Bit() ? Triple::ppc64 : Triple::ppc;
541}
542
543SubtargetFeatures XCOFFObjectFile::getFeatures() const {
544 return SubtargetFeatures();
545}
546
547bool XCOFFObjectFile::isRelocatableObject() const {
548 if (is64Bit())
549 return !(fileHeader64()->Flags & NoRelMask);
550 return !(fileHeader32()->Flags & NoRelMask);
551}
552
553Expected<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
559StringRef 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
575size_t XCOFFObjectFile::getFileHeaderSize() const {
576 return is64Bit() ? sizeof(XCOFFFileHeader64) : sizeof(XCOFFFileHeader32);
577}
578
579size_t XCOFFObjectFile::getSectionHeaderSize() const {
580 return is64Bit() ? sizeof(XCOFFSectionHeader64) :
581 sizeof(XCOFFSectionHeader32);
582}
583
584bool XCOFFObjectFile::is64Bit() const {
585 return Binary::ID_XCOFF64 == getType();
586}
587
588uint16_t XCOFFObjectFile::getMagic() const {
589 return is64Bit() ? fileHeader64()->Magic : fileHeader32()->Magic;
590}
591
592Expected<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
602Expected<StringRef>
603XCOFFObjectFile::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
622unsigned XCOFFObjectFile::getSymbolSectionID(SymbolRef Sym) const {
623 XCOFFSymbolRef XCOFFSymRef(Sym.getRawDataRefImpl(), this);
624 return XCOFFSymRef.getSectionNumber();
625}
626
627bool XCOFFObjectFile::isReservedSectionNumber(int16_t SectionNumber) {
628 return (SectionNumber <= 0 && SectionNumber >= -2);
629}
630
631uint16_t XCOFFObjectFile::getNumberOfSections() const {
632 return is64Bit() ? fileHeader64()->NumberOfSections
633 : fileHeader32()->NumberOfSections;
634}
635
636int32_t XCOFFObjectFile::getTimeStamp() const {
637 return is64Bit() ? fileHeader64()->TimeStamp : fileHeader32()->TimeStamp;
638}
639
640uint16_t XCOFFObjectFile::getOptionalHeaderSize() const {
641 return is64Bit() ? fileHeader64()->AuxHeaderSize
642 : fileHeader32()->AuxHeaderSize;
643}
644
645uint32_t XCOFFObjectFile::getSymbolTableOffset32() const {
646 return fileHeader32()->SymbolTableOffset;
647}
648
649int32_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
656uint32_t XCOFFObjectFile::getLogicalNumberOfSymbolTableEntries32() const {
657 return (fileHeader32()->NumberOfSymTableEntries >= 0
658 ? fileHeader32()->NumberOfSymTableEntries
659 : 0);
660}
661
662uint64_t XCOFFObjectFile::getSymbolTableOffset64() const {
663 return fileHeader64()->SymbolTableOffset;
664}
665
666uint32_t XCOFFObjectFile::getNumberOfSymbolTableEntries64() const {
667 return fileHeader64()->NumberOfSymTableEntries;
668}
669
670uint32_t XCOFFObjectFile::getNumberOfSymbolTableEntries() const {
671 return is64Bit() ? getNumberOfSymbolTableEntries64()
672 : getLogicalNumberOfSymbolTableEntries32();
673}
674
675uintptr_t XCOFFObjectFile::getEndOfSymbolTableAddress() const {
676 const uint32_t NumberOfSymTableEntries = getNumberOfSymbolTableEntries();
677 return getWithOffset(reinterpret_cast<uintptr_t>(SymbolTblPtr),
678 XCOFF::SymbolTableEntrySize * NumberOfSymTableEntries);
679}
680
681void 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
696uint32_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
702uintptr_t XCOFFObjectFile::getSymbolEntryAddressByIndex(uint32_t Index) const {
703 return getAdvancedSymbolEntryAddress(
704 reinterpret_cast<uintptr_t>(getPointerToSymbolTable()), Index);
705}
706
707Expected<StringRef>
708XCOFFObjectFile::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
719uint16_t XCOFFObjectFile::getFlags() const {
720 return is64Bit() ? fileHeader64()->Flags : fileHeader32()->Flags;
721}
722
723const char *XCOFFObjectFile::getSectionNameInternal(DataRefImpl Sec) const {
724 return is64Bit() ? toSection64(Sec)->Name : toSection32(Sec)->Name;
725}
726
727uintptr_t XCOFFObjectFile::getSectionHeaderTableAddress() const {
728 return reinterpret_cast<uintptr_t>(SectionHeaderTable);
729}
730
731int32_t XCOFFObjectFile::getSectionFlags(DataRefImpl Sec) const {
732 return is64Bit() ? toSection64(Sec)->Flags : toSection32(Sec)->Flags;
733}
734
735XCOFFObjectFile::XCOFFObjectFile(unsigned int Type, MemoryBufferRef Object)
736 : ObjectFile(Type, Object) {
737 assert(Type == Binary::ID_XCOFF32 || Type == Binary::ID_XCOFF64)(static_cast<void> (0));
738}
739
740ArrayRef<XCOFFSectionHeader64> XCOFFObjectFile::sections64() const {
741 assert(is64Bit() && "64-bit interface called for non 64-bit file.")(static_cast<void> (0));
742 const XCOFFSectionHeader64 *TablePtr = sectionHeaderTable64();
743 return ArrayRef<XCOFFSectionHeader64>(TablePtr,
744 TablePtr + getNumberOfSections());
745}
746
747ArrayRef<XCOFFSectionHeader32> XCOFFObjectFile::sections32() const {
748 assert(!is64Bit() && "32-bit interface called for non 32-bit file.")(static_cast<void> (0));
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.
758template <typename T>
759Expected<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
776template <typename Shdr, typename Reloc>
777Expected<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
799Expected<XCOFFStringTable>
800XCOFFObjectFile::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".
831Expected<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
870Expected<std::unique_ptr<XCOFFObjectFile>>
871XCOFFObjectFile::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
932Expected<std::unique_ptr<ObjectFile>>
933ObjectFile::createXCOFFObjectFile(MemoryBufferRef MemBufRef,
934 unsigned FileType) {
935 return XCOFFObjectFile::create(FileType, MemBufRef);
936}
937
938bool 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
972bool 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
978Expected<XCOFFCsectAuxRef> XCOFFSymbolRef::getXCOFFCsectAuxRef() const {
979 assert(isCsectSymbol() &&(static_cast<void> (0))
980 "Calling csect symbol interface with a non-csect symbol.")(static_cast<void> (0));
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 NDEBUG1
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
1021Expected<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.
1038template struct XCOFFSectionHeader<XCOFFSectionHeader32>;
1039template struct XCOFFSectionHeader<XCOFFSectionHeader64>;
1040
1041template struct XCOFFRelocation<llvm::support::ubig32_t>;
1042template struct XCOFFRelocation<llvm::support::ubig64_t>;
1043
1044template llvm::Expected<llvm::ArrayRef<llvm::object::XCOFFRelocation64>>
1045llvm::object::XCOFFObjectFile::relocations<llvm::object::XCOFFSectionHeader64,
1046 llvm::object::XCOFFRelocation64>(
1047 llvm::object::XCOFFSectionHeader64 const &) const;
1048template llvm::Expected<llvm::ArrayRef<llvm::object::XCOFFRelocation32>>
1049llvm::object::XCOFFObjectFile::relocations<llvm::object::XCOFFSectionHeader32,
1050 llvm::object::XCOFFRelocation32>(
1051 llvm::object::XCOFFSectionHeader32 const &) const;
1052
1053bool 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
1064Expected<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
1072TBVectorExt::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
1088uint8_t TBVectorExt::getNumberOfVRSaved() const {
1089 return GETVALUEWITHMASKSHIFT(NumberOfVRSavedMask, NumberOfVRSavedShift);
1090}
1091
1092bool TBVectorExt::isVRSavedOnStack() const {
1093 return GETVALUEWITHMASK(IsVRSavedOnStackMask);
1094}
1095
1096bool TBVectorExt::hasVarArgs() const {
1097 return GETVALUEWITHMASK(HasVarArgsMask);
1098}
1099
1100uint8_t TBVectorExt::getNumberOfVectorParms() const {
1101 return GETVALUEWITHMASKSHIFT(NumberOfVectorParmsMask,
1102 NumberOfVectorParmsShift);
1103}
1104
1105bool TBVectorExt::hasVMXInstruction() const {
1106 return GETVALUEWITHMASK(HasVMXInstructionMask);
1107}
1108#undef GETVALUEWITHMASK
1109#undef GETVALUEWITHMASKSHIFT
1110
1111Expected<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
1120XCOFFTracebackTable::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
1212uint8_t XCOFFTracebackTable::getVersion() const {
1213 return GETBITWITHMASKSHIFT(0, VersionMask, VersionShift);
1214}
1215
1216uint8_t XCOFFTracebackTable::getLanguageID() const {
1217 return GETBITWITHMASKSHIFT(0, LanguageIdMask, LanguageIdShift);
1218}
1219
1220bool XCOFFTracebackTable::isGlobalLinkage() const {
1221 return GETBITWITHMASK(0, IsGlobaLinkageMask);
1222}
1223
1224bool XCOFFTracebackTable::isOutOfLineEpilogOrPrologue() const {
1225 return GETBITWITHMASK(0, IsOutOfLineEpilogOrPrologueMask);
1226}
1227
1228bool XCOFFTracebackTable::hasTraceBackTableOffset() const {
1229 return GETBITWITHMASK(0, HasTraceBackTableOffsetMask);
1230}
1231
1232bool XCOFFTracebackTable::isInternalProcedure() const {
1233 return GETBITWITHMASK(0, IsInternalProcedureMask);
1234}
1235
1236bool XCOFFTracebackTable::hasControlledStorage() const {
1237 return GETBITWITHMASK(0, HasControlledStorageMask);
1238}
1239
1240bool XCOFFTracebackTable::isTOCless() const {
1241 return GETBITWITHMASK(0, IsTOClessMask);
1242}
1243
1244bool XCOFFTracebackTable::isFloatingPointPresent() const {
1245 return GETBITWITHMASK(0, IsFloatingPointPresentMask);
1246}
1247
1248bool XCOFFTracebackTable::isFloatingPointOperationLogOrAbortEnabled() const {
1249 return GETBITWITHMASK(0, IsFloatingPointOperationLogOrAbortEnabledMask);
1250}
1251
1252bool XCOFFTracebackTable::isInterruptHandler() const {
1253 return GETBITWITHMASK(0, IsInterruptHandlerMask);
1254}
1255
1256bool XCOFFTracebackTable::isFuncNamePresent() const {
1257 return GETBITWITHMASK(0, IsFunctionNamePresentMask);
1258}
1259
1260bool XCOFFTracebackTable::isAllocaUsed() const {
1261 return GETBITWITHMASK(0, IsAllocaUsedMask);
1262}
1263
1264uint8_t XCOFFTracebackTable::getOnConditionDirective() const {
1265 return GETBITWITHMASKSHIFT(0, OnConditionDirectiveMask,
1266 OnConditionDirectiveShift);
1267}
1268
1269bool XCOFFTracebackTable::isCRSaved() const {
1270 return GETBITWITHMASK(0, IsCRSavedMask);
1271}
1272
1273bool XCOFFTracebackTable::isLRSaved() const {
1274 return GETBITWITHMASK(0, IsLRSavedMask);
1275}
1276
1277bool XCOFFTracebackTable::isBackChainStored() const {
1278 return GETBITWITHMASK(4, IsBackChainStoredMask);
1279}
1280
1281bool XCOFFTracebackTable::isFixup() const {
1282 return GETBITWITHMASK(4, IsFixupMask);
1283}
1284
1285uint8_t XCOFFTracebackTable::getNumOfFPRsSaved() const {
1286 return GETBITWITHMASKSHIFT(4, FPRSavedMask, FPRSavedShift);
1287}
1288
1289bool XCOFFTracebackTable::hasExtensionTable() const {
1290 return GETBITWITHMASK(4, HasExtensionTableMask);
1291}
1292
1293bool XCOFFTracebackTable::hasVectorInfo() const {
1294 return GETBITWITHMASK(4, HasVectorInfoMask);
1295}
1296
1297uint8_t XCOFFTracebackTable::getNumOfGPRsSaved() const {
1298 return GETBITWITHMASKSHIFT(4, GPRSavedMask, GPRSavedShift);
1299}
1300
1301uint8_t XCOFFTracebackTable::getNumberOfFixedParms() const {
1302 return GETBITWITHMASKSHIFT(4, NumberOfFixedParmsMask,
1303 NumberOfFixedParmsShift);
1304}
1305
1306uint8_t XCOFFTracebackTable::getNumberOfFPParms() const {
1307 return GETBITWITHMASKSHIFT(4, NumberOfFloatingPointParmsMask,
1308 NumberOfFloatingPointParmsShift);
1309}
1310
1311bool XCOFFTracebackTable::hasParmsOnStack() const {
1312 return GETBITWITHMASK(4, HasParmsOnStackMask);
1313}
1314
1315#undef GETBITWITHMASK
1316#undef GETBITWITHMASKSHIFT
1317} // namespace object
1318} // namespace llvm

/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/llvm/include/llvm/Object/XCOFFObjectFile.h

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
23namespace llvm {
24namespace object {
25
26struct XCOFFFileHeader32 {
27 support::ubig16_t Magic;
28 support::ubig16_t NumberOfSections;
29
30 // Unix time value, value of 0 indicates no timestamp.
31 // Negative values are reserved.
32 support::big32_t TimeStamp;
33
34 support::ubig32_t SymbolTableOffset; // File offset to symbol table.
35 support::big32_t NumberOfSymTableEntries;
36 support::ubig16_t AuxHeaderSize;
37 support::ubig16_t Flags;
38};
39
40struct XCOFFFileHeader64 {
41 support::ubig16_t Magic;
42 support::ubig16_t NumberOfSections;
43
44 // Unix time value, value of 0 indicates no timestamp.
45 // Negative values are reserved.
46 support::big32_t TimeStamp;
47
48 support::ubig64_t SymbolTableOffset; // File offset to symbol table.
49 support::ubig16_t AuxHeaderSize;
50 support::ubig16_t Flags;
51 support::ubig32_t NumberOfSymTableEntries;
52};
53
54template <typename T> struct XCOFFSectionHeader {
55 // Least significant 3 bits are reserved.
56 static constexpr unsigned SectionFlagsReservedMask = 0x7;
57
58 // The low order 16 bits of section flags denotes the section type.
59 static constexpr unsigned SectionFlagsTypeMask = 0xffffu;
60
61public:
62 StringRef getName() const;
63 uint16_t getSectionType() const;
64 bool isReservedSectionType() const;
65};
66
67// Explicit extern template declarations.
68struct XCOFFSectionHeader32;
69struct XCOFFSectionHeader64;
70extern template struct XCOFFSectionHeader<XCOFFSectionHeader32>;
71extern template struct XCOFFSectionHeader<XCOFFSectionHeader64>;
72
73struct XCOFFSectionHeader32 : XCOFFSectionHeader<XCOFFSectionHeader32> {
74 char Name[XCOFF::NameSize];
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
86struct 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
100struct 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
111struct 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
125struct XCOFFStringTable {
126 uint32_t Size;
127 const char *Data;
128};
129
130struct 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
140struct 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
151class XCOFFCsectAuxRef {
152public:
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<void> (0));
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<void> (0));
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<void> (0));
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<void> (0));
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<void> (0));
220 return Entry64->AuxType;
221 }
222
223private:
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
234struct 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
249struct 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
256template <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
271public:
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
280public:
281 bool isRelocationSigned() const;
282 bool isFixupIndicated() const;
283
284 // Returns the number of bits being relocated.
285 uint8_t getRelocatedLength() const;
286};
287
288extern template struct XCOFFRelocation<llvm::support::ubig32_t>;
289extern template struct XCOFFRelocation<llvm::support::ubig64_t>;
290
291struct XCOFFRelocation32 : XCOFFRelocation<llvm::support::ubig32_t> {};
292struct XCOFFRelocation64 : XCOFFRelocation<llvm::support::ubig64_t> {};
293
294class XCOFFSymbolRef;
295
296class XCOFFObjectFile : public ObjectFile {
297private:
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
345public:
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
475typedef struct {
476 uint8_t LanguageId;
477 uint8_t CpuTypeId;
478} CFileLanguageIdAndTypeIdType;
479
480struct 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
503struct 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
517class XCOFFSymbolRef {
518public:
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<void> (0));
525 assert(SymEntDataRef.p != 0 &&(static_cast<void> (0))
526 "Symbol table entry pointer cannot be nullptr!")(static_cast<void> (0));
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<void> (0))
548 "This interface is for C_FILE only.")(static_cast<void> (0));
549 return GETVALUE(CFileLanguageIdAndTypeId.LanguageId);
550 }
551
552 uint8_t getCPUTypeIddForCFile() const {
553 assert(getStorageClass() == XCOFF::C_FILE &&(static_cast<void> (0))
554 "This interface is for C_FILE only.")(static_cast<void> (0));
555 return GETVALUE(CFileLanguageIdAndTypeId.CpuTypeId);
556 }
557
558 XCOFF::StorageClass getStorageClass() const { return GETVALUE(StorageClass); }
559
560 uint8_t getNumberOfAuxEntries() const { return GETVALUE(NumberOfAuxEntries); }
2
Assuming field 'Entry32' is null
3
'?' condition is false
4
Dereference of null pointer
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
574private:
575 const XCOFFObjectFile *OwningObjectPtr;
576 const XCOFFSymbolEntry32 *Entry32 = nullptr;
577 const XCOFFSymbolEntry64 *Entry64 = nullptr;
578};
579
580class TBVectorExt {
581 uint16_t Data;
582 SmallString<32> VecParmsInfo;
583
584 TBVectorExt(StringRef TBvectorStrRef, Error &Err);
585
586public:
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
599class 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
613public:
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
676bool doesXCOFFTracebackTableBegin(ArrayRef<uint8_t> Bytes);
677} // namespace object
678} // namespace llvm
679
680#endif // LLVM_OBJECT_XCOFFOBJECTFILE_H