Skip to content

[SystemZ][z/OS] TXT records in the GOFF reader #87648

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -165,6 +165,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 @@ -361,6 +366,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 @@ -391,6 +403,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>(SectionDataCache[Sec.d.a]);
}

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 @@ -473,6 +633,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