1 | //===- ModuleDebugStream.cpp - PDB Module Info Stream Access --------------===// |
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/PDB/Native/ModuleDebugStream.h" |
10 | #include "llvm/ADT/iterator_range.h" |
11 | #include "llvm/DebugInfo/CodeView/CodeView.h" |
12 | #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" |
13 | #include "llvm/DebugInfo/CodeView/SymbolRecordHelpers.h" |
14 | #include "llvm/DebugInfo/MSF/MSFCommon.h" |
15 | #include "llvm/DebugInfo/MSF/MappedBlockStream.h" |
16 | #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" |
17 | #include "llvm/DebugInfo/PDB/Native/RawConstants.h" |
18 | #include "llvm/DebugInfo/PDB/Native/RawError.h" |
19 | #include "llvm/DebugInfo/PDB/Native/RawTypes.h" |
20 | #include "llvm/Support/BinaryStreamArray.h" |
21 | #include "llvm/Support/BinaryStreamReader.h" |
22 | #include "llvm/Support/BinaryStreamRef.h" |
23 | #include "llvm/Support/Error.h" |
24 | #include <cstdint> |
25 | |
26 | using namespace llvm; |
27 | using namespace llvm::codeview; |
28 | using namespace llvm::msf; |
29 | using namespace llvm::pdb; |
30 | |
31 | ModuleDebugStreamRef::ModuleDebugStreamRef( |
32 | const DbiModuleDescriptor &Module, |
33 | std::unique_ptr<MappedBlockStream> Stream) |
34 | : Mod(Module), Stream(std::move(Stream)) {} |
35 | |
36 | ModuleDebugStreamRef::~ModuleDebugStreamRef() = default; |
37 | |
38 | Error ModuleDebugStreamRef::reload() { |
39 | BinaryStreamReader Reader(*Stream); |
40 | |
41 | if (Mod.getModuleStreamIndex() != llvm::pdb::kInvalidStreamIndex) { |
42 | if (Error E = reloadSerialize(Reader)) |
43 | return E; |
44 | } |
45 | if (Reader.bytesRemaining() > 0) |
46 | return make_error<RawError>(Args: raw_error_code::corrupt_file, |
47 | Args: "Unexpected bytes in module stream." ); |
48 | return Error::success(); |
49 | } |
50 | |
51 | Error ModuleDebugStreamRef::reloadSerialize(BinaryStreamReader &Reader) { |
52 | uint32_t SymbolSize = Mod.getSymbolDebugInfoByteSize(); |
53 | uint32_t C11Size = Mod.getC11LineInfoByteSize(); |
54 | uint32_t C13Size = Mod.getC13LineInfoByteSize(); |
55 | |
56 | if (C11Size > 0 && C13Size > 0) |
57 | return make_error<RawError>(Args: raw_error_code::corrupt_file, |
58 | Args: "Module has both C11 and C13 line info" ); |
59 | |
60 | BinaryStreamRef S; |
61 | |
62 | if (auto EC = Reader.readInteger(Dest&: Signature)) |
63 | return EC; |
64 | Reader.setOffset(0); |
65 | if (auto EC = Reader.readSubstream(Ref&: SymbolsSubstream, Length: SymbolSize)) |
66 | return EC; |
67 | if (auto EC = Reader.readSubstream(Ref&: C11LinesSubstream, Length: C11Size)) |
68 | return EC; |
69 | if (auto EC = Reader.readSubstream(Ref&: C13LinesSubstream, Length: C13Size)) |
70 | return EC; |
71 | |
72 | BinaryStreamReader SymbolReader(SymbolsSubstream.StreamData); |
73 | if (auto EC = SymbolReader.readArray( |
74 | Array&: SymbolArray, Size: SymbolReader.bytesRemaining(), Skew: sizeof(uint32_t))) |
75 | return EC; |
76 | |
77 | BinaryStreamReader SubsectionsReader(C13LinesSubstream.StreamData); |
78 | if (auto EC = SubsectionsReader.readArray(Array&: Subsections, |
79 | Size: SubsectionsReader.bytesRemaining())) |
80 | return EC; |
81 | |
82 | uint32_t GlobalRefsSize; |
83 | if (auto EC = Reader.readInteger(Dest&: GlobalRefsSize)) |
84 | return EC; |
85 | if (auto EC = Reader.readSubstream(Ref&: GlobalRefsSubstream, Length: GlobalRefsSize)) |
86 | return EC; |
87 | return Error::success(); |
88 | } |
89 | |
90 | const codeview::CVSymbolArray |
91 | ModuleDebugStreamRef::getSymbolArrayForScope(uint32_t ScopeBegin) const { |
92 | return limitSymbolArrayToScope(Symbols: SymbolArray, ScopeBegin); |
93 | } |
94 | |
95 | BinarySubstreamRef ModuleDebugStreamRef::getSymbolsSubstream() const { |
96 | return SymbolsSubstream; |
97 | } |
98 | |
99 | BinarySubstreamRef ModuleDebugStreamRef::getC11LinesSubstream() const { |
100 | return C11LinesSubstream; |
101 | } |
102 | |
103 | BinarySubstreamRef ModuleDebugStreamRef::getC13LinesSubstream() const { |
104 | return C13LinesSubstream; |
105 | } |
106 | |
107 | BinarySubstreamRef ModuleDebugStreamRef::getGlobalRefsSubstream() const { |
108 | return GlobalRefsSubstream; |
109 | } |
110 | |
111 | iterator_range<codeview::CVSymbolArray::Iterator> |
112 | ModuleDebugStreamRef::symbols(bool *HadError) const { |
113 | return make_range(x: SymbolArray.begin(HadError), y: SymbolArray.end()); |
114 | } |
115 | |
116 | CVSymbol ModuleDebugStreamRef::readSymbolAtOffset(uint32_t Offset) const { |
117 | auto Iter = SymbolArray.at(Offset); |
118 | assert(Iter != SymbolArray.end()); |
119 | return *Iter; |
120 | } |
121 | |
122 | iterator_range<ModuleDebugStreamRef::DebugSubsectionIterator> |
123 | ModuleDebugStreamRef::subsections() const { |
124 | return make_range(x: Subsections.begin(), y: Subsections.end()); |
125 | } |
126 | |
127 | bool ModuleDebugStreamRef::hasDebugSubsections() const { |
128 | return !C13LinesSubstream.empty(); |
129 | } |
130 | |
131 | Error ModuleDebugStreamRef::commit() { return Error::success(); } |
132 | |
133 | Expected<codeview::DebugChecksumsSubsectionRef> |
134 | ModuleDebugStreamRef::findChecksumsSubsection() const { |
135 | codeview::DebugChecksumsSubsectionRef Result; |
136 | for (const auto &SS : subsections()) { |
137 | if (SS.kind() != DebugSubsectionKind::FileChecksums) |
138 | continue; |
139 | |
140 | if (auto EC = Result.initialize(Stream: SS.getRecordData())) |
141 | return std::move(EC); |
142 | return Result; |
143 | } |
144 | return Result; |
145 | } |
146 | |