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