SerializedDiagnosticReader.cpp 12 KB

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