189cb50c9SDimitry Andric //===- DebugChecksumsSubsection.cpp ----------------------*- C++ -*-===//
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"
1189cb50c9SDimitry Andric 
1289cb50c9SDimitry Andric #include "llvm/DebugInfo/CodeView/CodeViewError.h"
1389cb50c9SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
1489cb50c9SDimitry Andric #include "llvm/Support/BinaryStreamReader.h"
1589cb50c9SDimitry Andric 
1689cb50c9SDimitry Andric using namespace llvm;
1789cb50c9SDimitry Andric using namespace llvm::codeview;
1889cb50c9SDimitry Andric 
1989cb50c9SDimitry Andric struct FileChecksumEntryHeader {
2089cb50c9SDimitry Andric   using ulittle32_t = support::ulittle32_t;
2189cb50c9SDimitry Andric 
2289cb50c9SDimitry Andric   ulittle32_t FileNameOffset; // Byte offset of filename in global string table.
2389cb50c9SDimitry Andric   uint8_t ChecksumSize;       // Number of bytes of checksum.
2489cb50c9SDimitry Andric   uint8_t ChecksumKind;       // FileChecksumKind
2589cb50c9SDimitry Andric                               // Checksum bytes follow.
2689cb50c9SDimitry Andric };
2789cb50c9SDimitry Andric 
28db17bf38SDimitry Andric Error llvm::VarStreamArrayExtractor<FileChecksumEntry>::
29db17bf38SDimitry Andric operator()(BinaryStreamRef Stream, uint32_t &Len, FileChecksumEntry &Item) {
3089cb50c9SDimitry Andric   BinaryStreamReader Reader(Stream);
3189cb50c9SDimitry Andric 
3289cb50c9SDimitry Andric   const FileChecksumEntryHeader *Header;
3389cb50c9SDimitry Andric   if (auto EC = Reader.readObject(Header))
3489cb50c9SDimitry Andric     return EC;
3589cb50c9SDimitry Andric 
3689cb50c9SDimitry Andric   Item.FileNameOffset = Header->FileNameOffset;
3789cb50c9SDimitry Andric   Item.Kind = static_cast<FileChecksumKind>(Header->ChecksumKind);
3889cb50c9SDimitry Andric   if (auto EC = Reader.readBytes(Item.Checksum, Header->ChecksumSize))
3989cb50c9SDimitry Andric     return EC;
4089cb50c9SDimitry Andric 
4189cb50c9SDimitry Andric   Len = alignTo(Header->ChecksumSize + sizeof(FileChecksumEntryHeader), 4);
4289cb50c9SDimitry Andric   return Error::success();
4389cb50c9SDimitry Andric }
4489cb50c9SDimitry Andric 
4589cb50c9SDimitry Andric Error DebugChecksumsSubsectionRef::initialize(BinaryStreamReader Reader) {
4689cb50c9SDimitry Andric   if (auto EC = Reader.readArray(Checksums, Reader.bytesRemaining()))
4789cb50c9SDimitry Andric     return EC;
4889cb50c9SDimitry Andric 
4989cb50c9SDimitry Andric   return Error::success();
5089cb50c9SDimitry Andric }
5189cb50c9SDimitry Andric Error DebugChecksumsSubsectionRef::initialize(BinaryStreamRef Section) {
5289cb50c9SDimitry Andric   BinaryStreamReader Reader(Section);
5389cb50c9SDimitry Andric   return initialize(Reader);
5489cb50c9SDimitry Andric }
5589cb50c9SDimitry Andric 
5689cb50c9SDimitry Andric DebugChecksumsSubsection::DebugChecksumsSubsection(
5789cb50c9SDimitry Andric     DebugStringTableSubsection &Strings)
5889cb50c9SDimitry Andric     : DebugSubsection(DebugSubsectionKind::FileChecksums), Strings(Strings) {}
5989cb50c9SDimitry Andric 
6089cb50c9SDimitry Andric void DebugChecksumsSubsection::addChecksum(StringRef FileName,
6189cb50c9SDimitry Andric                                            FileChecksumKind Kind,
6289cb50c9SDimitry Andric                                            ArrayRef<uint8_t> Bytes) {
6389cb50c9SDimitry Andric   FileChecksumEntry Entry;
6489cb50c9SDimitry Andric   if (!Bytes.empty()) {
6589cb50c9SDimitry Andric     uint8_t *Copy = Storage.Allocate<uint8_t>(Bytes.size());
6689cb50c9SDimitry Andric     ::memcpy(Copy, Bytes.data(), Bytes.size());
6789cb50c9SDimitry Andric     Entry.Checksum = makeArrayRef(Copy, Bytes.size());
6889cb50c9SDimitry Andric   }
6989cb50c9SDimitry Andric 
7089cb50c9SDimitry Andric   Entry.FileNameOffset = Strings.insert(FileName);
7189cb50c9SDimitry Andric   Entry.Kind = Kind;
7289cb50c9SDimitry Andric   Checksums.push_back(Entry);
7389cb50c9SDimitry Andric 
7489cb50c9SDimitry Andric   // This maps the offset of this string in the string table to the offset
7589cb50c9SDimitry Andric   // of this checksum entry in the checksum buffer.
7689cb50c9SDimitry Andric   OffsetMap[Entry.FileNameOffset] = SerializedSize;
7789cb50c9SDimitry Andric   assert(SerializedSize % 4 == 0);
7889cb50c9SDimitry Andric 
7989cb50c9SDimitry Andric   uint32_t Len = alignTo(sizeof(FileChecksumEntryHeader) + Bytes.size(), 4);
8089cb50c9SDimitry Andric   SerializedSize += Len;
8189cb50c9SDimitry Andric }
8289cb50c9SDimitry Andric 
8389cb50c9SDimitry Andric uint32_t DebugChecksumsSubsection::calculateSerializedSize() const {
8489cb50c9SDimitry Andric   return SerializedSize;
8589cb50c9SDimitry Andric }
8689cb50c9SDimitry Andric 
8789cb50c9SDimitry Andric Error DebugChecksumsSubsection::commit(BinaryStreamWriter &Writer) const {
8889cb50c9SDimitry Andric   for (const auto &FC : Checksums) {
8989cb50c9SDimitry Andric     FileChecksumEntryHeader Header;
9089cb50c9SDimitry Andric     Header.ChecksumKind = uint8_t(FC.Kind);
9189cb50c9SDimitry Andric     Header.ChecksumSize = FC.Checksum.size();
9289cb50c9SDimitry Andric     Header.FileNameOffset = FC.FileNameOffset;
9389cb50c9SDimitry Andric     if (auto EC = Writer.writeObject(Header))
9489cb50c9SDimitry Andric       return EC;
9589cb50c9SDimitry Andric     if (auto EC = Writer.writeArray(makeArrayRef(FC.Checksum)))
9689cb50c9SDimitry Andric       return EC;
9789cb50c9SDimitry Andric     if (auto EC = Writer.padToAlignment(4))
9889cb50c9SDimitry Andric       return EC;
9989cb50c9SDimitry Andric   }
10089cb50c9SDimitry Andric   return Error::success();
10189cb50c9SDimitry Andric }
10289cb50c9SDimitry Andric 
10389cb50c9SDimitry Andric uint32_t DebugChecksumsSubsection::mapChecksumOffset(StringRef FileName) const {
10489cb50c9SDimitry Andric   uint32_t Offset = Strings.getStringId(FileName);
10589cb50c9SDimitry Andric   auto Iter = OffsetMap.find(Offset);
10689cb50c9SDimitry Andric   assert(Iter != OffsetMap.end());
10789cb50c9SDimitry Andric   return Iter->second;
10889cb50c9SDimitry Andric }
109