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