1a580b014SDimitry Andric //===- DebugChecksumsSubsection.cpp ---------------------------------------===//
289cb50c9SDimitry Andric //
389cb50c9SDimitry Andric // The LLVM Compiler Infrastructure
489cb50c9SDimitry Andric //
589cb50c9SDimitry Andric // This file is distributed under the University of Illinois Open Source
689cb50c9SDimitry Andric // License. See LICENSE.TXT for details.
789cb50c9SDimitry Andric //
889cb50c9SDimitry Andric //===----------------------------------------------------------------------===//
989cb50c9SDimitry Andric
1089cb50c9SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
11a580b014SDimitry Andric #include "llvm/ADT/ArrayRef.h"
12a580b014SDimitry Andric #include "llvm/DebugInfo/CodeView/CodeView.h"
1389cb50c9SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
1489cb50c9SDimitry Andric #include "llvm/Support/BinaryStreamReader.h"
15a580b014SDimitry Andric #include "llvm/Support/BinaryStreamWriter.h"
16a580b014SDimitry Andric #include "llvm/Support/Endian.h"
17a580b014SDimitry Andric #include "llvm/Support/Error.h"
18a580b014SDimitry Andric #include "llvm/Support/MathExtras.h"
19a580b014SDimitry Andric #include <cassert>
20a580b014SDimitry Andric #include <cstdint>
21a580b014SDimitry Andric #include <cstring>
2289cb50c9SDimitry Andric
2389cb50c9SDimitry Andric using namespace llvm;
2489cb50c9SDimitry Andric using namespace llvm::codeview;
2589cb50c9SDimitry Andric
2689cb50c9SDimitry Andric struct FileChecksumEntryHeader {
2789cb50c9SDimitry Andric using ulittle32_t = support::ulittle32_t;
2889cb50c9SDimitry Andric
2989cb50c9SDimitry Andric ulittle32_t FileNameOffset; // Byte offset of filename in global string table.
3089cb50c9SDimitry Andric uint8_t ChecksumSize; // Number of bytes of checksum.
3189cb50c9SDimitry Andric uint8_t ChecksumKind; // FileChecksumKind
3289cb50c9SDimitry Andric // Checksum bytes follow.
3389cb50c9SDimitry Andric };
3489cb50c9SDimitry Andric
35a580b014SDimitry Andric Error VarStreamArrayExtractor<FileChecksumEntry>::
operator ()(BinaryStreamRef Stream,uint32_t & Len,FileChecksumEntry & Item)36db17bf38SDimitry Andric operator()(BinaryStreamRef Stream, uint32_t &Len, FileChecksumEntry &Item) {
3789cb50c9SDimitry Andric BinaryStreamReader Reader(Stream);
3889cb50c9SDimitry Andric
3989cb50c9SDimitry Andric const FileChecksumEntryHeader *Header;
4089cb50c9SDimitry Andric if (auto EC = Reader.readObject(Header))
4189cb50c9SDimitry Andric return EC;
4289cb50c9SDimitry Andric
4389cb50c9SDimitry Andric Item.FileNameOffset = Header->FileNameOffset;
4489cb50c9SDimitry Andric Item.Kind = static_cast<FileChecksumKind>(Header->ChecksumKind);
4589cb50c9SDimitry Andric if (auto EC = Reader.readBytes(Item.Checksum, Header->ChecksumSize))
4689cb50c9SDimitry Andric return EC;
4789cb50c9SDimitry Andric
4889cb50c9SDimitry Andric Len = alignTo(Header->ChecksumSize + sizeof(FileChecksumEntryHeader), 4);
4989cb50c9SDimitry Andric return Error::success();
5089cb50c9SDimitry Andric }
5189cb50c9SDimitry Andric
initialize(BinaryStreamReader Reader)5289cb50c9SDimitry Andric Error DebugChecksumsSubsectionRef::initialize(BinaryStreamReader Reader) {
5389cb50c9SDimitry Andric if (auto EC = Reader.readArray(Checksums, Reader.bytesRemaining()))
5489cb50c9SDimitry Andric return EC;
5589cb50c9SDimitry Andric
5689cb50c9SDimitry Andric return Error::success();
5789cb50c9SDimitry Andric }
58a580b014SDimitry Andric
initialize(BinaryStreamRef Section)5989cb50c9SDimitry Andric Error DebugChecksumsSubsectionRef::initialize(BinaryStreamRef Section) {
6089cb50c9SDimitry Andric BinaryStreamReader Reader(Section);
6189cb50c9SDimitry Andric return initialize(Reader);
6289cb50c9SDimitry Andric }
6389cb50c9SDimitry Andric
DebugChecksumsSubsection(DebugStringTableSubsection & Strings)6489cb50c9SDimitry Andric DebugChecksumsSubsection::DebugChecksumsSubsection(
6589cb50c9SDimitry Andric DebugStringTableSubsection &Strings)
6689cb50c9SDimitry Andric : DebugSubsection(DebugSubsectionKind::FileChecksums), Strings(Strings) {}
6789cb50c9SDimitry Andric
addChecksum(StringRef FileName,FileChecksumKind Kind,ArrayRef<uint8_t> Bytes)6889cb50c9SDimitry Andric void DebugChecksumsSubsection::addChecksum(StringRef FileName,
6989cb50c9SDimitry Andric FileChecksumKind Kind,
7089cb50c9SDimitry Andric ArrayRef<uint8_t> Bytes) {
7189cb50c9SDimitry Andric FileChecksumEntry Entry;
7289cb50c9SDimitry Andric if (!Bytes.empty()) {
7389cb50c9SDimitry Andric uint8_t *Copy = Storage.Allocate<uint8_t>(Bytes.size());
7489cb50c9SDimitry Andric ::memcpy(Copy, Bytes.data(), Bytes.size());
7589cb50c9SDimitry Andric Entry.Checksum = makeArrayRef(Copy, Bytes.size());
7689cb50c9SDimitry Andric }
7789cb50c9SDimitry Andric
7889cb50c9SDimitry Andric Entry.FileNameOffset = Strings.insert(FileName);
7989cb50c9SDimitry Andric Entry.Kind = Kind;
8089cb50c9SDimitry Andric Checksums.push_back(Entry);
8189cb50c9SDimitry Andric
8289cb50c9SDimitry Andric // This maps the offset of this string in the string table to the offset
8389cb50c9SDimitry Andric // of this checksum entry in the checksum buffer.
8489cb50c9SDimitry Andric OffsetMap[Entry.FileNameOffset] = SerializedSize;
8589cb50c9SDimitry Andric assert(SerializedSize % 4 == 0);
8689cb50c9SDimitry Andric
8789cb50c9SDimitry Andric uint32_t Len = alignTo(sizeof(FileChecksumEntryHeader) + Bytes.size(), 4);
8889cb50c9SDimitry Andric SerializedSize += Len;
8989cb50c9SDimitry Andric }
9089cb50c9SDimitry Andric
calculateSerializedSize() const9189cb50c9SDimitry Andric uint32_t DebugChecksumsSubsection::calculateSerializedSize() const {
9289cb50c9SDimitry Andric return SerializedSize;
9389cb50c9SDimitry Andric }
9489cb50c9SDimitry Andric
commit(BinaryStreamWriter & Writer) const9589cb50c9SDimitry Andric Error DebugChecksumsSubsection::commit(BinaryStreamWriter &Writer) const {
9689cb50c9SDimitry Andric for (const auto &FC : Checksums) {
9789cb50c9SDimitry Andric FileChecksumEntryHeader Header;
9889cb50c9SDimitry Andric Header.ChecksumKind = uint8_t(FC.Kind);
9989cb50c9SDimitry Andric Header.ChecksumSize = FC.Checksum.size();
10089cb50c9SDimitry Andric Header.FileNameOffset = FC.FileNameOffset;
10189cb50c9SDimitry Andric if (auto EC = Writer.writeObject(Header))
10289cb50c9SDimitry Andric return EC;
10389cb50c9SDimitry Andric if (auto EC = Writer.writeArray(makeArrayRef(FC.Checksum)))
10489cb50c9SDimitry Andric return EC;
10589cb50c9SDimitry Andric if (auto EC = Writer.padToAlignment(4))
10689cb50c9SDimitry Andric return EC;
10789cb50c9SDimitry Andric }
10889cb50c9SDimitry Andric return Error::success();
10989cb50c9SDimitry Andric }
11089cb50c9SDimitry Andric
mapChecksumOffset(StringRef FileName) const11189cb50c9SDimitry Andric uint32_t DebugChecksumsSubsection::mapChecksumOffset(StringRef FileName) const {
112*4ba319b5SDimitry Andric uint32_t Offset = Strings.getIdForString(FileName);
11389cb50c9SDimitry Andric auto Iter = OffsetMap.find(Offset);
11489cb50c9SDimitry Andric assert(Iter != OffsetMap.end());
11589cb50c9SDimitry Andric return Iter->second;
11689cb50c9SDimitry Andric }
117