xref: /llvm-project/llvm/lib/Object/GOFFObjectFile.cpp (revision aeb8628c218f8224e08dddcdd3199a445d8607a8)
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_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");
179     }
180     PrevRecordType = RecordType;
181     PrevContinuationBits = I[1] & 0x03;
182   }
183 }
184 
185 const uint8_t *GOFFObjectFile::getSymbolEsdRecord(DataRefImpl Symb) const {
186   const uint8_t *EsdRecord = EsdPtrs[Symb.d.a];
187   return EsdRecord;
188 }
189 
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);
194   }
195 
196   SmallString<256> SymbolName;
197   if (auto Err = ESDRecord::getData(getSymbolEsdRecord(Symb), SymbolName))
198     return std::move(Err);
199 
200   SmallString<256> SymbolNameConverted;
201   ConverterEBCDIC::convertToUTF8(SymbolName, SymbolNameConverted);
202 
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);
209 }
210 
211 Expected<StringRef> GOFFObjectFile::getSymbolName(SymbolRef Symbol) const {
212   return getSymbolName(Symbol.getRawDataRefImpl());
213 }
214 
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);
220 }
221 
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);
227 }
228 
229 uint64_t GOFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
230   return 0;
231 }
232 
233 bool GOFFObjectFile::isSymbolUnresolved(DataRefImpl Symb) const {
234   const uint8_t *Record = getSymbolEsdRecord(Symb);
235   GOFF::ESDSymbolType SymbolType;
236   ESDRecord::getSymbolType(Record, SymbolType);
237 
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;
245   }
246   return false;
247 }
248 
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;
254 }
255 
256 Expected<uint32_t> GOFFObjectFile::getSymbolFlags(DataRefImpl Symb) const {
257   uint32_t Flags = 0;
258   if (isSymbolUnresolved(Symb))
259     Flags |= SymbolRef::SF_Undefined;
260 
261   const uint8_t *Record = getSymbolEsdRecord(Symb);
262 
263   GOFF::ESDBindingStrength BindingStrength;
264   ESDRecord::getBindingStrength(Record, BindingStrength);
265   if (BindingStrength == GOFF::ESD_BST_Weak)
266     Flags |= SymbolRef::SF_Weak;
267 
268   GOFF::ESDBindingScope BindingScope;
269   ESDRecord::getBindingScope(Record, BindingScope);
270 
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;
279     }
280   }
281 
282   return Flags;
283 }
284 
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);
292 
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);
304   }
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);
320     }
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;
328     }
329     llvm_unreachable("Unhandled ESDExecutable");
330   }
331   llvm_unreachable("Unhandled ESDSymbolType");
332 }
333 
334 Expected<section_iterator>
335 GOFFObjectFile::getSymbolSection(DataRefImpl Symb) const {
336   DataRefImpl Sec;
337 
338   if (isSymbolUnresolved(Symb))
339     return section_iterator(SectionRef(Sec, this));
340 
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];
345 
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;
354     }
355 
356     if (Found) {
357       Sec.d.a = I;
358       return section_iterator(SectionRef(Sec, this));
359     }
360   }
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));
365 }
366 
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;
371 }
372 
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;
379 }
380 
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;
387 }
388 
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;
395 }
396 
397 uint32_t GOFFObjectFile::getSectionDefEsdId(DataRefImpl &Sec) const {
398   const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
399   uint32_t Length;
400   ESDRecord::getLength(EsdRecord, Length);
401   if (Length == 0) {
402     const uint8_t *PrEsdRecord = getSectionPrEsdRecord(Sec);
403     if (PrEsdRecord)
404       EsdRecord = PrEsdRecord;
405   }
406 
407   uint32_t DefEsdId;
408   ESDRecord::getEsdId(EsdRecord, DefEsdId);
409   LLVM_DEBUG(dbgs() << "Got def EsdId: " << DefEsdId << '\n');
410   return DefEsdId;
411 }
412 
413 void GOFFObjectFile::moveSectionNext(DataRefImpl &Sec) const {
414   Sec.d.a++;
415   if ((Sec.d.a) >= SectionList.size())
416     Sec.d.a = 0;
417 }
418 
419 Expected<StringRef> GOFFObjectFile::getSectionName(DataRefImpl Sec) const {
420   DataRefImpl EdSym;
421   SectionEntryImpl EsdIds = SectionList[Sec.d.a];
422   EdSym.d.a = EsdIds.d.a;
423   Expected<StringRef> Name = getSymbolName(EdSym);
424   if (Name) {
425     StringRef Res = *Name;
426     LLVM_DEBUG(dbgs() << "Got section: " << Res << '\n');
427     LLVM_DEBUG(dbgs() << "Final section name: " << Res << '\n');
428     Name = Res;
429   }
430   return Name;
431 }
432 
433 uint64_t GOFFObjectFile::getSectionAddress(DataRefImpl Sec) const {
434   uint32_t Offset;
435   const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
436   ESDRecord::getOffset(EsdRecord, Offset);
437   return Offset;
438 }
439 
440 uint64_t GOFFObjectFile::getSectionSize(DataRefImpl Sec) const {
441   uint32_t Length;
442   uint32_t DefEsdId = getSectionDefEsdId(Sec);
443   const uint8_t *EsdRecord = EsdPtrs[DefEsdId];
444   ESDRecord::getLength(EsdRecord, Length);
445   LLVM_DEBUG(dbgs() << "Got section size: " << Length << '\n');
446   return static_cast<uint64_t>(Length);
447 }
448 
449 // Unravel TXT records and expand fill characters to produce
450 // a contiguous sequence of bytes.
451 Expected<ArrayRef<uint8_t>>
452 GOFFObjectFile::getSectionContents(DataRefImpl Sec) const {
453   if (SectionDataCache.count(Sec.d.a)) {
454     auto &Buf = SectionDataCache[Sec.d.a];
455     return ArrayRef<uint8_t>(Buf);
456   }
457   uint64_t SectionSize = getSectionSize(Sec);
458   uint32_t DefEsdId = getSectionDefEsdId(Sec);
459 
460   const uint8_t *EdEsdRecord = getSectionEdEsdRecord(Sec);
461   bool FillBytePresent;
462   ESDRecord::getFillBytePresent(EdEsdRecord, FillBytePresent);
463   uint8_t FillByte = '\0';
464   if (FillBytePresent)
465     ESDRecord::getFillByteValue(EdEsdRecord, FillByte);
466 
467   // Initialize section with fill byte.
468   SmallVector<uint8_t> Data(SectionSize, FillByte);
469 
470   // Replace section with content from text records.
471   for (const uint8_t *TxtRecordInt : TextPtrs) {
472     const uint8_t *TxtRecordPtr = TxtRecordInt;
473     uint32_t TxtEsdId;
474     TXTRecord::getElementEsdId(TxtRecordPtr, TxtEsdId);
475     LLVM_DEBUG(dbgs() << "Got txt EsdId: " << TxtEsdId << '\n');
476 
477     if (TxtEsdId != DefEsdId)
478       continue;
479 
480     uint32_t TxtDataOffset;
481     TXTRecord::getOffset(TxtRecordPtr, TxtDataOffset);
482 
483     uint16_t TxtDataSize;
484     TXTRecord::getDataLength(TxtRecordPtr, TxtDataSize);
485 
486     LLVM_DEBUG(dbgs() << "Record offset " << TxtDataOffset << ", data size "
487                       << TxtDataSize << "\n");
488 
489     SmallString<256> CompleteData;
490     CompleteData.reserve(TxtDataSize);
491     if (Error Err = TXTRecord::getData(TxtRecordPtr, CompleteData))
492       return std::move(Err);
493     assert(CompleteData.size() == TxtDataSize && "Wrong length of data");
494     std::copy(CompleteData.data(), CompleteData.data() + TxtDataSize,
495               Data.begin() + TxtDataOffset);
496   }
497   SectionDataCache[Sec.d.a] = Data;
498   return ArrayRef<uint8_t>(Data);
499 }
500 
501 uint64_t GOFFObjectFile::getSectionAlignment(DataRefImpl Sec) const {
502   const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
503   GOFF::ESDAlignment Pow2Alignment;
504   ESDRecord::getAlignment(EsdRecord, Pow2Alignment);
505   return 1ULL << static_cast<uint64_t>(Pow2Alignment);
506 }
507 
508 bool GOFFObjectFile::isSectionText(DataRefImpl Sec) const {
509   const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
510   GOFF::ESDExecutable Executable;
511   ESDRecord::getExecutable(EsdRecord, Executable);
512   return Executable == GOFF::ESD_EXE_CODE;
513 }
514 
515 bool GOFFObjectFile::isSectionData(DataRefImpl Sec) const {
516   const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
517   GOFF::ESDExecutable Executable;
518   ESDRecord::getExecutable(EsdRecord, Executable);
519   return Executable == GOFF::ESD_EXE_DATA;
520 }
521 
522 bool GOFFObjectFile::isSectionNoLoad(DataRefImpl Sec) const {
523   const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
524   GOFF::ESDLoadingBehavior LoadingBehavior;
525   ESDRecord::getLoadingBehavior(EsdRecord, LoadingBehavior);
526   return LoadingBehavior == GOFF::ESD_LB_NoLoad;
527 }
528 
529 bool GOFFObjectFile::isSectionReadOnlyData(DataRefImpl Sec) const {
530   if (!isSectionData(Sec))
531     return false;
532 
533   const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
534   GOFF::ESDLoadingBehavior LoadingBehavior;
535   ESDRecord::getLoadingBehavior(EsdRecord, LoadingBehavior);
536   return LoadingBehavior == GOFF::ESD_LB_Initial;
537 }
538 
539 bool GOFFObjectFile::isSectionZeroInit(DataRefImpl Sec) const {
540   // GOFF uses fill characters and fill characters are applied
541   // on getSectionContents() - so we say false to zero init.
542   return false;
543 }
544 
545 section_iterator GOFFObjectFile::section_begin() const {
546   DataRefImpl Sec;
547   moveSectionNext(Sec);
548   return section_iterator(SectionRef(Sec, this));
549 }
550 
551 section_iterator GOFFObjectFile::section_end() const {
552   DataRefImpl Sec;
553   return section_iterator(SectionRef(Sec, this));
554 }
555 
556 void GOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const {
557   for (uint32_t I = Symb.d.a + 1, E = EsdPtrs.size(); I < E; ++I) {
558     if (EsdPtrs[I]) {
559       const uint8_t *EsdRecord = EsdPtrs[I];
560       GOFF::ESDSymbolType SymbolType;
561       ESDRecord::getSymbolType(EsdRecord, SymbolType);
562       // Skip EDs - i.e. section symbols.
563       bool IgnoreSpecialGOFFSymbols = true;
564       bool SkipSymbol = ((SymbolType == GOFF::ESD_ST_ElementDefinition) ||
565                          (SymbolType == GOFF::ESD_ST_SectionDefinition)) &&
566                         IgnoreSpecialGOFFSymbols;
567       if (!SkipSymbol) {
568         Symb.d.a = I;
569         return;
570       }
571     }
572   }
573   Symb.d.a = 0;
574 }
575 
576 basic_symbol_iterator GOFFObjectFile::symbol_begin() const {
577   DataRefImpl Symb;
578   moveSymbolNext(Symb);
579   return basic_symbol_iterator(SymbolRef(Symb, this));
580 }
581 
582 basic_symbol_iterator GOFFObjectFile::symbol_end() const {
583   DataRefImpl Symb;
584   return basic_symbol_iterator(SymbolRef(Symb, this));
585 }
586 
587 Error Record::getContinuousData(const uint8_t *Record, uint16_t DataLength,
588                                 int DataIndex, SmallString<256> &CompleteData) {
589   // First record.
590   const uint8_t *Slice = Record + DataIndex;
591   size_t SliceLength =
592       std::min(DataLength, (uint16_t)(GOFF::RecordLength - DataIndex));
593   CompleteData.append(Slice, Slice + SliceLength);
594   DataLength -= SliceLength;
595   Slice += SliceLength;
596 
597   // Continuation records.
598   for (; DataLength > 0;
599        DataLength -= SliceLength, Slice += GOFF::PayloadLength) {
600     // Slice points to the start of the new record.
601     // Check that this block is a Continuation.
602     assert(Record::isContinuation(Slice) && "Continuation bit must be set");
603     // Check that the last Continuation is terminated correctly.
604     if (DataLength <= 77 && Record::isContinued(Slice))
605       return createStringError(object_error::parse_failed,
606                                "continued bit should not be set");
607 
608     SliceLength = std::min(DataLength, (uint16_t)GOFF::PayloadLength);
609     Slice += GOFF::RecordPrefixLength;
610     CompleteData.append(Slice, Slice + SliceLength);
611   }
612   return Error::success();
613 }
614 
615 Error HDRRecord::getData(const uint8_t *Record,
616                          SmallString<256> &CompleteData) {
617   uint16_t Length = getPropertyModuleLength(Record);
618   return getContinuousData(Record, Length, 60, CompleteData);
619 }
620 
621 Error ESDRecord::getData(const uint8_t *Record,
622                          SmallString<256> &CompleteData) {
623   uint16_t DataSize = getNameLength(Record);
624   return getContinuousData(Record, DataSize, 72, CompleteData);
625 }
626 
627 Error ENDRecord::getData(const uint8_t *Record,
628                          SmallString<256> &CompleteData) {
629   uint16_t Length = getNameLength(Record);
630   return getContinuousData(Record, Length, 26, CompleteData);
631 }
632