// This header contains common, non-processor-specific data structures and
// constants for the GOFF file format.
//
-// GOFF specifics can be found in MVS Program Management: Advanced Facilities
+// GOFF specifics can be found in MVS Program Management: Advanced Facilities.
+//
//===----------------------------------------------------------------------===//
#ifndef LLVM_BINARYFORMAT_GOFF_H
#include "llvm/Support/DataTypes.h"
namespace llvm {
-
namespace GOFF {
+constexpr uint8_t RecordLength = 80;
+constexpr uint8_t RecordPrefixLength = 3;
+constexpr uint8_t PayloadLength = 77;
+
+// Prefix byte on every record. This indicates GOFF format.
+constexpr uint8_t PTVPrefix = 0x03;
+
+enum RecordType : uint8_t {
+ RT_ESD = 0,
+ RT_TXT = 1,
+ RT_RLD = 2,
+ RT_LEN = 3,
+ RT_END = 4,
+ RT_HDR = 15,
+};
+
+enum ESDSymbolType : uint8_t {
+ ESD_ST_SectionDefinition = 0,
+ ESD_ST_ElementDefinition = 1,
+ ESD_ST_LabelDefinition = 2,
+ ESD_ST_PartReference = 3,
+ ESD_ST_ExternalReference = 4,
+};
+
+enum ESDNameSpaceId : uint8_t {
+ ESD_NS_ProgramManagementBinder = 0,
+ ESD_NS_NormalName = 1,
+ ESD_NS_PseudoRegister = 2,
+ ESD_NS_Parts = 3
+};
+
+enum ESDReserveQwords : uint8_t {
+ ESD_RQ_0 = 0,
+ ESD_RQ_1 = 1,
+ ESD_RQ_2 = 2,
+ ESD_RQ_3 = 3
+};
+
+enum ESDAmode : uint8_t {
+ ESD_AMODE_None = 0,
+ ESD_AMODE_24 = 1,
+ ESD_AMODE_31 = 2,
+ ESD_AMODE_ANY = 3,
+ ESD_AMODE_64 = 4,
+ ESD_AMODE_MIN = 16,
+};
+
+enum ESDRmode : uint8_t {
+ ESD_RMODE_None = 0,
+ ESD_RMODE_24 = 1,
+ ESD_RMODE_31 = 3,
+ ESD_RMODE_64 = 4,
+};
+
+enum ESDTextStyle : uint8_t {
+ ESD_TS_ByteOriented = 0,
+ ESD_TS_Structured = 1,
+ ESD_TS_Unstructured = 2,
+};
+
+enum ESDBindingAlgorithm : uint8_t {
+ ESD_BA_Concatenate = 0,
+ ESD_BA_Merge = 1,
+};
+
+enum ESDTaskingBehavior : uint8_t {
+ ESD_TA_Unspecified = 0,
+ ESD_TA_NonReus = 1,
+ ESD_TA_Reus = 2,
+ ESD_TA_Rent = 3,
+};
+
+enum ESDExecutable : uint8_t {
+ ESD_EXE_Unspecified = 0,
+ ESD_EXE_DATA = 1,
+ ESD_EXE_CODE = 2,
+};
+
+enum ESDDuplicateSymbolSeverity : uint8_t {
+ ESD_DSS_NoWarning = 0,
+ ESD_DSS_Warning = 1,
+ ESD_DSS_Error = 2,
+ ESD_DSS_Reserved = 3,
+};
+
+enum ESDBindingStrength : uint8_t {
+ ESD_BST_Strong = 0,
+ ESD_BST_Weak = 1,
+};
+
+enum ESDLoadingBehavior : uint8_t {
+ ESD_LB_Initial = 0,
+ ESD_LB_Deferred = 1,
+ ESD_LB_NoLoad = 2,
+ ESD_LB_Reserved = 3,
+};
+
+enum ESDBindingScope : uint8_t {
+ ESD_BSC_Unspecified = 0,
+ ESD_BSC_Section = 1,
+ ESD_BSC_Module = 2,
+ ESD_BSC_Library = 3,
+ ESD_BSC_ImportExport = 4,
+};
+
+enum ESDLinkageType : uint8_t { ESD_LT_OS = 0, ESD_LT_XPLink = 1 };
+
+enum ESDAlignment : uint8_t {
+ ESD_ALIGN_Byte = 0,
+ ESD_ALIGN_Halfword = 1,
+ ESD_ALIGN_Fullword = 2,
+ ESD_ALIGN_Doubleword = 3,
+ ESD_ALIGN_Quadword = 4,
+ ESD_ALIGN_32byte = 5,
+ ESD_ALIGN_64byte = 6,
+ ESD_ALIGN_128byte = 7,
+ ESD_ALIGN_256byte = 8,
+ ESD_ALIGN_512byte = 9,
+ ESD_ALIGN_1024byte = 10,
+ ESD_ALIGN_2Kpage = 11,
+ ESD_ALIGN_4Kpage = 12,
+};
+
+enum ENDEntryPointRequest : uint8_t {
+ END_EPR_None = 0,
+ END_EPR_EsdidOffset = 1,
+ END_EPR_ExternalName = 2,
+ END_EPR_Reserved = 3,
+};
+
// \brief Subsections of the primary C_CODE section in the object file.
enum SubsectionKind : uint8_t {
SK_PPA1 = 2,
};
-
} // end namespace GOFF
} // end namespace llvm
ID_MachO64L, // MachO 64-bit, little endian
ID_MachO64B, // MachO 64-bit, big endian
+ ID_GOFF,
ID_Wasm,
ID_EndObjects
return TypeID == ID_IR;
}
+ bool isGOFF() const { return TypeID == ID_GOFF; }
+
bool isMinidump() const { return TypeID == ID_Minidump; }
bool isTapiFile() const { return TypeID == ID_TapiFile; }
return Triple::MachO;
if (isELF())
return Triple::ELF;
+ if (isGOFF())
+ return Triple::GOFF;
return Triple::UnknownObjectFormat;
}
--- /dev/null
+//===- GOFF.h - 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the GOFFObjectFile class.
+// Record classes and derivatives are also declared and implemented.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECT_GOFF_H
+#define LLVM_OBJECT_GOFF_H
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/BinaryFormat/GOFF.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+namespace object {
+
+/// \brief Represents a GOFF physical record.
+///
+/// Specifies protected member functions to manipulate the record. These should
+/// be called from deriving classes to change values as that record specifies.
+class Record {
+public:
+ static Error getContinuousData(const uint8_t *Record, uint16_t DataLength,
+ int DataIndex, SmallString<256> &CompleteData);
+
+ static bool isContinued(const uint8_t *Record) {
+ uint8_t IsContinued;
+ getBits(Record, 1, 7, 1, IsContinued);
+ return IsContinued;
+ }
+
+ static bool isContinuation(const uint8_t *Record) {
+ uint8_t IsContinuation;
+ getBits(Record, 1, 6, 1, IsContinuation);
+ return IsContinuation;
+ }
+
+protected:
+ /// \brief Get bit field of specified byte.
+ ///
+ /// Used to pack bit fields into one byte. Fields are packed left to right.
+ /// Bit index zero is the most significant bit of the byte.
+ ///
+ /// \param ByteIndex index of byte the field is in.
+ /// \param BitIndex index of first bit of field.
+ /// \param Length length of bit field.
+ /// \param Value value of bit field.
+ static void getBits(const uint8_t *Bytes, uint8_t ByteIndex, uint8_t BitIndex,
+ uint8_t Length, uint8_t &Value) {
+ assert(ByteIndex < GOFF::RecordLength && "Byte index out of bounds!");
+ assert(BitIndex < 8 && "Bit index out of bounds!");
+ assert(Length + BitIndex <= 8 && "Bit length too long!");
+
+ get<uint8_t>(Bytes, ByteIndex, Value);
+ Value = (Value >> (8 - BitIndex - Length)) & ((1 << Length) - 1);
+ }
+
+ template <class T>
+ static void get(const uint8_t *Bytes, uint8_t ByteIndex, T &Value) {
+ assert(ByteIndex + sizeof(T) <= GOFF::RecordLength &&
+ "Byte index out of bounds!");
+ Value = support::endian::read<T, support::big, support::unaligned>(
+ &Bytes[ByteIndex]);
+ }
+};
+
+class HDRRecord : public Record {
+public:
+ static Error getData(const uint8_t *Record, SmallString<256> &CompleteData);
+
+ static uint16_t getPropertyModuleLength(const uint8_t *Record) {
+ uint16_t Length;
+ get<uint16_t>(Record, 52, Length);
+ return Length;
+ }
+};
+
+class ESDRecord : public Record {
+public:
+ /// \brief Number of bytes for name; any more must go in continuation.
+ /// This is the number of bytes that can fit into the data field of an ESD
+ /// record.
+ static const uint8_t ESDMaxUncontinuedNameLength = 8;
+
+ /// \brief Maximum name length for ESD records and continuations.
+ /// This is the number of bytes that can fit into the data field of an ESD
+ /// record AND following continuations. This is limited fundamentally by the
+ /// 16 bit SIGNED length field.
+ static const uint16_t MaxNameLength = 32 * 1024;
+
+public:
+ static Error getData(const uint8_t *Record, SmallString<256> &CompleteData);
+
+ // ESD Get routines.
+ static void getSymbolType(const uint8_t *Record,
+ GOFF::ESDSymbolType &SymbolType) {
+ uint8_t Value;
+ get<uint8_t>(Record, 3, Value);
+ SymbolType = (GOFF::ESDSymbolType)Value;
+ }
+
+ static void getEsdId(const uint8_t *Record, uint32_t &EsdId) {
+ get<uint32_t>(Record, 4, EsdId);
+ }
+
+ static void getParentEsdId(const uint8_t *Record, uint32_t &EsdId) {
+ get<uint32_t>(Record, 8, EsdId);
+ }
+
+ static void getOffset(const uint8_t *Record, uint32_t &Offset) {
+ get<uint32_t>(Record, 16, Offset);
+ }
+
+ static void getLength(const uint8_t *Record, uint32_t &Length) {
+ get<uint32_t>(Record, 24, Length);
+ }
+
+ static void getNameSpaceId(const uint8_t *Record, GOFF::ESDNameSpaceId &Id) {
+ uint8_t Value;
+ get<uint8_t>(Record, 40, Value);
+ Id = (GOFF::ESDNameSpaceId)Value;
+ }
+
+ static void getFillBytePresent(const uint8_t *Record, bool &Present) {
+ uint8_t Value;
+ getBits(Record, 41, 0, 1, Value);
+ Present = (bool)Value;
+ }
+
+ static void getNameMangled(const uint8_t *Record, bool &Mangled) {
+ uint8_t Value;
+ getBits(Record, 41, 1, 1, Value);
+ Mangled = (bool)Value;
+ }
+
+ static void getRenamable(const uint8_t *Record, bool &Renamable) {
+ uint8_t Value;
+ getBits(Record, 41, 2, 1, Value);
+ Renamable = (bool)Value;
+ }
+
+ static void getRemovable(const uint8_t *Record, bool &Removable) {
+ uint8_t Value;
+ getBits(Record, 41, 3, 1, Value);
+ Removable = (bool)Value;
+ }
+
+ static void getFillByteValue(const uint8_t *Record, uint8_t &Fill) {
+ get<uint8_t>(Record, 42, Fill);
+ }
+
+ static void getAdaEsdId(const uint8_t *Record, uint32_t &EsdId) {
+ get<uint32_t>(Record, 44, EsdId);
+ }
+
+ static void getSortPriority(const uint8_t *Record, uint32_t &Priority) {
+ get<uint32_t>(Record, 48, Priority);
+ }
+
+ static void getAmode(const uint8_t *Record, GOFF::ESDAmode &Amode) {
+ uint8_t Value;
+ get<uint8_t>(Record, 60, Value);
+ Amode = (GOFF::ESDAmode)Value;
+ }
+
+ static void getRmode(const uint8_t *Record, GOFF::ESDRmode &Rmode) {
+ uint8_t Value;
+ get<uint8_t>(Record, 61, Value);
+ Rmode = (GOFF::ESDRmode)Value;
+ }
+
+ static void getTextStyle(const uint8_t *Record, GOFF::ESDTextStyle &Style) {
+ uint8_t Value;
+ getBits(Record, 62, 0, 4, Value);
+ Style = (GOFF::ESDTextStyle)Value;
+ }
+
+ static void getBindingAlgorithm(const uint8_t *Record,
+ GOFF::ESDBindingAlgorithm &Algorithm) {
+ uint8_t Value;
+ getBits(Record, 62, 4, 4, Value);
+ Algorithm = (GOFF::ESDBindingAlgorithm)Value;
+ }
+
+ static void getTaskingBehavior(const uint8_t *Record,
+ GOFF::ESDTaskingBehavior &TaskingBehavior) {
+ uint8_t Value;
+ getBits(Record, 63, 0, 3, Value);
+ TaskingBehavior = (GOFF::ESDTaskingBehavior)Value;
+ }
+
+ static void getReadOnly(const uint8_t *Record, bool &ReadOnly) {
+ uint8_t Value;
+ getBits(Record, 63, 4, 1, Value);
+ ReadOnly = (bool)Value;
+ }
+
+ static void getExecutable(const uint8_t *Record,
+ GOFF::ESDExecutable &Executable) {
+ uint8_t Value;
+ getBits(Record, 63, 5, 3, Value);
+ Executable = (GOFF::ESDExecutable)Value;
+ }
+
+ static void getDuplicateSeverity(const uint8_t *Record,
+ GOFF::ESDDuplicateSymbolSeverity &DSS) {
+ uint8_t Value;
+ getBits(Record, 64, 2, 2, Value);
+ DSS = (GOFF::ESDDuplicateSymbolSeverity)Value;
+ }
+
+ static void getBindingStrength(const uint8_t *Record,
+ GOFF::ESDBindingStrength &Strength) {
+ uint8_t Value;
+ getBits(Record, 64, 4, 4, Value);
+ Strength = (GOFF::ESDBindingStrength)Value;
+ }
+
+ static void getLoadingBehavior(const uint8_t *Record,
+ GOFF::ESDLoadingBehavior &Behavior) {
+ uint8_t Value;
+ getBits(Record, 65, 0, 2, Value);
+ Behavior = (GOFF::ESDLoadingBehavior)Value;
+ }
+
+ static void getIndirectReference(const uint8_t *Record, bool &Indirect) {
+ uint8_t Value;
+ getBits(Record, 65, 3, 1, Value);
+ Indirect = (bool)Value;
+ }
+
+ static void getBindingScope(const uint8_t *Record,
+ GOFF::ESDBindingScope &Scope) {
+ uint8_t Value;
+ getBits(Record, 65, 4, 4, Value);
+ Scope = (GOFF::ESDBindingScope)Value;
+ }
+
+ static void getLinkageType(const uint8_t *Record,
+ GOFF::ESDLinkageType &Type) {
+ uint8_t Value;
+ getBits(Record, 66, 2, 1, Value);
+ Type = (GOFF::ESDLinkageType)Value;
+ }
+
+ static void getAlignment(const uint8_t *Record,
+ GOFF::ESDAlignment &Alignment) {
+ uint8_t Value;
+ getBits(Record, 66, 3, 5, Value);
+ Alignment = (GOFF::ESDAlignment)Value;
+ }
+
+ static uint16_t getNameLength(const uint8_t *Record) {
+ uint16_t Length;
+ get<uint16_t>(Record, 70, Length);
+ return Length;
+ }
+};
+
+class ENDRecord : public Record {
+public:
+ static Error getData(const uint8_t *Record, SmallString<256> &CompleteData);
+
+ static uint16_t getNameLength(const uint8_t *Record) {
+ uint16_t Length;
+ get<uint16_t>(Record, 24, Length);
+ return Length;
+ }
+};
+
+} // end namespace object
+} // end namespace llvm
+
+#endif
--- /dev/null
+//===- GOFFObjectFile.h - 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the GOFFObjectFile class.
+// Record classes and derivatives are also declared and implemented.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECT_GOFFOBJECTFILE_H
+#define LLVM_OBJECT_GOFFOBJECTFILE_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/IndexedMap.h"
+#include "llvm/BinaryFormat/GOFF.h"
+#include "llvm/MC/SubtargetFeature.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/ConvertEBCDIC.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/TargetParser/Triple.h"
+
+namespace llvm {
+
+namespace object {
+
+class GOFFObjectFile : public ObjectFile {
+ IndexedMap<const uint8_t *> EsdPtrs; // Indexed by EsdId.
+
+ mutable DenseMap<uint32_t, std::pair<size_t, std::unique_ptr<char[]>>>
+ EsdNamesCache;
+
+ typedef DataRefImpl SectionEntryImpl;
+ // (EDID, 0) code, r/o data section
+ // (EDID,PRID) r/w data section
+ SmallVector<SectionEntryImpl, 256> SectionList;
+ mutable DenseMap<uint32_t, std::string> SectionDataCache;
+
+public:
+ Expected<StringRef> getSymbolName(SymbolRef Symbol) const;
+
+ GOFFObjectFile(MemoryBufferRef Object, Error &Err);
+ static inline bool classof(const Binary *V) { return V->isGOFF(); }
+ section_iterator section_begin() const override;
+ section_iterator section_end() const override;
+
+ uint8_t getBytesInAddress() const override { return 8; }
+
+ StringRef getFileFormatName() const override { return "GOFF-SystemZ"; }
+
+ Triple::ArchType getArch() const override { return Triple::systemz; }
+
+ Expected<SubtargetFeatures> getFeatures() const override { return SubtargetFeatures(); }
+
+ bool isRelocatableObject() const override { return true; }
+
+ void moveSymbolNext(DataRefImpl &Symb) const override;
+ basic_symbol_iterator symbol_begin() const override;
+ basic_symbol_iterator symbol_end() const override;
+
+ bool is64Bit() const override {
+ return true;
+ }
+
+private:
+ // SymbolRef.
+ Expected<StringRef> getSymbolName(DataRefImpl Symb) const override;
+ Expected<uint64_t> getSymbolAddress(DataRefImpl Symb) const override;
+ uint64_t getSymbolValueImpl(DataRefImpl Symb) const override;
+ uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const override;
+ Expected<uint32_t> getSymbolFlags(DataRefImpl Symb) const override;
+ Expected<SymbolRef::Type> getSymbolType(DataRefImpl Symb) const override;
+ Expected<section_iterator> getSymbolSection(DataRefImpl Symb) const override;
+
+ 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; }
+ 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; }
+ 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 isSectionBSS(DataRefImpl Sec) const override { return false; }
+ bool isSectionVirtual(DataRefImpl Sec) const override { return false; }
+ relocation_iterator section_rel_begin(DataRefImpl Sec) const override {
+ return relocation_iterator(RelocationRef(Sec, this));
+ }
+ relocation_iterator section_rel_end(DataRefImpl Sec) const override {
+ return relocation_iterator(RelocationRef(Sec, this));
+ }
+
+ const uint8_t *getSectionEdEsdRecord(DataRefImpl &Sec) const;
+ const uint8_t *getSectionPrEsdRecord(DataRefImpl &Sec) const;
+ const uint8_t *getSectionEdEsdRecord(uint32_t SectionIndex) const;
+ const uint8_t *getSectionPrEsdRecord(uint32_t SectionIndex) const;
+
+ // RelocationRef.
+ void moveRelocationNext(DataRefImpl &Rel) const override{};
+ uint64_t getRelocationOffset(DataRefImpl Rel) const override { return 0; }
+ symbol_iterator getRelocationSymbol(DataRefImpl Rel) const override {
+ DataRefImpl Temp;
+ return basic_symbol_iterator(SymbolRef(Temp, this));
+ }
+ uint64_t getRelocationType(DataRefImpl Rel) const override { return 0; }
+ void getRelocationTypeName(DataRefImpl Rel,
+ SmallVectorImpl<char> &Result) const override{};
+};
+
+} // namespace object
+
+} // namespace llvm
+
+#endif
uint32_t UniversalCputype = 0,
uint32_t UniversalIndex = 0);
+ static Expected<std::unique_ptr<ObjectFile>>
+ createGOFFObjectFile(MemoryBufferRef Object);
+
static Expected<std::unique_ptr<WasmObjectFile>>
createWasmObjectFile(MemoryBufferRef Object);
};
ELF.cpp
ELFObjectFile.cpp
Error.cpp
+ GOFFObjectFile.cpp
FaultMapParser.cpp
IRObjectFile.cpp
IRSymtab.cpp
--- /dev/null
+//===- 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;
+ }
+
+ for (size_t J = 0; J < GOFF::RecordLength; ++J) {
+ const uint8_t *P = I + J;
+ if (J % 8 == 0)
+ LLVM_DEBUG(dbgs() << " ");
+
+ LLVM_DEBUG(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_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 (EsdNamesCache.count(Symb.d.a)) {
+ auto &StrPtr = EsdNamesCache[Symb.d.a];
+ 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;
+ }
+ }
+}
+
+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));
+}
+
+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;
+}
+
+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 (EsdPtrs[I]) {
+ 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 ENDRecord::getData(const uint8_t *Record,
+ SmallString<256> &CompleteData) {
+ uint16_t Length = getNameLength(Record);
+ return getContinuousData(Record, Length, 26, CompleteData);
+}
TheTriple.setOS(Triple::AIX);
TheTriple.setObjectFormat(Triple::XCOFF);
}
+ else if (isGOFF()) {
+ TheTriple.setOS(Triple::ZOS);
+ TheTriple.setObjectFormat(Triple::GOFF);
+ }
return TheTriple;
}
ELFObjectFileTest.cpp
ELFTypesTest.cpp
ELFTest.cpp
+ GOFFObjectFileTest.cpp
MinidumpTest.cpp
ObjectFileTest.cpp
OffloadingTest.cpp
--- /dev/null
+//===- GOFFObjectFileTest.cpp - Tests for GOFFObjectFile ------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/GOFFObjectFile.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Testing/Support/Error.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::GOFF;
+
+namespace {
+char GOFFData[GOFF::RecordLength * 3] = {0x00};
+
+void constructValidGOFF(size_t Size) {
+ StringRef ValidSize(GOFFData, Size);
+ Expected<std::unique_ptr<ObjectFile>> GOFFObjOrErr =
+ object::ObjectFile::createGOFFObjectFile(
+ MemoryBufferRef(ValidSize, "dummyGOFF"));
+
+ ASSERT_THAT_EXPECTED(GOFFObjOrErr, Succeeded());
+}
+
+void constructInvalidGOFF(size_t Size) {
+ // Construct GOFFObject with record of length != multiple of 80.
+ StringRef InvalidData(GOFFData, Size);
+ Expected<std::unique_ptr<ObjectFile>> GOFFObjOrErr =
+ object::ObjectFile::createGOFFObjectFile(
+ MemoryBufferRef(InvalidData, "dummyGOFF"));
+
+ ASSERT_THAT_EXPECTED(
+ GOFFObjOrErr,
+ FailedWithMessage("object file is not the right size. Must be a multiple "
+ "of 80 bytes, but is " +
+ std::to_string(Size) + " bytes"));
+}
+} // namespace
+
+TEST(GOFFObjectFileTest, ConstructGOFFObjectValidSize) {
+ GOFFData[0] = 0x03;
+ GOFFData[1] = 0xF0;
+ GOFFData[80] = 0x03;
+ GOFFData[81] = 0x40;
+ constructValidGOFF(160);
+ constructValidGOFF(0);
+}
+
+TEST(GOFFObjectFileTest, ConstructGOFFObjectInvalidSize) {
+ constructInvalidGOFF(70);
+ constructInvalidGOFF(79);
+ constructInvalidGOFF(81);
+}
+
+TEST(GOFFObjectFileTest, MissingHDR) {
+ char GOFFData[GOFF::RecordLength * 2] = {0x00};
+
+ // ESD record.
+ GOFFData[0] = 0x03;
+
+ // END record.
+ GOFFData[GOFF::RecordLength] = 0x03;
+ GOFFData[GOFF::RecordLength + 1] = 0x40;
+
+ StringRef Data(GOFFData, GOFF::RecordLength * 2);
+
+ Expected<std::unique_ptr<ObjectFile>> GOFFObjOrErr =
+ object::ObjectFile::createGOFFObjectFile(
+ MemoryBufferRef(Data, "dummyGOFF"));
+
+ ASSERT_THAT_EXPECTED(
+ GOFFObjOrErr,
+ FailedWithMessage("object file must start with HDR record"));
+}
+
+TEST(GOFFObjectFileTest, MissingEND) {
+ char GOFFData[GOFF::RecordLength * 2] = {0x00};
+
+ // HDR record.
+ GOFFData[0] = 0x03;
+ GOFFData[1] = 0xF0;
+
+ // ESD record.
+ GOFFData[GOFF::RecordLength] = 0x03;
+
+ StringRef Data(GOFFData, GOFF::RecordLength * 2);
+
+ Expected<std::unique_ptr<ObjectFile>> GOFFObjOrErr =
+ object::ObjectFile::createGOFFObjectFile(
+ MemoryBufferRef(Data, "dummyGOFF"));
+
+ ASSERT_THAT_EXPECTED(
+ GOFFObjOrErr, FailedWithMessage("object file must end with END record"));
+}
+
+TEST(GOFFObjectFileTest, GetSymbolName) {
+ char GOFFData[GOFF::RecordLength * 3] = {0x00};
+
+ // HDR record.
+ GOFFData[0] = 0x03;
+ GOFFData[1] = 0xF0;
+
+ // ESD record.
+ GOFFData[GOFF::RecordLength] = 0x03;
+ GOFFData[GOFF::RecordLength + 3] = 0x02;
+ GOFFData[GOFF::RecordLength + 7] = 0x01;
+ GOFFData[GOFF::RecordLength + 11] = 0x01;
+ GOFFData[GOFF::RecordLength + 71] = 0x05; // Size of symbol name.
+ GOFFData[GOFF::RecordLength + 72] = 0xC8; // Symbol name is Hello.
+ GOFFData[GOFF::RecordLength + 73] = 0x85;
+ GOFFData[GOFF::RecordLength + 74] = 0x93;
+ GOFFData[GOFF::RecordLength + 75] = 0x93;
+ GOFFData[GOFF::RecordLength + 76] = 0x96;
+
+ // END record.
+ GOFFData[GOFF::RecordLength * 2] = 0x03;
+ GOFFData[GOFF::RecordLength * 2 + 1] = 0x40;
+
+ StringRef Data(GOFFData, GOFF::RecordLength * 3);
+
+ Expected<std::unique_ptr<ObjectFile>> GOFFObjOrErr =
+ object::ObjectFile::createGOFFObjectFile(
+ MemoryBufferRef(Data, "dummyGOFF"));
+
+ ASSERT_THAT_EXPECTED(GOFFObjOrErr, Succeeded());
+
+ GOFFObjectFile *GOFFObj = dyn_cast<GOFFObjectFile>((*GOFFObjOrErr).get());
+
+ for (SymbolRef Symbol : GOFFObj->symbols()) {
+ Expected<StringRef> SymbolNameOrErr = GOFFObj->getSymbolName(Symbol);
+ ASSERT_THAT_EXPECTED(SymbolNameOrErr, Succeeded());
+ StringRef SymbolName = SymbolNameOrErr.get();
+
+ EXPECT_EQ(SymbolName, "Hello");
+ }
+}
+
+TEST(GOFFObjectFileTest, ConcatenatedGOFFFile) {
+ char GOFFData[GOFF::RecordLength * 6] = {0x00};
+
+ // HDR record.
+ GOFFData[0] = 0x03;
+ GOFFData[1] = 0xF0;
+ // ESD record.
+ GOFFData[GOFF::RecordLength] = 0x03;
+ // END record.
+ GOFFData[GOFF::RecordLength * 2] = 0x03;
+ GOFFData[GOFF::RecordLength * 2 + 1] = 0x40;
+ // HDR record.
+ GOFFData[GOFF::RecordLength * 3] = 0x03;
+ GOFFData[GOFF::RecordLength * 3 + 1] = 0xF0;
+ // ESD record.
+ GOFFData[GOFF::RecordLength * 4] = 0x03;
+ // END record.
+ GOFFData[GOFF::RecordLength * 5] = 0x03;
+ GOFFData[GOFF::RecordLength * 5 + 1] = 0x40;
+
+ StringRef Data(GOFFData, GOFF::RecordLength * 6);
+
+ Expected<std::unique_ptr<ObjectFile>> GOFFObjOrErr =
+ object::ObjectFile::createGOFFObjectFile(
+ MemoryBufferRef(Data, "dummyGOFF"));
+
+ ASSERT_THAT_EXPECTED(GOFFObjOrErr, Succeeded());
+}
+
+TEST(GOFFObjectFileTest, ContinuationGetSymbolName) {
+ char GOFFContData[GOFF::RecordLength * 4] = {0x00};
+
+ // HDR record.
+ GOFFContData[0] = 0x03;
+ GOFFContData[1] = 0xF0;
+
+ // ESD record.
+ GOFFContData[GOFF::RecordLength] = 0x03;
+ GOFFContData[GOFF::RecordLength + 1] = 0x01;
+ GOFFContData[GOFF::RecordLength + 3] = 0x02;
+ GOFFContData[GOFF::RecordLength + 7] = 0x01;
+ GOFFContData[GOFF::RecordLength + 11] = 0x01;
+ GOFFContData[GOFF::RecordLength + 71] = 0x0A; // Size of symbol name.
+ GOFFContData[GOFF::RecordLength + 72] = 0xC8; // Symbol name is HelloWorld.
+ GOFFContData[GOFF::RecordLength + 73] = 0x85;
+ GOFFContData[GOFF::RecordLength + 74] = 0x93;
+ GOFFContData[GOFF::RecordLength + 75] = 0x93;
+ GOFFContData[GOFF::RecordLength + 76] = 0x96;
+ GOFFContData[GOFF::RecordLength + 77] = 0xA6;
+ GOFFContData[GOFF::RecordLength + 78] = 0x96;
+ GOFFContData[GOFF::RecordLength + 79] = 0x99;
+
+ // ESD continuation record.
+ GOFFContData[GOFF::RecordLength * 2] = 0x03;
+ GOFFContData[GOFF::RecordLength * 2 + 1] = 0x02; // No further continuations.
+ GOFFContData[GOFF::RecordLength * 2 + 3] = 0x93;
+ GOFFContData[GOFF::RecordLength * 2 + 4] = 0x84;
+
+ // END record.
+ GOFFContData[GOFF::RecordLength * 3] = 0x03;
+ GOFFContData[GOFF::RecordLength * 3 + 1] = 0x40;
+
+ StringRef Data(GOFFContData, GOFF::RecordLength * 4);
+
+ Expected<std::unique_ptr<ObjectFile>> GOFFObjOrErr =
+ object::ObjectFile::createGOFFObjectFile(
+ MemoryBufferRef(Data, "dummyGOFF"));
+
+ ASSERT_THAT_EXPECTED(GOFFObjOrErr, Succeeded());
+
+ GOFFObjectFile *GOFFObj = dyn_cast<GOFFObjectFile>((*GOFFObjOrErr).get());
+
+ for (SymbolRef Symbol : GOFFObj->symbols()) {
+ Expected<StringRef> SymbolNameOrErr = GOFFObj->getSymbolName(Symbol);
+ ASSERT_THAT_EXPECTED(SymbolNameOrErr, Succeeded());
+ StringRef SymbolName = SymbolNameOrErr.get();
+ EXPECT_EQ(SymbolName, "Helloworld");
+ }
+}
+
+TEST(GOFFObjectFileTest, ContinuationBitNotSet) {
+ char GOFFContData[GOFF::RecordLength * 4] = {0x00};
+
+ // HDR record.
+ GOFFContData[0] = 0x03;
+ GOFFContData[1] = 0xF0;
+
+ // ESD record.
+ GOFFContData[GOFF::RecordLength] = 0x03;
+ GOFFContData[GOFF::RecordLength + 1] = 0x01;
+ GOFFContData[GOFF::RecordLength + 3] = 0x02;
+ GOFFContData[GOFF::RecordLength + 7] = 0x01;
+ GOFFContData[GOFF::RecordLength + 11] = 0x01;
+ GOFFContData[GOFF::RecordLength + 71] = 0x0A; // Size of symbol name.
+ GOFFContData[GOFF::RecordLength + 72] = 0xC8; // Symbol name is HelloWorld.
+ GOFFContData[GOFF::RecordLength + 73] = 0x85;
+ GOFFContData[GOFF::RecordLength + 74] = 0x93;
+ GOFFContData[GOFF::RecordLength + 75] = 0x93;
+ GOFFContData[GOFF::RecordLength + 76] = 0x96;
+ GOFFContData[GOFF::RecordLength + 77] = 0xA6;
+ GOFFContData[GOFF::RecordLength + 78] = 0x96;
+ GOFFContData[GOFF::RecordLength + 79] = 0x99;
+
+ // ESD continuation record.
+ GOFFContData[GOFF::RecordLength * 2] = 0x03;
+ GOFFContData[GOFF::RecordLength * 2 + 1] = 0x00;
+ GOFFContData[GOFF::RecordLength * 2 + 3] = 0x93;
+ GOFFContData[GOFF::RecordLength * 2 + 4] = 0x84;
+
+ // END record.
+ GOFFContData[GOFF::RecordLength * 3] = 0x03;
+ GOFFContData[GOFF::RecordLength * 3 + 1] = 0x40;
+
+ StringRef Data(GOFFContData, GOFF::RecordLength * 4);
+
+ Expected<std::unique_ptr<ObjectFile>> GOFFObjOrErr =
+ object::ObjectFile::createGOFFObjectFile(
+ MemoryBufferRef(Data, "dummyGOFF"));
+ EXPECT_THAT_EXPECTED(
+ GOFFObjOrErr,
+ FailedWithMessage("record 2 is not a continuation record but the "
+ "preceding record is continued"));
+}
+
+TEST(GOFFObjectFileTest, ContinuationRecordNotTerminated) {
+ char GOFFContData[GOFF::RecordLength * 4] = {0x00};
+
+ // HDR record.
+ GOFFContData[0] = 0x03;
+ GOFFContData[1] = 0xF0;
+
+ // ESD record.
+ GOFFContData[GOFF::RecordLength] = 0x03;
+ GOFFContData[GOFF::RecordLength + 1] = 0x01;
+ GOFFContData[GOFF::RecordLength + 3] = 0x02;
+ GOFFContData[GOFF::RecordLength + 7] = 0x01;
+ GOFFContData[GOFF::RecordLength + 11] = 0x01;
+ GOFFContData[GOFF::RecordLength + 71] = 0x0A; // Size of symbol name.
+ GOFFContData[GOFF::RecordLength + 72] = 0xC8; // Symbol name is HelloWorld.
+ GOFFContData[GOFF::RecordLength + 73] = 0x85;
+ GOFFContData[GOFF::RecordLength + 74] = 0x93;
+ GOFFContData[GOFF::RecordLength + 75] = 0x93;
+ GOFFContData[GOFF::RecordLength + 76] = 0x96;
+ GOFFContData[GOFF::RecordLength + 77] = 0xA6;
+ GOFFContData[GOFF::RecordLength + 78] = 0x96;
+ GOFFContData[GOFF::RecordLength + 79] = 0x99;
+
+ // ESD continuation record.
+ GOFFContData[GOFF::RecordLength * 2] = 0x03;
+ GOFFContData[GOFF::RecordLength * 2 + 1] = 0x03; // Continued bit set.
+ GOFFContData[GOFF::RecordLength * 2 + 3] = 0x93;
+ GOFFContData[GOFF::RecordLength * 2 + 4] = 0x84;
+
+ // END record.
+ GOFFContData[GOFF::RecordLength * 3] = 0x03;
+ GOFFContData[GOFF::RecordLength * 3 + 1] = 0x40;
+
+ StringRef Data(GOFFContData, GOFF::RecordLength * 4);
+
+ Expected<std::unique_ptr<ObjectFile>> GOFFObjOrErr =
+ object::ObjectFile::createGOFFObjectFile(
+ MemoryBufferRef(Data, "dummyGOFF"));
+ ASSERT_THAT_EXPECTED(GOFFObjOrErr, Succeeded());
+
+ GOFFObjectFile *GOFFObj = dyn_cast<GOFFObjectFile>((*GOFFObjOrErr).get());
+
+ for (SymbolRef Symbol : GOFFObj->symbols()) {
+ Expected<StringRef> SymbolNameOrErr = GOFFObj->getSymbolName(Symbol);
+ EXPECT_THAT_EXPECTED(SymbolNameOrErr,
+ FailedWithMessage("continued bit should not be set"));
+ }
+}
+
+TEST(GOFFObjectFileTest, PrevNotContinued) {
+ char GOFFContData[GOFF::RecordLength * 4] = {0x00};
+
+ // HDR record.
+ GOFFContData[0] = 0x03;
+ GOFFContData[1] = 0xF0;
+
+ // ESD record, with continued bit not set.
+ GOFFContData[GOFF::RecordLength] = 0x03;
+
+ // ESD continuation record.
+ GOFFContData[GOFF::RecordLength * 2] = 0x03;
+ GOFFContData[GOFF::RecordLength * 2 + 1] = 0x02;
+
+ // END record.
+ GOFFContData[GOFF::RecordLength * 3] = 0x03;
+ GOFFContData[GOFF::RecordLength * 3 + 1] = 0x40;
+
+ StringRef Data(GOFFContData, GOFF::RecordLength * 4);
+
+ Expected<std::unique_ptr<ObjectFile>> GOFFObjOrErr =
+ object::ObjectFile::createGOFFObjectFile(
+ MemoryBufferRef(Data, "dummyGOFF"));
+
+ ASSERT_THAT_EXPECTED(
+ GOFFObjOrErr,
+ FailedWithMessage("record 2 is a continuation record that is not "
+ "preceded by a continued record"));
+}
+
+TEST(GOFFObjectFileTest, ContinuationTypeMismatch) {
+ char GOFFContData[GOFF::RecordLength * 4] = {0x00};
+
+ // HDR record.
+ GOFFContData[0] = 0x03;
+ GOFFContData[1] = 0xF0;
+
+ // ESD record.
+ GOFFContData[GOFF::RecordLength] = 0x03;
+ GOFFContData[GOFF::RecordLength + 1] = 0x01; // Continued to next record.
+
+ // END continuation record.
+ GOFFContData[GOFF::RecordLength * 2] = 0x03;
+ GOFFContData[GOFF::RecordLength * 2 + 1] = 0x42;
+
+ // END record.
+ GOFFContData[GOFF::RecordLength * 3] = 0x03;
+ GOFFContData[GOFF::RecordLength * 3 + 1] = 0x40;
+
+ StringRef Data(GOFFContData, GOFF::RecordLength * 4);
+
+ Expected<std::unique_ptr<ObjectFile>> GOFFObjOrErr =
+ object::ObjectFile::createGOFFObjectFile(
+ MemoryBufferRef(Data, "dummyGOFF"));
+
+ ASSERT_THAT_EXPECTED(
+ GOFFObjOrErr,
+ FailedWithMessage("record 2 is a continuation record that does not match "
+ "the type of the previous record"));
+}
+
+TEST(GOFFObjectFileTest, TwoSymbols) {
+ char GOFFData[GOFF::RecordLength * 4] = {0x00};
+
+ // HDR record.
+ GOFFData[0] = 0x03;
+ GOFFData[1] = 0xF0;
+
+ // ESD record 1.
+ GOFFData[GOFF::RecordLength] = 0x03;
+ GOFFData[GOFF::RecordLength + 3] = 0x00;
+ GOFFData[GOFF::RecordLength + 7] = 0x01; // ESDID.
+ GOFFData[GOFF::RecordLength + 71] = 0x01; // Size of symbol name.
+ GOFFData[GOFF::RecordLength + 72] = 0xa7; // Symbol name is x.
+
+ // ESD record 2.
+ GOFFData[GOFF::RecordLength * 2] = 0x03;
+ GOFFData[GOFF::RecordLength * 2 + 3] = 0x03;
+ GOFFData[GOFF::RecordLength * 2 + 7] = 0x02; // ESDID.
+ GOFFData[GOFF::RecordLength * 2 + 11] = 0x01; // Parent ESDID.
+ GOFFData[GOFF::RecordLength * 2 + 71] = 0x05; // Size of symbol name.
+ GOFFData[GOFF::RecordLength * 2 + 72] = 0xC8; // Symbol name is Hello.
+ GOFFData[GOFF::RecordLength * 2 + 73] = 0x85;
+ GOFFData[GOFF::RecordLength * 2 + 74] = 0x93;
+ GOFFData[GOFF::RecordLength * 2 + 75] = 0x93;
+ GOFFData[GOFF::RecordLength * 2 + 76] = 0x96;
+
+ // END record.
+ GOFFData[GOFF::RecordLength * 3] = 0x03;
+ GOFFData[GOFF::RecordLength * 3 + 1] = 0x40;
+
+ StringRef Data(GOFFData, GOFF::RecordLength * 4);
+
+ Expected<std::unique_ptr<ObjectFile>> GOFFObjOrErr =
+ object::ObjectFile::createGOFFObjectFile(
+ MemoryBufferRef(Data, "dummyGOFF"));
+
+ ASSERT_THAT_EXPECTED(GOFFObjOrErr, Succeeded());
+
+ GOFFObjectFile *GOFFObj = dyn_cast<GOFFObjectFile>((*GOFFObjOrErr).get());
+
+ for (SymbolRef Symbol : GOFFObj->symbols()) {
+ Expected<StringRef> SymbolNameOrErr = GOFFObj->getSymbolName(Symbol);
+ ASSERT_THAT_EXPECTED(SymbolNameOrErr, Succeeded());
+ StringRef SymbolName = SymbolNameOrErr.get();
+ EXPECT_EQ(SymbolName, "Hello");
+ }
+}
+
+TEST(GOFFObjectFileTest, InvalidSymbolType) {
+ char GOFFData[GOFF::RecordLength * 3] = {0x00};
+
+ // HDR record.
+ GOFFData[0] = 0x03;
+ GOFFData[1] = 0xF0;
+
+ // ESD record.
+ GOFFData[GOFF::RecordLength] = 0x03;
+ GOFFData[GOFF::RecordLength + 3] = 0x05;
+ GOFFData[GOFF::RecordLength + 7] = 0x01;
+ GOFFData[GOFF::RecordLength + 11] = 0x01;
+ GOFFData[GOFF::RecordLength + 71] = 0x01; // Size of symbol name.
+ GOFFData[GOFF::RecordLength + 72] = 0xC8; // Symbol name.
+
+ // END record.
+ GOFFData[GOFF::RecordLength * 2] = 0x03;
+ GOFFData[GOFF::RecordLength * 2 + 1] = 0x40;
+
+ StringRef Data(GOFFData, GOFF::RecordLength * 3);
+
+ Expected<std::unique_ptr<ObjectFile>> GOFFObjOrErr =
+ object::ObjectFile::createGOFFObjectFile(
+ MemoryBufferRef(Data, "dummyGOFF"));
+
+ ASSERT_THAT_EXPECTED(GOFFObjOrErr, Succeeded());
+
+ GOFFObjectFile *GOFFObj = dyn_cast<GOFFObjectFile>((*GOFFObjOrErr).get());
+
+ for (SymbolRef Symbol : GOFFObj->symbols()) {
+ Expected<SymbolRef::Type> SymbolType = Symbol.getType();
+ EXPECT_THAT_EXPECTED(
+ SymbolType,
+ FailedWithMessage("ESD record 1 has invalid symbol type 0x05"));
+
+ Expected<section_iterator> SymSI = Symbol.getSection();
+ ASSERT_THAT_EXPECTED(
+ SymSI,
+ FailedWithMessage(
+ "symbol with ESD id 1 refers to invalid section with ESD id 1"));
+ }
+}
+
+TEST(GOFFObjectFileTest, InvalidERSymbolType) {
+ char GOFFData[GOFF::RecordLength * 3] = {0x00};
+
+ // HDR record.
+ GOFFData[0] = 0x03;
+ GOFFData[1] = 0xF0;
+
+ // ESD record.
+ GOFFData[GOFF::RecordLength] = 0x03;
+ GOFFData[GOFF::RecordLength + 3] = 0x04;
+ GOFFData[GOFF::RecordLength + 7] = 0x01;
+ GOFFData[GOFF::RecordLength + 11] = 0x01;
+ GOFFData[GOFF::RecordLength + 63] = 0x03; // Unknown executable type.
+ GOFFData[GOFF::RecordLength + 71] = 0x01; // Size of symbol name.
+ GOFFData[GOFF::RecordLength + 72] = 0xC8; // Symbol name.
+
+ // END record.
+ GOFFData[GOFF::RecordLength * 2] = 0x03;
+ GOFFData[GOFF::RecordLength * 2 + 1] = 0x40;
+
+ StringRef Data(GOFFData, GOFF::RecordLength * 3);
+
+ Expected<std::unique_ptr<ObjectFile>> GOFFObjOrErr =
+ object::ObjectFile::createGOFFObjectFile(
+ MemoryBufferRef(Data, "dummyGOFF"));
+
+ ASSERT_THAT_EXPECTED(GOFFObjOrErr, Succeeded());
+
+ GOFFObjectFile *GOFFObj = dyn_cast<GOFFObjectFile>((*GOFFObjOrErr).get());
+
+ for (SymbolRef Symbol : GOFFObj->symbols()) {
+ Expected<SymbolRef::Type> SymbolType = Symbol.getType();
+ EXPECT_THAT_EXPECTED(
+ SymbolType,
+ FailedWithMessage("ESD record 1 has unknown Executable type 0x03"));
+ }
+}