Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / llvm / lib / Object / GOFFObjectFile.cpp
blob76a13559ebfe352cd0ad7160e3e23fe913eaedcb
1 //===- GOFFObjectFile.cpp - GOFF object file implementation -----*- C++ -*-===//
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 // Implementation of the GOFFObjectFile class.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/Object/GOFFObjectFile.h"
14 #include "llvm/BinaryFormat/GOFF.h"
15 #include "llvm/Object/GOFF.h"
16 #include "llvm/Support/Debug.h"
17 #include "llvm/Support/Errc.h"
18 #include "llvm/Support/raw_ostream.h"
20 #ifndef DEBUG_TYPE
21 #define DEBUG_TYPE "goff"
22 #endif
24 using namespace llvm::object;
25 using namespace llvm;
27 Expected<std::unique_ptr<ObjectFile>>
28 ObjectFile::createGOFFObjectFile(MemoryBufferRef Object) {
29 Error Err = Error::success();
30 std::unique_ptr<GOFFObjectFile> Ret(new GOFFObjectFile(Object, Err));
31 if (Err)
32 return std::move(Err);
33 return std::move(Ret);
36 GOFFObjectFile::GOFFObjectFile(MemoryBufferRef Object, Error &Err)
37 : ObjectFile(Binary::ID_GOFF, Object) {
38 ErrorAsOutParameter ErrAsOutParam(&Err);
39 // Object file isn't the right size, bail out early.
40 if ((Object.getBufferSize() % GOFF::RecordLength) != 0) {
41 Err = createStringError(
42 object_error::unexpected_eof,
43 "object file is not the right size. Must be a multiple "
44 "of 80 bytes, but is " +
45 std::to_string(Object.getBufferSize()) + " bytes");
46 return;
48 // Object file doesn't start/end with HDR/END records.
49 // Bail out early.
50 if (Object.getBufferSize() != 0) {
51 if ((base()[1] & 0xF0) >> 4 != GOFF::RT_HDR) {
52 Err = createStringError(object_error::parse_failed,
53 "object file must start with HDR record");
54 return;
56 if ((base()[Object.getBufferSize() - GOFF::RecordLength + 1] & 0xF0) >> 4 !=
57 GOFF::RT_END) {
58 Err = createStringError(object_error::parse_failed,
59 "object file must end with END record");
60 return;
64 SectionEntryImpl DummySection;
65 SectionList.emplace_back(DummySection); // Dummy entry at index 0.
67 uint8_t PrevRecordType = 0;
68 uint8_t PrevContinuationBits = 0;
69 const uint8_t *End = reinterpret_cast<const uint8_t *>(Data.getBufferEnd());
70 for (const uint8_t *I = base(); I < End; I += GOFF::RecordLength) {
71 uint8_t RecordType = (I[1] & 0xF0) >> 4;
72 bool IsContinuation = I[1] & 0x02;
73 bool PrevWasContinued = PrevContinuationBits & 0x01;
74 size_t RecordNum = (I - base()) / GOFF::RecordLength;
76 // If the previous record was continued, the current record should be a
77 // continuation.
78 if (PrevWasContinued && !IsContinuation) {
79 if (PrevRecordType == RecordType) {
80 Err = createStringError(object_error::parse_failed,
81 "record " + std::to_string(RecordNum) +
82 " is not a continuation record but the "
83 "preceding record is continued");
84 return;
87 // Don't parse continuations records, only parse initial record.
88 if (IsContinuation) {
89 if (RecordType != PrevRecordType) {
90 Err = createStringError(object_error::parse_failed,
91 "record " + std::to_string(RecordNum) +
92 " is a continuation record that does not "
93 "match the type of the previous record");
94 return;
96 if (!PrevWasContinued) {
97 Err = createStringError(object_error::parse_failed,
98 "record " + std::to_string(RecordNum) +
99 " is a continuation record that is not "
100 "preceded by a continued record");
101 return;
103 PrevRecordType = RecordType;
104 PrevContinuationBits = I[1] & 0x03;
105 continue;
108 #ifndef NDEBUG
109 for (size_t J = 0; J < GOFF::RecordLength; ++J) {
110 const uint8_t *P = I + J;
111 if (J % 8 == 0)
112 dbgs() << " ";
114 dbgs() << format("%02hhX", *P);
116 #endif
117 switch (RecordType) {
118 case GOFF::RT_ESD: {
119 // Save ESD record.
120 uint32_t EsdId;
121 ESDRecord::getEsdId(I, EsdId);
122 EsdPtrs.grow(EsdId);
123 EsdPtrs[EsdId] = I;
125 // Determine and save the "sections" in GOFF.
126 // A section is saved as a tuple of the form
127 // case (1): (ED,child PR)
128 // - where the PR must have non-zero length.
129 // case (2a) (ED,0)
130 // - where the ED is of non-zero length.
131 // case (2b) (ED,0)
132 // - where the ED is zero length but
133 // contains a label (LD).
134 GOFF::ESDSymbolType SymbolType;
135 ESDRecord::getSymbolType(I, SymbolType);
136 SectionEntryImpl Section;
137 uint32_t Length;
138 ESDRecord::getLength(I, Length);
139 if (SymbolType == GOFF::ESD_ST_ElementDefinition) {
140 // case (2a)
141 if (Length != 0) {
142 Section.d.a = EsdId;
143 SectionList.emplace_back(Section);
145 } else if (SymbolType == GOFF::ESD_ST_PartReference) {
146 // case (1)
147 if (Length != 0) {
148 uint32_t SymEdId;
149 ESDRecord::getParentEsdId(I, SymEdId);
150 Section.d.a = SymEdId;
151 Section.d.b = EsdId;
152 SectionList.emplace_back(Section);
154 } else if (SymbolType == GOFF::ESD_ST_LabelDefinition) {
155 // case (2b)
156 uint32_t SymEdId;
157 ESDRecord::getParentEsdId(I, SymEdId);
158 const uint8_t *SymEdRecord = EsdPtrs[SymEdId];
159 uint32_t EdLength;
160 ESDRecord::getLength(SymEdRecord, EdLength);
161 if (!EdLength) { // [ EDID, PRID ]
162 // LD child of a zero length parent ED.
163 // Add the section ED which was previously ignored.
164 Section.d.a = SymEdId;
165 SectionList.emplace_back(Section);
168 LLVM_DEBUG(dbgs() << " -- ESD " << EsdId << "\n");
169 break;
171 case GOFF::RT_END:
172 LLVM_DEBUG(dbgs() << " -- END (GOFF record type) unhandled\n");
173 break;
174 case GOFF::RT_HDR:
175 LLVM_DEBUG(dbgs() << " -- HDR (GOFF record type) unhandled\n");
176 break;
177 default:
178 llvm_unreachable("Unknown record type");
180 PrevRecordType = RecordType;
181 PrevContinuationBits = I[1] & 0x03;
185 const uint8_t *GOFFObjectFile::getSymbolEsdRecord(DataRefImpl Symb) const {
186 const uint8_t *EsdRecord = EsdPtrs[Symb.d.a];
187 return EsdRecord;
190 Expected<StringRef> GOFFObjectFile::getSymbolName(DataRefImpl Symb) const {
191 if (EsdNamesCache.count(Symb.d.a)) {
192 auto &StrPtr = EsdNamesCache[Symb.d.a];
193 return StringRef(StrPtr.second.get(), StrPtr.first);
196 SmallString<256> SymbolName;
197 if (auto Err = ESDRecord::getData(getSymbolEsdRecord(Symb), SymbolName))
198 return std::move(Err);
200 SmallString<256> SymbolNameConverted;
201 ConverterEBCDIC::convertToUTF8(SymbolName, SymbolNameConverted);
203 size_t Size = SymbolNameConverted.size();
204 auto StrPtr = std::make_pair(Size, std::make_unique<char[]>(Size));
205 char *Buf = StrPtr.second.get();
206 memcpy(Buf, SymbolNameConverted.data(), Size);
207 EsdNamesCache[Symb.d.a] = std::move(StrPtr);
208 return StringRef(Buf, Size);
211 Expected<StringRef> GOFFObjectFile::getSymbolName(SymbolRef Symbol) const {
212 return getSymbolName(Symbol.getRawDataRefImpl());
215 Expected<uint64_t> GOFFObjectFile::getSymbolAddress(DataRefImpl Symb) const {
216 uint32_t Offset;
217 const uint8_t *EsdRecord = getSymbolEsdRecord(Symb);
218 ESDRecord::getOffset(EsdRecord, Offset);
219 return static_cast<uint64_t>(Offset);
222 uint64_t GOFFObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
223 uint32_t Offset;
224 const uint8_t *EsdRecord = getSymbolEsdRecord(Symb);
225 ESDRecord::getOffset(EsdRecord, Offset);
226 return static_cast<uint64_t>(Offset);
229 uint64_t GOFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
230 return 0;
233 bool GOFFObjectFile::isSymbolUnresolved(DataRefImpl Symb) const {
234 const uint8_t *Record = getSymbolEsdRecord(Symb);
235 GOFF::ESDSymbolType SymbolType;
236 ESDRecord::getSymbolType(Record, SymbolType);
238 if (SymbolType == GOFF::ESD_ST_ExternalReference)
239 return true;
240 if (SymbolType == GOFF::ESD_ST_PartReference) {
241 uint32_t Length;
242 ESDRecord::getLength(Record, Length);
243 if (Length == 0)
244 return true;
246 return false;
249 bool GOFFObjectFile::isSymbolIndirect(DataRefImpl Symb) const {
250 const uint8_t *Record = getSymbolEsdRecord(Symb);
251 bool Indirect;
252 ESDRecord::getIndirectReference(Record, Indirect);
253 return Indirect;
256 Expected<uint32_t> GOFFObjectFile::getSymbolFlags(DataRefImpl Symb) const {
257 uint32_t Flags = 0;
258 if (isSymbolUnresolved(Symb))
259 Flags |= SymbolRef::SF_Undefined;
261 const uint8_t *Record = getSymbolEsdRecord(Symb);
263 GOFF::ESDBindingStrength BindingStrength;
264 ESDRecord::getBindingStrength(Record, BindingStrength);
265 if (BindingStrength == GOFF::ESD_BST_Weak)
266 Flags |= SymbolRef::SF_Weak;
268 GOFF::ESDBindingScope BindingScope;
269 ESDRecord::getBindingScope(Record, BindingScope);
271 if (BindingScope != GOFF::ESD_BSC_Section) {
272 Expected<StringRef> Name = getSymbolName(Symb);
273 if (Name && *Name != " ") { // Blank name is local.
274 Flags |= SymbolRef::SF_Global;
275 if (BindingScope == GOFF::ESD_BSC_ImportExport)
276 Flags |= SymbolRef::SF_Exported;
277 else if (!(Flags & SymbolRef::SF_Undefined))
278 Flags |= SymbolRef::SF_Hidden;
282 return Flags;
285 Expected<SymbolRef::Type>
286 GOFFObjectFile::getSymbolType(DataRefImpl Symb) const {
287 const uint8_t *Record = getSymbolEsdRecord(Symb);
288 GOFF::ESDSymbolType SymbolType;
289 ESDRecord::getSymbolType(Record, SymbolType);
290 GOFF::ESDExecutable Executable;
291 ESDRecord::getExecutable(Record, Executable);
293 if (SymbolType != GOFF::ESD_ST_SectionDefinition &&
294 SymbolType != GOFF::ESD_ST_ElementDefinition &&
295 SymbolType != GOFF::ESD_ST_LabelDefinition &&
296 SymbolType != GOFF::ESD_ST_PartReference &&
297 SymbolType != GOFF::ESD_ST_ExternalReference) {
298 uint32_t EsdId;
299 ESDRecord::getEsdId(Record, EsdId);
300 return createStringError(llvm::errc::invalid_argument,
301 "ESD record %" PRIu32
302 " has invalid symbol type 0x%02" PRIX8,
303 EsdId, SymbolType);
305 switch (SymbolType) {
306 case GOFF::ESD_ST_SectionDefinition:
307 case GOFF::ESD_ST_ElementDefinition:
308 return SymbolRef::ST_Other;
309 case GOFF::ESD_ST_LabelDefinition:
310 case GOFF::ESD_ST_PartReference:
311 case GOFF::ESD_ST_ExternalReference:
312 if (Executable != GOFF::ESD_EXE_CODE && Executable != GOFF::ESD_EXE_DATA &&
313 Executable != GOFF::ESD_EXE_Unspecified) {
314 uint32_t EsdId;
315 ESDRecord::getEsdId(Record, EsdId);
316 return createStringError(llvm::errc::invalid_argument,
317 "ESD record %" PRIu32
318 " has unknown Executable type 0x%02X",
319 EsdId, Executable);
321 switch (Executable) {
322 case GOFF::ESD_EXE_CODE:
323 return SymbolRef::ST_Function;
324 case GOFF::ESD_EXE_DATA:
325 return SymbolRef::ST_Data;
326 case GOFF::ESD_EXE_Unspecified:
327 return SymbolRef::ST_Unknown;
329 llvm_unreachable("Unhandled ESDExecutable");
331 llvm_unreachable("Unhandled ESDSymbolType");
334 Expected<section_iterator>
335 GOFFObjectFile::getSymbolSection(DataRefImpl Symb) const {
336 DataRefImpl Sec;
338 if (isSymbolUnresolved(Symb))
339 return section_iterator(SectionRef(Sec, this));
341 const uint8_t *SymEsdRecord = EsdPtrs[Symb.d.a];
342 uint32_t SymEdId;
343 ESDRecord::getParentEsdId(SymEsdRecord, SymEdId);
344 const uint8_t *SymEdRecord = EsdPtrs[SymEdId];
346 for (size_t I = 0, E = SectionList.size(); I < E; ++I) {
347 bool Found;
348 const uint8_t *SectionPrRecord = getSectionPrEsdRecord(I);
349 if (SectionPrRecord) {
350 Found = SymEsdRecord == SectionPrRecord;
351 } else {
352 const uint8_t *SectionEdRecord = getSectionEdEsdRecord(I);
353 Found = SymEdRecord == SectionEdRecord;
356 if (Found) {
357 Sec.d.a = I;
358 return section_iterator(SectionRef(Sec, this));
361 return createStringError(llvm::errc::invalid_argument,
362 "symbol with ESD id " + std::to_string(Symb.d.a) +
363 " refers to invalid section with ESD id " +
364 std::to_string(SymEdId));
367 const uint8_t *GOFFObjectFile::getSectionEdEsdRecord(DataRefImpl &Sec) const {
368 SectionEntryImpl EsdIds = SectionList[Sec.d.a];
369 const uint8_t *EsdRecord = EsdPtrs[EsdIds.d.a];
370 return EsdRecord;
373 const uint8_t *GOFFObjectFile::getSectionPrEsdRecord(DataRefImpl &Sec) const {
374 SectionEntryImpl EsdIds = SectionList[Sec.d.a];
375 const uint8_t *EsdRecord = nullptr;
376 if (EsdIds.d.b)
377 EsdRecord = EsdPtrs[EsdIds.d.b];
378 return EsdRecord;
381 const uint8_t *
382 GOFFObjectFile::getSectionEdEsdRecord(uint32_t SectionIndex) const {
383 DataRefImpl Sec;
384 Sec.d.a = SectionIndex;
385 const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
386 return EsdRecord;
389 const uint8_t *
390 GOFFObjectFile::getSectionPrEsdRecord(uint32_t SectionIndex) const {
391 DataRefImpl Sec;
392 Sec.d.a = SectionIndex;
393 const uint8_t *EsdRecord = getSectionPrEsdRecord(Sec);
394 return EsdRecord;
397 section_iterator GOFFObjectFile::section_begin() const {
398 DataRefImpl Sec;
399 moveSectionNext(Sec);
400 return section_iterator(SectionRef(Sec, this));
403 section_iterator GOFFObjectFile::section_end() const {
404 DataRefImpl Sec;
405 return section_iterator(SectionRef(Sec, this));
408 void GOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const {
409 for (uint32_t I = Symb.d.a + 1, E = EsdPtrs.size(); I < E; ++I) {
410 if (EsdPtrs[I]) {
411 const uint8_t *EsdRecord = EsdPtrs[I];
412 GOFF::ESDSymbolType SymbolType;
413 ESDRecord::getSymbolType(EsdRecord, SymbolType);
414 // Skip EDs - i.e. section symbols.
415 bool IgnoreSpecialGOFFSymbols = true;
416 bool SkipSymbol = ((SymbolType == GOFF::ESD_ST_ElementDefinition) ||
417 (SymbolType == GOFF::ESD_ST_SectionDefinition)) &&
418 IgnoreSpecialGOFFSymbols;
419 if (!SkipSymbol) {
420 Symb.d.a = I;
421 return;
425 Symb.d.a = 0;
428 basic_symbol_iterator GOFFObjectFile::symbol_begin() const {
429 DataRefImpl Symb;
430 moveSymbolNext(Symb);
431 return basic_symbol_iterator(SymbolRef(Symb, this));
434 basic_symbol_iterator GOFFObjectFile::symbol_end() const {
435 DataRefImpl Symb;
436 return basic_symbol_iterator(SymbolRef(Symb, this));
439 Error Record::getContinuousData(const uint8_t *Record, uint16_t DataLength,
440 int DataIndex, SmallString<256> &CompleteData) {
441 // First record.
442 const uint8_t *Slice = Record + DataIndex;
443 size_t SliceLength =
444 std::min(DataLength, (uint16_t)(GOFF::RecordLength - DataIndex));
445 CompleteData.append(Slice, Slice + SliceLength);
446 DataLength -= SliceLength;
447 Slice += SliceLength;
449 // Continuation records.
450 for (; DataLength > 0;
451 DataLength -= SliceLength, Slice += GOFF::PayloadLength) {
452 // Slice points to the start of the new record.
453 // Check that this block is a Continuation.
454 assert(Record::isContinuation(Slice) && "Continuation bit must be set");
455 // Check that the last Continuation is terminated correctly.
456 if (DataLength <= 77 && Record::isContinued(Slice))
457 return createStringError(object_error::parse_failed,
458 "continued bit should not be set");
460 SliceLength = std::min(DataLength, (uint16_t)GOFF::PayloadLength);
461 Slice += GOFF::RecordPrefixLength;
462 CompleteData.append(Slice, Slice + SliceLength);
464 return Error::success();
467 Error HDRRecord::getData(const uint8_t *Record,
468 SmallString<256> &CompleteData) {
469 uint16_t Length = getPropertyModuleLength(Record);
470 return getContinuousData(Record, Length, 60, CompleteData);
473 Error ESDRecord::getData(const uint8_t *Record,
474 SmallString<256> &CompleteData) {
475 uint16_t DataSize = getNameLength(Record);
476 return getContinuousData(Record, DataSize, 72, CompleteData);
479 Error ENDRecord::getData(const uint8_t *Record,
480 SmallString<256> &CompleteData) {
481 uint16_t Length = getNameLength(Record);
482 return getContinuousData(Record, Length, 26, CompleteData);