static std::vector<std::pair<uint64_t, uint64_t>> findX86PltEntries(uint64_t PltSectionVA, ArrayRef<uint8_t> PltContents, uint64_t GotPltSectionVA) { // Do a lightweight parsing of PLT entries. std::vector<std::pair<uint64_t, uint64_t>> Result; for (uint64_t Byte = 0, End = PltContents.size(); Byte + 6 < End; ) { // Recognize a jmp. if (PltContents[Byte] == 0xff && PltContents[Byte + 1] == 0xa3) { // The jmp instruction at the beginning of each PLT entry jumps to the // address of the base of the .got.plt section plus the immediate. uint32_t Imm = support::endian::read32le(PltContents.data() + Byte + 2); Result.push_back( std::make_pair(PltSectionVA + Byte, GotPltSectionVA + Imm)); Byte += 6; } else if (PltContents[Byte] == 0xff && PltContents[Byte + 1] == 0x25) { // The jmp instruction at the beginning of each PLT entry jumps to the // immediate. uint32_t Imm = support::endian::read32le(PltContents.data() + Byte + 2); Result.push_back(std::make_pair(PltSectionVA + Byte, Imm)); Byte += 6; } else Byte++; } return Result; }
// Parses a given list of options. opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) { // Make InputArgList from string vectors. unsigned MissingIndex; unsigned MissingCount; SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size()); // We need to get the quoting style for response files before parsing all // options so we parse here before and ignore all the options but // --rsp-quoting. opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount); // Expand response files (arguments in the form of @<filename>) // and then parse the argument again. cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec); Args = this->ParseArgs(Vec, MissingIndex, MissingCount); // Interpret -color-diagnostics early so that error messages // for unknown flags are colored. Config->ColorDiagnostics = getColorDiagnostics(Args); if (MissingCount) error(Twine(Args.getArgString(MissingIndex)) + ": missing argument"); for (auto *Arg : Args.filtered(OPT_UNKNOWN)) error("unknown argument: " + Arg->getSpelling()); return Args; }
bool SymbolTable::AtomMappingInfo::isEqual(const DefinedAtom * const l, const DefinedAtom * const r) { if (l == r) return true; if (l == getEmptyKey()) return false; if (r == getEmptyKey()) return false; if (l == getTombstoneKey()) return false; if (r == getTombstoneKey()) return false; if (l->contentType() != r->contentType()) return false; if (l->size() != r->size()) return false; if (l->sectionChoice() != r->sectionChoice()) return false; if (l->sectionChoice() == DefinedAtom::sectionCustomRequired) { if (!l->customSectionName().equals(r->customSectionName())) return false; } ArrayRef<uint8_t> lc = l->rawContent(); ArrayRef<uint8_t> rc = r->rawContent(); return memcmp(lc.data(), rc.data(), lc.size()) == 0; }
ErrorOr<const typename MipsELFFile<ELFT>::Elf_Mips_RegInfo *> MipsELFFile<ELFT>::findRegInfoSec() const { using namespace llvm::ELF; if (const Elf_Shdr *sec = findSectionByType(SHT_MIPS_OPTIONS)) { auto contents = this->getSectionContents(sec); if (std::error_code ec = contents.getError()) return ec; ArrayRef<uint8_t> raw = contents.get(); while (!raw.empty()) { if (raw.size() < sizeof(Elf_Mips_Options)) return make_dynamic_error_code( StringRef("Invalid size of MIPS_OPTIONS section")); const auto *opt = reinterpret_cast<const Elf_Mips_Options *>(raw.data()); if (opt->kind == ODK_REGINFO) return &opt->getRegInfo(); raw = raw.slice(opt->size); } } else if (const Elf_Shdr *sec = findSectionByType(SHT_MIPS_REGINFO)) { auto contents = this->getSectionContents(sec); if (std::error_code ec = contents.getError()) return ec; ArrayRef<uint8_t> raw = contents.get(); if (raw.size() != sizeof(Elf_Mips_RegInfo)) return make_dynamic_error_code( StringRef("Invalid size of MIPS_REGINFO section")); return reinterpret_cast<const Elf_Mips_RegInfo *>(raw.data()); } return nullptr; }
Error MappedBlockStream::readLongestContiguousChunk( uint32_t Offset, ArrayRef<uint8_t> &Buffer) const { // Make sure we aren't trying to read beyond the end of the stream. if (Offset >= StreamLayout.Length) return make_error<MSFError>(msf_error_code::insufficient_buffer); uint32_t First = Offset / BlockSize; uint32_t Last = First; while (Last < NumBlocks - 1) { if (StreamLayout.Blocks[Last] != StreamLayout.Blocks[Last + 1] - 1) break; ++Last; } uint32_t OffsetInFirstBlock = Offset % BlockSize; uint32_t BytesFromFirstBlock = BlockSize - OffsetInFirstBlock; uint32_t BlockSpan = Last - First + 1; uint32_t ByteSpan = BytesFromFirstBlock + (BlockSpan - 1) * BlockSize; ArrayRef<uint8_t> BlockData; uint32_t MsfOffset = blockToOffset(StreamLayout.Blocks[First], BlockSize); if (auto EC = MsfData.readBytes(MsfOffset, BlockSize, BlockData)) return EC; BlockData = BlockData.drop_front(OffsetInFirstBlock); Buffer = ArrayRef<uint8_t>(BlockData.data(), ByteSpan); return Error::success(); }
error_code MachOObjectFile::getSectionName(DataRefImpl Sec, StringRef &Result) const { ArrayRef<char> Raw = getSectionRawName(Sec); Result = parseSegmentOrSectionName(Raw.data()); return object_error::success; }
/// Compute the address map. The address map is an array of symbol offsets /// sorted so that it can be binary searched by address. static std::vector<ulittle32_t> computeAddrMap(ArrayRef<CVSymbol> Records) { // Make a vector of pointers to the symbols so we can sort it by address. // Also gather the symbol offsets while we're at it. std::vector<PublicSym32> DeserializedPublics; std::vector<std::pair<const CVSymbol *, const PublicSym32 *>> PublicsByAddr; std::vector<uint32_t> SymOffsets; DeserializedPublics.reserve(Records.size()); PublicsByAddr.reserve(Records.size()); SymOffsets.reserve(Records.size()); uint32_t SymOffset = 0; for (const CVSymbol &Sym : Records) { assert(Sym.kind() == SymbolKind::S_PUB32); DeserializedPublics.push_back( cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(Sym))); PublicsByAddr.emplace_back(&Sym, &DeserializedPublics.back()); SymOffsets.push_back(SymOffset); SymOffset += Sym.length(); } llvm::stable_sort(PublicsByAddr, comparePubSymByAddrAndName); // Fill in the symbol offsets in the appropriate order. std::vector<ulittle32_t> AddrMap; AddrMap.reserve(Records.size()); for (auto &Sym : PublicsByAddr) { ptrdiff_t Idx = std::distance(Records.data(), Sym.first); assert(Idx >= 0 && size_t(Idx) < Records.size()); AddrMap.push_back(ulittle32_t(SymOffsets[Idx])); } return AddrMap; }
static void writeCieFde(uint8_t *Buf, ArrayRef<uint8_t> D) { memcpy(Buf, D.data(), D.size()); // Fix the size field. -4 since size does not include the size field itself. const endianness E = ELFT::TargetEndianness; write32<E>(Buf, alignTo(D.size(), sizeof(typename ELFT::uint)) - 4); }
void Dumper::printData(const Context &Ctx) { for (const auto &Section : Ctx.COFF.sections()) { StringRef Name; Section.getName(Name); if (Name != ".pdata" && !Name.startswith(".pdata$")) continue; const coff_section *PData = Ctx.COFF.getCOFFSection(Section); ArrayRef<uint8_t> Contents; error(Ctx.COFF.getSectionContents(PData, Contents)); if (Contents.empty()) continue; const RuntimeFunction *Entries = reinterpret_cast<const RuntimeFunction *>(Contents.data()); const size_t Count = Contents.size() / sizeof(RuntimeFunction); ArrayRef<RuntimeFunction> RuntimeFunctions(Entries, Count); size_t Index = 0; for (const auto &RF : RuntimeFunctions) { printRuntimeFunction(Ctx, Ctx.COFF.getCOFFSection(Section), Index * sizeof(RuntimeFunction), RF); ++Index; } } }
// 伸長 std::vector<byte> uncompress(ArrayRef<byte> src, size_t uncompSize) { // データを格納するバッファの確保 std::vector<byte> data; data.resize(uncompSize); // 初期化 z_stream zs = {}; zs.next_in = const_cast<byte*>(src.data()); // データは書き換えられない zs.avail_in = static_cast<uInt>(src.size()); zs.next_out = &data[0]; zs.avail_out = data.size(); if(inflateInit2(&zs, -MAX_WBITS)) BELL_THROW(DeflateError, "Failed to initialize uncompress stream."); // 伸長 int res = inflate(&zs, Z_FINISH); data.resize(zs.total_out); inflateEnd(&zs); if(res != Z_STREAM_END) BELL_THROW(DeflateError, "Failed to uncompress."); return data; }
// 圧縮 std::vector<byte> compress(ArrayRef<byte> src, int level) { // レベルを[1, 9]にクリップ level = clamp(level, 1, 9); // データを格納するバッファの確保 std::vector<byte> data; data.resize(compressBound(static_cast<uLong>(src.size()))); // 初期化 z_stream zs = {}; zs.next_in = const_cast<byte*>(src.data()); // データは書き換えられない zs.avail_in = static_cast<uInt>(src.size()); zs.next_out = &data[0]; zs.avail_out = data.size(); if(deflateInit2(&zs, level, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY)) BELL_THROW(DeflateError, "Failed to initialize compress stream."); // 圧縮 int res = ::deflate(&zs, Z_FINISH); data.resize(zs.total_out); // 片付け deflateEnd(&zs); if(res != Z_STREAM_END) BELL_THROW(DeflateError, "Failed to compress."); return data; }
static std::error_code getSymbolAuxData(const COFFObjectFile *Obj, const coff_symbol *Symbol, const T *&Aux) { ArrayRef<uint8_t> AuxData = Obj->getSymbolAuxData(Symbol); Aux = reinterpret_cast<const T*>(AuxData.data()); return readobj_error::success; }
void MappedBlockStream::fixCacheAfterWrite(uint32_t Offset, ArrayRef<uint8_t> Data) const { // If this write overlapped a read which previously came from the pool, // someone may still be holding a pointer to that alloc which is now invalid. // Compute the overlapping range and update the cache entry, so any // outstanding buffers are automatically updated. for (const auto &MapEntry : CacheMap) { // If the end of the written extent precedes the beginning of the cached // extent, ignore this map entry. if (Offset + Data.size() < MapEntry.first) continue; for (const auto &Alloc : MapEntry.second) { // If the end of the cached extent precedes the beginning of the written // extent, ignore this alloc. if (MapEntry.first + Alloc.size() < Offset) continue; // If we get here, they are guaranteed to overlap. Interval WriteInterval = std::make_pair(Offset, Offset + Data.size()); Interval CachedInterval = std::make_pair(MapEntry.first, MapEntry.first + Alloc.size()); // If they overlap, we need to write the new data into the overlapping // range. auto Intersection = intersect(WriteInterval, CachedInterval); assert(Intersection.first <= Intersection.second); uint32_t Length = Intersection.second - Intersection.first; uint32_t SrcOffset = AbsoluteDifference(WriteInterval.first, Intersection.first); uint32_t DestOffset = AbsoluteDifference(CachedInterval.first, Intersection.first); ::memcpy(Alloc.data() + DestOffset, Data.data() + SrcOffset, Length); } } }
Error MappedBlockStream::readBytes(uint32_t Offset, MutableArrayRef<uint8_t> Buffer) const { uint32_t BlockNum = Offset / BlockSize; uint32_t OffsetInBlock = Offset % BlockSize; // Make sure we aren't trying to read beyond the end of the stream. if (Buffer.size() > StreamLayout.Length) return make_error<MSFError>(msf_error_code::insufficient_buffer); if (Offset > StreamLayout.Length - Buffer.size()) return make_error<MSFError>(msf_error_code::insufficient_buffer); uint32_t BytesLeft = Buffer.size(); uint32_t BytesWritten = 0; uint8_t *WriteBuffer = Buffer.data(); while (BytesLeft > 0) { uint32_t StreamBlockAddr = StreamLayout.Blocks[BlockNum]; ArrayRef<uint8_t> BlockData; uint32_t Offset = blockToOffset(StreamBlockAddr, BlockSize); if (auto EC = MsfData.readBytes(Offset, BlockSize, BlockData)) return EC; const uint8_t *ChunkStart = BlockData.data() + OffsetInBlock; uint32_t BytesInChunk = std::min(BytesLeft, BlockSize - OffsetInBlock); ::memcpy(WriteBuffer + BytesWritten, ChunkStart, BytesInChunk); BytesWritten += BytesInChunk; BytesLeft -= BytesInChunk; ++BlockNum; OffsetInBlock = 0; } return Error::success(); }
// Given the COFF object file, this function returns the relocations for .pdata // and the pointer to "runtime function" structs. static bool getPDataSection(const COFFObjectFile *Obj, std::vector<RelocationRef> &Rels, const RuntimeFunction *&RFStart, int &NumRFs) { for (const SectionRef &Section : Obj->sections()) { StringRef Name; error(Section.getName(Name)); if (Name != ".pdata") continue; const coff_section *Pdata = Obj->getCOFFSection(Section); for (const RelocationRef &Reloc : Section.relocations()) Rels.push_back(Reloc); // Sort relocations by address. std::sort(Rels.begin(), Rels.end(), RelocAddressLess); ArrayRef<uint8_t> Contents; error(Obj->getSectionContents(Pdata, Contents)); if (Contents.empty()) continue; RFStart = reinterpret_cast<const RuntimeFunction *>(Contents.data()); NumRFs = Contents.size() / sizeof(RuntimeFunction); return true; } return false; }
void ObjectFile::initializeChunks() { uint32_t NumSections = COFFObj->getNumberOfSections(); Chunks.reserve(NumSections); SparseChunks.resize(NumSections + 1); for (uint32_t I = 1; I < NumSections + 1; ++I) { const coff_section *Sec; StringRef Name; std::error_code EC = COFFObj->getSection(I, Sec); error(EC, Twine("getSection failed: ") + Name); EC = COFFObj->getSectionName(Sec, Name); error(EC, Twine("getSectionName failed: ") + Name); if (Name == ".sxdata") { SXData = Sec; continue; } if (Name == ".drectve") { ArrayRef<uint8_t> Data; COFFObj->getSectionContents(Sec, Data); Directives = std::string((const char *)Data.data(), Data.size()); continue; } // Skip non-DWARF debug info. MSVC linker converts the sections into // a PDB file, but we don't support that. if (Name == ".debug" || Name.startswith(".debug$")) continue; // We want to preserve DWARF debug sections only when /debug is on. if (!Config->Debug && Name.startswith(".debug")) continue; if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE) continue; auto *C = new (Alloc) SectionChunk(this, Sec); Chunks.push_back(C); SparseChunks[I] = C; } }
void printSymbolVersionDefinition(const typename ELFT::Shdr &Shdr, ArrayRef<uint8_t> Contents, StringRef StrTab) { outs() << "Version definitions:\n"; const uint8_t *Buf = Contents.data(); uint32_t VerdefIndex = 1; // sh_info contains the number of entries in the SHT_GNU_verdef section. To // make the index column have consistent width, we should insert blank spaces // according to sh_info. uint16_t VerdefIndexWidth = std::to_string(Shdr.sh_info).size(); while (Buf) { auto *Verdef = reinterpret_cast<const typename ELFT::Verdef *>(Buf); outs() << format_decimal(VerdefIndex++, VerdefIndexWidth) << " " << format("0x%02" PRIx16 " ", (uint16_t)Verdef->vd_flags) << format("0x%08" PRIx32 " ", (uint32_t)Verdef->vd_hash); const uint8_t *BufAux = Buf + Verdef->vd_aux; uint16_t VerdauxIndex = 0; while (BufAux) { auto *Verdaux = reinterpret_cast<const typename ELFT::Verdaux *>(BufAux); if (VerdauxIndex) outs() << std::string(VerdefIndexWidth + 17, ' '); outs() << StringRef(StrTab.drop_front(Verdaux->vda_name).data()) << '\n'; BufAux = Verdaux->vda_next ? BufAux + Verdaux->vda_next : nullptr; ++VerdauxIndex; } Buf = Verdef->vd_next ? Buf + Verdef->vd_next : nullptr; } }
static void handleMethodOverloadList(ArrayRef<uint8_t> Content, SmallVectorImpl<TiReference> &Refs) { uint32_t Offset = 0; while (!Content.empty()) { // Array of: // 0: Attrs // 2: Padding // 4: TypeIndex // if (isIntroVirtual()) // 8: VFTableOffset // At least 8 bytes are guaranteed. 4 extra bytes come iff function is an // intro virtual. uint32_t Len = 8; uint16_t Attrs = support::endian::read16le(Content.data()); Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1}); if (LLVM_UNLIKELY(isIntroVirtual(Attrs))) Len += 4; Offset += Len; Content = Content.drop_front(Len); } }
Error MappedBlockStream::readLongestContiguousChunk( uint32_t Offset, ArrayRef<uint8_t> &Buffer) const { // Make sure we aren't trying to read beyond the end of the stream. if (Offset >= Data->getLength()) return make_error<RawError>(raw_error_code::insufficient_buffer); uint32_t First = Offset / Pdb.getBlockSize(); uint32_t Last = First; auto BlockList = Data->getStreamBlocks(); while (Last < Pdb.getBlockCount() - 1) { if (BlockList[Last] != BlockList[Last + 1] - 1) break; ++Last; } uint32_t OffsetInFirstBlock = Offset % Pdb.getBlockSize(); uint32_t BytesFromFirstBlock = Pdb.getBlockSize() - OffsetInFirstBlock; uint32_t BlockSpan = Last - First + 1; uint32_t ByteSpan = BytesFromFirstBlock + (BlockSpan - 1) * Pdb.getBlockSize(); Buffer = Pdb.getBlockData(BlockList[First], Pdb.getBlockSize()); Buffer = Buffer.drop_front(OffsetInFirstBlock); Buffer = ArrayRef<uint8_t>(Buffer.data(), ByteSpan); return Error::success(); }
DelayedDiagnostic DelayedDiagnostic::makeAvailability(AvailabilityResult AR, ArrayRef<SourceLocation> Locs, const NamedDecl *ReferringDecl, const NamedDecl *OffendingDecl, const ObjCInterfaceDecl *UnknownObjCClass, const ObjCPropertyDecl *ObjCProperty, StringRef Msg, bool ObjCPropertyAccess) { assert(!Locs.empty()); DelayedDiagnostic DD; DD.Kind = Availability; DD.Triggered = false; DD.Loc = Locs.front(); DD.AvailabilityData.ReferringDecl = ReferringDecl; DD.AvailabilityData.OffendingDecl = OffendingDecl; DD.AvailabilityData.UnknownObjCClass = UnknownObjCClass; DD.AvailabilityData.ObjCProperty = ObjCProperty; char *MessageData = nullptr; if (!Msg.empty()) { MessageData = new char [Msg.size()]; memcpy(MessageData, Msg.data(), Msg.size()); } DD.AvailabilityData.Message = MessageData; DD.AvailabilityData.MessageLen = Msg.size(); DD.AvailabilityData.SelectorLocs = new SourceLocation[Locs.size()]; memcpy(DD.AvailabilityData.SelectorLocs, Locs.data(), sizeof(SourceLocation) * Locs.size()); DD.AvailabilityData.NumSelectorLocs = Locs.size(); DD.AvailabilityData.AR = AR; DD.AvailabilityData.ObjCPropertyAccess = ObjCPropertyAccess; return DD; }
void llvm::codeview::discoverTypeIndices(ArrayRef<uint8_t> RecordData, SmallVectorImpl<TiReference> &Refs) { const RecordPrefix *P = reinterpret_cast<const RecordPrefix *>(RecordData.data()); TypeLeafKind K = static_cast<TypeLeafKind>(uint16_t(P->RecordKind)); ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K, Refs); }
// When directly dumping the .debug_loc without a compile unit, we have to guess // at the DWARF version. This only affects DW_OP_call_ref, which is a rare // expression that LLVM doesn't produce. Guessing the wrong version means we // won't be able to pretty print expressions in DWARF2 binaries produced by // non-LLVM tools. static void dumpExpression(raw_ostream &OS, ArrayRef<char> Data, bool IsLittleEndian, unsigned AddressSize, const MCRegisterInfo *MRI) { DWARFDataExtractor Extractor(StringRef(Data.data(), Data.size()), IsLittleEndian, AddressSize); DWARFExpression(Extractor, AddressSize, dwarf::DWARF_VERSION).print(OS, MRI); }
static void writeWithCommas(raw_ostream &S, ArrayRef<char> Buffer) { assert(!Buffer.empty()); ArrayRef<char> ThisGroup; int InitialDigits = ((Buffer.size() - 1) % 3) + 1; ThisGroup = Buffer.take_front(InitialDigits); S.write(ThisGroup.data(), ThisGroup.size()); Buffer = Buffer.drop_front(InitialDigits); assert(Buffer.size() % 3 == 0); while (!Buffer.empty()) { S << ','; ThisGroup = Buffer.take_front(3); S.write(ThisGroup.data(), 3); Buffer = Buffer.drop_front(3); } }
static std::error_code getSymbolAuxData(const COFFObjectFile *Obj, COFFSymbolRef Symbol, uint8_t AuxSymbolIdx, const T *&Aux) { ArrayRef<uint8_t> AuxData = Obj->getSymbolAuxData(Symbol); AuxData = AuxData.slice(AuxSymbolIdx * Obj->getSymbolTableEntrySize()); Aux = reinterpret_cast<const T*>(AuxData.data()); return readobj_error::success; }
BraceStmt::BraceStmt(SourceLoc lbloc, ArrayRef<ASTNode> elts, SourceLoc rbloc, Optional<bool> implicit) : Stmt(StmtKind::Brace, getDefaultImplicitFlag(implicit, lbloc)), NumElements(elts.size()), LBLoc(lbloc), RBLoc(rbloc) { memcpy(getElementsStorage(), elts.data(), elts.size() * sizeof(ASTNode)); }
std::error_code COFFObjectFile::getSectionContents(DataRefImpl Ref, StringRef &Result) const { const coff_section *Sec = toSec(Ref); ArrayRef<uint8_t> Res; std::error_code EC = getSectionContents(Sec, Res); Result = StringRef(reinterpret_cast<const char*>(Res.data()), Res.size()); return EC; }
void ARMAttributeParser::Parse(ArrayRef<uint8_t> Section) { size_t Offset = 1; unsigned SectionNumber = 0; while (Offset < Section.size()) { uint32_t SectionLength = *reinterpret_cast<const support::ulittle32_t*>(Section.data() + Offset); SW.startLine() << "Section " << ++SectionNumber << " {\n"; SW.indent(); ParseSubsection(Section.data() + Offset, SectionLength); Offset = Offset + SectionLength; SW.unindent(); SW.startLine() << "}\n"; } }
static ArrayRef<uint8_t> consumeDebugMagic(ArrayRef<uint8_t> Data, StringRef SecName) { // First 4 bytes are section magic. if (Data.size() < 4) fatal(SecName + " too short"); if (support::endian::read32le(Data.data()) != COFF::DEBUG_SECTION_MAGIC) fatal(SecName + " has an invalid magic"); return Data.slice(4); }
void APValue::MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember, ArrayRef<const CXXRecordDecl*> Path) { assert(isUninit() && "Bad state change"); MemberPointerData *MPD = new ((void*)(char*)Data.buffer) MemberPointerData; Kind = MemberPointer; MPD->MemberAndIsDerivedMember.setPointer(Member); MPD->MemberAndIsDerivedMember.setInt(IsDerivedMember); MPD->resizePath(Path.size()); memcpy(MPD->getPath(), Path.data(), Path.size()*sizeof(const CXXRecordDecl*)); }
static Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Src, MutableArrayRef<uint8_t> Dest) { if (Dest.size() < Src.size()) return make_error<CodeViewError>(cv_error_code::insufficient_buffer); if (Offset > Src.size() - Dest.size()) return make_error<CodeViewError>(cv_error_code::insufficient_buffer); ::memcpy(Dest.data() + Offset, Src.data(), Src.size()); return Error::success(); }