YAMLRemarkParser.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. //===- YAMLRemarkParser.cpp -----------------------------------------------===//
  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. // This file provides utility methods used by clients that want to use the
  10. // parser for remark diagnostics in LLVM.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #include "YAMLRemarkParser.h"
  14. #include "llvm/ADT/StringSwitch.h"
  15. #include "llvm/Support/Endian.h"
  16. #include "llvm/Support/Path.h"
  17. #include <optional>
  18. using namespace llvm;
  19. using namespace llvm::remarks;
  20. char YAMLParseError::ID = 0;
  21. static void handleDiagnostic(const SMDiagnostic &Diag, void *Ctx) {
  22. assert(Ctx && "Expected non-null Ctx in diagnostic handler.");
  23. std::string &Message = *static_cast<std::string *>(Ctx);
  24. assert(Message.empty() && "Expected an empty string.");
  25. raw_string_ostream OS(Message);
  26. Diag.print(/*ProgName=*/nullptr, OS, /*ShowColors*/ false,
  27. /*ShowKindLabels*/ true);
  28. OS << '\n';
  29. OS.flush();
  30. }
  31. YAMLParseError::YAMLParseError(StringRef Msg, SourceMgr &SM,
  32. yaml::Stream &Stream, yaml::Node &Node) {
  33. // 1) Set up a diagnostic handler to avoid errors being printed out to
  34. // stderr.
  35. // 2) Use the stream to print the error with the associated node.
  36. // 3) The stream will use the source manager to print the error, which will
  37. // call the diagnostic handler.
  38. // 4) The diagnostic handler will stream the error directly into this object's
  39. // Message member, which is used when logging is asked for.
  40. auto OldDiagHandler = SM.getDiagHandler();
  41. auto OldDiagCtx = SM.getDiagContext();
  42. SM.setDiagHandler(handleDiagnostic, &Message);
  43. Stream.printError(&Node, Twine(Msg) + Twine('\n'));
  44. // Restore the old handlers.
  45. SM.setDiagHandler(OldDiagHandler, OldDiagCtx);
  46. }
  47. static SourceMgr setupSM(std::string &LastErrorMessage) {
  48. SourceMgr SM;
  49. SM.setDiagHandler(handleDiagnostic, &LastErrorMessage);
  50. return SM;
  51. }
  52. // Parse the magic number. This function returns true if this represents remark
  53. // metadata, false otherwise.
  54. static Expected<bool> parseMagic(StringRef &Buf) {
  55. if (!Buf.consume_front(remarks::Magic))
  56. return false;
  57. if (Buf.size() < 1 || !Buf.consume_front(StringRef("\0", 1)))
  58. return createStringError(std::errc::illegal_byte_sequence,
  59. "Expecting \\0 after magic number.");
  60. return true;
  61. }
  62. static Expected<uint64_t> parseVersion(StringRef &Buf) {
  63. if (Buf.size() < sizeof(uint64_t))
  64. return createStringError(std::errc::illegal_byte_sequence,
  65. "Expecting version number.");
  66. uint64_t Version =
  67. support::endian::read<uint64_t, support::little, support::unaligned>(
  68. Buf.data());
  69. if (Version != remarks::CurrentRemarkVersion)
  70. return createStringError(std::errc::illegal_byte_sequence,
  71. "Mismatching remark version. Got %" PRId64
  72. ", expected %" PRId64 ".",
  73. Version, remarks::CurrentRemarkVersion);
  74. Buf = Buf.drop_front(sizeof(uint64_t));
  75. return Version;
  76. }
  77. static Expected<uint64_t> parseStrTabSize(StringRef &Buf) {
  78. if (Buf.size() < sizeof(uint64_t))
  79. return createStringError(std::errc::illegal_byte_sequence,
  80. "Expecting string table size.");
  81. uint64_t StrTabSize =
  82. support::endian::read<uint64_t, support::little, support::unaligned>(
  83. Buf.data());
  84. Buf = Buf.drop_front(sizeof(uint64_t));
  85. return StrTabSize;
  86. }
  87. static Expected<ParsedStringTable> parseStrTab(StringRef &Buf,
  88. uint64_t StrTabSize) {
  89. if (Buf.size() < StrTabSize)
  90. return createStringError(std::errc::illegal_byte_sequence,
  91. "Expecting string table.");
  92. // Attach the string table to the parser.
  93. ParsedStringTable Result(StringRef(Buf.data(), StrTabSize));
  94. Buf = Buf.drop_front(StrTabSize);
  95. return Expected<ParsedStringTable>(std::move(Result));
  96. }
  97. Expected<std::unique_ptr<YAMLRemarkParser>> remarks::createYAMLParserFromMeta(
  98. StringRef Buf, std::optional<ParsedStringTable> StrTab,
  99. std::optional<StringRef> ExternalFilePrependPath) {
  100. // We now have a magic number. The metadata has to be correct.
  101. Expected<bool> isMeta = parseMagic(Buf);
  102. if (!isMeta)
  103. return isMeta.takeError();
  104. // If it's not recognized as metadata, roll back.
  105. std::unique_ptr<MemoryBuffer> SeparateBuf;
  106. if (*isMeta) {
  107. Expected<uint64_t> Version = parseVersion(Buf);
  108. if (!Version)
  109. return Version.takeError();
  110. Expected<uint64_t> StrTabSize = parseStrTabSize(Buf);
  111. if (!StrTabSize)
  112. return StrTabSize.takeError();
  113. // If the size of string table is not 0, try to build one.
  114. if (*StrTabSize != 0) {
  115. if (StrTab)
  116. return createStringError(std::errc::illegal_byte_sequence,
  117. "String table already provided.");
  118. Expected<ParsedStringTable> MaybeStrTab = parseStrTab(Buf, *StrTabSize);
  119. if (!MaybeStrTab)
  120. return MaybeStrTab.takeError();
  121. StrTab = std::move(*MaybeStrTab);
  122. }
  123. // If it starts with "---", there is no external file.
  124. if (!Buf.startswith("---")) {
  125. // At this point, we expect Buf to contain the external file path.
  126. StringRef ExternalFilePath = Buf;
  127. SmallString<80> FullPath;
  128. if (ExternalFilePrependPath)
  129. FullPath = *ExternalFilePrependPath;
  130. sys::path::append(FullPath, ExternalFilePath);
  131. // Try to open the file and start parsing from there.
  132. ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
  133. MemoryBuffer::getFile(FullPath);
  134. if (std::error_code EC = BufferOrErr.getError())
  135. return createFileError(FullPath, EC);
  136. // Keep the buffer alive.
  137. SeparateBuf = std::move(*BufferOrErr);
  138. Buf = SeparateBuf->getBuffer();
  139. }
  140. }
  141. std::unique_ptr<YAMLRemarkParser> Result =
  142. StrTab
  143. ? std::make_unique<YAMLStrTabRemarkParser>(Buf, std::move(*StrTab))
  144. : std::make_unique<YAMLRemarkParser>(Buf);
  145. if (SeparateBuf)
  146. Result->SeparateBuf = std::move(SeparateBuf);
  147. return std::move(Result);
  148. }
  149. YAMLRemarkParser::YAMLRemarkParser(StringRef Buf)
  150. : YAMLRemarkParser(Buf, std::nullopt) {}
  151. YAMLRemarkParser::YAMLRemarkParser(StringRef Buf,
  152. std::optional<ParsedStringTable> StrTab)
  153. : RemarkParser{Format::YAML}, StrTab(std::move(StrTab)),
  154. SM(setupSM(LastErrorMessage)), Stream(Buf, SM), YAMLIt(Stream.begin()) {}
  155. Error YAMLRemarkParser::error(StringRef Message, yaml::Node &Node) {
  156. return make_error<YAMLParseError>(Message, SM, Stream, Node);
  157. }
  158. Error YAMLRemarkParser::error() {
  159. if (LastErrorMessage.empty())
  160. return Error::success();
  161. Error E = make_error<YAMLParseError>(LastErrorMessage);
  162. LastErrorMessage.clear();
  163. return E;
  164. }
  165. Expected<std::unique_ptr<Remark>>
  166. YAMLRemarkParser::parseRemark(yaml::Document &RemarkEntry) {
  167. if (Error E = error())
  168. return std::move(E);
  169. yaml::Node *YAMLRoot = RemarkEntry.getRoot();
  170. if (!YAMLRoot) {
  171. return createStringError(std::make_error_code(std::errc::invalid_argument),
  172. "not a valid YAML file.");
  173. }
  174. auto *Root = dyn_cast<yaml::MappingNode>(YAMLRoot);
  175. if (!Root)
  176. return error("document root is not of mapping type.", *YAMLRoot);
  177. std::unique_ptr<Remark> Result = std::make_unique<Remark>();
  178. Remark &TheRemark = *Result;
  179. // First, the type. It needs special handling since is not part of the
  180. // key-value stream.
  181. Expected<Type> T = parseType(*Root);
  182. if (!T)
  183. return T.takeError();
  184. else
  185. TheRemark.RemarkType = *T;
  186. // Then, parse the fields, one by one.
  187. for (yaml::KeyValueNode &RemarkField : *Root) {
  188. Expected<StringRef> MaybeKey = parseKey(RemarkField);
  189. if (!MaybeKey)
  190. return MaybeKey.takeError();
  191. StringRef KeyName = *MaybeKey;
  192. if (KeyName == "Pass") {
  193. if (Expected<StringRef> MaybeStr = parseStr(RemarkField))
  194. TheRemark.PassName = *MaybeStr;
  195. else
  196. return MaybeStr.takeError();
  197. } else if (KeyName == "Name") {
  198. if (Expected<StringRef> MaybeStr = parseStr(RemarkField))
  199. TheRemark.RemarkName = *MaybeStr;
  200. else
  201. return MaybeStr.takeError();
  202. } else if (KeyName == "Function") {
  203. if (Expected<StringRef> MaybeStr = parseStr(RemarkField))
  204. TheRemark.FunctionName = *MaybeStr;
  205. else
  206. return MaybeStr.takeError();
  207. } else if (KeyName == "Hotness") {
  208. if (Expected<unsigned> MaybeU = parseUnsigned(RemarkField))
  209. TheRemark.Hotness = *MaybeU;
  210. else
  211. return MaybeU.takeError();
  212. } else if (KeyName == "DebugLoc") {
  213. if (Expected<RemarkLocation> MaybeLoc = parseDebugLoc(RemarkField))
  214. TheRemark.Loc = *MaybeLoc;
  215. else
  216. return MaybeLoc.takeError();
  217. } else if (KeyName == "Args") {
  218. auto *Args = dyn_cast<yaml::SequenceNode>(RemarkField.getValue());
  219. if (!Args)
  220. return error("wrong value type for key.", RemarkField);
  221. for (yaml::Node &Arg : *Args) {
  222. if (Expected<Argument> MaybeArg = parseArg(Arg))
  223. TheRemark.Args.push_back(*MaybeArg);
  224. else
  225. return MaybeArg.takeError();
  226. }
  227. } else {
  228. return error("unknown key.", RemarkField);
  229. }
  230. }
  231. // Check if any of the mandatory fields are missing.
  232. if (TheRemark.RemarkType == Type::Unknown || TheRemark.PassName.empty() ||
  233. TheRemark.RemarkName.empty() || TheRemark.FunctionName.empty())
  234. return error("Type, Pass, Name or Function missing.",
  235. *RemarkEntry.getRoot());
  236. return std::move(Result);
  237. }
  238. Expected<Type> YAMLRemarkParser::parseType(yaml::MappingNode &Node) {
  239. auto Type = StringSwitch<remarks::Type>(Node.getRawTag())
  240. .Case("!Passed", remarks::Type::Passed)
  241. .Case("!Missed", remarks::Type::Missed)
  242. .Case("!Analysis", remarks::Type::Analysis)
  243. .Case("!AnalysisFPCommute", remarks::Type::AnalysisFPCommute)
  244. .Case("!AnalysisAliasing", remarks::Type::AnalysisAliasing)
  245. .Case("!Failure", remarks::Type::Failure)
  246. .Default(remarks::Type::Unknown);
  247. if (Type == remarks::Type::Unknown)
  248. return error("expected a remark tag.", Node);
  249. return Type;
  250. }
  251. Expected<StringRef> YAMLRemarkParser::parseKey(yaml::KeyValueNode &Node) {
  252. if (auto *Key = dyn_cast<yaml::ScalarNode>(Node.getKey()))
  253. return Key->getRawValue();
  254. return error("key is not a string.", Node);
  255. }
  256. Expected<StringRef> YAMLRemarkParser::parseStr(yaml::KeyValueNode &Node) {
  257. auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue());
  258. if (!Value)
  259. return error("expected a value of scalar type.", Node);
  260. StringRef Result = Value->getRawValue();
  261. if (Result.front() == '\'')
  262. Result = Result.drop_front();
  263. if (Result.back() == '\'')
  264. Result = Result.drop_back();
  265. return Result;
  266. }
  267. Expected<unsigned> YAMLRemarkParser::parseUnsigned(yaml::KeyValueNode &Node) {
  268. SmallVector<char, 4> Tmp;
  269. auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue());
  270. if (!Value)
  271. return error("expected a value of scalar type.", Node);
  272. unsigned UnsignedValue = 0;
  273. if (Value->getValue(Tmp).getAsInteger(10, UnsignedValue))
  274. return error("expected a value of integer type.", *Value);
  275. return UnsignedValue;
  276. }
  277. Expected<RemarkLocation>
  278. YAMLRemarkParser::parseDebugLoc(yaml::KeyValueNode &Node) {
  279. auto *DebugLoc = dyn_cast<yaml::MappingNode>(Node.getValue());
  280. if (!DebugLoc)
  281. return error("expected a value of mapping type.", Node);
  282. std::optional<StringRef> File;
  283. std::optional<unsigned> Line;
  284. std::optional<unsigned> Column;
  285. for (yaml::KeyValueNode &DLNode : *DebugLoc) {
  286. Expected<StringRef> MaybeKey = parseKey(DLNode);
  287. if (!MaybeKey)
  288. return MaybeKey.takeError();
  289. StringRef KeyName = *MaybeKey;
  290. if (KeyName == "File") {
  291. if (Expected<StringRef> MaybeStr = parseStr(DLNode))
  292. File = *MaybeStr;
  293. else
  294. return MaybeStr.takeError();
  295. } else if (KeyName == "Column") {
  296. if (Expected<unsigned> MaybeU = parseUnsigned(DLNode))
  297. Column = *MaybeU;
  298. else
  299. return MaybeU.takeError();
  300. } else if (KeyName == "Line") {
  301. if (Expected<unsigned> MaybeU = parseUnsigned(DLNode))
  302. Line = *MaybeU;
  303. else
  304. return MaybeU.takeError();
  305. } else {
  306. return error("unknown entry in DebugLoc map.", DLNode);
  307. }
  308. }
  309. // If any of the debug loc fields is missing, return an error.
  310. if (!File || !Line || !Column)
  311. return error("DebugLoc node incomplete.", Node);
  312. return RemarkLocation{*File, *Line, *Column};
  313. }
  314. Expected<Argument> YAMLRemarkParser::parseArg(yaml::Node &Node) {
  315. auto *ArgMap = dyn_cast<yaml::MappingNode>(&Node);
  316. if (!ArgMap)
  317. return error("expected a value of mapping type.", Node);
  318. std::optional<StringRef> KeyStr;
  319. std::optional<StringRef> ValueStr;
  320. std::optional<RemarkLocation> Loc;
  321. for (yaml::KeyValueNode &ArgEntry : *ArgMap) {
  322. Expected<StringRef> MaybeKey = parseKey(ArgEntry);
  323. if (!MaybeKey)
  324. return MaybeKey.takeError();
  325. StringRef KeyName = *MaybeKey;
  326. // Try to parse debug locs.
  327. if (KeyName == "DebugLoc") {
  328. // Can't have multiple DebugLoc entries per argument.
  329. if (Loc)
  330. return error("only one DebugLoc entry is allowed per argument.",
  331. ArgEntry);
  332. if (Expected<RemarkLocation> MaybeLoc = parseDebugLoc(ArgEntry)) {
  333. Loc = *MaybeLoc;
  334. continue;
  335. } else
  336. return MaybeLoc.takeError();
  337. }
  338. // If we already have a string, error out.
  339. if (ValueStr)
  340. return error("only one string entry is allowed per argument.", ArgEntry);
  341. // Try to parse the value.
  342. if (Expected<StringRef> MaybeStr = parseStr(ArgEntry))
  343. ValueStr = *MaybeStr;
  344. else
  345. return MaybeStr.takeError();
  346. // Keep the key from the string.
  347. KeyStr = KeyName;
  348. }
  349. if (!KeyStr)
  350. return error("argument key is missing.", *ArgMap);
  351. if (!ValueStr)
  352. return error("argument value is missing.", *ArgMap);
  353. return Argument{*KeyStr, *ValueStr, Loc};
  354. }
  355. Expected<std::unique_ptr<Remark>> YAMLRemarkParser::next() {
  356. if (YAMLIt == Stream.end())
  357. return make_error<EndOfFileError>();
  358. Expected<std::unique_ptr<Remark>> MaybeResult = parseRemark(*YAMLIt);
  359. if (!MaybeResult) {
  360. // Avoid garbage input, set the iterator to the end.
  361. YAMLIt = Stream.end();
  362. return MaybeResult.takeError();
  363. }
  364. ++YAMLIt;
  365. return std::move(*MaybeResult);
  366. }
  367. Expected<StringRef> YAMLStrTabRemarkParser::parseStr(yaml::KeyValueNode &Node) {
  368. auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue());
  369. if (!Value)
  370. return error("expected a value of scalar type.", Node);
  371. StringRef Result;
  372. // If we have a string table, parse it as an unsigned.
  373. unsigned StrID = 0;
  374. if (Expected<unsigned> MaybeStrID = parseUnsigned(Node))
  375. StrID = *MaybeStrID;
  376. else
  377. return MaybeStrID.takeError();
  378. if (Expected<StringRef> Str = (*StrTab)[StrID])
  379. Result = *Str;
  380. else
  381. return Str.takeError();
  382. if (Result.front() == '\'')
  383. Result = Result.drop_front();
  384. if (Result.back() == '\'')
  385. Result = Result.drop_back();
  386. return Result;
  387. }