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.
10//
11//===----------------------------------------------------------------------===//
12
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"
19
20#ifndef DEBUG_TYPE
21#define DEBUG_TYPE "goff"
22#endif
23
24using namespace llvm::object;
25using namespace llvm;
26
27Expected<std::unique_ptr<ObjectFile>>
28ObjectFile::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);
34}
35
36GOFFObjectFile::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 EC: object_error::unexpected_eof,
43 S: "object file is not the right size. Must be a multiple "
44 "of 80 bytes, but is " +
45 std::to_string(val: Object.getBufferSize()) + " bytes");
46 return;
47 }
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(EC: object_error::parse_failed,
53 S: "object file must start with HDR record");
54 return;
55 }
56 if ((base()[Object.getBufferSize() - GOFF::RecordLength + 1] & 0xF0) >> 4 !=
57 GOFF::RT_END) {
58 Err = createStringError(EC: object_error::parse_failed,
59 S: "object file must end with END record");
60 return;
61 }
62 }
63
64 SectionEntryImpl DummySection;
65 SectionList.emplace_back(Args&: DummySection); // Dummy entry at index 0.
66
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;
75
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(EC: object_error::parse_failed,
81 S: "record " + std::to_string(val: RecordNum) +
82 " is not a continuation record but the "
83 "preceding record is continued");
84 return;
85 }
86 }
87 // Don't parse continuations records, only parse initial record.
88 if (IsContinuation) {
89 if (RecordType != PrevRecordType) {
90 Err = createStringError(EC: object_error::parse_failed,
91 S: "record " + std::to_string(val: RecordNum) +
92 " is a continuation record that does not "
93 "match the type of the previous record");
94 return;
95 }
96 if (!PrevWasContinued) {
97 Err = createStringError(EC: object_error::parse_failed,
98 S: "record " + std::to_string(val: RecordNum) +
99 " is a continuation record that is not "
100 "preceded by a continued record");
101 return;
102 }
103 PrevRecordType = RecordType;
104 PrevContinuationBits = I[1] & 0x03;
105 continue;
106 }
107 LLVM_DEBUG(for (size_t J = 0; J < GOFF::RecordLength; ++J) {
108 const uint8_t *P = I + J;
109 if (J % 8 == 0)
110 dbgs() << " ";
111 dbgs() << format("%02hhX", *P);
112 });
113
114 switch (RecordType) {
115 case GOFF::RT_ESD: {
116 // Save ESD record.
117 uint32_t EsdId;
118 ESDRecord::getEsdId(Record: I, EsdId);
119 EsdPtrs.grow(N: EsdId);
120 EsdPtrs[EsdId] = I;
121
122 // Determine and save the "sections" in GOFF.
123 // A section is saved as a tuple of the form
124 // case (1): (ED,child PR)
125 // - where the PR must have non-zero length.
126 // case (2a) (ED,0)
127 // - where the ED is of non-zero length.
128 // case (2b) (ED,0)
129 // - where the ED is zero length but
130 // contains a label (LD).
131 GOFF::ESDSymbolType SymbolType;
132 ESDRecord::getSymbolType(Record: I, SymbolType);
133 SectionEntryImpl Section;
134 uint32_t Length;
135 ESDRecord::getLength(Record: I, Length);
136 if (SymbolType == GOFF::ESD_ST_ElementDefinition) {
137 // case (2a)
138 if (Length != 0) {
139 Section.d.a = EsdId;
140 SectionList.emplace_back(Args&: Section);
141 }
142 } else if (SymbolType == GOFF::ESD_ST_PartReference) {
143 // case (1)
144 if (Length != 0) {
145 uint32_t SymEdId;
146 ESDRecord::getParentEsdId(Record: I, EsdId&: SymEdId);
147 Section.d.a = SymEdId;
148 Section.d.b = EsdId;
149 SectionList.emplace_back(Args&: Section);
150 }
151 } else if (SymbolType == GOFF::ESD_ST_LabelDefinition) {
152 // case (2b)
153 uint32_t SymEdId;
154 ESDRecord::getParentEsdId(Record: I, EsdId&: SymEdId);
155 const uint8_t *SymEdRecord = EsdPtrs[SymEdId];
156 uint32_t EdLength;
157 ESDRecord::getLength(Record: SymEdRecord, Length&: EdLength);
158 if (!EdLength) { // [ EDID, PRID ]
159 // LD child of a zero length parent ED.
160 // Add the section ED which was previously ignored.
161 Section.d.a = SymEdId;
162 SectionList.emplace_back(Args&: Section);
163 }
164 }
165 LLVM_DEBUG(dbgs() << " -- ESD " << EsdId << "\n");
166 break;
167 }
168 case GOFF::RT_TXT:
169 // Save TXT records.
170 TextPtrs.emplace_back(Args&: I);
171 LLVM_DEBUG(dbgs() << " -- TXT\n");
172 break;
173 case GOFF::RT_RLD:
174 LLVM_DEBUG(dbgs() << " -- RLD (GOFF record type) unhandled\n");
175 break;
176 case GOFF::RT_LEN:
177 LLVM_DEBUG(dbgs() << " -- LEN (GOFF record type) unhandled\n");
178 break;
179 case GOFF::RT_END:
180 LLVM_DEBUG(dbgs() << " -- END (GOFF record type) unhandled\n");
181 break;
182 case GOFF::RT_HDR:
183 LLVM_DEBUG(dbgs() << " -- HDR (GOFF record type) unhandled\n");
184 break;
185 default:
186 Err = createStringError(EC: object_error::parse_failed,
187 Fmt: "record %zu has unknown record type 0x%02" PRIX8,
188 Vals: RecordNum, Vals: RecordType);
189 return;
190 }
191 PrevRecordType = RecordType;
192 PrevContinuationBits = I[1] & 0x03;
193 }
194}
195
196const uint8_t *GOFFObjectFile::getSymbolEsdRecord(DataRefImpl Symb) const {
197 const uint8_t *EsdRecord = EsdPtrs[Symb.d.a];
198 return EsdRecord;
199}
200
201Expected<StringRef> GOFFObjectFile::getSymbolName(DataRefImpl Symb) const {
202 if (auto It = EsdNamesCache.find(Val: Symb.d.a); It != EsdNamesCache.end()) {
203 auto &StrPtr = It->second;
204 return StringRef(StrPtr.second.get(), StrPtr.first);
205 }
206
207 SmallString<256> SymbolName;
208 if (auto Err = ESDRecord::getData(Record: getSymbolEsdRecord(Symb), CompleteData&: SymbolName))
209 return std::move(Err);
210
211 SmallString<256> SymbolNameConverted;
212 ConverterEBCDIC::convertToUTF8(Source: SymbolName, Result&: SymbolNameConverted);
213
214 size_t Size = SymbolNameConverted.size();
215 auto StrPtr = std::make_pair(x&: Size, y: std::make_unique<char[]>(num: Size));
216 char *Buf = StrPtr.second.get();
217 memcpy(dest: Buf, src: SymbolNameConverted.data(), n: Size);
218 EsdNamesCache[Symb.d.a] = std::move(StrPtr);
219 return StringRef(Buf, Size);
220}
221
222Expected<StringRef> GOFFObjectFile::getSymbolName(SymbolRef Symbol) const {
223 return getSymbolName(Symb: Symbol.getRawDataRefImpl());
224}
225
226Expected<uint64_t> GOFFObjectFile::getSymbolAddress(DataRefImpl Symb) const {
227 uint32_t Offset;
228 const uint8_t *EsdRecord = getSymbolEsdRecord(Symb);
229 ESDRecord::getOffset(Record: EsdRecord, Offset);
230 return static_cast<uint64_t>(Offset);
231}
232
233uint64_t GOFFObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
234 uint32_t Offset;
235 const uint8_t *EsdRecord = getSymbolEsdRecord(Symb);
236 ESDRecord::getOffset(Record: EsdRecord, Offset);
237 return static_cast<uint64_t>(Offset);
238}
239
240uint64_t GOFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
241 return 0;
242}
243
244bool GOFFObjectFile::isSymbolUnresolved(DataRefImpl Symb) const {
245 const uint8_t *Record = getSymbolEsdRecord(Symb);
246 GOFF::ESDSymbolType SymbolType;
247 ESDRecord::getSymbolType(Record, SymbolType);
248
249 if (SymbolType == GOFF::ESD_ST_ExternalReference)
250 return true;
251 if (SymbolType == GOFF::ESD_ST_PartReference) {
252 uint32_t Length;
253 ESDRecord::getLength(Record, Length);
254 if (Length == 0)
255 return true;
256 }
257 return false;
258}
259
260bool GOFFObjectFile::isSymbolIndirect(DataRefImpl Symb) const {
261 const uint8_t *Record = getSymbolEsdRecord(Symb);
262 bool Indirect;
263 ESDRecord::getIndirectReference(Record, Indirect);
264 return Indirect;
265}
266
267Expected<uint32_t> GOFFObjectFile::getSymbolFlags(DataRefImpl Symb) const {
268 uint32_t Flags = 0;
269 if (isSymbolUnresolved(Symb))
270 Flags |= SymbolRef::SF_Undefined;
271
272 const uint8_t *Record = getSymbolEsdRecord(Symb);
273
274 GOFF::ESDBindingStrength BindingStrength;
275 ESDRecord::getBindingStrength(Record, Strength&: BindingStrength);
276 if (BindingStrength == GOFF::ESD_BST_Weak)
277 Flags |= SymbolRef::SF_Weak;
278
279 GOFF::ESDBindingScope BindingScope;
280 ESDRecord::getBindingScope(Record, Scope&: BindingScope);
281
282 if (BindingScope != GOFF::ESD_BSC_Section) {
283 Expected<StringRef> Name = getSymbolName(Symb);
284 if (Name && *Name != " ") { // Blank name is local.
285 Flags |= SymbolRef::SF_Global;
286 if (BindingScope == GOFF::ESD_BSC_ImportExport)
287 Flags |= SymbolRef::SF_Exported;
288 else if (!(Flags & SymbolRef::SF_Undefined))
289 Flags |= SymbolRef::SF_Hidden;
290 }
291 }
292
293 return Flags;
294}
295
296Expected<SymbolRef::Type>
297GOFFObjectFile::getSymbolType(DataRefImpl Symb) const {
298 const uint8_t *Record = getSymbolEsdRecord(Symb);
299 GOFF::ESDSymbolType SymbolType;
300 ESDRecord::getSymbolType(Record, SymbolType);
301 GOFF::ESDExecutable Executable;
302 ESDRecord::getExecutable(Record, Executable);
303
304 if (SymbolType != GOFF::ESD_ST_SectionDefinition &&
305 SymbolType != GOFF::ESD_ST_ElementDefinition &&
306 SymbolType != GOFF::ESD_ST_LabelDefinition &&
307 SymbolType != GOFF::ESD_ST_PartReference &&
308 SymbolType != GOFF::ESD_ST_ExternalReference) {
309 uint32_t EsdId;
310 ESDRecord::getEsdId(Record, EsdId);
311 return createStringError(EC: llvm::errc::invalid_argument,
312 Fmt: "ESD record %" PRIu32
313 " has invalid symbol type 0x%02" PRIX8,
314 Vals: EsdId, Vals: SymbolType);
315 }
316 switch (SymbolType) {
317 case GOFF::ESD_ST_SectionDefinition:
318 case GOFF::ESD_ST_ElementDefinition:
319 return SymbolRef::ST_Other;
320 case GOFF::ESD_ST_LabelDefinition:
321 case GOFF::ESD_ST_PartReference:
322 case GOFF::ESD_ST_ExternalReference:
323 if (Executable != GOFF::ESD_EXE_CODE && Executable != GOFF::ESD_EXE_DATA &&
324 Executable != GOFF::ESD_EXE_Unspecified) {
325 uint32_t EsdId;
326 ESDRecord::getEsdId(Record, EsdId);
327 return createStringError(EC: llvm::errc::invalid_argument,
328 Fmt: "ESD record %" PRIu32
329 " has unknown Executable type 0x%02X",
330 Vals: EsdId, Vals: Executable);
331 }
332 switch (Executable) {
333 case GOFF::ESD_EXE_CODE:
334 return SymbolRef::ST_Function;
335 case GOFF::ESD_EXE_DATA:
336 return SymbolRef::ST_Data;
337 case GOFF::ESD_EXE_Unspecified:
338 return SymbolRef::ST_Unknown;
339 }
340 llvm_unreachable("Unhandled ESDExecutable");
341 }
342 llvm_unreachable("Unhandled ESDSymbolType");
343}
344
345Expected<section_iterator>
346GOFFObjectFile::getSymbolSection(DataRefImpl Symb) const {
347 DataRefImpl Sec;
348
349 if (isSymbolUnresolved(Symb))
350 return section_iterator(SectionRef(Sec, this));
351
352 const uint8_t *SymEsdRecord = EsdPtrs[Symb.d.a];
353 uint32_t SymEdId;
354 ESDRecord::getParentEsdId(Record: SymEsdRecord, EsdId&: SymEdId);
355 const uint8_t *SymEdRecord = EsdPtrs[SymEdId];
356
357 for (size_t I = 0, E = SectionList.size(); I < E; ++I) {
358 bool Found;
359 const uint8_t *SectionPrRecord = getSectionPrEsdRecord(SectionIndex: I);
360 if (SectionPrRecord) {
361 Found = SymEsdRecord == SectionPrRecord;
362 } else {
363 const uint8_t *SectionEdRecord = getSectionEdEsdRecord(SectionIndex: I);
364 Found = SymEdRecord == SectionEdRecord;
365 }
366
367 if (Found) {
368 Sec.d.a = I;
369 return section_iterator(SectionRef(Sec, this));
370 }
371 }
372 return createStringError(EC: llvm::errc::invalid_argument,
373 S: "symbol with ESD id " + std::to_string(val: Symb.d.a) +
374 " refers to invalid section with ESD id " +
375 std::to_string(val: SymEdId));
376}
377
378uint64_t GOFFObjectFile::getSymbolSize(DataRefImpl Symb) const {
379 const uint8_t *Record = getSymbolEsdRecord(Symb);
380 uint32_t Length;
381 ESDRecord::getLength(Record, Length);
382 return Length;
383}
384
385const uint8_t *GOFFObjectFile::getSectionEdEsdRecord(DataRefImpl &Sec) const {
386 SectionEntryImpl EsdIds = SectionList[Sec.d.a];
387 const uint8_t *EsdRecord = EsdPtrs[EsdIds.d.a];
388 return EsdRecord;
389}
390
391const uint8_t *GOFFObjectFile::getSectionPrEsdRecord(DataRefImpl &Sec) const {
392 SectionEntryImpl EsdIds = SectionList[Sec.d.a];
393 const uint8_t *EsdRecord = nullptr;
394 if (EsdIds.d.b)
395 EsdRecord = EsdPtrs[EsdIds.d.b];
396 return EsdRecord;
397}
398
399const uint8_t *
400GOFFObjectFile::getSectionEdEsdRecord(uint32_t SectionIndex) const {
401 DataRefImpl Sec;
402 Sec.d.a = SectionIndex;
403 const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
404 return EsdRecord;
405}
406
407const uint8_t *
408GOFFObjectFile::getSectionPrEsdRecord(uint32_t SectionIndex) const {
409 DataRefImpl Sec;
410 Sec.d.a = SectionIndex;
411 const uint8_t *EsdRecord = getSectionPrEsdRecord(Sec);
412 return EsdRecord;
413}
414
415uint32_t GOFFObjectFile::getSectionDefEsdId(DataRefImpl &Sec) const {
416 const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
417 uint32_t Length;
418 ESDRecord::getLength(Record: EsdRecord, Length);
419 if (Length == 0) {
420 const uint8_t *PrEsdRecord = getSectionPrEsdRecord(Sec);
421 if (PrEsdRecord)
422 EsdRecord = PrEsdRecord;
423 }
424
425 uint32_t DefEsdId;
426 ESDRecord::getEsdId(Record: EsdRecord, EsdId&: DefEsdId);
427 LLVM_DEBUG(dbgs() << "Got def EsdId: " << DefEsdId << '\n');
428 return DefEsdId;
429}
430
431void GOFFObjectFile::moveSectionNext(DataRefImpl &Sec) const {
432 Sec.d.a++;
433 if ((Sec.d.a) >= SectionList.size())
434 Sec.d.a = 0;
435}
436
437Expected<StringRef> GOFFObjectFile::getSectionName(DataRefImpl Sec) const {
438 DataRefImpl EdSym;
439 SectionEntryImpl EsdIds = SectionList[Sec.d.a];
440 EdSym.d.a = EsdIds.d.a;
441 Expected<StringRef> Name = getSymbolName(Symb: EdSym);
442 if (Name) {
443 StringRef Res = *Name;
444 LLVM_DEBUG(dbgs() << "Got section: " << Res << '\n');
445 LLVM_DEBUG(dbgs() << "Final section name: " << Res << '\n');
446 Name = Res;
447 }
448 return Name;
449}
450
451uint64_t GOFFObjectFile::getSectionAddress(DataRefImpl Sec) const {
452 uint32_t Offset;
453 const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
454 ESDRecord::getOffset(Record: EsdRecord, Offset);
455 return Offset;
456}
457
458uint64_t GOFFObjectFile::getSectionSize(DataRefImpl Sec) const {
459 uint32_t Length;
460 uint32_t DefEsdId = getSectionDefEsdId(Sec);
461 const uint8_t *EsdRecord = EsdPtrs[DefEsdId];
462 ESDRecord::getLength(Record: EsdRecord, Length);
463 LLVM_DEBUG(dbgs() << "Got section size: " << Length << '\n');
464 return static_cast<uint64_t>(Length);
465}
466
467// Unravel TXT records and expand fill characters to produce
468// a contiguous sequence of bytes.
469Expected<ArrayRef<uint8_t>>
470GOFFObjectFile::getSectionContents(DataRefImpl Sec) const {
471 if (auto It = SectionDataCache.find(Val: Sec.d.a); It != SectionDataCache.end()) {
472 auto &Buf = It->second;
473 return ArrayRef<uint8_t>(Buf);
474 }
475 uint64_t SectionSize = getSectionSize(Sec);
476 uint32_t DefEsdId = getSectionDefEsdId(Sec);
477
478 const uint8_t *EdEsdRecord = getSectionEdEsdRecord(Sec);
479 bool FillBytePresent;
480 ESDRecord::getFillBytePresent(Record: EdEsdRecord, Present&: FillBytePresent);
481 uint8_t FillByte = '\0';
482 if (FillBytePresent)
483 ESDRecord::getFillByteValue(Record: EdEsdRecord, Fill&: FillByte);
484
485 // Initialize section with fill byte.
486 SmallVector<uint8_t> Data(SectionSize, FillByte);
487
488 // Replace section with content from text records.
489 for (const uint8_t *TxtRecordInt : TextPtrs) {
490 const uint8_t *TxtRecordPtr = TxtRecordInt;
491 uint32_t TxtEsdId;
492 TXTRecord::getElementEsdId(Record: TxtRecordPtr, EsdId&: TxtEsdId);
493 LLVM_DEBUG(dbgs() << "Got txt EsdId: " << TxtEsdId << '\n');
494
495 if (TxtEsdId != DefEsdId)
496 continue;
497
498 uint32_t TxtDataOffset;
499 TXTRecord::getOffset(Record: TxtRecordPtr, Offset&: TxtDataOffset);
500
501 uint16_t TxtDataSize;
502 TXTRecord::getDataLength(Record: TxtRecordPtr, Length&: TxtDataSize);
503
504 LLVM_DEBUG(dbgs() << "Record offset " << TxtDataOffset << ", data size "
505 << TxtDataSize << "\n");
506
507 SmallString<256> CompleteData;
508 CompleteData.reserve(N: TxtDataSize);
509 if (Error Err = TXTRecord::getData(Record: TxtRecordPtr, CompleteData))
510 return std::move(Err);
511 assert(CompleteData.size() == TxtDataSize && "Wrong length of data");
512 std::copy(first: CompleteData.data(), last: CompleteData.data() + TxtDataSize,
513 result: Data.begin() + TxtDataOffset);
514 }
515 auto &Cache = SectionDataCache[Sec.d.a];
516 Cache = std::move(Data);
517 return ArrayRef<uint8_t>(Cache);
518}
519
520uint64_t GOFFObjectFile::getSectionAlignment(DataRefImpl Sec) const {
521 const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
522 GOFF::ESDAlignment Pow2Alignment;
523 ESDRecord::getAlignment(Record: EsdRecord, Alignment&: Pow2Alignment);
524 return 1ULL << static_cast<uint64_t>(Pow2Alignment);
525}
526
527bool GOFFObjectFile::isSectionText(DataRefImpl Sec) const {
528 const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
529 GOFF::ESDExecutable Executable;
530 ESDRecord::getExecutable(Record: EsdRecord, Executable);
531 return Executable == GOFF::ESD_EXE_CODE;
532}
533
534bool GOFFObjectFile::isSectionData(DataRefImpl Sec) const {
535 const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
536 GOFF::ESDExecutable Executable;
537 ESDRecord::getExecutable(Record: EsdRecord, Executable);
538 return Executable == GOFF::ESD_EXE_DATA;
539}
540
541bool GOFFObjectFile::isSectionNoLoad(DataRefImpl Sec) const {
542 const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
543 GOFF::ESDLoadingBehavior LoadingBehavior;
544 ESDRecord::getLoadingBehavior(Record: EsdRecord, Behavior&: LoadingBehavior);
545 return LoadingBehavior == GOFF::ESD_LB_NoLoad;
546}
547
548bool GOFFObjectFile::isSectionReadOnlyData(DataRefImpl Sec) const {
549 if (!isSectionData(Sec))
550 return false;
551
552 const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
553 GOFF::ESDLoadingBehavior LoadingBehavior;
554 ESDRecord::getLoadingBehavior(Record: EsdRecord, Behavior&: LoadingBehavior);
555 return LoadingBehavior == GOFF::ESD_LB_Initial;
556}
557
558bool GOFFObjectFile::isSectionZeroInit(DataRefImpl Sec) const {
559 // GOFF uses fill characters and fill characters are applied
560 // on getSectionContents() - so we say false to zero init.
561 return false;
562}
563
564section_iterator GOFFObjectFile::section_begin() const {
565 DataRefImpl Sec;
566 moveSectionNext(Sec);
567 return section_iterator(SectionRef(Sec, this));
568}
569
570section_iterator GOFFObjectFile::section_end() const {
571 DataRefImpl Sec;
572 return section_iterator(SectionRef(Sec, this));
573}
574
575void GOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const {
576 for (uint32_t I = Symb.d.a + 1, E = EsdPtrs.size(); I < E; ++I) {
577 if (const uint8_t *EsdRecord = EsdPtrs[I]) {
578 GOFF::ESDSymbolType SymbolType;
579 ESDRecord::getSymbolType(Record: EsdRecord, SymbolType);
580 // Skip EDs - i.e. section symbols.
581 bool IgnoreSpecialGOFFSymbols = true;
582 bool SkipSymbol = ((SymbolType == GOFF::ESD_ST_ElementDefinition) ||
583 (SymbolType == GOFF::ESD_ST_SectionDefinition)) &&
584 IgnoreSpecialGOFFSymbols;
585 if (!SkipSymbol) {
586 Symb.d.a = I;
587 return;
588 }
589 }
590 }
591 Symb.d.a = 0;
592}
593
594basic_symbol_iterator GOFFObjectFile::symbol_begin() const {
595 DataRefImpl Symb;
596 moveSymbolNext(Symb);
597 return basic_symbol_iterator(SymbolRef(Symb, this));
598}
599
600basic_symbol_iterator GOFFObjectFile::symbol_end() const {
601 DataRefImpl Symb;
602 return basic_symbol_iterator(SymbolRef(Symb, this));
603}
604
605Error Record::getContinuousData(const uint8_t *Record, uint16_t DataLength,
606 int DataIndex, SmallString<256> &CompleteData) {
607 // First record.
608 const uint8_t *Slice = Record + DataIndex;
609 size_t SliceLength =
610 std::min(a: DataLength, b: (uint16_t)(GOFF::RecordLength - DataIndex));
611 CompleteData.append(in_start: Slice, in_end: Slice + SliceLength);
612 DataLength -= SliceLength;
613 Slice += SliceLength;
614
615 // Continuation records.
616 for (; DataLength > 0;
617 DataLength -= SliceLength, Slice += GOFF::PayloadLength) {
618 // Slice points to the start of the new record.
619 // Check that this block is a Continuation.
620 assert(Record::isContinuation(Slice) && "Continuation bit must be set");
621 // Check that the last Continuation is terminated correctly.
622 if (DataLength <= 77 && Record::isContinued(Record: Slice))
623 return createStringError(EC: object_error::parse_failed,
624 S: "continued bit should not be set");
625
626 SliceLength = std::min(a: DataLength, b: (uint16_t)GOFF::PayloadLength);
627 Slice += GOFF::RecordPrefixLength;
628 CompleteData.append(in_start: Slice, in_end: Slice + SliceLength);
629 }
630 return Error::success();
631}
632
633Error HDRRecord::getData(const uint8_t *Record,
634 SmallString<256> &CompleteData) {
635 uint16_t Length = getPropertyModuleLength(Record);
636 return getContinuousData(Record, DataLength: Length, DataIndex: 60, CompleteData);
637}
638
639Error ESDRecord::getData(const uint8_t *Record,
640 SmallString<256> &CompleteData) {
641 uint16_t DataSize = getNameLength(Record);
642 return getContinuousData(Record, DataLength: DataSize, DataIndex: 72, CompleteData);
643}
644
645Error TXTRecord::getData(const uint8_t *Record,
646 SmallString<256> &CompleteData) {
647 uint16_t Length;
648 getDataLength(Record, Length);
649 return getContinuousData(Record, DataLength: Length, DataIndex: 24, CompleteData);
650}
651
652Error ENDRecord::getData(const uint8_t *Record,
653 SmallString<256> &CompleteData) {
654 uint16_t Length = getNameLength(Record);
655 return getContinuousData(Record, DataLength: Length, DataIndex: 26, CompleteData);
656}
657