116 lines · cpp
1//===- DebugChecksumsSubsection.cpp ---------------------------------------===//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#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"10#include "llvm/ADT/ArrayRef.h"11#include "llvm/DebugInfo/CodeView/CodeView.h"12#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"13#include "llvm/Support/BinaryStreamReader.h"14#include "llvm/Support/BinaryStreamWriter.h"15#include "llvm/Support/Endian.h"16#include "llvm/Support/Error.h"17#include "llvm/Support/MathExtras.h"18#include <cassert>19#include <cstdint>20#include <cstring>21 22using namespace llvm;23using namespace llvm::codeview;24 25struct FileChecksumEntryHeader {26 using ulittle32_t = support::ulittle32_t;27 28 ulittle32_t FileNameOffset; // Byte offset of filename in global string table.29 uint8_t ChecksumSize; // Number of bytes of checksum.30 uint8_t ChecksumKind; // FileChecksumKind31 // Checksum bytes follow.32};33 34Error VarStreamArrayExtractor<FileChecksumEntry>::35operator()(BinaryStreamRef Stream, uint32_t &Len, FileChecksumEntry &Item) {36 BinaryStreamReader Reader(Stream);37 38 const FileChecksumEntryHeader *Header;39 if (auto EC = Reader.readObject(Header))40 return EC;41 42 Item.FileNameOffset = Header->FileNameOffset;43 Item.Kind = static_cast<FileChecksumKind>(Header->ChecksumKind);44 if (auto EC = Reader.readBytes(Item.Checksum, Header->ChecksumSize))45 return EC;46 47 Len = alignTo(Header->ChecksumSize + sizeof(FileChecksumEntryHeader), 4);48 return Error::success();49}50 51Error DebugChecksumsSubsectionRef::initialize(BinaryStreamReader Reader) {52 if (auto EC = Reader.readArray(Checksums, Reader.bytesRemaining()))53 return EC;54 55 return Error::success();56}57 58Error DebugChecksumsSubsectionRef::initialize(BinaryStreamRef Section) {59 BinaryStreamReader Reader(Section);60 return initialize(Reader);61}62 63DebugChecksumsSubsection::DebugChecksumsSubsection(64 DebugStringTableSubsection &Strings)65 : DebugSubsection(DebugSubsectionKind::FileChecksums), Strings(Strings) {}66 67void DebugChecksumsSubsection::addChecksum(StringRef FileName,68 FileChecksumKind Kind,69 ArrayRef<uint8_t> Bytes) {70 FileChecksumEntry Entry;71 if (!Bytes.empty()) {72 uint8_t *Copy = Storage.Allocate<uint8_t>(Bytes.size());73 ::memcpy(Copy, Bytes.data(), Bytes.size());74 Entry.Checksum = ArrayRef(Copy, Bytes.size());75 }76 77 Entry.FileNameOffset = Strings.insert(FileName);78 Entry.Kind = Kind;79 Checksums.push_back(Entry);80 81 // This maps the offset of this string in the string table to the offset82 // of this checksum entry in the checksum buffer.83 OffsetMap[Entry.FileNameOffset] = SerializedSize;84 assert(SerializedSize % 4 == 0);85 86 uint32_t Len = alignTo(sizeof(FileChecksumEntryHeader) + Bytes.size(), 4);87 SerializedSize += Len;88}89 90uint32_t DebugChecksumsSubsection::calculateSerializedSize() const {91 return SerializedSize;92}93 94Error DebugChecksumsSubsection::commit(BinaryStreamWriter &Writer) const {95 for (const auto &FC : Checksums) {96 FileChecksumEntryHeader Header;97 Header.ChecksumKind = uint8_t(FC.Kind);98 Header.ChecksumSize = FC.Checksum.size();99 Header.FileNameOffset = FC.FileNameOffset;100 if (auto EC = Writer.writeObject(Header))101 return EC;102 if (auto EC = Writer.writeArray(ArrayRef(FC.Checksum)))103 return EC;104 if (auto EC = Writer.padToAlignment(4))105 return EC;106 }107 return Error::success();108}109 110uint32_t DebugChecksumsSubsection::mapChecksumOffset(StringRef FileName) const {111 uint32_t Offset = Strings.getIdForString(FileName);112 auto Iter = OffsetMap.find(Offset);113 assert(Iter != OffsetMap.end());114 return Iter->second;115}116