1//===------ goff2yaml.cpp - obj2yaml conversion tool ----------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "obj2yaml.h"
10#include "llvm/Object/GOFF.h"
11#include "llvm/Object/GOFFObjectFile.h"
12#include "llvm/ObjectYAML/ObjectYAML.h"
13#include "llvm/Support/ConvertEBCDIC.h"
14
15using namespace llvm;
16
17static std::string getFixedLengthEBCDICString(DataExtractor &Data,
18 DataExtractor::Cursor &C,
19 uint64_t Length,
20 StringRef TrimChars = {"\0", 1}) {
21 StringRef FixedLenStr = Data.getBytes(C, Length);
22 SmallString<16> Str;
23 ConverterEBCDIC::convertToUTF8(Source: FixedLenStr, Result&: Str);
24 return Str.str().trim(Chars: TrimChars).str();
25}
26
27class GOFFDumper {
28 const object::GOFFObjectFile &Obj;
29 GOFFYAML::Object YAMLObj;
30
31 Error dumpHeader(ArrayRef<uint8_t> Data);
32 Error dumpExternalSymbol(ArrayRef<uint8_t> Data);
33 Error dumpText(ArrayRef<uint8_t> Data);
34 Error dumpRelocationDirectory(ArrayRef<uint8_t> Data);
35 Error dumpDeferredLength(ArrayRef<uint8_t> Data);
36 Error dumpEnd(ArrayRef<uint8_t> Data);
37
38public:
39 GOFFDumper(const object::GOFFObjectFile &Obj);
40 Error dump();
41 GOFFYAML::Object &getYAMLObj();
42};
43
44GOFFDumper::GOFFDumper(const object::GOFFObjectFile &Obj) : Obj(Obj) {}
45
46Error GOFFDumper::dumpHeader(ArrayRef<uint8_t> Data) {
47 DataExtractor DE(Data, false);
48 DataExtractor::Cursor C(0);
49
50 // Flattened data contains: PTV header (bytes 0-2) + bytes 3-60 (prefix) +
51 // data from byte 60 onwards HDR data starts at byte 4 in the original record
52 C.seek(NewOffSet: 4); // Skip PTV header and record type
53 YAMLObj.Header.TargetEnvironment = DE.getU32(C);
54 YAMLObj.Header.TargetOperatingSystem = DE.getU32(C);
55 DE.skip(C, Length: 2);
56 YAMLObj.Header.CCSID = DE.getU16(C);
57 YAMLObj.Header.CharacterSetName = getFixedLengthEBCDICString(Data&: DE, C, Length: 16);
58 YAMLObj.Header.LanguageProductIdentifier =
59 getFixedLengthEBCDICString(Data&: DE, C, Length: 16);
60 YAMLObj.Header.ArchitectureLevel = DE.getU32(C);
61 uint16_t PropertiesLength = DE.getU16(C);
62 DE.skip(C, Length: 6);
63 if (PropertiesLength) {
64 YAMLObj.Header.InternalCCSID = DE.getU16(C);
65 PropertiesLength -= 2;
66 }
67 if (PropertiesLength) {
68 YAMLObj.Header.TargetSoftwareEnvironment = DE.getU8(C);
69 PropertiesLength -= 1;
70 }
71 if (!C)
72 return C.takeError();
73 return Error::success();
74}
75
76Error GOFFDumper::dumpExternalSymbol(ArrayRef<uint8_t> Data) {
77 // TODO: Implement dumping ESD records
78 return Error::success();
79}
80
81Error GOFFDumper::dumpText(ArrayRef<uint8_t> Data) {
82 // TODO: Implement dumping TXT records
83 return Error::success();
84}
85
86Error GOFFDumper::dumpRelocationDirectory(ArrayRef<uint8_t> Data) {
87 // TODO: Implement dumping RLD records
88 return Error::success();
89}
90
91Error GOFFDumper::dumpDeferredLength(ArrayRef<uint8_t> Records) {
92 // TODO: Implement if/when GOFF LEN records are emitted by current producers
93 // or covered by handcrafted-object tests.
94 return Error::success();
95}
96
97Error GOFFDumper::dumpEnd(ArrayRef<uint8_t> Records) {
98 // TODO: implement dumping END records
99 return Error::success();
100}
101
102Error GOFFDumper::dump() {
103 Error Err = Error::success();
104
105 // Use the pre-flattened data structure instead of iterating through records
106 const auto &FlattenedData = Obj.getFlattenedData();
107
108 for (const auto &[RecordType, Data] : FlattenedData) {
109 switch (RecordType) {
110 case GOFF::RT_HDR:
111 if (auto Err = dumpHeader(Data))
112 return Err;
113 break;
114 case GOFF::RT_ESD:
115 if (auto Err = dumpExternalSymbol(Data))
116 return Err;
117 break;
118 case GOFF::RT_TXT:
119 if (auto Err = dumpText(Data))
120 return Err;
121 break;
122 case GOFF::RT_RLD:
123 if (auto Err = dumpRelocationDirectory(Data))
124 return Err;
125 break;
126 case GOFF::RT_LEN:
127 if (auto Err = dumpDeferredLength(Records: Data))
128 return Err;
129 break;
130 case GOFF::RT_END:
131 if (auto Err = dumpEnd(Records: Data))
132 return Err;
133 break;
134 }
135 }
136 return Err;
137}
138
139GOFFYAML::Object &GOFFDumper::getYAMLObj() { return YAMLObj; }
140
141Error goff2yaml(raw_ostream &Out, const llvm::object::GOFFObjectFile &Obj) {
142 GOFFDumper Dumper(Obj);
143
144 if (auto Err = Dumper.dump())
145 return Err;
146
147 yaml::Output Yout(Out);
148 Yout << Dumper.getYAMLObj();
149
150 return Error::success();
151}
152