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