Skip to content

Commit 009f88f

Browse files
authored
[SystemZ][z/OS] TXT records in the GOFF reader (#74526)
This PR adds handling for TXT records in the GOFF reader. --------- Authored-by: Yusra Syeda <[email protected]>
1 parent aa2c14d commit 009f88f

File tree

4 files changed

+326
-14
lines changed

4 files changed

+326
-14
lines changed

llvm/include/llvm/Object/GOFF.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,26 @@ class Record {
7373
}
7474
};
7575

76+
class TXTRecord : public Record {
77+
public:
78+
/// \brief Maximum length of data; any more must go in continuation.
79+
static const uint8_t TXTMaxDataLength = 56;
80+
81+
static Error getData(const uint8_t *Record, SmallString<256> &CompleteData);
82+
83+
static void getElementEsdId(const uint8_t *Record, uint32_t &EsdId) {
84+
get<uint32_t>(Record, 4, EsdId);
85+
}
86+
87+
static void getOffset(const uint8_t *Record, uint32_t &Offset) {
88+
get<uint32_t>(Record, 12, Offset);
89+
}
90+
91+
static void getDataLength(const uint8_t *Record, uint16_t &Length) {
92+
get<uint16_t>(Record, 22, Length);
93+
}
94+
};
95+
7696
class HDRRecord : public Record {
7797
public:
7898
static Error getData(const uint8_t *Record, SmallString<256> &CompleteData);

llvm/include/llvm/Object/GOFFObjectFile.h

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ namespace llvm {
2929
namespace object {
3030

3131
class GOFFObjectFile : public ObjectFile {
32+
friend class GOFFSymbolRef;
33+
3234
IndexedMap<const uint8_t *> EsdPtrs; // Indexed by EsdId.
35+
SmallVector<const uint8_t *, 256> TextPtrs;
3336

3437
mutable DenseMap<uint32_t, std::pair<size_t, std::unique_ptr<char[]>>>
3538
EsdNamesCache;
@@ -38,7 +41,7 @@ class GOFFObjectFile : public ObjectFile {
3841
// (EDID, 0) code, r/o data section
3942
// (EDID,PRID) r/w data section
4043
SmallVector<SectionEntryImpl, 256> SectionList;
41-
mutable DenseMap<uint32_t, std::string> SectionDataCache;
44+
mutable DenseMap<uint32_t, SmallVector<uint8_t>> SectionDataCache;
4245

4346
public:
4447
Expected<StringRef> getSymbolName(SymbolRef Symbol) const;
@@ -66,6 +69,10 @@ class GOFFObjectFile : public ObjectFile {
6669
return true;
6770
}
6871

72+
bool isSectionNoLoad(DataRefImpl Sec) const;
73+
bool isSectionReadOnlyData(DataRefImpl Sec) const;
74+
bool isSectionZeroInit(DataRefImpl Sec) const;
75+
6976
private:
7077
// SymbolRef.
7178
Expected<StringRef> getSymbolName(DataRefImpl Symb) const override;
@@ -75,27 +82,24 @@ class GOFFObjectFile : public ObjectFile {
7582
Expected<uint32_t> getSymbolFlags(DataRefImpl Symb) const override;
7683
Expected<SymbolRef::Type> getSymbolType(DataRefImpl Symb) const override;
7784
Expected<section_iterator> getSymbolSection(DataRefImpl Symb) const override;
85+
uint64_t getSymbolSize(DataRefImpl Symb) const;
7886

7987
const uint8_t *getSymbolEsdRecord(DataRefImpl Symb) const;
8088
bool isSymbolUnresolved(DataRefImpl Symb) const;
8189
bool isSymbolIndirect(DataRefImpl Symb) const;
8290

8391
// SectionRef.
84-
void moveSectionNext(DataRefImpl &Sec) const override {}
85-
virtual Expected<StringRef> getSectionName(DataRefImpl Sec) const override {
86-
return StringRef();
87-
}
88-
uint64_t getSectionAddress(DataRefImpl Sec) const override { return 0; }
89-
uint64_t getSectionSize(DataRefImpl Sec) const override { return 0; }
92+
void moveSectionNext(DataRefImpl &Sec) const override;
93+
virtual Expected<StringRef> getSectionName(DataRefImpl Sec) const override;
94+
uint64_t getSectionAddress(DataRefImpl Sec) const override;
95+
uint64_t getSectionSize(DataRefImpl Sec) const override;
9096
virtual Expected<ArrayRef<uint8_t>>
91-
getSectionContents(DataRefImpl Sec) const override {
92-
return ArrayRef<uint8_t>();
93-
}
94-
uint64_t getSectionIndex(DataRefImpl Sec) const override { return 0; }
95-
uint64_t getSectionAlignment(DataRefImpl Sec) const override { return 0; }
97+
getSectionContents(DataRefImpl Sec) const override;
98+
uint64_t getSectionIndex(DataRefImpl Sec) const override { return Sec.d.a; }
99+
uint64_t getSectionAlignment(DataRefImpl Sec) const override;
96100
bool isSectionCompressed(DataRefImpl Sec) const override { return false; }
97-
bool isSectionText(DataRefImpl Sec) const override { return false; }
98-
bool isSectionData(DataRefImpl Sec) const override { return false; }
101+
bool isSectionText(DataRefImpl Sec) const override;
102+
bool isSectionData(DataRefImpl Sec) const override;
99103
bool isSectionBSS(DataRefImpl Sec) const override { return false; }
100104
bool isSectionVirtual(DataRefImpl Sec) const override { return false; }
101105
relocation_iterator section_rel_begin(DataRefImpl Sec) const override {
@@ -109,6 +113,7 @@ class GOFFObjectFile : public ObjectFile {
109113
const uint8_t *getSectionPrEsdRecord(DataRefImpl &Sec) const;
110114
const uint8_t *getSectionEdEsdRecord(uint32_t SectionIndex) const;
111115
const uint8_t *getSectionPrEsdRecord(uint32_t SectionIndex) const;
116+
uint32_t getSectionDefEsdId(DataRefImpl &Sec) const;
112117

113118
// RelocationRef.
114119
void moveRelocationNext(DataRefImpl &Rel) const override {}
@@ -122,6 +127,29 @@ class GOFFObjectFile : public ObjectFile {
122127
SmallVectorImpl<char> &Result) const override {}
123128
};
124129

130+
class GOFFSymbolRef : public SymbolRef {
131+
public:
132+
GOFFSymbolRef(const SymbolRef &B) : SymbolRef(B) {
133+
assert(isa<GOFFObjectFile>(SymbolRef::getObject()));
134+
}
135+
136+
const GOFFObjectFile *getObject() const {
137+
return cast<GOFFObjectFile>(BasicSymbolRef::getObject());
138+
}
139+
140+
Expected<uint32_t> getSymbolGOFFFlags() const {
141+
return getObject()->getSymbolFlags(getRawDataRefImpl());
142+
}
143+
144+
Expected<SymbolRef::Type> getSymbolGOFFType() const {
145+
return getObject()->getSymbolType(getRawDataRefImpl());
146+
}
147+
148+
uint64_t getSize() const {
149+
return getObject()->getSymbolSize(getRawDataRefImpl());
150+
}
151+
};
152+
125153
} // namespace object
126154

127155
} // namespace llvm

llvm/lib/Object/GOFFObjectFile.cpp

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,11 @@ GOFFObjectFile::GOFFObjectFile(MemoryBufferRef Object, Error &Err)
168168
LLVM_DEBUG(dbgs() << " -- ESD " << EsdId << "\n");
169169
break;
170170
}
171+
case GOFF::RT_TXT:
172+
// Save TXT records.
173+
TextPtrs.emplace_back(I);
174+
LLVM_DEBUG(dbgs() << " -- TXT\n");
175+
break;
171176
case GOFF::RT_END:
172177
LLVM_DEBUG(dbgs() << " -- END (GOFF record type) unhandled\n");
173178
break;
@@ -364,6 +369,13 @@ GOFFObjectFile::getSymbolSection(DataRefImpl Symb) const {
364369
std::to_string(SymEdId));
365370
}
366371

372+
uint64_t GOFFObjectFile::getSymbolSize(DataRefImpl Symb) const {
373+
const uint8_t *Record = getSymbolEsdRecord(Symb);
374+
uint32_t Length;
375+
ESDRecord::getLength(Record, Length);
376+
return Length;
377+
}
378+
367379
const uint8_t *GOFFObjectFile::getSectionEdEsdRecord(DataRefImpl &Sec) const {
368380
SectionEntryImpl EsdIds = SectionList[Sec.d.a];
369381
const uint8_t *EsdRecord = EsdPtrs[EsdIds.d.a];
@@ -394,6 +406,154 @@ GOFFObjectFile::getSectionPrEsdRecord(uint32_t SectionIndex) const {
394406
return EsdRecord;
395407
}
396408

409+
uint32_t GOFFObjectFile::getSectionDefEsdId(DataRefImpl &Sec) const {
410+
const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
411+
uint32_t Length;
412+
ESDRecord::getLength(EsdRecord, Length);
413+
if (Length == 0) {
414+
const uint8_t *PrEsdRecord = getSectionPrEsdRecord(Sec);
415+
if (PrEsdRecord)
416+
EsdRecord = PrEsdRecord;
417+
}
418+
419+
uint32_t DefEsdId;
420+
ESDRecord::getEsdId(EsdRecord, DefEsdId);
421+
LLVM_DEBUG(dbgs() << "Got def EsdId: " << DefEsdId << '\n');
422+
return DefEsdId;
423+
}
424+
425+
void GOFFObjectFile::moveSectionNext(DataRefImpl &Sec) const {
426+
Sec.d.a++;
427+
if ((Sec.d.a) >= SectionList.size())
428+
Sec.d.a = 0;
429+
}
430+
431+
Expected<StringRef> GOFFObjectFile::getSectionName(DataRefImpl Sec) const {
432+
DataRefImpl EdSym;
433+
SectionEntryImpl EsdIds = SectionList[Sec.d.a];
434+
EdSym.d.a = EsdIds.d.a;
435+
Expected<StringRef> Name = getSymbolName(EdSym);
436+
if (Name) {
437+
StringRef Res = *Name;
438+
LLVM_DEBUG(dbgs() << "Got section: " << Res << '\n');
439+
LLVM_DEBUG(dbgs() << "Final section name: " << Res << '\n');
440+
Name = Res;
441+
}
442+
return Name;
443+
}
444+
445+
uint64_t GOFFObjectFile::getSectionAddress(DataRefImpl Sec) const {
446+
uint32_t Offset;
447+
const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
448+
ESDRecord::getOffset(EsdRecord, Offset);
449+
return Offset;
450+
}
451+
452+
uint64_t GOFFObjectFile::getSectionSize(DataRefImpl Sec) const {
453+
uint32_t Length;
454+
uint32_t DefEsdId = getSectionDefEsdId(Sec);
455+
const uint8_t *EsdRecord = EsdPtrs[DefEsdId];
456+
ESDRecord::getLength(EsdRecord, Length);
457+
LLVM_DEBUG(dbgs() << "Got section size: " << Length << '\n');
458+
return static_cast<uint64_t>(Length);
459+
}
460+
461+
// Unravel TXT records and expand fill characters to produce
462+
// a contiguous sequence of bytes.
463+
Expected<ArrayRef<uint8_t>>
464+
GOFFObjectFile::getSectionContents(DataRefImpl Sec) const {
465+
if (SectionDataCache.count(Sec.d.a)) {
466+
auto &Buf = SectionDataCache[Sec.d.a];
467+
return ArrayRef<uint8_t>(Buf);
468+
}
469+
uint64_t SectionSize = getSectionSize(Sec);
470+
uint32_t DefEsdId = getSectionDefEsdId(Sec);
471+
472+
const uint8_t *EdEsdRecord = getSectionEdEsdRecord(Sec);
473+
bool FillBytePresent;
474+
ESDRecord::getFillBytePresent(EdEsdRecord, FillBytePresent);
475+
uint8_t FillByte = '\0';
476+
if (FillBytePresent)
477+
ESDRecord::getFillByteValue(EdEsdRecord, FillByte);
478+
479+
// Initialize section with fill byte.
480+
SmallVector<uint8_t> Data(SectionSize, FillByte);
481+
482+
// Replace section with content from text records.
483+
for (const uint8_t *TxtRecordInt : TextPtrs) {
484+
const uint8_t *TxtRecordPtr = TxtRecordInt;
485+
uint32_t TxtEsdId;
486+
TXTRecord::getElementEsdId(TxtRecordPtr, TxtEsdId);
487+
LLVM_DEBUG(dbgs() << "Got txt EsdId: " << TxtEsdId << '\n');
488+
489+
if (TxtEsdId != DefEsdId)
490+
continue;
491+
492+
uint32_t TxtDataOffset;
493+
TXTRecord::getOffset(TxtRecordPtr, TxtDataOffset);
494+
495+
uint16_t TxtDataSize;
496+
TXTRecord::getDataLength(TxtRecordPtr, TxtDataSize);
497+
498+
LLVM_DEBUG(dbgs() << "Record offset " << TxtDataOffset << ", data size "
499+
<< TxtDataSize << "\n");
500+
501+
SmallString<256> CompleteData;
502+
CompleteData.reserve(TxtDataSize);
503+
if (Error Err = TXTRecord::getData(TxtRecordPtr, CompleteData))
504+
return std::move(Err);
505+
assert(CompleteData.size() == TxtDataSize && "Wrong length of data");
506+
std::copy(CompleteData.data(), CompleteData.data() + TxtDataSize,
507+
Data.begin() + TxtDataOffset);
508+
}
509+
SectionDataCache[Sec.d.a] = Data;
510+
return ArrayRef<uint8_t>(Data);
511+
}
512+
513+
uint64_t GOFFObjectFile::getSectionAlignment(DataRefImpl Sec) const {
514+
const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
515+
GOFF::ESDAlignment Pow2Alignment;
516+
ESDRecord::getAlignment(EsdRecord, Pow2Alignment);
517+
return 1 << static_cast<uint64_t>(Pow2Alignment);
518+
}
519+
520+
bool GOFFObjectFile::isSectionText(DataRefImpl Sec) const {
521+
const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
522+
GOFF::ESDExecutable Executable;
523+
ESDRecord::getExecutable(EsdRecord, Executable);
524+
return Executable == GOFF::ESD_EXE_CODE;
525+
}
526+
527+
bool GOFFObjectFile::isSectionData(DataRefImpl Sec) const {
528+
const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
529+
GOFF::ESDExecutable Executable;
530+
ESDRecord::getExecutable(EsdRecord, Executable);
531+
return Executable == GOFF::ESD_EXE_DATA;
532+
}
533+
534+
bool GOFFObjectFile::isSectionNoLoad(DataRefImpl Sec) const {
535+
const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
536+
GOFF::ESDLoadingBehavior LoadingBehavior;
537+
ESDRecord::getLoadingBehavior(EsdRecord, LoadingBehavior);
538+
return LoadingBehavior == GOFF::ESD_LB_NoLoad;
539+
}
540+
541+
bool GOFFObjectFile::isSectionReadOnlyData(DataRefImpl Sec) const {
542+
if (!isSectionData(Sec))
543+
return false;
544+
545+
const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
546+
GOFF::ESDLoadingBehavior LoadingBehavior;
547+
ESDRecord::getLoadingBehavior(EsdRecord, LoadingBehavior);
548+
return LoadingBehavior == GOFF::ESD_LB_Initial;
549+
}
550+
551+
bool GOFFObjectFile::isSectionZeroInit(DataRefImpl Sec) const {
552+
// GOFF uses fill characters and fill characters are applied
553+
// on getSectionContents() - so we say false to zero init.
554+
return false;
555+
}
556+
397557
section_iterator GOFFObjectFile::section_begin() const {
398558
DataRefImpl Sec;
399559
moveSectionNext(Sec);
@@ -476,6 +636,13 @@ Error ESDRecord::getData(const uint8_t *Record,
476636
return getContinuousData(Record, DataSize, 72, CompleteData);
477637
}
478638

639+
Error TXTRecord::getData(const uint8_t *Record,
640+
SmallString<256> &CompleteData) {
641+
uint16_t Length;
642+
getDataLength(Record, Length);
643+
return getContinuousData(Record, Length, 24, CompleteData);
644+
}
645+
479646
Error ENDRecord::getData(const uint8_t *Record,
480647
SmallString<256> &CompleteData) {
481648
uint16_t Length = getNameLength(Record);

0 commit comments

Comments
 (0)