Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/Frontend/SerializedDiagnosticReader.cpp
35234 views
1
//===- SerializedDiagnosticReader.cpp - Reads diagnostics -----------------===//
2
//
3
// 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
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "clang/Frontend/SerializedDiagnosticReader.h"
10
#include "clang/Basic/FileManager.h"
11
#include "clang/Basic/FileSystemOptions.h"
12
#include "clang/Frontend/SerializedDiagnostics.h"
13
#include "llvm/ADT/SmallVector.h"
14
#include "llvm/ADT/StringRef.h"
15
#include "llvm/Bitstream/BitCodes.h"
16
#include "llvm/Bitstream/BitstreamReader.h"
17
#include "llvm/Support/Compiler.h"
18
#include "llvm/Support/ErrorHandling.h"
19
#include "llvm/Support/ErrorOr.h"
20
#include "llvm/Support/ManagedStatic.h"
21
#include <cstdint>
22
#include <optional>
23
#include <system_error>
24
25
using namespace clang;
26
using namespace serialized_diags;
27
28
std::error_code SerializedDiagnosticReader::readDiagnostics(StringRef File) {
29
// Open the diagnostics file.
30
FileSystemOptions FO;
31
FileManager FileMgr(FO);
32
33
auto Buffer = FileMgr.getBufferForFile(File);
34
if (!Buffer)
35
return SDError::CouldNotLoad;
36
37
llvm::BitstreamCursor Stream(**Buffer);
38
std::optional<llvm::BitstreamBlockInfo> BlockInfo;
39
40
if (Stream.AtEndOfStream())
41
return SDError::InvalidSignature;
42
43
// Sniff for the signature.
44
for (unsigned char C : {'D', 'I', 'A', 'G'}) {
45
if (Expected<llvm::SimpleBitstreamCursor::word_t> Res = Stream.Read(8)) {
46
if (Res.get() == C)
47
continue;
48
} else {
49
// FIXME this drops the error on the floor.
50
consumeError(Res.takeError());
51
}
52
return SDError::InvalidSignature;
53
}
54
55
// Read the top level blocks.
56
while (!Stream.AtEndOfStream()) {
57
if (Expected<unsigned> Res = Stream.ReadCode()) {
58
if (Res.get() != llvm::bitc::ENTER_SUBBLOCK)
59
return SDError::InvalidDiagnostics;
60
} else {
61
// FIXME this drops the error on the floor.
62
consumeError(Res.takeError());
63
return SDError::InvalidDiagnostics;
64
}
65
66
std::error_code EC;
67
Expected<unsigned> MaybeSubBlockID = Stream.ReadSubBlockID();
68
if (!MaybeSubBlockID) {
69
// FIXME this drops the error on the floor.
70
consumeError(MaybeSubBlockID.takeError());
71
return SDError::InvalidDiagnostics;
72
}
73
74
switch (MaybeSubBlockID.get()) {
75
case llvm::bitc::BLOCKINFO_BLOCK_ID: {
76
Expected<std::optional<llvm::BitstreamBlockInfo>> MaybeBlockInfo =
77
Stream.ReadBlockInfoBlock();
78
if (!MaybeBlockInfo) {
79
// FIXME this drops the error on the floor.
80
consumeError(MaybeBlockInfo.takeError());
81
return SDError::InvalidDiagnostics;
82
}
83
BlockInfo = std::move(MaybeBlockInfo.get());
84
}
85
if (!BlockInfo)
86
return SDError::MalformedBlockInfoBlock;
87
Stream.setBlockInfo(&*BlockInfo);
88
continue;
89
case BLOCK_META:
90
if ((EC = readMetaBlock(Stream)))
91
return EC;
92
continue;
93
case BLOCK_DIAG:
94
if ((EC = readDiagnosticBlock(Stream)))
95
return EC;
96
continue;
97
default:
98
if (llvm::Error Err = Stream.SkipBlock()) {
99
// FIXME this drops the error on the floor.
100
consumeError(std::move(Err));
101
return SDError::MalformedTopLevelBlock;
102
}
103
continue;
104
}
105
}
106
return {};
107
}
108
109
enum class SerializedDiagnosticReader::Cursor {
110
Record = 1,
111
BlockEnd,
112
BlockBegin
113
};
114
115
llvm::ErrorOr<SerializedDiagnosticReader::Cursor>
116
SerializedDiagnosticReader::skipUntilRecordOrBlock(
117
llvm::BitstreamCursor &Stream, unsigned &BlockOrRecordID) {
118
BlockOrRecordID = 0;
119
120
while (!Stream.AtEndOfStream()) {
121
unsigned Code;
122
if (Expected<unsigned> Res = Stream.ReadCode())
123
Code = Res.get();
124
else
125
return llvm::errorToErrorCode(Res.takeError());
126
127
if (Code >= static_cast<unsigned>(llvm::bitc::FIRST_APPLICATION_ABBREV)) {
128
// We found a record.
129
BlockOrRecordID = Code;
130
return Cursor::Record;
131
}
132
switch (static_cast<llvm::bitc::FixedAbbrevIDs>(Code)) {
133
case llvm::bitc::ENTER_SUBBLOCK:
134
if (Expected<unsigned> Res = Stream.ReadSubBlockID())
135
BlockOrRecordID = Res.get();
136
else
137
return llvm::errorToErrorCode(Res.takeError());
138
return Cursor::BlockBegin;
139
140
case llvm::bitc::END_BLOCK:
141
if (Stream.ReadBlockEnd())
142
return SDError::InvalidDiagnostics;
143
return Cursor::BlockEnd;
144
145
case llvm::bitc::DEFINE_ABBREV:
146
if (llvm::Error Err = Stream.ReadAbbrevRecord())
147
return llvm::errorToErrorCode(std::move(Err));
148
continue;
149
150
case llvm::bitc::UNABBREV_RECORD:
151
return SDError::UnsupportedConstruct;
152
153
case llvm::bitc::FIRST_APPLICATION_ABBREV:
154
llvm_unreachable("Unexpected abbrev id.");
155
}
156
}
157
158
return SDError::InvalidDiagnostics;
159
}
160
161
std::error_code
162
SerializedDiagnosticReader::readMetaBlock(llvm::BitstreamCursor &Stream) {
163
if (llvm::Error Err =
164
Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META)) {
165
// FIXME this drops the error on the floor.
166
consumeError(std::move(Err));
167
return SDError::MalformedMetadataBlock;
168
}
169
170
bool VersionChecked = false;
171
172
while (true) {
173
unsigned BlockOrCode = 0;
174
llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode);
175
if (!Res)
176
Res.getError();
177
178
switch (Res.get()) {
179
case Cursor::Record:
180
break;
181
case Cursor::BlockBegin:
182
if (llvm::Error Err = Stream.SkipBlock()) {
183
// FIXME this drops the error on the floor.
184
consumeError(std::move(Err));
185
return SDError::MalformedMetadataBlock;
186
}
187
[[fallthrough]];
188
case Cursor::BlockEnd:
189
if (!VersionChecked)
190
return SDError::MissingVersion;
191
return {};
192
}
193
194
SmallVector<uint64_t, 1> Record;
195
Expected<unsigned> MaybeRecordID = Stream.readRecord(BlockOrCode, Record);
196
if (!MaybeRecordID)
197
return errorToErrorCode(MaybeRecordID.takeError());
198
unsigned RecordID = MaybeRecordID.get();
199
200
if (RecordID == RECORD_VERSION) {
201
if (Record.size() < 1)
202
return SDError::MissingVersion;
203
if (Record[0] > VersionNumber)
204
return SDError::VersionMismatch;
205
VersionChecked = true;
206
}
207
}
208
}
209
210
std::error_code
211
SerializedDiagnosticReader::readDiagnosticBlock(llvm::BitstreamCursor &Stream) {
212
if (llvm::Error Err =
213
Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG)) {
214
// FIXME this drops the error on the floor.
215
consumeError(std::move(Err));
216
return SDError::MalformedDiagnosticBlock;
217
}
218
219
std::error_code EC;
220
if ((EC = visitStartOfDiagnostic()))
221
return EC;
222
223
SmallVector<uint64_t, 16> Record;
224
while (true) {
225
unsigned BlockOrCode = 0;
226
llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode);
227
if (!Res)
228
Res.getError();
229
230
switch (Res.get()) {
231
case Cursor::BlockBegin:
232
// The only blocks we care about are subdiagnostics.
233
if (BlockOrCode == serialized_diags::BLOCK_DIAG) {
234
if ((EC = readDiagnosticBlock(Stream)))
235
return EC;
236
} else if (llvm::Error Err = Stream.SkipBlock()) {
237
// FIXME this drops the error on the floor.
238
consumeError(std::move(Err));
239
return SDError::MalformedSubBlock;
240
}
241
continue;
242
case Cursor::BlockEnd:
243
if ((EC = visitEndOfDiagnostic()))
244
return EC;
245
return {};
246
case Cursor::Record:
247
break;
248
}
249
250
// Read the record.
251
Record.clear();
252
StringRef Blob;
253
Expected<unsigned> MaybeRecID =
254
Stream.readRecord(BlockOrCode, Record, &Blob);
255
if (!MaybeRecID)
256
return errorToErrorCode(MaybeRecID.takeError());
257
unsigned RecID = MaybeRecID.get();
258
259
if (RecID < serialized_diags::RECORD_FIRST ||
260
RecID > serialized_diags::RECORD_LAST)
261
continue;
262
263
switch ((RecordIDs)RecID) {
264
case RECORD_CATEGORY:
265
// A category has ID and name size.
266
if (Record.size() != 2)
267
return SDError::MalformedDiagnosticRecord;
268
if ((EC = visitCategoryRecord(Record[0], Blob)))
269
return EC;
270
continue;
271
case RECORD_DIAG:
272
// A diagnostic has severity, location (4), category, flag, and message
273
// size.
274
if (Record.size() != 8)
275
return SDError::MalformedDiagnosticRecord;
276
if ((EC = visitDiagnosticRecord(
277
Record[0], Location(Record[1], Record[2], Record[3], Record[4]),
278
Record[5], Record[6], Blob)))
279
return EC;
280
continue;
281
case RECORD_DIAG_FLAG:
282
// A diagnostic flag has ID and name size.
283
if (Record.size() != 2)
284
return SDError::MalformedDiagnosticRecord;
285
if ((EC = visitDiagFlagRecord(Record[0], Blob)))
286
return EC;
287
continue;
288
case RECORD_FILENAME:
289
// A filename has ID, size, timestamp, and name size. The size and
290
// timestamp are legacy fields that are always zero these days.
291
if (Record.size() != 4)
292
return SDError::MalformedDiagnosticRecord;
293
if ((EC = visitFilenameRecord(Record[0], Record[1], Record[2], Blob)))
294
return EC;
295
continue;
296
case RECORD_FIXIT:
297
// A fixit has two locations (4 each) and message size.
298
if (Record.size() != 9)
299
return SDError::MalformedDiagnosticRecord;
300
if ((EC = visitFixitRecord(
301
Location(Record[0], Record[1], Record[2], Record[3]),
302
Location(Record[4], Record[5], Record[6], Record[7]), Blob)))
303
return EC;
304
continue;
305
case RECORD_SOURCE_RANGE:
306
// A source range is two locations (4 each).
307
if (Record.size() != 8)
308
return SDError::MalformedDiagnosticRecord;
309
if ((EC = visitSourceRangeRecord(
310
Location(Record[0], Record[1], Record[2], Record[3]),
311
Location(Record[4], Record[5], Record[6], Record[7]))))
312
return EC;
313
continue;
314
case RECORD_VERSION:
315
// A version is just a number.
316
if (Record.size() != 1)
317
return SDError::MalformedDiagnosticRecord;
318
if ((EC = visitVersionRecord(Record[0])))
319
return EC;
320
continue;
321
}
322
}
323
}
324
325
namespace {
326
327
class SDErrorCategoryType final : public std::error_category {
328
const char *name() const noexcept override {
329
return "clang.serialized_diags";
330
}
331
332
std::string message(int IE) const override {
333
auto E = static_cast<SDError>(IE);
334
switch (E) {
335
case SDError::CouldNotLoad:
336
return "Failed to open diagnostics file";
337
case SDError::InvalidSignature:
338
return "Invalid diagnostics signature";
339
case SDError::InvalidDiagnostics:
340
return "Parse error reading diagnostics";
341
case SDError::MalformedTopLevelBlock:
342
return "Malformed block at top-level of diagnostics";
343
case SDError::MalformedSubBlock:
344
return "Malformed sub-block in a diagnostic";
345
case SDError::MalformedBlockInfoBlock:
346
return "Malformed BlockInfo block";
347
case SDError::MalformedMetadataBlock:
348
return "Malformed Metadata block";
349
case SDError::MalformedDiagnosticBlock:
350
return "Malformed Diagnostic block";
351
case SDError::MalformedDiagnosticRecord:
352
return "Malformed Diagnostic record";
353
case SDError::MissingVersion:
354
return "No version provided in diagnostics";
355
case SDError::VersionMismatch:
356
return "Unsupported diagnostics version";
357
case SDError::UnsupportedConstruct:
358
return "Bitcode constructs that are not supported in diagnostics appear";
359
case SDError::HandlerFailed:
360
return "Generic error occurred while handling a record";
361
}
362
llvm_unreachable("Unknown error type!");
363
}
364
};
365
366
} // namespace
367
368
static llvm::ManagedStatic<SDErrorCategoryType> ErrorCategory;
369
const std::error_category &clang::serialized_diags::SDErrorCategory() {
370
return *ErrorCategory;
371
}
372
373