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-exception 6 // 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 22 using namespace llvm; 23 using namespace llvm::codeview; 24 25 struct 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; // FileChecksumKind 31 // Checksum bytes follow. 32 }; 33 34 Error VarStreamArrayExtractor<FileChecksumEntry>:: 35 operator()(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 51 Error DebugChecksumsSubsectionRef::initialize(BinaryStreamReader Reader) { 52 if (auto EC = Reader.readArray(Checksums, Reader.bytesRemaining())) 53 return EC; 54 55 return Error::success(); 56 } 57 58 Error DebugChecksumsSubsectionRef::initialize(BinaryStreamRef Section) { 59 BinaryStreamReader Reader(Section); 60 return initialize(Reader); 61 } 62 63 DebugChecksumsSubsection::DebugChecksumsSubsection( 64 DebugStringTableSubsection &Strings) 65 : DebugSubsection(DebugSubsectionKind::FileChecksums), Strings(Strings) {} 66 67 void 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 = makeArrayRef(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 offset 82 // 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 90 uint32_t DebugChecksumsSubsection::calculateSerializedSize() const { 91 return SerializedSize; 92 } 93 94 Error 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(makeArrayRef(FC.Checksum))) 103 return EC; 104 if (auto EC = Writer.padToAlignment(4)) 105 return EC; 106 } 107 return Error::success(); 108 } 109 110 uint32_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