mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-17 03:36:37 +00:00
648 lines
22 KiB
C++
648 lines
22 KiB
C++
//===- 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/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;
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
SectionEntryImpl DummySection;
|
|
SectionList.emplace_back(DummySection); // Dummy entry at index 0.
|
|
|
|
uint8_t PrevRecordType = 0;
|
|
uint8_t PrevContinuationBits = 0;
|
|
const uint8_t *End = reinterpret_cast<const uint8_t *>(Data.getBufferEnd());
|
|
for (const uint8_t *I = base(); I < End; I += GOFF::RecordLength) {
|
|
uint8_t RecordType = (I[1] & 0xF0) >> 4;
|
|
bool IsContinuation = I[1] & 0x02;
|
|
bool PrevWasContinued = PrevContinuationBits & 0x01;
|
|
size_t RecordNum = (I - base()) / GOFF::RecordLength;
|
|
|
|
// If the previous record was continued, the current record should be a
|
|
// continuation.
|
|
if (PrevWasContinued && !IsContinuation) {
|
|
if (PrevRecordType == RecordType) {
|
|
Err = createStringError(object_error::parse_failed,
|
|
"record " + std::to_string(RecordNum) +
|
|
" is not a continuation record but the "
|
|
"preceding record is continued");
|
|
return;
|
|
}
|
|
}
|
|
// Don't parse continuations records, only parse initial record.
|
|
if (IsContinuation) {
|
|
if (RecordType != PrevRecordType) {
|
|
Err = createStringError(object_error::parse_failed,
|
|
"record " + std::to_string(RecordNum) +
|
|
" is a continuation record that does not "
|
|
"match the type of the previous record");
|
|
return;
|
|
}
|
|
if (!PrevWasContinued) {
|
|
Err = createStringError(object_error::parse_failed,
|
|
"record " + std::to_string(RecordNum) +
|
|
" is a continuation record that is not "
|
|
"preceded by a continued record");
|
|
return;
|
|
}
|
|
PrevRecordType = RecordType;
|
|
PrevContinuationBits = I[1] & 0x03;
|
|
continue;
|
|
}
|
|
LLVM_DEBUG(for (size_t J = 0; J < GOFF::RecordLength; ++J) {
|
|
const uint8_t *P = I + J;
|
|
if (J % 8 == 0)
|
|
dbgs() << " ";
|
|
dbgs() << format("%02hhX", *P);
|
|
});
|
|
|
|
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_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;
|
|
default:
|
|
llvm_unreachable("Unknown record type");
|
|
}
|
|
PrevRecordType = RecordType;
|
|
PrevContinuationBits = I[1] & 0x03;
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
SmallString<256> SymbolName;
|
|
if (auto Err = ESDRecord::getData(getSymbolEsdRecord(Symb), SymbolName))
|
|
return std::move(Err);
|
|
|
|
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);
|
|
|
|
if (BindingScope != GOFF::ESD_BSC_Section) {
|
|
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 *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);
|
|
}
|
|
auto &Cache = SectionDataCache[Sec.d.a];
|
|
Cache = 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));
|
|
}
|
|
|
|
Error Record::getContinuousData(const uint8_t *Record, uint16_t DataLength,
|
|
int DataIndex, SmallString<256> &CompleteData) {
|
|
// First record.
|
|
const uint8_t *Slice = Record + DataIndex;
|
|
size_t SliceLength =
|
|
std::min(DataLength, (uint16_t)(GOFF::RecordLength - DataIndex));
|
|
CompleteData.append(Slice, Slice + SliceLength);
|
|
DataLength -= SliceLength;
|
|
Slice += SliceLength;
|
|
|
|
// Continuation records.
|
|
for (; DataLength > 0;
|
|
DataLength -= SliceLength, Slice += GOFF::PayloadLength) {
|
|
// Slice points to the start of the new record.
|
|
// Check that this block is a Continuation.
|
|
assert(Record::isContinuation(Slice) && "Continuation bit must be set");
|
|
// Check that the last Continuation is terminated correctly.
|
|
if (DataLength <= 77 && Record::isContinued(Slice))
|
|
return createStringError(object_error::parse_failed,
|
|
"continued bit should not be set");
|
|
|
|
SliceLength = std::min(DataLength, (uint16_t)GOFF::PayloadLength);
|
|
Slice += GOFF::RecordPrefixLength;
|
|
CompleteData.append(Slice, Slice + SliceLength);
|
|
}
|
|
return Error::success();
|
|
}
|
|
|
|
Error HDRRecord::getData(const uint8_t *Record,
|
|
SmallString<256> &CompleteData) {
|
|
uint16_t Length = getPropertyModuleLength(Record);
|
|
return getContinuousData(Record, Length, 60, CompleteData);
|
|
}
|
|
|
|
Error ESDRecord::getData(const uint8_t *Record,
|
|
SmallString<256> &CompleteData) {
|
|
uint16_t DataSize = getNameLength(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);
|
|
return getContinuousData(Record, Length, 26, CompleteData);
|
|
}
|