blob: 197132d61627e498eb1e280116335beb9deea426 [file] [log] [blame]
Justin Bognerf8847232014-10-14 06:30:31 +00001//===--- SerializedDiagnosticReader.cpp - Reads diagnostics ---------------===//
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 "clang/Frontend/SerializedDiagnosticReader.h"
11#include "clang/Frontend/SerializedDiagnostics.h"
12#include "clang/Basic/FileManager.h"
13#include "llvm/Support/ManagedStatic.h"
14#include "llvm/Support/MemoryBuffer.h"
15
16using namespace clang;
17using namespace clang::serialized_diags;
18
19std::error_code SerializedDiagnosticReader::readDiagnostics(StringRef File) {
20 // Open the diagnostics file.
21 FileSystemOptions FO;
22 FileManager FileMgr(FO);
23
Benjamin Kramera8857962014-10-26 22:44:13 +000024 auto Buffer = FileMgr.getBufferForFile(File);
Justin Bognerf8847232014-10-14 06:30:31 +000025 if (!Buffer)
26 return SDError::CouldNotLoad;
27
28 llvm::BitstreamReader StreamFile;
Benjamin Kramera8857962014-10-26 22:44:13 +000029 StreamFile.init((const unsigned char *)(*Buffer)->getBufferStart(),
30 (const unsigned char *)(*Buffer)->getBufferEnd());
Justin Bognerf8847232014-10-14 06:30:31 +000031
32 llvm::BitstreamCursor Stream;
33 Stream.init(StreamFile);
34
35 // Sniff for the signature.
36 if (Stream.Read(8) != 'D' ||
37 Stream.Read(8) != 'I' ||
38 Stream.Read(8) != 'A' ||
39 Stream.Read(8) != 'G')
40 return SDError::InvalidSignature;
41
42 // Read the top level blocks.
43 while (!Stream.AtEndOfStream()) {
44 if (Stream.ReadCode() != llvm::bitc::ENTER_SUBBLOCK)
45 return SDError::InvalidDiagnostics;
46
47 std::error_code EC;
48 switch (Stream.ReadSubBlockID()) {
49 case llvm::bitc::BLOCKINFO_BLOCK_ID:
50 if (Stream.ReadBlockInfoBlock())
51 return SDError::MalformedBlockInfoBlock;
52 continue;
53 case BLOCK_META:
54 if ((EC = readMetaBlock(Stream)))
55 return EC;
56 continue;
57 case BLOCK_DIAG:
58 if ((EC = readDiagnosticBlock(Stream)))
59 return EC;
60 continue;
61 default:
62 if (!Stream.SkipBlock())
63 return SDError::MalformedTopLevelBlock;
64 continue;
65 }
66 }
67 return std::error_code();
68}
69
70enum class SerializedDiagnosticReader::Cursor {
71 Record = 1,
72 BlockEnd,
73 BlockBegin
74};
75
76llvm::ErrorOr<SerializedDiagnosticReader::Cursor>
77SerializedDiagnosticReader::skipUntilRecordOrBlock(
78 llvm::BitstreamCursor &Stream, unsigned &BlockOrRecordID) {
79 BlockOrRecordID = 0;
80
81 while (!Stream.AtEndOfStream()) {
82 unsigned Code = Stream.ReadCode();
83
84 switch ((llvm::bitc::FixedAbbrevIDs)Code) {
85 case llvm::bitc::ENTER_SUBBLOCK:
86 BlockOrRecordID = Stream.ReadSubBlockID();
87 return Cursor::BlockBegin;
88
89 case llvm::bitc::END_BLOCK:
90 if (Stream.ReadBlockEnd())
91 return SDError::InvalidDiagnostics;
92 return Cursor::BlockEnd;
93
94 case llvm::bitc::DEFINE_ABBREV:
95 Stream.ReadAbbrevRecord();
96 continue;
97
98 case llvm::bitc::UNABBREV_RECORD:
99 return SDError::UnsupportedConstruct;
100
101 default:
102 // We found a record.
103 BlockOrRecordID = Code;
104 return Cursor::Record;
105 }
106 }
107
108 return SDError::InvalidDiagnostics;
109}
110
111std::error_code
112SerializedDiagnosticReader::readMetaBlock(llvm::BitstreamCursor &Stream) {
113 if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META))
114 return SDError::MalformedMetadataBlock;
115
116 bool VersionChecked = false;
117
118 while (true) {
119 unsigned BlockOrCode = 0;
120 llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode);
121 if (!Res)
122 Res.getError();
123
124 switch (Res.get()) {
125 case Cursor::Record:
126 break;
127 case Cursor::BlockBegin:
128 if (Stream.SkipBlock())
129 return SDError::MalformedMetadataBlock;
130 case Cursor::BlockEnd:
131 if (!VersionChecked)
132 return SDError::MissingVersion;
133 return std::error_code();
134 }
135
136 SmallVector<uint64_t, 1> Record;
137 unsigned RecordID = Stream.readRecord(BlockOrCode, Record);
138
139 if (RecordID == RECORD_VERSION) {
140 if (Record.size() < 1)
141 return SDError::MissingVersion;
142 if (Record[0] > VersionNumber)
143 return SDError::VersionMismatch;
144 VersionChecked = true;
145 }
146 }
147}
148
149std::error_code
150SerializedDiagnosticReader::readDiagnosticBlock(llvm::BitstreamCursor &Stream) {
151 if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG))
152 return SDError::MalformedDiagnosticBlock;
153
154 std::error_code EC;
155 if ((EC = visitStartOfDiagnostic()))
156 return EC;
157
158 SmallVector<uint64_t, 16> Record;
159 while (true) {
160 unsigned BlockOrCode = 0;
161 llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode);
162 if (!Res)
163 Res.getError();
164
165 switch (Res.get()) {
166 case Cursor::BlockBegin:
167 // The only blocks we care about are subdiagnostics.
168 if (BlockOrCode == serialized_diags::BLOCK_DIAG) {
169 if ((EC = readDiagnosticBlock(Stream)))
170 return EC;
171 } else if (!Stream.SkipBlock())
172 return SDError::MalformedSubBlock;
173 continue;
174 case Cursor::BlockEnd:
175 if ((EC = visitEndOfDiagnostic()))
176 return EC;
177 return std::error_code();
178 case Cursor::Record:
179 break;
180 }
181
182 // Read the record.
183 Record.clear();
184 StringRef Blob;
185 unsigned RecID = Stream.readRecord(BlockOrCode, Record, &Blob);
186
187 if (RecID < serialized_diags::RECORD_FIRST ||
188 RecID > serialized_diags::RECORD_LAST)
189 continue;
190
191 switch ((RecordIDs)RecID) {
192 case RECORD_CATEGORY:
193 // A category has ID and name size.
194 if (Record.size() != 2)
195 return SDError::MalformedDiagnosticRecord;
196 if ((EC = visitCategoryRecord(Record[0], Blob)))
197 return EC;
198 continue;
199 case RECORD_DIAG:
200 // A diagnostic has severity, location (4), category, flag, and message
201 // size.
202 if (Record.size() != 8)
203 return SDError::MalformedDiagnosticRecord;
204 if ((EC = visitDiagnosticRecord(
205 Record[0], Location(Record[1], Record[2], Record[3], Record[4]),
206 Record[5], Record[6], Blob)))
207 return EC;
208 continue;
209 case RECORD_DIAG_FLAG:
210 // A diagnostic flag has ID and name size.
211 if (Record.size() != 2)
212 return SDError::MalformedDiagnosticRecord;
213 if ((EC = visitDiagFlagRecord(Record[0], Blob)))
214 return EC;
215 continue;
216 case RECORD_FILENAME:
217 // A filename has ID, size, timestamp, and name size. The size and
218 // timestamp are legacy fields that are always zero these days.
219 if (Record.size() != 4)
220 return SDError::MalformedDiagnosticRecord;
221 if ((EC = visitFilenameRecord(Record[0], Record[1], Record[2], Blob)))
222 return EC;
223 continue;
224 case RECORD_FIXIT:
225 // A fixit has two locations (4 each) and message size.
226 if (Record.size() != 9)
227 return SDError::MalformedDiagnosticRecord;
228 if ((EC = visitFixitRecord(
229 Location(Record[0], Record[1], Record[2], Record[3]),
230 Location(Record[4], Record[5], Record[6], Record[7]), Blob)))
231 return EC;
232 continue;
233 case RECORD_SOURCE_RANGE:
234 // A source range is two locations (4 each).
235 if (Record.size() != 8)
236 return SDError::MalformedDiagnosticRecord;
237 if ((EC = visitSourceRangeRecord(
238 Location(Record[0], Record[1], Record[2], Record[3]),
239 Location(Record[4], Record[5], Record[6], Record[7]))))
240 return EC;
241 continue;
242 case RECORD_VERSION:
243 // A version is just a number.
244 if (Record.size() != 1)
245 return SDError::MalformedDiagnosticRecord;
246 if ((EC = visitVersionRecord(Record[0])))
247 return EC;
248 continue;
249 }
250 }
251}
252
253namespace {
254class SDErrorCategoryType final : public std::error_category {
255 const char *name() const LLVM_NOEXCEPT override {
256 return "clang.serialized_diags";
257 }
258 std::string message(int IE) const override {
259 SDError E = static_cast<SDError>(IE);
260 switch (E) {
261 case SDError::CouldNotLoad:
262 return "Failed to open diagnostics file";
263 case SDError::InvalidSignature:
264 return "Invalid diagnostics signature";
265 case SDError::InvalidDiagnostics:
266 return "Parse error reading diagnostics";
267 case SDError::MalformedTopLevelBlock:
268 return "Malformed block at top-level of diagnostics";
269 case SDError::MalformedSubBlock:
270 return "Malformed sub-block in a diagnostic";
271 case SDError::MalformedBlockInfoBlock:
272 return "Malformed BlockInfo block";
273 case SDError::MalformedMetadataBlock:
274 return "Malformed Metadata block";
275 case SDError::MalformedDiagnosticBlock:
276 return "Malformed Diagnostic block";
277 case SDError::MalformedDiagnosticRecord:
278 return "Malformed Diagnostic record";
279 case SDError::MissingVersion:
280 return "No version provided in diagnostics";
281 case SDError::VersionMismatch:
282 return "Unsupported diagnostics version";
283 case SDError::UnsupportedConstruct:
284 return "Bitcode constructs that are not supported in diagnostics appear";
285 case SDError::HandlerFailed:
286 return "Generic error occurred while handling a record";
287 }
288 llvm_unreachable("Unknown error type!");
289 }
290};
291}
292
293static llvm::ManagedStatic<SDErrorCategoryType> ErrorCategory;
294const std::error_category &clang::serialized_diags::SDErrorCategory() {
295 return *ErrorCategory;
296}