blob: e18fcfa0f880cce6087bb50189c83f8f040bdd90 [file]
//===- GOFFObjectFile.cpp - GOFF object file implementation -----*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Implementation of the GOFFObjectFile class.
//
//===----------------------------------------------------------------------===//
#include "llvm/Object/GOFFObjectFile.h"
#include "llvm/BinaryFormat/GOFF.h"
#include "llvm/Object/GOFF.h"
#include "llvm/Support/DataExtractor.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/raw_ostream.h"
#ifndef DEBUG_TYPE
#define DEBUG_TYPE "goff"
#endif
using namespace llvm::object;
using namespace llvm;
// Return the type of the record.
static GOFF::RecordType getRecordType(const uint8_t *PhysicalRecord) {
return GOFF::RecordType((PhysicalRecord[1] & 0xF0) >> 4);
}
// Return true if the record is a continuation record.
static bool isContinuation(const uint8_t *PhysicalRecord) {
return PhysicalRecord[1] & 0x02;
}
// Return true if the record has a continuation.
static bool isContinued(const uint8_t *PhysicalRecord) {
return PhysicalRecord[1] & 0x01;
}
// Helper function to get continuous data from a logical record
// Includes PTV header + everything from first record + continuation payloads
// Returns the number of physical records consumed (including the initial
// record)
Expected<unsigned>
GOFFObjectFile::getContinuousData(SmallVectorImpl<uint8_t> &CompleteData,
int DataIndex, uint16_t DataLength,
const uint8_t *Record) const {
CompleteData.reserve(DataLength + GOFF::RecordLength - DataIndex);
// First record - include PTV header (bytes 0-2)
CompleteData.append(Record, Record + GOFF::RecordPrefixLength);
// Append everything from the first record before the start of the data.
CompleteData.append(Record + GOFF::RecordPrefixLength, Record + DataIndex);
// Append the data.
const uint8_t *Ptr = Record + DataIndex;
size_t SliceLength = std::min(
DataLength, static_cast<uint16_t>(GOFF::RecordLength - DataIndex));
CompleteData.append(Ptr, Ptr + SliceLength);
DataLength -= SliceLength;
Ptr += SliceLength;
unsigned BlocksConsumed = 1; // Count the initial record
// Continuation records.
while (DataLength > 0) {
// Ptr now points to the start of the next physical record.
// Check that this block is a Continuation.
assert(isContinuation(Ptr) && "Continuation bit must be set");
// Check that the last Continuation is terminated correctly.
if (DataLength <= GOFF::PayloadLength && isContinued(Ptr))
return createStringError(object_error::parse_failed,
"continued bit should not be set");
SliceLength =
std::min(DataLength, static_cast<uint16_t>(GOFF::PayloadLength));
Ptr += GOFF::RecordPrefixLength; // Skip the 3-byte prefix
CompleteData.append(Ptr, Ptr + SliceLength);
DataLength -= SliceLength;
// Advance to the start of the next record
Ptr += (GOFF::RecordLength - GOFF::RecordPrefixLength);
BlocksConsumed++;
}
return BlocksConsumed;
}
// Walk over the object file and populate FlattenedData.
Error GOFFObjectFile::createFlattenedData() {
const uint8_t *It = base();
const uint8_t *End = base() + getData().size();
// First pass: validate continuation records.
const uint8_t *ValidateIt = It;
unsigned ValidateIndex = 0;
bool PrevContinued = false;
bool PrevWasContinuation = false;
GOFF::RecordType PrevRecordType = GOFF::RT_HDR;
while (ValidateIt < End) {
bool IsCont = isContinuation(ValidateIt);
bool IsContd = isContinued(ValidateIt);
GOFF::RecordType CurrentType = ::getRecordType(ValidateIt);
if (IsCont) {
// Continuation record must be preceded by a continued record.
if (!PrevContinued) {
return createStringError(object_error::parse_failed,
"record " + std::to_string(ValidateIndex) +
" is a continuation record that is not "
"preceded by a continued record");
}
// Continuation record type must match previous record type.
if (CurrentType != PrevRecordType) {
return createStringError(
object_error::parse_failed,
"record " + std::to_string(ValidateIndex) +
" is a continuation record that does not match "
"the type of the previous record");
}
// Update PrevContinued for continuation records.
PrevContinued = IsContd;
} else {
// Check if previous non-continuation was marked as continued.
if (PrevContinued && !PrevWasContinuation) {
return createStringError(object_error::parse_failed,
"record " + std::to_string(ValidateIndex) +
" is not a continuation record but the "
"preceding record is continued");
}
PrevRecordType = CurrentType;
PrevContinued = IsContd;
}
PrevWasContinuation = IsCont;
ValidateIt += GOFF::RecordLength;
ValidateIndex++;
}
// Second pass: process records now that we know they're valid.
while (It < End) {
// Skip continuation records - only process first physical record of each
// logical record.
if (isContinuation(It)) {
It += GOFF::RecordLength;
continue;
}
GOFF::RecordType RecordType = ::getRecordType(It);
// Call get continuous data based on record type.
int DataIndex = 0;
uint16_t DataLength = 0;
ArrayRef<uint8_t> Slice(It, GOFF::RecordLength);
DataExtractor DE(Slice, false);
switch (RecordType) {
case GOFF::RT_ESD: {
DataIndex = 72;
uint64_t Offset = 70;
DataLength = DE.getU16(&Offset);
break;
}
case GOFF::RT_TXT: {
DataIndex = 24;
uint64_t Offset = 22;
DataLength = DE.getU16(&Offset);
break;
}
case GOFF::RT_RLD: {
DataIndex = 6;
uint64_t Offset = 4;
DataLength = DE.getU16(&Offset);
break;
}
case GOFF::RT_LEN: {
DataIndex = 8;
uint64_t Offset = 6;
DataLength = DE.getU16(&Offset);
break;
}
case GOFF::RT_END: {
DataIndex = 26;
uint64_t Offset = 24;
DataLength = DE.getU16(&Offset);
break;
}
case GOFF::RT_HDR: {
DataIndex = 60;
uint64_t Offset = 52;
DataLength = DE.getU16(&Offset);
break;
}
}
// Get the flattened data for this logical record (including continuations).
SmallVector<uint8_t> CompleteData;
Expected<unsigned> BlocksConsumed =
getContinuousData(CompleteData, DataIndex, DataLength, It);
if (!BlocksConsumed) {
// Log the error but don't fail construction - errors in continuation
// data will be caught when the data is actually accessed.
llvm::handleAllErrors(
BlocksConsumed.takeError(), [](const llvm::ErrorInfoBase &EIB) {
llvm::errs() << "ERROR: " << EIB.message() << "\n";
});
// Skip this record and continue.
It += GOFF::RecordLength;
continue;
}
FlattenedData.push_back({RecordType, std::move(CompleteData)});
// Move to next logical record using the number of blocks consumed.
It += (*BlocksConsumed) * GOFF::RecordLength;
}
return Error::success();
}
Expected<std::unique_ptr<ObjectFile>>
ObjectFile::createGOFFObjectFile(MemoryBufferRef Object) {
Error Err = Error::success();
std::unique_ptr<GOFFObjectFile> Ret(new GOFFObjectFile(Object, Err));
if (Err)
return std::move(Err);
return std::move(Ret);
}
GOFFObjectFile::GOFFObjectFile(MemoryBufferRef Object, Error &Err)
: ObjectFile(Binary::ID_GOFF, Object) {
ErrorAsOutParameter ErrAsOutParam(Err);
// Object file isn't the right size, bail out early.
if ((Object.getBufferSize() % GOFF::RecordLength) != 0) {
Err = createStringError(
object_error::unexpected_eof,
"object file is not the right size. Must be a multiple "
"of 80 bytes, but is " +
std::to_string(Object.getBufferSize()) + " bytes");
return;
}
// Object file doesn't start/end with HDR/END records.
// Bail out early.
if (Object.getBufferSize() != 0) {
if ((base()[1] & 0xF0) >> 4 != GOFF::RT_HDR) {
Err = createStringError(object_error::parse_failed,
"object file must start with HDR record");
return;
}
if ((base()[Object.getBufferSize() - GOFF::RecordLength + 1] & 0xF0) >> 4 !=
GOFF::RT_END) {
Err = createStringError(object_error::parse_failed,
"object file must end with END record");
return;
}
}
if (Error E = createFlattenedData()) {
Err = std::move(E);
return;
}
SectionEntryImpl DummySection;
SectionList.emplace_back(DummySection); // Dummy entry at index 0.
for (const auto &[RecordType, Data] : FlattenedData) {
const uint8_t *I = Data.data();
switch (RecordType) {
case GOFF::RT_ESD: {
// Save ESD record.
uint32_t EsdId;
ESDRecord::getEsdId(I, EsdId);
EsdPtrs.grow(EsdId);
EsdPtrs[EsdId] = I;
// Determine and save the "sections" in GOFF.
// A section is saved as a tuple of the form
// case (1): (ED,child PR)
// - where the PR must have non-zero length.
// case (2a) (ED,0)
// - where the ED is of non-zero length.
// case (2b) (ED,0)
// - where the ED is zero length but
// contains a label (LD).
GOFF::ESDSymbolType SymbolType;
ESDRecord::getSymbolType(I, SymbolType);
SectionEntryImpl Section;
uint32_t Length;
ESDRecord::getLength(I, Length);
if (SymbolType == GOFF::ESD_ST_ElementDefinition) {
// case (2a)
if (Length != 0) {
Section.d.a = EsdId;
SectionList.emplace_back(Section);
}
} else if (SymbolType == GOFF::ESD_ST_PartReference) {
// case (1)
if (Length != 0) {
uint32_t SymEdId;
ESDRecord::getParentEsdId(I, SymEdId);
Section.d.a = SymEdId;
Section.d.b = EsdId;
SectionList.emplace_back(Section);
}
} else if (SymbolType == GOFF::ESD_ST_LabelDefinition) {
// case (2b)
uint32_t SymEdId;
ESDRecord::getParentEsdId(I, SymEdId);
const uint8_t *SymEdRecord = EsdPtrs[SymEdId];
uint32_t EdLength;
ESDRecord::getLength(SymEdRecord, EdLength);
if (!EdLength) { // [ EDID, PRID ]
// LD child of a zero length parent ED.
// Add the section ED which was previously ignored.
Section.d.a = SymEdId;
SectionList.emplace_back(Section);
}
}
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_RLD:
LLVM_DEBUG(dbgs() << " -- RLD (GOFF record type) unhandled\n");
break;
case GOFF::RT_LEN:
LLVM_DEBUG(dbgs() << " -- LEN (GOFF record type) unhandled\n");
break;
case GOFF::RT_END:
LLVM_DEBUG(dbgs() << " -- END (GOFF record type) unhandled\n");
break;
case GOFF::RT_HDR:
LLVM_DEBUG(dbgs() << " -- HDR (GOFF record type) unhandled\n");
break;
}
}
}
const uint8_t *GOFFObjectFile::getSymbolEsdRecord(DataRefImpl Symb) const {
const uint8_t *EsdRecord = EsdPtrs[Symb.d.a];
return EsdRecord;
}
Expected<StringRef> GOFFObjectFile::getSymbolName(DataRefImpl Symb) const {
if (auto It = EsdNamesCache.find(Symb.d.a); It != EsdNamesCache.end()) {
auto &StrPtr = It->second;
return StringRef(StrPtr.second.get(), StrPtr.first);
}
// Get the ESD record pointer from EsdPtrs (points to FlattenedData)
const uint8_t *EsdRecord = getSymbolEsdRecord(Symb);
// Extract name from the flattened ESD record
// Name length is at byte 70-71, name data starts at byte 72
uint16_t NameLength = ESDRecord::getNameLength(EsdRecord);
SmallString<256> SymbolName;
if (NameLength > 0) {
// Name starts at byte 72 in the record (already flattened, no
// continuations)
const uint8_t *NameStart = EsdRecord + 72;
SymbolName.append(NameStart, NameStart + NameLength);
}
SmallString<256> SymbolNameConverted;
ConverterEBCDIC::convertToUTF8(SymbolName, SymbolNameConverted);
size_t Size = SymbolNameConverted.size();
auto StrPtr = std::make_pair(Size, std::make_unique<char[]>(Size));
char *Buf = StrPtr.second.get();
memcpy(Buf, SymbolNameConverted.data(), Size);
EsdNamesCache[Symb.d.a] = std::move(StrPtr);
return StringRef(Buf, Size);
}
Expected<StringRef> GOFFObjectFile::getSymbolName(SymbolRef Symbol) const {
return getSymbolName(Symbol.getRawDataRefImpl());
}
Expected<uint64_t> GOFFObjectFile::getSymbolAddress(DataRefImpl Symb) const {
uint32_t Offset;
const uint8_t *EsdRecord = getSymbolEsdRecord(Symb);
ESDRecord::getOffset(EsdRecord, Offset);
return static_cast<uint64_t>(Offset);
}
uint64_t GOFFObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
uint32_t Offset;
const uint8_t *EsdRecord = getSymbolEsdRecord(Symb);
ESDRecord::getOffset(EsdRecord, Offset);
return static_cast<uint64_t>(Offset);
}
uint64_t GOFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
return 0;
}
bool GOFFObjectFile::isSymbolUnresolved(DataRefImpl Symb) const {
const uint8_t *Record = getSymbolEsdRecord(Symb);
GOFF::ESDSymbolType SymbolType;
ESDRecord::getSymbolType(Record, SymbolType);
if (SymbolType == GOFF::ESD_ST_ExternalReference)
return true;
if (SymbolType == GOFF::ESD_ST_PartReference) {
uint32_t Length;
ESDRecord::getLength(Record, Length);
if (Length == 0)
return true;
}
return false;
}
bool GOFFObjectFile::isSymbolIndirect(DataRefImpl Symb) const {
const uint8_t *Record = getSymbolEsdRecord(Symb);
bool Indirect;
ESDRecord::getIndirectReference(Record, Indirect);
return Indirect;
}
Expected<uint32_t> GOFFObjectFile::getSymbolFlags(DataRefImpl Symb) const {
uint32_t Flags = 0;
if (isSymbolUnresolved(Symb))
Flags |= SymbolRef::SF_Undefined;
const uint8_t *Record = getSymbolEsdRecord(Symb);
GOFF::ESDBindingStrength BindingStrength;
ESDRecord::getBindingStrength(Record, BindingStrength);
if (BindingStrength == GOFF::ESD_BST_Weak)
Flags |= SymbolRef::SF_Weak;
GOFF::ESDBindingScope BindingScope;
ESDRecord::getBindingScope(Record, BindingScope);
GOFF::ESDSymbolType Type;
ESDRecord::getSymbolType(Record, Type);
if (Type != GOFF::ESD_ST_SectionDefinition &&
Type != GOFF::ESD_ST_ElementDefinition &&
BindingScope != GOFF::ESD_BSC_Section &&
BindingScope != GOFF::ESD_BSC_Module) {
Expected<StringRef> Name = getSymbolName(Symb);
if (Name && *Name != " ") { // Blank name is local.
Flags |= SymbolRef::SF_Global;
if (BindingScope == GOFF::ESD_BSC_ImportExport)
Flags |= SymbolRef::SF_Exported;
else if (!(Flags & SymbolRef::SF_Undefined))
Flags |= SymbolRef::SF_Hidden;
}
}
return Flags;
}
Expected<SymbolRef::Type>
GOFFObjectFile::getSymbolType(DataRefImpl Symb) const {
const uint8_t *Record = getSymbolEsdRecord(Symb);
GOFF::ESDSymbolType SymbolType;
ESDRecord::getSymbolType(Record, SymbolType);
GOFF::ESDExecutable Executable;
ESDRecord::getExecutable(Record, Executable);
if (SymbolType != GOFF::ESD_ST_SectionDefinition &&
SymbolType != GOFF::ESD_ST_ElementDefinition &&
SymbolType != GOFF::ESD_ST_LabelDefinition &&
SymbolType != GOFF::ESD_ST_PartReference &&
SymbolType != GOFF::ESD_ST_ExternalReference) {
uint32_t EsdId;
ESDRecord::getEsdId(Record, EsdId);
return createStringError(llvm::errc::invalid_argument,
"ESD record %" PRIu32
" has invalid symbol type 0x%02" PRIX8,
EsdId, SymbolType);
}
switch (SymbolType) {
case GOFF::ESD_ST_SectionDefinition:
case GOFF::ESD_ST_ElementDefinition:
return SymbolRef::ST_Other;
case GOFF::ESD_ST_LabelDefinition:
case GOFF::ESD_ST_PartReference:
case GOFF::ESD_ST_ExternalReference:
if (Executable != GOFF::ESD_EXE_CODE && Executable != GOFF::ESD_EXE_DATA &&
Executable != GOFF::ESD_EXE_Unspecified) {
uint32_t EsdId;
ESDRecord::getEsdId(Record, EsdId);
return createStringError(llvm::errc::invalid_argument,
"ESD record %" PRIu32
" has unknown Executable type 0x%02X",
EsdId, Executable);
}
switch (Executable) {
case GOFF::ESD_EXE_CODE:
return SymbolRef::ST_Function;
case GOFF::ESD_EXE_DATA:
return SymbolRef::ST_Data;
case GOFF::ESD_EXE_Unspecified:
return SymbolRef::ST_Unknown;
}
llvm_unreachable("Unhandled ESDExecutable");
}
llvm_unreachable("Unhandled ESDSymbolType");
}
Expected<section_iterator>
GOFFObjectFile::getSymbolSection(DataRefImpl Symb) const {
DataRefImpl Sec;
if (isSymbolUnresolved(Symb))
return section_iterator(SectionRef(Sec, this));
const uint8_t *SymEsdRecord = EsdPtrs[Symb.d.a];
uint32_t SymEdId;
ESDRecord::getParentEsdId(SymEsdRecord, SymEdId);
const uint8_t *SymEdRecord = EsdPtrs[SymEdId];
for (size_t I = 0, E = SectionList.size(); I < E; ++I) {
bool Found;
const uint8_t *SectionPrRecord = getSectionPrEsdRecord(I);
if (SectionPrRecord) {
Found = SymEsdRecord == SectionPrRecord;
} else {
const uint8_t *SectionEdRecord = getSectionEdEsdRecord(I);
Found = SymEdRecord == SectionEdRecord;
}
if (Found) {
Sec.d.a = I;
return section_iterator(SectionRef(Sec, this));
}
}
return createStringError(llvm::errc::invalid_argument,
"symbol with ESD id " + std::to_string(Symb.d.a) +
" refers to invalid section with ESD id " +
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];
return EsdRecord;
}
const uint8_t *GOFFObjectFile::getSectionPrEsdRecord(DataRefImpl &Sec) const {
SectionEntryImpl EsdIds = SectionList[Sec.d.a];
const uint8_t *EsdRecord = nullptr;
if (EsdIds.d.b)
EsdRecord = EsdPtrs[EsdIds.d.b];
return EsdRecord;
}
const uint8_t *
GOFFObjectFile::getSectionEdEsdRecord(uint32_t SectionIndex) const {
DataRefImpl Sec;
Sec.d.a = SectionIndex;
const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
return EsdRecord;
}
const uint8_t *
GOFFObjectFile::getSectionPrEsdRecord(uint32_t SectionIndex) const {
DataRefImpl Sec;
Sec.d.a = SectionIndex;
const uint8_t *EsdRecord = getSectionPrEsdRecord(Sec);
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 (auto It = SectionDataCache.find(Sec.d.a); It != SectionDataCache.end()) {
auto &Buf = It->second;
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 *TxtRecordPtr : TextPtrs) {
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");
// Text data starts at byte 24 in the flattened record (already processed
// continuations)
const uint8_t *TxtData = TxtRecordPtr + 24;
assert(TxtDataSize <= Data.size() - TxtDataOffset &&
"Text data exceeds section size");
std::copy(TxtData, TxtData + TxtDataSize, Data.begin() + TxtDataOffset);
}
auto &Cache = SectionDataCache[Sec.d.a];
Cache = std::move(Data);
return ArrayRef<uint8_t>(Cache);
}
uint64_t GOFFObjectFile::getSectionAlignment(DataRefImpl Sec) const {
const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
GOFF::ESDAlignment Pow2Alignment;
ESDRecord::getAlignment(EsdRecord, Pow2Alignment);
return 1ULL << 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);
return section_iterator(SectionRef(Sec, this));
}
section_iterator GOFFObjectFile::section_end() const {
DataRefImpl Sec;
return section_iterator(SectionRef(Sec, this));
}
void GOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const {
for (uint32_t I = Symb.d.a + 1, E = EsdPtrs.size(); I < E; ++I) {
if (const uint8_t *EsdRecord = EsdPtrs[I]) {
GOFF::ESDSymbolType SymbolType;
ESDRecord::getSymbolType(EsdRecord, SymbolType);
// Skip EDs - i.e. section symbols.
bool IgnoreSpecialGOFFSymbols = true;
bool SkipSymbol = ((SymbolType == GOFF::ESD_ST_ElementDefinition) ||
(SymbolType == GOFF::ESD_ST_SectionDefinition)) &&
IgnoreSpecialGOFFSymbols;
if (!SkipSymbol) {
Symb.d.a = I;
return;
}
}
}
Symb.d.a = 0;
}
basic_symbol_iterator GOFFObjectFile::symbol_begin() const {
DataRefImpl Symb;
moveSymbolNext(Symb);
return basic_symbol_iterator(SymbolRef(Symb, this));
}
basic_symbol_iterator GOFFObjectFile::symbol_end() const {
DataRefImpl Symb;
return basic_symbol_iterator(SymbolRef(Symb, this));
}