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