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