LLVM 24.0.0git
GOFFObjectFile.cpp
Go to the documentation of this file.
1//===- GOFFObjectFile.cpp - GOFF 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// Implementation of the GOFFObjectFile class.
10//
11//===----------------------------------------------------------------------===//
12
15#include "llvm/Object/GOFF.h"
17#include "llvm/Support/Debug.h"
18#include "llvm/Support/Errc.h"
21
22#ifndef DEBUG_TYPE
23#define DEBUG_TYPE "goff"
24#endif
25
26using namespace llvm::object;
27using namespace llvm;
28
29// Return the type of the record.
30static GOFF::RecordType getRecordType(const uint8_t *PhysicalRecord) {
31 return GOFF::RecordType((PhysicalRecord[1] & 0xF0) >> 4);
32}
33
34// Return true if the record is a continuation record.
35static bool isContinuation(const uint8_t *PhysicalRecord) {
36 return PhysicalRecord[1] & 0x02;
37}
38
39// Return true if the record has a continuation.
40static bool isContinued(const uint8_t *PhysicalRecord) {
41 return PhysicalRecord[1] & 0x01;
42}
43
44// Helper function to get continuous data from a logical record
45// Includes PTV header + everything from first record + continuation payloads
46// Returns the number of physical records consumed (including the initial
47// record)
49GOFFObjectFile::getContinuousData(SmallVectorImpl<uint8_t> &CompleteData,
50 int DataIndex, uint16_t DataLength,
51 const uint8_t *Record) const {
52
53 CompleteData.reserve(DataLength + GOFF::RecordLength - DataIndex);
54
55 // First record - include PTV header (bytes 0-2)
56 CompleteData.append(Record, Record + GOFF::RecordPrefixLength);
57 // Append everything from the first record before the start of the data.
58 CompleteData.append(Record + GOFF::RecordPrefixLength, Record + DataIndex);
59 // Append the data.
60 const uint8_t *Ptr = Record + DataIndex;
61 size_t SliceLength = std::min(
62 DataLength, static_cast<uint16_t>(GOFF::RecordLength - DataIndex));
63 CompleteData.append(Ptr, Ptr + SliceLength);
64 DataLength -= SliceLength;
65 Ptr += SliceLength;
66
67 unsigned BlocksConsumed = 1; // Count the initial record
68 // Continuation records.
69 while (DataLength > 0) {
70 // Ptr now points to the start of the next physical record.
71 // Check that this block is a Continuation.
72 assert(isContinuation(Ptr) && "Continuation bit must be set");
73 // Check that the last Continuation is terminated correctly.
74 if (DataLength <= GOFF::PayloadLength && isContinued(Ptr))
76 "continued bit should not be set");
77
78 SliceLength =
79 std::min(DataLength, static_cast<uint16_t>(GOFF::PayloadLength));
80 Ptr += GOFF::RecordPrefixLength; // Skip the 3-byte prefix
81 CompleteData.append(Ptr, Ptr + SliceLength);
82 DataLength -= SliceLength;
83 // Advance to the start of the next record
85 BlocksConsumed++;
86 }
87 return BlocksConsumed;
88}
89
90// Walk over the object file and populate FlattenedData.
91Error GOFFObjectFile::createFlattenedData() {
92 const uint8_t *It = base();
93 const uint8_t *End = base() + getData().size();
94
95 // First pass: validate continuation records.
96 const uint8_t *ValidateIt = It;
97 unsigned ValidateIndex = 0;
98 bool PrevContinued = false;
99 bool PrevWasContinuation = false;
100 GOFF::RecordType PrevRecordType = GOFF::RT_HDR;
101
102 while (ValidateIt < End) {
103 bool IsCont = isContinuation(ValidateIt);
104 bool IsContd = isContinued(ValidateIt);
105 GOFF::RecordType CurrentType = ::getRecordType(ValidateIt);
106
107 if (IsCont) {
108 // Continuation record must be preceded by a continued record.
109 if (!PrevContinued) {
111 "record " + std::to_string(ValidateIndex) +
112 " is a continuation record that is not "
113 "preceded by a continued record");
114 }
115 // Continuation record type must match previous record type.
116 if (CurrentType != PrevRecordType) {
117 return createStringError(
119 "record " + std::to_string(ValidateIndex) +
120 " is a continuation record that does not match "
121 "the type of the previous record");
122 }
123 // Update PrevContinued for continuation records.
124 PrevContinued = IsContd;
125 } else {
126 // Check if previous non-continuation was marked as continued.
127 if (PrevContinued && !PrevWasContinuation) {
129 "record " + std::to_string(ValidateIndex) +
130 " is not a continuation record but the "
131 "preceding record is continued");
132 }
133 PrevRecordType = CurrentType;
134 PrevContinued = IsContd;
135 }
136
137 PrevWasContinuation = IsCont;
138 ValidateIt += GOFF::RecordLength;
139 ValidateIndex++;
140 }
141
142 // Second pass: process records now that we know they're valid.
143 while (It < End) {
144 // Skip continuation records - only process first physical record of each
145 // logical record.
146 if (isContinuation(It)) {
147 It += GOFF::RecordLength;
148 continue;
149 }
150
152
153 // Call get continuous data based on record type.
154 int DataIndex = 0;
155 uint16_t DataLength = 0;
156 ArrayRef<uint8_t> Slice(It, GOFF::RecordLength);
157 DataExtractor DE(Slice, false);
158
159 switch (RecordType) {
160 case GOFF::RT_ESD: {
161 DataIndex = 72;
162 uint64_t Offset = 70;
163 DataLength = DE.getU16(&Offset);
164 break;
165 }
166 case GOFF::RT_TXT: {
167 DataIndex = 24;
168 uint64_t Offset = 22;
169 DataLength = DE.getU16(&Offset);
170 break;
171 }
172 case GOFF::RT_RLD: {
173 DataIndex = 6;
174 uint64_t Offset = 4;
175 DataLength = DE.getU16(&Offset);
176 break;
177 }
178 case GOFF::RT_LEN: {
179 DataIndex = 8;
180 uint64_t Offset = 6;
181 DataLength = DE.getU16(&Offset);
182 break;
183 }
184 case GOFF::RT_END: {
185 DataIndex = 26;
186 uint64_t Offset = 24;
187 DataLength = DE.getU16(&Offset);
188 break;
189 }
190 case GOFF::RT_HDR: {
191 DataIndex = 60;
192 uint64_t Offset = 52;
193 DataLength = DE.getU16(&Offset);
194 break;
195 }
196 }
197 // Get the flattened data for this logical record (including continuations).
198 SmallVector<uint8_t> CompleteData;
199 Expected<unsigned> BlocksConsumed =
200 getContinuousData(CompleteData, DataIndex, DataLength, It);
201 if (!BlocksConsumed) {
202 // Log the error but don't fail construction - errors in continuation
203 // data will be caught when the data is actually accessed.
205 BlocksConsumed.takeError(), [](const llvm::ErrorInfoBase &EIB) {
206 llvm::errs() << "ERROR: " << EIB.message() << "\n";
207 });
208 // Skip this record and continue.
209 It += GOFF::RecordLength;
210 continue;
211 }
212 FlattenedData.push_back({RecordType, std::move(CompleteData)});
213
214 // Move to next logical record using the number of blocks consumed.
215 It += (*BlocksConsumed) * GOFF::RecordLength;
216 }
217 return Error::success();
218}
219
220Expected<std::unique_ptr<ObjectFile>>
222 Error Err = Error::success();
223 std::unique_ptr<GOFFObjectFile> Ret(new GOFFObjectFile(Object, Err));
224 if (Err)
225 return std::move(Err);
226 return std::move(Ret);
227}
228
230 : ObjectFile(Binary::ID_GOFF, Object) {
231 ErrorAsOutParameter ErrAsOutParam(Err);
232 // Object file isn't the right size, bail out early.
233 if ((Object.getBufferSize() % GOFF::RecordLength) != 0) {
234 Err = createStringError(
236 "object file is not the right size. Must be a multiple "
237 "of 80 bytes, but is " +
238 std::to_string(Object.getBufferSize()) + " bytes");
239 return;
240 }
241 // Object file doesn't start/end with HDR/END records.
242 // Bail out early.
243 if (Object.getBufferSize() != 0) {
244 if ((base()[1] & 0xF0) >> 4 != GOFF::RT_HDR) {
246 "object file must start with HDR record");
247 return;
248 }
249 if ((base()[Object.getBufferSize() - GOFF::RecordLength + 1] & 0xF0) >> 4 !=
250 GOFF::RT_END) {
252 "object file must end with END record");
253 return;
254 }
255 }
256
257 if (Error E = createFlattenedData()) {
258 Err = std::move(E);
259 return;
260 }
261
262 SectionEntryImpl DummySection;
263 SectionList.emplace_back(DummySection); // Dummy entry at index 0.
264
265 // Dummy relocation entry at index 0.
266 GOFFRelEntry DummyRelEntry;
267 DummyRelEntry.PEsdId = 0;
268 RelEntries.emplace_back(DummyRelEntry);
269
270 for (const auto &[RecordType, Data] : FlattenedData) {
271 const uint8_t *I = Data.data();
272 switch (RecordType) {
273 case GOFF::RT_ESD: {
274 // Save ESD record.
275 uint32_t EsdId;
276 ESDRecord::getEsdId(I, EsdId);
277 EsdPtrs.grow(EsdId);
278 EsdPtrs[EsdId] = I;
279
280 // Determine and save the "sections" in GOFF.
281 // A section is saved as a tuple of the form
282 // case (1): (ED,child PR)
283 // - where the PR must have non-zero length.
284 // case (2a) (ED,0)
285 // - where the ED is of non-zero length.
286 // case (2b) (ED,0)
287 // - where the ED is zero length but
288 // contains a label (LD).
291 SectionEntryImpl Section;
295 // case (2a)
296 if (Length != 0) {
297 Section.d.a = EsdId;
298 SectionList.emplace_back(Section);
299 }
301 // case (1)
302 if (Length != 0) {
303 uint32_t SymEdId;
305 Section.d.a = SymEdId;
306 Section.d.b = EsdId;
307 SectionList.emplace_back(Section);
308 }
310 // case (2b)
311 uint32_t SymEdId;
313 const uint8_t *SymEdRecord = EsdPtrs[SymEdId];
314 uint32_t EdLength;
315 ESDRecord::getLength(SymEdRecord, EdLength);
316 if (!EdLength) { // [ EDID, PRID ]
317 // LD child of a zero length parent ED.
318 // Add the section ED which was previously ignored.
319 Section.d.a = SymEdId;
320 SectionList.emplace_back(Section);
321 }
322 }
323 LLVM_DEBUG(dbgs() << " -- ESD " << EsdId << "\n");
324 break;
325 }
326 case GOFF::RT_TXT:
327 // Save TXT records.
328 TextPtrs.emplace_back(I);
329 LLVM_DEBUG(dbgs() << " -- TXT\n");
330 break;
331 case GOFF::RT_RLD:
332 setRelocationData(I);
333 LLVM_DEBUG(dbgs() << " -- RLD\n");
334 break;
335 case GOFF::RT_LEN:
336 LLVM_DEBUG(dbgs() << " -- LEN (GOFF record type) unhandled\n");
337 break;
338 case GOFF::RT_END:
339 LLVM_DEBUG(dbgs() << " -- END (GOFF record type) unhandled\n");
340 break;
341 case GOFF::RT_HDR:
342 LLVM_DEBUG(dbgs() << " -- HDR (GOFF record type) unhandled\n");
343 break;
344 }
345 }
346}
347
348const uint8_t *GOFFObjectFile::getSymbolEsdRecord(DataRefImpl Symb) const {
349 const uint8_t *EsdRecord = EsdPtrs[Symb.d.a];
350 return EsdRecord;
351}
352
354 if (auto It = EsdNamesCache.find(Symb.d.a); It != EsdNamesCache.end()) {
355 auto &StrPtr = It->second;
356 return StringRef(StrPtr.second.get(), StrPtr.first);
357 }
358
359 // Get the ESD record pointer from EsdPtrs (points to FlattenedData)
360 const uint8_t *EsdRecord = getSymbolEsdRecord(Symb);
361 // Extract name from the flattened ESD record
362 // Name length is at byte 70-71, name data starts at byte 72
363 uint16_t NameLength = ESDRecord::getNameLength(EsdRecord);
364 SmallString<256> SymbolName;
365 if (NameLength > 0) {
366 // Name starts at byte 72 in the record (already flattened, no
367 // continuations)
368 const uint8_t *NameStart = EsdRecord + 72;
369 SymbolName.append(NameStart, NameStart + NameLength);
370 }
371
372 SmallString<256> SymbolNameConverted;
373 ConverterEBCDIC::convertToUTF8(SymbolName, SymbolNameConverted);
374
375 size_t Size = SymbolNameConverted.size();
376 auto StrPtr = std::make_pair(Size, std::make_unique<char[]>(Size));
377 char *Buf = StrPtr.second.get();
378 memcpy(Buf, SymbolNameConverted.data(), Size);
379 EsdNamesCache[Symb.d.a] = std::move(StrPtr);
380 return StringRef(Buf, Size);
381}
382
384 return getSymbolName(Symbol.getRawDataRefImpl());
385}
386
387Expected<uint64_t> GOFFObjectFile::getSymbolAddress(DataRefImpl Symb) const {
389 const uint8_t *EsdRecord = getSymbolEsdRecord(Symb);
390 ESDRecord::getOffset(EsdRecord, Offset);
391 return static_cast<uint64_t>(Offset);
392}
393
394uint64_t GOFFObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
396 const uint8_t *EsdRecord = getSymbolEsdRecord(Symb);
397 ESDRecord::getOffset(EsdRecord, Offset);
398 return static_cast<uint64_t>(Offset);
399}
400
401uint64_t GOFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
402 return 0;
403}
404
405bool GOFFObjectFile::isSymbolUnresolved(DataRefImpl Symb) const {
406 const uint8_t *Record = getSymbolEsdRecord(Symb);
409
411 return true;
413 uint32_t Length;
415 if (Length == 0)
416 return true;
417 }
418 return false;
419}
420
421bool GOFFObjectFile::isSymbolIndirect(DataRefImpl Symb) const {
422 const uint8_t *Record = getSymbolEsdRecord(Symb);
423 bool Indirect;
424 ESDRecord::getIndirectReference(Record, Indirect);
425 return Indirect;
426}
427
428Expected<uint32_t> GOFFObjectFile::getSymbolFlags(DataRefImpl Symb) const {
429 uint32_t Flags = 0;
430 if (isSymbolUnresolved(Symb))
432
433 const uint8_t *Record = getSymbolEsdRecord(Symb);
434
435 GOFF::ESDBindingStrength BindingStrength;
436 ESDRecord::getBindingStrength(Record, BindingStrength);
437 if (BindingStrength == GOFF::ESD_BST_Weak)
439
440 GOFF::ESDBindingScope BindingScope;
441 ESDRecord::getBindingScope(Record, BindingScope);
442
445
448 BindingScope != GOFF::ESD_BSC_Section &&
449 BindingScope != GOFF::ESD_BSC_Module) {
450 Expected<StringRef> Name = getSymbolName(Symb);
451 if (Name && *Name != " ") { // Blank name is local.
453 if (BindingScope == GOFF::ESD_BSC_ImportExport)
455 else if (!(Flags & SymbolRef::SF_Undefined))
457 }
458 }
459
460 return Flags;
461}
462
463Expected<SymbolRef::Type>
464GOFFObjectFile::getSymbolType(DataRefImpl Symb) const {
465 const uint8_t *Record = getSymbolEsdRecord(Symb);
468 GOFF::ESDExecutable Executable;
469 ESDRecord::getExecutable(Record, Executable);
470
476 uint32_t EsdId;
477 ESDRecord::getEsdId(Record, EsdId);
479 "ESD record %" PRIu32
480 " has invalid symbol type 0x%02" PRIX8,
481 EsdId, SymbolType);
482 }
483 switch (SymbolType) {
486 return SymbolRef::ST_Other;
490 if (Executable != GOFF::ESD_EXE_CODE && Executable != GOFF::ESD_EXE_DATA &&
491 Executable != GOFF::ESD_EXE_Unspecified) {
492 uint32_t EsdId;
493 ESDRecord::getEsdId(Record, EsdId);
495 "ESD record %" PRIu32
496 " has unknown Executable type 0x%02X",
497 EsdId, Executable);
498 }
499 switch (Executable) {
503 return SymbolRef::ST_Data;
506 }
507 llvm_unreachable("Unhandled ESDExecutable");
508 }
509 llvm_unreachable("Unhandled ESDSymbolType");
510}
511
512Expected<section_iterator>
513GOFFObjectFile::getSymbolSection(DataRefImpl Symb) const {
514 DataRefImpl Sec;
515
516 if (isSymbolUnresolved(Symb))
517 return section_iterator(SectionRef(Sec, this));
518
519 const uint8_t *SymEsdRecord = EsdPtrs[Symb.d.a];
520 uint32_t SymEdId;
521 ESDRecord::getParentEsdId(SymEsdRecord, SymEdId);
522 const uint8_t *SymEdRecord = EsdPtrs[SymEdId];
523
524 for (size_t I = 0, E = SectionList.size(); I < E; ++I) {
525 bool Found;
526 const uint8_t *SectionPrRecord = getSectionPrEsdRecord(I);
527 if (SectionPrRecord) {
528 Found = SymEsdRecord == SectionPrRecord;
529 } else {
530 const uint8_t *SectionEdRecord = getSectionEdEsdRecord(I);
531 Found = SymEdRecord == SectionEdRecord;
532 }
533
534 if (Found) {
535 Sec.d.a = I;
536 return section_iterator(SectionRef(Sec, this));
537 }
538 }
540 "symbol with ESD id " + std::to_string(Symb.d.a) +
541 " refers to invalid section with ESD id " +
542 std::to_string(SymEdId));
543}
544
546 const uint8_t *SymRecord = getSymbolEsdRecord(Symb);
547 uint32_t Attrs = 0;
548
549 // Bit 2 (0x4): 64-bit AMODE. If the child AMODE is unspecified,
550 // query the parent ED.
551 // TODO: The parent-walk path (child ESD_AMODE_None with a parent that has
552 // ESD_AMODE_64) cannot currently be tested as GOFFObjectWriter always emits
553 // ESD_AMODE_64 directly on LD/ER records and does not set AMODE on ED
554 // records. Full coverage requires yaml2obj GOFF ESD record support.
555 GOFF::ESDAmode Amode;
556 ESDRecord::getAmode(SymRecord, Amode);
557 if (Amode == GOFF::ESD_AMODE_None) {
558 uint32_t ParentEsdId;
559 ESDRecord::getParentEsdId(SymRecord, ParentEsdId);
560 if (ParentEsdId) {
561 const uint8_t *EdRecord = EsdPtrs[ParentEsdId];
562 ESDRecord::getAmode(EdRecord, Amode);
563 }
564 }
565 if (Amode == GOFF::ESD_AMODE_64)
566 Attrs |= 0x4;
567
568 // Bit 1 (0x2): XPLink — LinkageType is ESD_LT_XPLink.
569 GOFF::ESDLinkageType LinkageType;
570 ESDRecord::getLinkageType(SymRecord, LinkageType);
571 if (LinkageType == GOFF::ESD_LT_XPLink)
572 Attrs |= 0x2;
573
574 // Bit 0 (0x1): Writable Static Area.
575 GOFF::ESDNameSpaceId NameSpace;
576 ESDRecord::getNameSpaceId(SymRecord, NameSpace);
577 if (NameSpace == GOFF::ESD_NS_Parts)
578 Attrs |= 0x1;
579
580 return Attrs;
581}
582
583uint64_t GOFFObjectFile::getSymbolSize(DataRefImpl Symb) const {
584 const uint8_t *Record = getSymbolEsdRecord(Symb);
587 return Length;
588}
589
590const uint8_t *GOFFObjectFile::getSectionEdEsdRecord(DataRefImpl &Sec) const {
591 SectionEntryImpl EsdIds = SectionList[Sec.d.a];
592 const uint8_t *EsdRecord = EsdPtrs[EsdIds.d.a];
593 return EsdRecord;
594}
595
596const uint8_t *GOFFObjectFile::getSectionPrEsdRecord(DataRefImpl &Sec) const {
597 SectionEntryImpl EsdIds = SectionList[Sec.d.a];
598 const uint8_t *EsdRecord = nullptr;
599 if (EsdIds.d.b)
600 EsdRecord = EsdPtrs[EsdIds.d.b];
601 return EsdRecord;
602}
603
604const uint8_t *
605GOFFObjectFile::getSectionEdEsdRecord(uint32_t SectionIndex) const {
606 DataRefImpl Sec;
607 Sec.d.a = SectionIndex;
608 const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
609 return EsdRecord;
610}
611
612const uint8_t *
613GOFFObjectFile::getSectionPrEsdRecord(uint32_t SectionIndex) const {
614 DataRefImpl Sec;
615 Sec.d.a = SectionIndex;
616 const uint8_t *EsdRecord = getSectionPrEsdRecord(Sec);
617 return EsdRecord;
618}
619
620uint32_t GOFFObjectFile::getSectionDefEsdId(DataRefImpl &Sec) const {
621 const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
622 uint32_t Length;
623 ESDRecord::getLength(EsdRecord, Length);
624 if (Length == 0) {
625 const uint8_t *PrEsdRecord = getSectionPrEsdRecord(Sec);
626 if (PrEsdRecord)
627 EsdRecord = PrEsdRecord;
628 }
629
630 uint32_t DefEsdId;
631 ESDRecord::getEsdId(EsdRecord, DefEsdId);
632 LLVM_DEBUG(dbgs() << "Got def EsdId: " << DefEsdId << '\n');
633 return DefEsdId;
634}
635
636void GOFFObjectFile::moveSectionNext(DataRefImpl &Sec) const {
637 Sec.d.a++;
638 if ((Sec.d.a) >= SectionList.size())
639 Sec.d.a = 0;
640}
641
642Expected<StringRef> GOFFObjectFile::getSectionName(DataRefImpl Sec) const {
643 DataRefImpl EdSym;
644 SectionEntryImpl EsdIds = SectionList[Sec.d.a];
645 EdSym.d.a = EsdIds.d.a;
646 Expected<StringRef> Name = getSymbolName(EdSym);
647 if (Name) {
648 StringRef Res = *Name;
649 LLVM_DEBUG(dbgs() << "Got section: " << Res << '\n');
650 LLVM_DEBUG(dbgs() << "Final section name: " << Res << '\n');
651 Name = Res;
652 }
653 return Name;
654}
655
656uint64_t GOFFObjectFile::getSectionAddress(DataRefImpl Sec) const {
657 uint32_t Offset;
658 const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
659 ESDRecord::getOffset(EsdRecord, Offset);
660 return Offset;
661}
662
663uint64_t GOFFObjectFile::getSectionSize(DataRefImpl Sec) const {
664 uint32_t Length;
665 uint32_t DefEsdId = getSectionDefEsdId(Sec);
666 const uint8_t *EsdRecord = EsdPtrs[DefEsdId];
667 ESDRecord::getLength(EsdRecord, Length);
668 LLVM_DEBUG(dbgs() << "Got section size: " << Length << '\n');
669 return static_cast<uint64_t>(Length);
670}
671
672// Unravel TXT records and expand fill characters to produce
673// a contiguous sequence of bytes.
674Expected<ArrayRef<uint8_t>>
675GOFFObjectFile::getSectionContents(DataRefImpl Sec) const {
676 if (auto It = SectionDataCache.find(Sec.d.a); It != SectionDataCache.end()) {
677 auto &Buf = It->second;
678 return ArrayRef<uint8_t>(Buf);
679 }
680 uint64_t SectionSize = getSectionSize(Sec);
681 uint32_t DefEsdId = getSectionDefEsdId(Sec);
682
683 const uint8_t *EdEsdRecord = getSectionEdEsdRecord(Sec);
684 bool FillBytePresent;
685 ESDRecord::getFillBytePresent(EdEsdRecord, FillBytePresent);
686 uint8_t FillByte = '\0';
687 if (FillBytePresent)
688 ESDRecord::getFillByteValue(EdEsdRecord, FillByte);
689
690 // Initialize section with fill byte.
691 SmallVector<uint8_t> Data(SectionSize, FillByte);
692
693 // Replace section with content from text records.
694 for (const uint8_t *TxtRecordPtr : TextPtrs) {
695 uint32_t TxtEsdId;
696 TXTRecord::getElementEsdId(TxtRecordPtr, TxtEsdId);
697 LLVM_DEBUG(dbgs() << "Got txt EsdId: " << TxtEsdId << '\n');
698
699 if (TxtEsdId != DefEsdId)
700 continue;
701
702 uint32_t TxtDataOffset;
703 TXTRecord::getOffset(TxtRecordPtr, TxtDataOffset);
704
705 uint16_t TxtDataSize;
706 TXTRecord::getDataLength(TxtRecordPtr, TxtDataSize);
707
708 LLVM_DEBUG(dbgs() << "Record offset " << TxtDataOffset << ", data size "
709 << TxtDataSize << "\n");
710
711 // Text data starts at byte 24 in the flattened record (already processed
712 // continuations)
713 const uint8_t *TxtData = TxtRecordPtr + 24;
714 assert(TxtDataSize <= Data.size() - TxtDataOffset &&
715 "Text data exceeds section size");
716 std::copy(TxtData, TxtData + TxtDataSize, Data.begin() + TxtDataOffset);
717 }
718 auto &Cache = SectionDataCache[Sec.d.a];
719 Cache = std::move(Data);
720 return ArrayRef<uint8_t>(Cache);
721}
722
723uint64_t GOFFObjectFile::getSectionAlignment(DataRefImpl Sec) const {
724 const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
725 GOFF::ESDAlignment Pow2Alignment;
726 ESDRecord::getAlignment(EsdRecord, Pow2Alignment);
727 return 1ULL << static_cast<uint64_t>(Pow2Alignment);
728}
729
730bool GOFFObjectFile::isSectionText(DataRefImpl Sec) const {
731 const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
732 GOFF::ESDExecutable Executable;
733 ESDRecord::getExecutable(EsdRecord, Executable);
734 return Executable == GOFF::ESD_EXE_CODE;
735}
736
737bool GOFFObjectFile::isSectionData(DataRefImpl Sec) const {
738 const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
739 GOFF::ESDExecutable Executable;
740 ESDRecord::getExecutable(EsdRecord, Executable);
741 return Executable == GOFF::ESD_EXE_DATA;
742}
743
745 const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
746 GOFF::ESDLoadingBehavior LoadingBehavior;
747 ESDRecord::getLoadingBehavior(EsdRecord, LoadingBehavior);
748 return LoadingBehavior == GOFF::ESD_LB_NoLoad;
749}
750
752 if (!isSectionData(Sec))
753 return false;
754
755 const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
756 GOFF::ESDLoadingBehavior LoadingBehavior;
757 ESDRecord::getLoadingBehavior(EsdRecord, LoadingBehavior);
758 return LoadingBehavior == GOFF::ESD_LB_Initial;
759}
760
762 // GOFF uses fill characters and fill characters are applied
763 // on getSectionContents() - so we say false to zero init.
764 return false;
765}
766
768 DataRefImpl Sec;
769 moveSectionNext(Sec);
770 return section_iterator(SectionRef(Sec, this));
771}
772
777
779 for (uint32_t I = Symb.d.a + 1, E = EsdPtrs.size(); I < E; ++I) {
780 if (const uint8_t *EsdRecord = EsdPtrs[I]) {
783 // Skip EDs - i.e. section symbols.
784 bool IgnoreSpecialGOFFSymbols = true;
785 bool SkipSymbol = ((SymbolType == GOFF::ESD_ST_ElementDefinition) ||
787 IgnoreSpecialGOFFSymbols;
788 if (!SkipSymbol) {
789 Symb.d.a = I;
790 return;
791 }
792 }
793 }
794 Symb.d.a = 0;
795}
796
802
807
808inline constexpr uint8_t SAME_R_ID = 0x80;
809inline constexpr uint8_t SAME_P_ID = 0x40;
810inline constexpr uint8_t SAME_OFFSET = 0x20;
811inline constexpr uint8_t EXT_ATTR_PRESENT = 0x04;
812inline constexpr uint8_t BYTE_OFFSET_8 = 0x02;
813
814// Populate the relocation entries.
815void GOFFObjectFile::setRelocationData(const uint8_t *RldRecord) {
816 SmallVector<uint8_t, 8> RelocationData;
817 int DataIndex = 6;
818 uint16_t DataLength;
819 RLDRecord::getDataLength(RldRecord, DataLength);
820
821 // The record is already flattened if it's continued.
822 const uint8_t *RldI = RldRecord + DataIndex;
823 const uint8_t *RldE = RldI + DataLength;
824 uint32_t CurREsdId = 0;
825 uint32_t CurPEsdId = 0;
826 uint64_t CurPOffset = 0;
827 for (const uint8_t *Rld = RldI; Rld < RldE;) {
828 GOFFRelEntry RelEntry;
829 uint8_t Flags = Rld[0];
830 int32_t Length = 8;
831 if (!(Flags & SAME_R_ID)) {
832 CurREsdId = support::endian::read32be(&Rld[Length]);
833 Length += 4;
834 }
835 if (!(Flags & SAME_P_ID)) {
836 CurPEsdId = support::endian::read32be(&Rld[Length]);
837 Length += 4;
838 }
839 if (!(Flags & SAME_OFFSET)) {
840 if (Flags & BYTE_OFFSET_8) {
841 CurPOffset = support::endian::read64be(&Rld[Length]);
842 Length += 8;
843 } else {
844 CurPOffset = support::endian::read32be(&Rld[Length]);
845 Length += 4;
846 }
847 }
848 if (Flags & EXT_ATTR_PRESENT)
849 Length += 8;
850
851 RelEntry.PEsdId = CurPEsdId;
852 RelEntry.REsdId = CurREsdId;
853 RelEntry.POffset = CurPOffset;
854 RelEntry.RelType = getRldType(Rld);
855 RelEntries.emplace_back(RelEntry);
856
857 Rld += Length;
858 assert(Rld <= RldE && "RLD length?");
859 }
860}
861
862void GOFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const {
863 for (size_t I = Rel.d.b + 1, E = RelEntries.size(); I < E; ++I) {
864 const GOFFRelEntry &RelEntry = RelEntries[I];
865 if (Rel.d.a == RelEntry.PEsdId) {
866 Rel.d.b = I;
867 return;
868 }
869 }
870
871 Rel.d.b = 0;
872}
873
874uint64_t GOFFObjectFile::getRelocationOffset(DataRefImpl Rel) const {
875 assert(Rel.d.b > 0 && Rel.d.b < RelEntries.size() &&
876 "Rel Index out of boundary");
877 const GOFFRelEntry &RelEntry = RelEntries[Rel.d.b];
878 return RelEntry.POffset;
879}
880
881symbol_iterator GOFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
882 assert(Rel.d.b > 0 && Rel.d.b < RelEntries.size() &&
883 "Rel Index out of boundary");
884 const GOFFRelEntry &RelEntry = RelEntries[Rel.d.b];
885 DataRefImpl RefSym;
886 RefSym.d.a = RelEntry.REsdId;
887 return basic_symbol_iterator(SymbolRef(RefSym, this));
888}
889
890uint64_t GOFFObjectFile::getRelocationType(DataRefImpl Rel) const {
891 assert(Rel.d.b > 0 && Rel.d.b < RelEntries.size() &&
892 "Rel Index out of boundary");
893 const GOFFRelEntry &RelEntry = RelEntries[Rel.d.b];
894 return RelEntry.RelType;
895}
896
897void GOFFObjectFile::getRelocationTypeName(
898 DataRefImpl Rel, SmallVectorImpl<char> &Result) const {
899 uint64_t RelType = getRelocationType(Rel);
900 std::string HexStr = formatv("R_{0:x-8}", RelType).str();
901 Result.append(HexStr.begin(), HexStr.end());
902}
903
904relocation_iterator GOFFObjectFile::section_rel_begin(DataRefImpl Sec) const {
905 DataRefImpl Rel;
906 Rel.d.a = getSectionDefEsdId(Sec);
907 Rel.d.b = 0;
908 moveRelocationNext(Rel);
909 return relocation_iterator(RelocationRef(Rel, this));
910}
911
912relocation_iterator GOFFObjectFile::section_rel_end(DataRefImpl Sec) const {
913 DataRefImpl Rel;
914 Rel.d.a = getSectionDefEsdId(Sec);
915 Rel.d.b = 0;
916 return relocation_iterator(RelocationRef(Rel, this));
917}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned uint64_t
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
constexpr uint8_t SAME_R_ID
static bool isContinued(const uint8_t *PhysicalRecord)
constexpr uint8_t SAME_P_ID
constexpr uint8_t EXT_ATTR_PRESENT
constexpr uint8_t SAME_OFFSET
constexpr uint8_t BYTE_OFFSET_8
static bool isContinuation(const uint8_t *PhysicalRecord)
static GOFF::RecordType getRecordType(const uint8_t *PhysicalRecord)
#define I(x, y, z)
Definition MD5.cpp:57
FunctionLoweringInfo::StatepointRelocationRecord RecordType
#define LLVM_DEBUG(...)
Definition Debug.h:119
Helper for Errors used as out-parameters.
Definition Error.h:1160
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Tagged union holding either a T or a Error.
Definition Error.h:485
Error takeError()
Take ownership of the stored error.
Definition Error.h:612
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition SmallString.h:26
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void reserve(size_type N)
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
pointer data()
Return a pointer to the vector's buffer, even if empty().
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
constexpr size_t size() const
Get the string size.
Definition StringRef.h:144
MemoryBufferRef Data
Definition Binary.h:38
StringRef getData() const
Definition Binary.cpp:39
static void getIndirectReference(const uint8_t *Record, bool &Indirect)
Definition GOFF.h:259
static void getBindingStrength(const uint8_t *Record, GOFF::ESDBindingStrength &Strength)
Definition GOFF.h:245
static void getOffset(const uint8_t *Record, uint32_t &Offset)
Definition GOFF.h:143
static void getEsdId(const uint8_t *Record, uint32_t &EsdId)
Definition GOFF.h:135
static void getLoadingBehavior(const uint8_t *Record, GOFF::ESDLoadingBehavior &Behavior)
Definition GOFF.h:252
static void getFillBytePresent(const uint8_t *Record, bool &Present)
Definition GOFF.h:157
static void getLength(const uint8_t *Record, uint32_t &Length)
Definition GOFF.h:147
static void getAmode(const uint8_t *Record, GOFF::ESDAmode &Amode)
Definition GOFF.h:193
static void getParentEsdId(const uint8_t *Record, uint32_t &EsdId)
Definition GOFF.h:139
static void getFillByteValue(const uint8_t *Record, uint8_t &Fill)
Definition GOFF.h:181
static void getSymbolType(const uint8_t *Record, GOFF::ESDSymbolType &SymbolType)
Definition GOFF.h:128
static void getAlignment(const uint8_t *Record, GOFF::ESDAlignment &Alignment)
Definition GOFF.h:279
static void getLinkageType(const uint8_t *Record, GOFF::ESDLinkageType &Type)
Definition GOFF.h:272
static uint16_t getNameLength(const uint8_t *Record)
Definition GOFF.h:286
static void getExecutable(const uint8_t *Record, GOFF::ESDExecutable &Executable)
Definition GOFF.h:231
static void getBindingScope(const uint8_t *Record, GOFF::ESDBindingScope &Scope)
Definition GOFF.h:265
static void getNameSpaceId(const uint8_t *Record, GOFF::ESDNameSpaceId &Id)
Definition GOFF.h:151
uint32_t getZOSSymbolArchiveAttributes(DataRefImpl Symb) const
section_iterator section_begin() const override
basic_symbol_iterator symbol_end() const override
GOFFObjectFile(MemoryBufferRef Object, Error &Err)
bool isSectionReadOnlyData(DataRefImpl Sec) const
bool isSectionNoLoad(DataRefImpl Sec) const
section_iterator section_end() const override
Expected< StringRef > getSymbolName(SymbolRef Symbol) const
void moveSymbolNext(DataRefImpl &Symb) const override
basic_symbol_iterator symbol_begin() const override
bool isSectionZeroInit(DataRefImpl Sec) const
friend class RelocationRef
Definition ObjectFile.h:289
const uint8_t * base() const
Definition ObjectFile.h:237
static Expected< std::unique_ptr< ObjectFile > > createGOFFObjectFile(MemoryBufferRef Object)
ObjectFile(unsigned int Type, MemoryBufferRef Source)
static void getDataLength(const uint8_t *Record, uint16_t &Length)
Definition GOFF.h:298
Represents a GOFF physical record.
Definition GOFF.h:31
static void getElementEsdId(const uint8_t *Record, uint32_t &EsdId)
Definition GOFF.h:85
static void getDataLength(const uint8_t *Record, uint16_t &Length)
Definition GOFF.h:93
static void getOffset(const uint8_t *Record, uint32_t &Offset)
Definition GOFF.h:89
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ SectionSize
Definition COFF.h:61
LLVM_ABI void convertToUTF8(StringRef Source, SmallVectorImpl< char > &Result)
ESDLoadingBehavior
Definition GOFF.h:127
@ ESD_LB_NoLoad
Definition GOFF.h:130
@ ESD_LB_Initial
Definition GOFF.h:128
RecordType
Definition GOFF.h:44
@ RT_RLD
Definition GOFF.h:47
@ RT_TXT
Definition GOFF.h:46
@ RT_ESD
Definition GOFF.h:45
@ RT_LEN
Definition GOFF.h:48
@ RT_HDR
Definition GOFF.h:50
@ RT_END
Definition GOFF.h:49
constexpr uint8_t RecordPrefixLength
Definition GOFF.h:29
constexpr uint8_t PayloadLength
Definition GOFF.h:30
ESDExecutable
Definition GOFF.h:109
@ ESD_EXE_Unspecified
Definition GOFF.h:110
@ ESD_EXE_CODE
Definition GOFF.h:112
@ ESD_EXE_DATA
Definition GOFF.h:111
ESDAlignment
Definition GOFF.h:144
@ ESD_AMODE_None
Definition GOFF.h:76
@ ESD_AMODE_64
Definition GOFF.h:80
ESDBindingScope
Definition GOFF.h:134
@ ESD_BSC_Module
Definition GOFF.h:137
@ ESD_BSC_ImportExport
Definition GOFF.h:139
@ ESD_BSC_Section
Definition GOFF.h:136
ESDLinkageType
Definition GOFF.h:142
@ ESD_LT_XPLink
Definition GOFF.h:142
constexpr uint8_t RecordLength
Length of the parts of a physical GOFF record.
Definition GOFF.h:28
ESDNameSpaceId
Definition GOFF.h:61
@ ESD_NS_Parts
Definition GOFF.h:65
ESDSymbolType
Definition GOFF.h:53
@ ESD_ST_PartReference
Definition GOFF.h:57
@ ESD_ST_ElementDefinition
Definition GOFF.h:55
@ ESD_ST_LabelDefinition
Definition GOFF.h:56
@ ESD_ST_SectionDefinition
Definition GOFF.h:54
@ ESD_ST_ExternalReference
Definition GOFF.h:58
ESDBindingStrength
Definition GOFF.h:122
@ ESD_BST_Weak
Definition GOFF.h:124
content_iterator< SectionRef > section_iterator
Definition ObjectFile.h:49
content_iterator< BasicSymbolRef > basic_symbol_iterator
uint64_t getRldType(const uint8_t *Rld)
content_iterator< RelocationRef > relocation_iterator
Definition ObjectFile.h:79
uint64_t read64be(const void *P)
Definition Endian.h:424
uint32_t read32be(const void *P)
Definition Endian.h:421
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:577
@ Length
Definition DWP.cpp:577
void handleAllErrors(Error E, HandlerTs &&... Handlers)
Behaves the same as handleErrors, except that by contract all errors must be handled by the given han...
Definition Error.h:1013
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition Error.h:1321
@ invalid_argument
Definition Errc.h:56
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
struct llvm::object::DataRefImpl::@005117267142344013370254144343227032034000327225 d