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