brintos

brintos / llvm-project-archived public Read only

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