[llvm] [SystemZ][z/OS] Implement yaml2obj for GOFF Object File Format (PR #71445)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Nov 6 13:38:19 PST 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-objectyaml
@llvm/pr-subscribers-llvm-binary-utilities
Author: Yusra Syeda (ysyeda)
<details>
<summary>Changes</summary>
This PR implements yaml2obj for the GOFF Object File Format.
---
Patch is 58.02 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/71445.diff
14 Files Affected:
- (modified) llvm/include/llvm/BinaryFormat/GOFF.h (+27)
- (added) llvm/include/llvm/ObjectYAML/GOFFYAML.h (+245)
- (modified) llvm/include/llvm/ObjectYAML/ObjectYAML.h (+2)
- (modified) llvm/include/llvm/ObjectYAML/yaml2obj.h (+5)
- (modified) llvm/lib/ObjectYAML/CMakeLists.txt (+2)
- (added) llvm/lib/ObjectYAML/GOFFEmitter.cpp (+451)
- (added) llvm/lib/ObjectYAML/GOFFYAML.cpp (+375)
- (modified) llvm/lib/ObjectYAML/ObjectYAML.cpp (+5)
- (modified) llvm/lib/ObjectYAML/yaml2obj.cpp (+2)
- (added) llvm/test/ObjectYAML/GOFF/GOFF-Basic.yaml (+59)
- (added) llvm/test/ObjectYAML/GOFF/GOFF-LongSymbol.yaml (+92)
- (added) llvm/test/ObjectYAML/GOFF/GOFF-OneSymb.yaml (+40)
- (added) llvm/test/ObjectYAML/GOFF/GOFF-Relocation.yaml (+145)
- (added) llvm/test/ObjectYAML/GOFF/GOFF-TXTSection.yaml (+49)
``````````diff
diff --git a/llvm/include/llvm/BinaryFormat/GOFF.h b/llvm/include/llvm/BinaryFormat/GOFF.h
index f1a30e41b736bda..061b1b83370c3b6 100644
--- a/llvm/include/llvm/BinaryFormat/GOFF.h
+++ b/llvm/include/llvm/BinaryFormat/GOFF.h
@@ -157,6 +157,33 @@ enum ESDAlignment : uint8_t {
ESD_ALIGN_4Kpage = 12,
};
+enum TXTRecordStyle : uint8_t {
+ TXT_RS_Byte = 0,
+ TXT_RS_Structured = 1,
+ TXT_RS_Unstructured = 2,
+};
+
+enum RLDReferenceType : uint8_t {
+ RLD_RT_RAddress = 0,
+ RLD_RT_ROffset = 1,
+ RLD_RT_RLength = 2,
+ RLD_RT_RRelativeImmediate = 6,
+ RLD_RT_RTypeConstant = 7, // XPLink ADA
+ RLD_RT_RLongDisplacement = 9,
+};
+
+enum RLDReferentType : uint8_t {
+ RLD_RO_Label = 0,
+ RLD_RO_Element = 1,
+ RLD_RO_Class = 2,
+ RLD_RO_Part = 3,
+};
+
+enum RLDAction : uint8_t {
+ RLD_ACT_Add = 0,
+ RLD_ACT_Subtract = 1,
+};
+
enum ENDEntryPointRequest : uint8_t {
END_EPR_None = 0,
END_EPR_EsdidOffset = 1,
diff --git a/llvm/include/llvm/ObjectYAML/GOFFYAML.h b/llvm/include/llvm/ObjectYAML/GOFFYAML.h
new file mode 100644
index 000000000000000..9b58afe61e97864
--- /dev/null
+++ b/llvm/include/llvm/ObjectYAML/GOFFYAML.h
@@ -0,0 +1,245 @@
+//===- GOFFYAML.h - GOFF YAMLIO 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 classes for handling the YAML representation of GOFF.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECTYAML_GOFFYAML_H
+#define LLVM_OBJECTYAML_GOFFYAML_H
+
+//#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/GOFF.h"
+#include "llvm/ObjectYAML/YAML.h"
+#include <cstdint>
+#include <vector>
+
+namespace llvm {
+
+namespace GOFF {
+
+enum ESDFlags {
+ ESD_FillByteValuePresent = 1 << 7,
+ ESD_SymbolDisplayFlag = 1 << 6,
+ ESD_SymbolRenamingFlag = 1 << 5,
+ ESD_RemovableClass = 1 << 4
+};
+
+enum {
+ ESD_Mask_ERST = 0x07,
+ ESD_Mask_RQW = 0x07,
+ ESD_Mask_TextStyle = 0xf0,
+ ESD_Mask_BindingAlgorithm = 0x0f,
+};
+
+enum ESDBAFlags {
+ ESD_BA_Movable = 0x01,
+ ESD_BA_ReadOnly = 0x2,
+ ESD_BA_NoPrime = 0x4,
+ ESD_BA_COMMON = 0x8,
+ ESD_BA_Indirect = 0x10,
+};
+
+enum RLDFlags {
+ RLD_Same_RID = 0x80,
+ RLD_Same_PID = 0x40,
+ RLD_Same_Offset = 0x20,
+ RLD_EA_Present = 0x04,
+ RLD_Offset_Length = 0x02,
+ RLD_Adressing_Mode_Sensitivity = 0x01,
+ RLD_FetchStore = 0x100,
+};
+
+} // end namespace GOFF
+
+// The structure of the yaml files is not an exact 1:1 match to GOFF. In order
+// to use yaml::IO, we use these structures which are closer to the source.
+namespace GOFFYAML {
+
+LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_ESDSYMBOLTYPE)
+LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_ESDNAMESPACEID)
+LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_ESDFlags)
+LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_ESDAMODE)
+LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_ESDRMODE)
+LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_ESDTEXTSTYLE)
+LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_ESDBINDINGALGORITHM)
+LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_ESDTASKINGBEHAVIOR)
+LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_ESDEXECUTABLE)
+LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_ESDLINKAGETYPE)
+LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_ESDBINDINGSTRENGTH)
+LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_ESDLOADINGBEHAVIOR)
+LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_ESDBINDINGSCOPE)
+LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_ESDALIGNMENT)
+LLVM_YAML_STRONG_TYPEDEF(uint64_t, GOFF_BAFLAGS)
+
+LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_TEXTRECORDSTYLE)
+
+LLVM_YAML_STRONG_TYPEDEF(uint16_t, GOFF_RLDFLAGS)
+LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_RLDREFERENCETYPE)
+LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_RLDREFERENTTYPE)
+LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_RLDACTION)
+
+struct RecordBase {
+ enum RecordBaseKind { RBK_Relocations, RBK_Symbol, RBK_Section };
+
+private:
+ const RecordBaseKind Kind;
+
+protected:
+ RecordBase(RecordBaseKind Kind) : Kind(Kind) {}
+
+public:
+ RecordBaseKind getKind() const { return Kind; }
+};
+typedef std::unique_ptr<RecordBase> RecordPtr;
+
+struct Relocation {
+ GOFF_RLDFLAGS Flags;
+ GOFF_RLDREFERENCETYPE ReferenceType;
+ GOFF_RLDREFERENTTYPE ReferentType;
+ GOFF_RLDACTION Action;
+ uint32_t RPointer;
+ uint32_t PPointer;
+ uint64_t Offset;
+ uint32_t ExtAttrID;
+ uint32_t ExtAttrOffset;
+ uint8_t TargetFieldByteLength;
+ uint8_t BitLength;
+ uint8_t BitOffset;
+};
+
+struct Relocations : public RecordBase {
+ Relocations() : RecordBase(RBK_Relocations) {}
+
+ std::vector<Relocation> Relocs;
+
+ static bool classof(const RecordBase *Rec) {
+ return Rec->getKind() == RBK_Relocations;
+ }
+};
+
+struct Section : public RecordBase {
+ Section() : RecordBase(RBK_Section) {}
+
+ StringRef SymbolName;
+ uint32_t SymbolID;
+ uint32_t Offset;
+ uint32_t TrueLength;
+ uint16_t TextEncoding;
+ uint16_t DataLength;
+ GOFF_TEXTRECORDSTYLE TextStyle;
+
+ std::optional<yaml::BinaryRef> Data;
+
+ static bool classof(const RecordBase *Rec) {
+ return Rec->getKind() == RBK_Section;
+ }
+};
+
+struct Symbol : public RecordBase {
+ Symbol() : RecordBase(RBK_Symbol) {}
+
+ StringRef Name;
+ GOFF_ESDSYMBOLTYPE Type;
+ uint32_t ID;
+ uint32_t OwnerID;
+ uint32_t Address;
+ uint32_t Length;
+ uint32_t ExtAttrID;
+ uint32_t ExtAttrOffset;
+ GOFF_ESDNAMESPACEID NameSpace;
+ GOFF_ESDFlags Flags;
+ uint8_t FillByteValue;
+ uint32_t PSectID;
+ uint32_t Priority;
+ std::optional<llvm::yaml::Hex64> Signature;
+ GOFF_ESDAMODE Amode;
+ GOFF_ESDRMODE Rmode;
+ GOFF_ESDTEXTSTYLE TextStyle;
+ GOFF_ESDBINDINGALGORITHM BindingAlgorithm;
+ GOFF_ESDTASKINGBEHAVIOR TaskingBehavior;
+ GOFF_ESDEXECUTABLE Executable;
+ GOFF_ESDLINKAGETYPE LinkageType;
+ GOFF_ESDBINDINGSTRENGTH BindingStrength;
+ GOFF_ESDLOADINGBEHAVIOR LoadingBehavior;
+ GOFF_ESDBINDINGSCOPE BindingScope;
+ GOFF_ESDALIGNMENT Alignment;
+ GOFF_BAFLAGS BAFlags;
+
+ static bool classof(const RecordBase *Rec) {
+ return Rec->getKind() == RBK_Symbol;
+ }
+};
+
+struct FileHeader {
+ uint32_t TargetEnvironment;
+ uint32_t TargetOperatingSystem;
+ uint16_t CCSID;
+ StringRef CharacterSetName;
+ StringRef LanguageProductIdentifier;
+ uint32_t ArchitectureLevel;
+ std::optional<uint16_t> InternalCCSID;
+ std::optional<uint8_t> TargetSoftwareEnvironment;
+};
+
+struct Object {
+ FileHeader Header;
+ std::vector<RecordPtr> Records;
+
+ Object();
+};
+
+} // end namespace GOFFYAML
+
+} // end namespace llvm
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(GOFFYAML::Relocation)
+LLVM_YAML_IS_SEQUENCE_VECTOR(GOFFYAML::RecordPtr)
+
+LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_ESDSYMBOLTYPE)
+LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_ESDNAMESPACEID)
+LLVM_YAML_DECLARE_BITSET_TRAITS(GOFFYAML::GOFF_ESDFlags)
+LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_ESDAMODE)
+LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_ESDRMODE)
+LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_ESDTEXTSTYLE)
+LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_ESDBINDINGALGORITHM)
+LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_ESDTASKINGBEHAVIOR)
+LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_ESDEXECUTABLE)
+LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_ESDLINKAGETYPE)
+LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_ESDBINDINGSTRENGTH)
+LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_ESDLOADINGBEHAVIOR)
+LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_ESDBINDINGSCOPE)
+LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_ESDALIGNMENT)
+LLVM_YAML_DECLARE_BITSET_TRAITS(GOFFYAML::GOFF_BAFLAGS)
+
+LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_TEXTRECORDSTYLE)
+
+LLVM_YAML_DECLARE_BITSET_TRAITS(GOFFYAML::GOFF_RLDFLAGS)
+LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_RLDREFERENCETYPE)
+LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_RLDREFERENTTYPE)
+LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_RLDACTION)
+
+LLVM_YAML_DECLARE_MAPPING_TRAITS(GOFFYAML::Relocation)
+LLVM_YAML_DECLARE_MAPPING_TRAITS(GOFFYAML::Section)
+LLVM_YAML_DECLARE_MAPPING_TRAITS(GOFFYAML::Symbol)
+LLVM_YAML_DECLARE_MAPPING_TRAITS(GOFFYAML::FileHeader)
+LLVM_YAML_DECLARE_MAPPING_TRAITS(GOFFYAML::Object)
+
+namespace llvm {
+namespace yaml {
+
+template <> struct CustomMappingTraits<GOFFYAML::RecordPtr> {
+ static void inputOne(IO &IO, StringRef Key, GOFFYAML::RecordPtr &Elem);
+ static void output(IO &IO, GOFFYAML::RecordPtr &Elem);
+};
+
+} // end namespace yaml
+} // end namespace llvm
+
+#endif // LLVM_OBJECTYAML_GOFFYAML_H
diff --git a/llvm/include/llvm/ObjectYAML/ObjectYAML.h b/llvm/include/llvm/ObjectYAML/ObjectYAML.h
index b63607e6796b0b7..7fd15cf290f4a4b 100644
--- a/llvm/include/llvm/ObjectYAML/ObjectYAML.h
+++ b/llvm/include/llvm/ObjectYAML/ObjectYAML.h
@@ -13,6 +13,7 @@
#include "llvm/ObjectYAML/COFFYAML.h"
#include "llvm/ObjectYAML/DXContainerYAML.h"
#include "llvm/ObjectYAML/ELFYAML.h"
+#include "llvm/ObjectYAML/GOFFYAML.h"
#include "llvm/ObjectYAML/MachOYAML.h"
#include "llvm/ObjectYAML/MinidumpYAML.h"
#include "llvm/ObjectYAML/OffloadYAML.h"
@@ -30,6 +31,7 @@ struct YamlObjectFile {
std::unique_ptr<ArchYAML::Archive> Arch;
std::unique_ptr<ELFYAML::Object> Elf;
std::unique_ptr<COFFYAML::Object> Coff;
+ std::unique_ptr<GOFFYAML::Object> Goff;
std::unique_ptr<MachOYAML::Object> MachO;
std::unique_ptr<MachOYAML::UniversalBinary> FatMachO;
std::unique_ptr<MinidumpYAML::Object> Minidump;
diff --git a/llvm/include/llvm/ObjectYAML/yaml2obj.h b/llvm/include/llvm/ObjectYAML/yaml2obj.h
index 000da077bb18c6a..3b458c3cd890b12 100644
--- a/llvm/include/llvm/ObjectYAML/yaml2obj.h
+++ b/llvm/include/llvm/ObjectYAML/yaml2obj.h
@@ -32,6 +32,10 @@ namespace ELFYAML {
struct Object;
}
+namespace GOFFYAML {
+struct Object;
+}
+
namespace MinidumpYAML {
struct Object;
}
@@ -64,6 +68,7 @@ using ErrorHandler = llvm::function_ref<void(const Twine &Msg)>;
bool yaml2archive(ArchYAML::Archive &Doc, raw_ostream &Out, ErrorHandler EH);
bool yaml2coff(COFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH);
+bool yaml2goff(GOFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH);
bool yaml2elf(ELFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH,
uint64_t MaxSize);
bool yaml2macho(YamlObjectFile &Doc, raw_ostream &Out, ErrorHandler EH);
diff --git a/llvm/lib/ObjectYAML/CMakeLists.txt b/llvm/lib/ObjectYAML/CMakeLists.txt
index c081009653d4f8c..b36974d47d9f897 100644
--- a/llvm/lib/ObjectYAML/CMakeLists.txt
+++ b/llvm/lib/ObjectYAML/CMakeLists.txt
@@ -13,6 +13,8 @@ add_llvm_component_library(LLVMObjectYAML
DXContainerYAML.cpp
ELFEmitter.cpp
ELFYAML.cpp
+ GOFFEmitter.cpp
+ GOFFYAML.cpp
MachOEmitter.cpp
MachOYAML.cpp
ObjectYAML.cpp
diff --git a/llvm/lib/ObjectYAML/GOFFEmitter.cpp b/llvm/lib/ObjectYAML/GOFFEmitter.cpp
new file mode 100644
index 000000000000000..e3c4f7bce21cf5e
--- /dev/null
+++ b/llvm/lib/ObjectYAML/GOFFEmitter.cpp
@@ -0,0 +1,451 @@
+//===- yaml2goff - Convert YAML to a GOFF object file ---------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// The GOFF component of yaml2obj.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/IndexedMap.h"
+#include "llvm/ObjectYAML/ObjectYAML.h"
+#include "llvm/ObjectYAML/yaml2obj.h"
+#include "llvm/Support/ConvertEBCDIC.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+namespace {
+
+static const uint8_t TXTMaxDataLength = 56;
+
+// Common flag values on records.
+enum {
+ // Flag: This record is continued.
+ Rec_Continued = 1 << (8 - 7 - 1),
+
+ // Flag: This record is a continuation.
+ Rec_Continuation = 1 << (8 - 6 - 1),
+};
+
+template <typename value_type> struct BinaryBeImpl {
+ value_type Value;
+ BinaryBeImpl(value_type V) : Value(V) {}
+};
+
+template <typename value_type>
+raw_ostream &operator<<(raw_ostream &OS, const BinaryBeImpl<value_type> &BBE) {
+ char Buffer[sizeof(BBE.Value)];
+ support::endian::write<value_type, llvm::endianness::big, support::unaligned>(
+ Buffer, BBE.Value);
+ OS.write(Buffer, sizeof(BBE.Value));
+ return OS;
+}
+
+template <typename value_type> BinaryBeImpl<value_type> binaryBe(value_type V) {
+ return BinaryBeImpl<value_type>(V);
+}
+
+struct ZerosImpl {
+ size_t NumBytes;
+};
+
+raw_ostream &operator<<(raw_ostream &OS, const ZerosImpl &Z) {
+ OS.write_zeros(Z.NumBytes);
+ return OS;
+}
+
+ZerosImpl zeros(const size_t NumBytes) { return ZerosImpl{NumBytes}; }
+
+raw_ostream &operator<<(raw_ostream &OS, const yaml::BinaryRef &Data) {
+ Data.writeAsBinary(OS);
+ return OS;
+}
+
+// The GOFFOstream is responsible to write the data into the fixed physical
+// records of the format. A user of this class announces the the begin of a new
+// logical record and the size of its payload. While writing the payload, the
+// physical records are created for the data. Possible fill bytes at the end of
+// a physical record are written automatically.
+class GOFFOstream : public raw_ostream {
+ /// The underlying raw_ostream.
+ raw_ostream &OS;
+
+ /// The number of logical records emitted to far.
+ uint32_t LogicalRecords;
+
+ /// The remaining size of this logical record, including fill
+ /// bytes.
+ size_t RemainingSize;
+
+ /// The type of the current (logical) record.
+ GOFF::RecordType CurrentType;
+
+ /// Signals begin of new record.
+ bool NewLogicalRecord;
+
+ // Return the number of bytes left to write until next physical record.
+ // Please note that we maintain the total numbers of byte left, not the
+ // written size.
+ size_t bytesToNextPhysicalRecord() {
+ size_t Bytes = RemainingSize % GOFF::PayloadLength;
+ return Bytes ? Bytes : GOFF::PayloadLength;
+ }
+
+ /// Write the record prefix of a physical record, using the current record
+ /// type.
+ static void writeRecordPrefix(raw_ostream &OS, GOFF::RecordType Type,
+ size_t RemainingSize,
+ uint8_t Flags = Rec_Continuation);
+
+ /// Fill the last physical record of a logical record with zero bytes.
+ void fillRecord();
+
+ /// See raw_ostream::write_impl.
+ void write_impl(const char *Ptr, size_t Size) override;
+
+ /// Return the current position within the stream, not counting the bytes
+ /// currently in the buffer.
+ uint64_t current_pos() const override { return OS.tell(); }
+
+public:
+ explicit GOFFOstream(raw_ostream &OS)
+ : OS(OS), LogicalRecords(0), RemainingSize(0), NewLogicalRecord(false) {
+ SetBufferSize(GOFF::PayloadLength);
+ }
+
+ ~GOFFOstream() { finalize(); }
+
+ void newRecord(GOFF::RecordType Type, size_t Size);
+
+ void finalize() { fillRecord(); }
+
+ uint32_t logicalRecords() { return LogicalRecords; }
+};
+
+void GOFFOstream::writeRecordPrefix(raw_ostream &OS, GOFF::RecordType Type,
+ size_t RemainingSize, uint8_t Flags) {
+ uint8_t TypeAndFlags = Flags | (Type << 4);
+ if (RemainingSize > GOFF::RecordLength)
+ TypeAndFlags |= Rec_Continued;
+ OS << binaryBe(static_cast<unsigned char>(GOFF::PTVPrefix))
+ << binaryBe(static_cast<unsigned char>(TypeAndFlags))
+ << binaryBe(static_cast<unsigned char>(0));
+}
+
+void GOFFOstream::newRecord(GOFF::RecordType Type, size_t Size) {
+ fillRecord();
+ CurrentType = Type;
+ RemainingSize = Size;
+ if (size_t Gap = (RemainingSize % GOFF::PayloadLength))
+ RemainingSize += GOFF::PayloadLength - Gap;
+ NewLogicalRecord = true;
+ ++LogicalRecords;
+}
+
+void GOFFOstream::fillRecord() {
+ assert((GetNumBytesInBuffer() <= RemainingSize) &&
+ "More bytes in buffer than expected");
+ size_t Remains = RemainingSize - GetNumBytesInBuffer();
+ if (Remains) {
+ assert((Remains < GOFF::RecordLength) &&
+ "Attempt to fill more than one physical record");
+ raw_ostream::write_zeros(Remains);
+ }
+ flush();
+ assert(RemainingSize == 0 && "Not fully flushed");
+ assert(GetNumBytesInBuffer() == 0 && "Buffer not fully empty");
+}
+
+void GOFFOstream::write_impl(const char *Ptr, size_t Size) {
+ assert((RemainingSize >= Size) && "Attempt to write too much data");
+ assert(RemainingSize && "Logical record overflow");
+ if (!(RemainingSize % GOFF::PayloadLength)) {
+ writeRecordPrefix(OS, CurrentType, RemainingSize,
+ NewLogicalRecord ? 0 : Rec_Continuation);
+ NewLogicalRecord = false;
+ }
+ assert(!NewLogicalRecord &&
+ "New logical record not on physical record boundary");
+
+ size_t Idx = 0;
+ while (Size > 0) {
+ size_t BytesToWrite = bytesToNextPhysicalRecord();
+ if (BytesToWrite > Size)
+ BytesToWrite = Size;
+ OS.write(Ptr + Idx, BytesToWrite);
+ Idx += BytesToWrite;
+ Size -= BytesToWrite;
+ RemainingSize -= BytesToWrite;
+ if (Size) {
+ writeRecordPrefix(OS, CurrentType, RemainingSize);
+ }
+ }
+}
+
+class GOFFState {
+ void writeHeader(GOFFYAML::FileHeader &FileHdr);
+ void writeEnd();
+ void writeSymbol(GOFFYAML::Symbol Sym);
+ void writeSection(GOFFYAML::Section Sec);
+ void writeRelocationDirectory(GOFFYAML::Relocations Rel);
+
+ void reportError(const Twine &Msg) {
+ ErrHandler(Msg);
+ HasError = true;
+ }
+
+ GOFFState(raw_ostream &OS, GOFFYAML::Object &Doc,
+ yaml::ErrorHandler ErrHandler)
+ : GW(OS), Doc(Doc), ErrHandler(ErrHandler), SymbolID(0), HasError(false) {
+ }
+
+ ~GOFFState() { GW.finalize(); }
+
+ bool writeObject();
+
+public:
+ static bool writeGOFF(raw_ostream &OS, GOFFYAML::Object &Doc,
+ yaml::ErrorHandler ErrHandler);
+
+private:
+ GOFFOstream GW;
+ GOFFYAML::Object &Doc;
+ yaml::ErrorHandler ErrHandler;
+ uint16_t SymbolID;
+ bool HasError;
+};
+
+void GOFFState::writeHeader(GOFFYAML::FileHeader &FileHdr) {
+ SmallString<16> CCSIDName;
+ if (std::error_code EC =
+ ConverterEBCDIC::convertToEBCDIC(FileHdr.CharacterSetName, CCSIDName))
+ reportError("Conversion error on " + FileHdr.CharacterSetName);
+ if (CCSIDName.size() > 16) {
+ reportError("CharacterSetName too long");
+ CCSIDName.resize(16);
+ }
+ SmallString<16> LangProd;
+ if (std::error_code EC = ConverterEBCDIC::convertToEBCDIC(
+ FileHdr.LanguageProductIdentifier, LangProd))
+ reportError("Conversion error on " + FileHdr.LanguageProductIdentifier);
+ if (LangProd.size() > 16) {
+ reportError("LanguageProductIdentifier too long");
+ LangProd.resize(16);
+ }
+
+ GW.newRecord(GOFF::RT_HDR, GOFF::PayloadLength);
+ GW << binaryBe(FileHdr.TargetEnvironment) // TargetEnvironment
+ << binaryBe(FileHdr.TargetOperatingSystem) // TargetOperatingSystem
+ << zeros(2) // Reserved
+ << binaryBe(FileHdr.CCSID) // CCSID
+ << CCSIDName // CharacterSetName
+ << zeros(16 - CCSIDName.size()) // Fill bytes
+ << LangProd // LanguageProductIdentifier
+ << zeros(16 - LangProd.size()) // Fill bytes
+ << binaryBe(FileHdr.ArchitectureLevel); // ArchitectureLevel
+ // The module propties are optional. Figure out if we need to write them
+ uint16_t ModPropLen = 0;
+ if (FileHdr.TargetSoftwareEnvironment)
+ ModPropLen = 3;
+ else if (FileHdr.InternalCCSID)
+ ModPropLen = 2;
+ if (ModPropLen) {
+ GW << binaryBe(ModPropLen) << zeros(6);
+ if (ModPropLen >= 2)
+ GW << binaryBe(FileHdr.InternalCCSID ? *FileHdr.InternalCCSID : 0);
+ if (ModPropLen >= 3)
+ GW << binaryBe(FileHdr.TargetSoftwareEnvironment
+ ? *FileHdr.TargetSoftwareEnvironment
+ : 0);
+ }
+}
+
+void GOFFState::writeSymbol(GOFFYAML::Symbol Sym) {
+ if (Sym.ID != SymbolID + 1)
+ reportError("Symbol IDs not monoton " + Sym.Name);
+ else
+ ++SymbolID;
+ if (Sym.OwnerID >= SymbolID)
+ reportError("Owner ID not defined " + Sym.Name);
+ SmallString<80> SymName;
+ if (std::error_code EC = ConverterEBCDIC::convertToEBCDIC(Sym.Name, Sy...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/71445
More information about the llvm-commits
mailing list