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