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 { |
26 | using = support::ulittle32_t; |
27 | |
28 | ulittle32_t ; // Byte offset of filename in global string table. |
29 | uint8_t ; // Number of bytes of checksum. |
30 | uint8_t ; // FileChecksumKind |
31 | // Checksum bytes follow. |
32 | }; |
33 | |
34 | Error VarStreamArrayExtractor<FileChecksumEntry>:: |
35 | (BinaryStreamRef Stream, uint32_t &Len, FileChecksumEntry &Item) { |
36 | BinaryStreamReader Reader(Stream); |
37 | |
38 | const FileChecksumEntryHeader *; |
39 | if (auto EC = Reader.readObject(Dest&: Header)) |
40 | return EC; |
41 | |
42 | Item.FileNameOffset = Header->FileNameOffset; |
43 | Item.Kind = static_cast<FileChecksumKind>(Header->ChecksumKind); |
44 | if (auto EC = Reader.readBytes(Buffer&: Item.Checksum, Size: Header->ChecksumSize)) |
45 | return EC; |
46 | |
47 | Len = alignTo(Value: Header->ChecksumSize + sizeof(FileChecksumEntryHeader), Align: 4); |
48 | return Error::success(); |
49 | } |
50 | |
51 | Error DebugChecksumsSubsectionRef::initialize(BinaryStreamReader Reader) { |
52 | if (auto EC = Reader.readArray(Array&: Checksums, Size: 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>(Num: Bytes.size()); |
73 | ::memcpy(dest: Copy, src: Bytes.data(), n: Bytes.size()); |
74 | Entry.Checksum = ArrayRef(Copy, Bytes.size()); |
75 | } |
76 | |
77 | Entry.FileNameOffset = Strings.insert(S: FileName); |
78 | Entry.Kind = Kind; |
79 | Checksums.push_back(x: 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(Value: sizeof(FileChecksumEntryHeader) + Bytes.size(), Align: 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 ; |
97 | Header.ChecksumKind = uint8_t(FC.Kind); |
98 | Header.ChecksumSize = FC.Checksum.size(); |
99 | Header.FileNameOffset = FC.FileNameOffset; |
100 | if (auto EC = Writer.writeObject(Obj: Header)) |
101 | return EC; |
102 | if (auto EC = Writer.writeArray(Array: ArrayRef(FC.Checksum))) |
103 | return EC; |
104 | if (auto EC = Writer.padToAlignment(Align: 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(S: FileName); |
112 | auto Iter = OffsetMap.find(Val: Offset); |
113 | assert(Iter != OffsetMap.end()); |
114 | return Iter->second; |
115 | } |
116 | |