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