Skip to content

Commit

Permalink
[SystemZ][z/OS] TXT records in the GOFF reader (llvm#74526)
Browse files Browse the repository at this point in the history
This PR adds handling for TXT records in the GOFF reader.

---------

Authored-by: Yusra Syeda <[email protected]>
  • Loading branch information
ysyeda authored Mar 27, 2024
1 parent aa2c14d commit 009f88f
Show file tree
Hide file tree
Showing 4 changed files with 326 additions and 14 deletions.
20 changes: 20 additions & 0 deletions llvm/include/llvm/Object/GOFF.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,26 @@ class Record {
}
};

class TXTRecord : public Record {
public:
/// \brief Maximum length of data; any more must go in continuation.
static const uint8_t TXTMaxDataLength = 56;

static Error getData(const uint8_t *Record, SmallString<256> &CompleteData);

static void getElementEsdId(const uint8_t *Record, uint32_t &EsdId) {
get<uint32_t>(Record, 4, EsdId);
}

static void getOffset(const uint8_t *Record, uint32_t &Offset) {
get<uint32_t>(Record, 12, Offset);
}

static void getDataLength(const uint8_t *Record, uint16_t &Length) {
get<uint16_t>(Record, 22, Length);
}
};

class HDRRecord : public Record {
public:
static Error getData(const uint8_t *Record, SmallString<256> &CompleteData);
Expand Down
56 changes: 42 additions & 14 deletions llvm/include/llvm/Object/GOFFObjectFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ namespace llvm {
namespace object {

class GOFFObjectFile : public ObjectFile {
friend class GOFFSymbolRef;

IndexedMap<const uint8_t *> EsdPtrs; // Indexed by EsdId.
SmallVector<const uint8_t *, 256> TextPtrs;

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

public:
Expected<StringRef> getSymbolName(SymbolRef Symbol) const;
Expand Down Expand Up @@ -66,6 +69,10 @@ class GOFFObjectFile : public ObjectFile {
return true;
}

bool isSectionNoLoad(DataRefImpl Sec) const;
bool isSectionReadOnlyData(DataRefImpl Sec) const;
bool isSectionZeroInit(DataRefImpl Sec) const;

private:
// SymbolRef.
Expected<StringRef> getSymbolName(DataRefImpl Symb) const override;
Expand All @@ -75,27 +82,24 @@ class GOFFObjectFile : public ObjectFile {
Expected<uint32_t> getSymbolFlags(DataRefImpl Symb) const override;
Expected<SymbolRef::Type> getSymbolType(DataRefImpl Symb) const override;
Expected<section_iterator> getSymbolSection(DataRefImpl Symb) const override;
uint64_t getSymbolSize(DataRefImpl Symb) const;

const uint8_t *getSymbolEsdRecord(DataRefImpl Symb) const;
bool isSymbolUnresolved(DataRefImpl Symb) const;
bool isSymbolIndirect(DataRefImpl Symb) const;

// SectionRef.
void moveSectionNext(DataRefImpl &Sec) const override {}
virtual Expected<StringRef> getSectionName(DataRefImpl Sec) const override {
return StringRef();
}
uint64_t getSectionAddress(DataRefImpl Sec) const override { return 0; }
uint64_t getSectionSize(DataRefImpl Sec) const override { return 0; }
void moveSectionNext(DataRefImpl &Sec) const override;
virtual Expected<StringRef> getSectionName(DataRefImpl Sec) const override;
uint64_t getSectionAddress(DataRefImpl Sec) const override;
uint64_t getSectionSize(DataRefImpl Sec) const override;
virtual Expected<ArrayRef<uint8_t>>
getSectionContents(DataRefImpl Sec) const override {
return ArrayRef<uint8_t>();
}
uint64_t getSectionIndex(DataRefImpl Sec) const override { return 0; }
uint64_t getSectionAlignment(DataRefImpl Sec) const override { return 0; }
getSectionContents(DataRefImpl Sec) const override;
uint64_t getSectionIndex(DataRefImpl Sec) const override { return Sec.d.a; }
uint64_t getSectionAlignment(DataRefImpl Sec) const override;
bool isSectionCompressed(DataRefImpl Sec) const override { return false; }
bool isSectionText(DataRefImpl Sec) const override { return false; }
bool isSectionData(DataRefImpl Sec) const override { return false; }
bool isSectionText(DataRefImpl Sec) const override;
bool isSectionData(DataRefImpl Sec) const override;
bool isSectionBSS(DataRefImpl Sec) const override { return false; }
bool isSectionVirtual(DataRefImpl Sec) const override { return false; }
relocation_iterator section_rel_begin(DataRefImpl Sec) const override {
Expand All @@ -109,6 +113,7 @@ class GOFFObjectFile : public ObjectFile {
const uint8_t *getSectionPrEsdRecord(DataRefImpl &Sec) const;
const uint8_t *getSectionEdEsdRecord(uint32_t SectionIndex) const;
const uint8_t *getSectionPrEsdRecord(uint32_t SectionIndex) const;
uint32_t getSectionDefEsdId(DataRefImpl &Sec) const;

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

class GOFFSymbolRef : public SymbolRef {
public:
GOFFSymbolRef(const SymbolRef &B) : SymbolRef(B) {
assert(isa<GOFFObjectFile>(SymbolRef::getObject()));
}

const GOFFObjectFile *getObject() const {
return cast<GOFFObjectFile>(BasicSymbolRef::getObject());
}

Expected<uint32_t> getSymbolGOFFFlags() const {
return getObject()->getSymbolFlags(getRawDataRefImpl());
}

Expected<SymbolRef::Type> getSymbolGOFFType() const {
return getObject()->getSymbolType(getRawDataRefImpl());
}

uint64_t getSize() const {
return getObject()->getSymbolSize(getRawDataRefImpl());
}
};

} // namespace object

} // namespace llvm
Expand Down
167 changes: 167 additions & 0 deletions llvm/lib/Object/GOFFObjectFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,11 @@ GOFFObjectFile::GOFFObjectFile(MemoryBufferRef Object, Error &Err)
LLVM_DEBUG(dbgs() << " -- ESD " << EsdId << "\n");
break;
}
case GOFF::RT_TXT:
// Save TXT records.
TextPtrs.emplace_back(I);
LLVM_DEBUG(dbgs() << " -- TXT\n");
break;
case GOFF::RT_END:
LLVM_DEBUG(dbgs() << " -- END (GOFF record type) unhandled\n");
break;
Expand Down Expand Up @@ -364,6 +369,13 @@ GOFFObjectFile::getSymbolSection(DataRefImpl Symb) const {
std::to_string(SymEdId));
}

uint64_t GOFFObjectFile::getSymbolSize(DataRefImpl Symb) const {
const uint8_t *Record = getSymbolEsdRecord(Symb);
uint32_t Length;
ESDRecord::getLength(Record, Length);
return Length;
}

const uint8_t *GOFFObjectFile::getSectionEdEsdRecord(DataRefImpl &Sec) const {
SectionEntryImpl EsdIds = SectionList[Sec.d.a];
const uint8_t *EsdRecord = EsdPtrs[EsdIds.d.a];
Expand Down Expand Up @@ -394,6 +406,154 @@ GOFFObjectFile::getSectionPrEsdRecord(uint32_t SectionIndex) const {
return EsdRecord;
}

uint32_t GOFFObjectFile::getSectionDefEsdId(DataRefImpl &Sec) const {
const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
uint32_t Length;
ESDRecord::getLength(EsdRecord, Length);
if (Length == 0) {
const uint8_t *PrEsdRecord = getSectionPrEsdRecord(Sec);
if (PrEsdRecord)
EsdRecord = PrEsdRecord;
}

uint32_t DefEsdId;
ESDRecord::getEsdId(EsdRecord, DefEsdId);
LLVM_DEBUG(dbgs() << "Got def EsdId: " << DefEsdId << '\n');
return DefEsdId;
}

void GOFFObjectFile::moveSectionNext(DataRefImpl &Sec) const {
Sec.d.a++;
if ((Sec.d.a) >= SectionList.size())
Sec.d.a = 0;
}

Expected<StringRef> GOFFObjectFile::getSectionName(DataRefImpl Sec) const {
DataRefImpl EdSym;
SectionEntryImpl EsdIds = SectionList[Sec.d.a];
EdSym.d.a = EsdIds.d.a;
Expected<StringRef> Name = getSymbolName(EdSym);
if (Name) {
StringRef Res = *Name;
LLVM_DEBUG(dbgs() << "Got section: " << Res << '\n');
LLVM_DEBUG(dbgs() << "Final section name: " << Res << '\n');
Name = Res;
}
return Name;
}

uint64_t GOFFObjectFile::getSectionAddress(DataRefImpl Sec) const {
uint32_t Offset;
const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
ESDRecord::getOffset(EsdRecord, Offset);
return Offset;
}

uint64_t GOFFObjectFile::getSectionSize(DataRefImpl Sec) const {
uint32_t Length;
uint32_t DefEsdId = getSectionDefEsdId(Sec);
const uint8_t *EsdRecord = EsdPtrs[DefEsdId];
ESDRecord::getLength(EsdRecord, Length);
LLVM_DEBUG(dbgs() << "Got section size: " << Length << '\n');
return static_cast<uint64_t>(Length);
}

// Unravel TXT records and expand fill characters to produce
// a contiguous sequence of bytes.
Expected<ArrayRef<uint8_t>>
GOFFObjectFile::getSectionContents(DataRefImpl Sec) const {
if (SectionDataCache.count(Sec.d.a)) {
auto &Buf = SectionDataCache[Sec.d.a];
return ArrayRef<uint8_t>(Buf);
}
uint64_t SectionSize = getSectionSize(Sec);
uint32_t DefEsdId = getSectionDefEsdId(Sec);

const uint8_t *EdEsdRecord = getSectionEdEsdRecord(Sec);
bool FillBytePresent;
ESDRecord::getFillBytePresent(EdEsdRecord, FillBytePresent);
uint8_t FillByte = '\0';
if (FillBytePresent)
ESDRecord::getFillByteValue(EdEsdRecord, FillByte);

// Initialize section with fill byte.
SmallVector<uint8_t> Data(SectionSize, FillByte);

// Replace section with content from text records.
for (const uint8_t *TxtRecordInt : TextPtrs) {
const uint8_t *TxtRecordPtr = TxtRecordInt;
uint32_t TxtEsdId;
TXTRecord::getElementEsdId(TxtRecordPtr, TxtEsdId);
LLVM_DEBUG(dbgs() << "Got txt EsdId: " << TxtEsdId << '\n');

if (TxtEsdId != DefEsdId)
continue;

uint32_t TxtDataOffset;
TXTRecord::getOffset(TxtRecordPtr, TxtDataOffset);

uint16_t TxtDataSize;
TXTRecord::getDataLength(TxtRecordPtr, TxtDataSize);

LLVM_DEBUG(dbgs() << "Record offset " << TxtDataOffset << ", data size "
<< TxtDataSize << "\n");

SmallString<256> CompleteData;
CompleteData.reserve(TxtDataSize);
if (Error Err = TXTRecord::getData(TxtRecordPtr, CompleteData))
return std::move(Err);
assert(CompleteData.size() == TxtDataSize && "Wrong length of data");
std::copy(CompleteData.data(), CompleteData.data() + TxtDataSize,
Data.begin() + TxtDataOffset);
}
SectionDataCache[Sec.d.a] = Data;
return ArrayRef<uint8_t>(Data);
}

uint64_t GOFFObjectFile::getSectionAlignment(DataRefImpl Sec) const {
const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
GOFF::ESDAlignment Pow2Alignment;
ESDRecord::getAlignment(EsdRecord, Pow2Alignment);
return 1 << static_cast<uint64_t>(Pow2Alignment);
}

bool GOFFObjectFile::isSectionText(DataRefImpl Sec) const {
const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
GOFF::ESDExecutable Executable;
ESDRecord::getExecutable(EsdRecord, Executable);
return Executable == GOFF::ESD_EXE_CODE;
}

bool GOFFObjectFile::isSectionData(DataRefImpl Sec) const {
const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
GOFF::ESDExecutable Executable;
ESDRecord::getExecutable(EsdRecord, Executable);
return Executable == GOFF::ESD_EXE_DATA;
}

bool GOFFObjectFile::isSectionNoLoad(DataRefImpl Sec) const {
const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
GOFF::ESDLoadingBehavior LoadingBehavior;
ESDRecord::getLoadingBehavior(EsdRecord, LoadingBehavior);
return LoadingBehavior == GOFF::ESD_LB_NoLoad;
}

bool GOFFObjectFile::isSectionReadOnlyData(DataRefImpl Sec) const {
if (!isSectionData(Sec))
return false;

const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
GOFF::ESDLoadingBehavior LoadingBehavior;
ESDRecord::getLoadingBehavior(EsdRecord, LoadingBehavior);
return LoadingBehavior == GOFF::ESD_LB_Initial;
}

bool GOFFObjectFile::isSectionZeroInit(DataRefImpl Sec) const {
// GOFF uses fill characters and fill characters are applied
// on getSectionContents() - so we say false to zero init.
return false;
}

section_iterator GOFFObjectFile::section_begin() const {
DataRefImpl Sec;
moveSectionNext(Sec);
Expand Down Expand Up @@ -476,6 +636,13 @@ Error ESDRecord::getData(const uint8_t *Record,
return getContinuousData(Record, DataSize, 72, CompleteData);
}

Error TXTRecord::getData(const uint8_t *Record,
SmallString<256> &CompleteData) {
uint16_t Length;
getDataLength(Record, Length);
return getContinuousData(Record, Length, 24, CompleteData);
}

Error ENDRecord::getData(const uint8_t *Record,
SmallString<256> &CompleteData) {
uint16_t Length = getNameLength(Record);
Expand Down
Loading

0 comments on commit 009f88f

Please sign in to comment.