1 //===- YAMLRemarkParser.cpp -----------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file provides utility methods used by clients that want to use the
10 // parser for remark diagnostics in LLVM.
12 //===----------------------------------------------------------------------===//
14 #include "YAMLRemarkParser.h"
15 #include "llvm/ADT/StringSwitch.h"
16 #include "llvm/Remarks/RemarkParser.h"
17 #include "llvm/Support/Endian.h"
20 using namespace llvm::remarks
;
22 char YAMLParseError::ID
= 0;
24 static void handleDiagnostic(const SMDiagnostic
&Diag
, void *Ctx
) {
25 assert(Ctx
&& "Expected non-null Ctx in diagnostic handler.");
26 std::string
&Message
= *static_cast<std::string
*>(Ctx
);
27 assert(Message
.empty() && "Expected an empty string.");
28 raw_string_ostream
OS(Message
);
29 Diag
.print(/*ProgName=*/nullptr, OS
, /*ShowColors*/ false,
30 /*ShowKindLabels*/ true);
35 YAMLParseError::YAMLParseError(StringRef Msg
, SourceMgr
&SM
,
36 yaml::Stream
&Stream
, yaml::Node
&Node
) {
37 // 1) Set up a diagnostic handler to avoid errors being printed out to
39 // 2) Use the stream to print the error with the associated node.
40 // 3) The stream will use the source manager to print the error, which will
41 // call the diagnostic handler.
42 // 4) The diagnostic handler will stream the error directly into this object's
43 // Message member, which is used when logging is asked for.
44 auto OldDiagHandler
= SM
.getDiagHandler();
45 auto OldDiagCtx
= SM
.getDiagContext();
46 SM
.setDiagHandler(handleDiagnostic
, &Message
);
47 Stream
.printError(&Node
, Twine(Msg
) + Twine('\n'));
48 // Restore the old handlers.
49 SM
.setDiagHandler(OldDiagHandler
, OldDiagCtx
);
52 static SourceMgr
setupSM(std::string
&LastErrorMessage
) {
54 SM
.setDiagHandler(handleDiagnostic
, &LastErrorMessage
);
58 // Parse the magic number. This function returns true if this represents remark
59 // metadata, false otherwise.
60 static Expected
<bool> parseMagic(StringRef
&Buf
) {
61 if (!Buf
.consume_front(remarks::Magic
))
64 if (Buf
.size() < 1 || !Buf
.consume_front(StringRef("\0", 1)))
65 return createStringError(std::errc::illegal_byte_sequence
,
66 "Expecting \\0 after magic number.");
70 static Expected
<uint64_t> parseVersion(StringRef
&Buf
) {
71 if (Buf
.size() < sizeof(uint64_t))
72 return createStringError(std::errc::illegal_byte_sequence
,
73 "Expecting version number.");
76 support::endian::read
<uint64_t, support::little
, support::unaligned
>(
78 if (Version
!= remarks::CurrentRemarkVersion
)
79 return createStringError(std::errc::illegal_byte_sequence
,
80 "Mismatching remark version. Got %" PRId64
81 ", expected %" PRId64
".",
82 Version
, remarks::CurrentRemarkVersion
);
83 Buf
= Buf
.drop_front(sizeof(uint64_t));
87 static Expected
<uint64_t> parseStrTabSize(StringRef
&Buf
) {
88 if (Buf
.size() < sizeof(uint64_t))
89 return createStringError(std::errc::illegal_byte_sequence
,
90 "Expecting string table size.");
92 support::endian::read
<uint64_t, support::little
, support::unaligned
>(
94 Buf
= Buf
.drop_front(sizeof(uint64_t));
98 static Expected
<ParsedStringTable
> parseStrTab(StringRef
&Buf
,
99 uint64_t StrTabSize
) {
100 if (Buf
.size() < StrTabSize
)
101 return createStringError(std::errc::illegal_byte_sequence
,
102 "Expecting string table.");
104 // Attach the string table to the parser.
105 ParsedStringTable
Result(StringRef(Buf
.data(), StrTabSize
));
106 Buf
= Buf
.drop_front(StrTabSize
);
107 return Expected
<ParsedStringTable
>(std::move(Result
));
110 Expected
<std::unique_ptr
<YAMLRemarkParser
>>
111 remarks::createYAMLParserFromMeta(StringRef Buf
,
112 Optional
<ParsedStringTable
> StrTab
) {
113 // We now have a magic number. The metadata has to be correct.
114 Expected
<bool> isMeta
= parseMagic(Buf
);
116 return isMeta
.takeError();
117 // If it's not recognized as metadata, roll back.
118 std::unique_ptr
<MemoryBuffer
> SeparateBuf
;
120 Expected
<uint64_t> Version
= parseVersion(Buf
);
122 return Version
.takeError();
124 Expected
<uint64_t> StrTabSize
= parseStrTabSize(Buf
);
126 return StrTabSize
.takeError();
128 // If the size of string table is not 0, try to build one.
129 if (*StrTabSize
!= 0) {
131 return createStringError(std::errc::illegal_byte_sequence
,
132 "String table already provided.");
133 Expected
<ParsedStringTable
> MaybeStrTab
= parseStrTab(Buf
, *StrTabSize
);
135 return MaybeStrTab
.takeError();
136 StrTab
= std::move(*MaybeStrTab
);
138 // If it starts with "---", there is no external file.
139 if (!Buf
.startswith("---")) {
140 // At this point, we expect Buf to contain the external file path.
141 // Try to open the file and start parsing from there.
142 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> BufferOrErr
=
143 MemoryBuffer::getFile(Buf
);
144 if (std::error_code EC
= BufferOrErr
.getError())
145 return errorCodeToError(EC
);
147 // Keep the buffer alive.
148 SeparateBuf
= std::move(*BufferOrErr
);
149 Buf
= SeparateBuf
->getBuffer();
153 std::unique_ptr
<YAMLRemarkParser
> Result
=
155 ? std::make_unique
<YAMLStrTabRemarkParser
>(Buf
, std::move(*StrTab
))
156 : std::make_unique
<YAMLRemarkParser
>(Buf
);
158 Result
->SeparateBuf
= std::move(SeparateBuf
);
159 return std::move(Result
);
162 YAMLRemarkParser::YAMLRemarkParser(StringRef Buf
)
163 : YAMLRemarkParser(Buf
, None
) {}
165 YAMLRemarkParser::YAMLRemarkParser(StringRef Buf
,
166 Optional
<ParsedStringTable
> StrTab
)
167 : RemarkParser
{Format::YAML
}, StrTab(std::move(StrTab
)), LastErrorMessage(),
168 SM(setupSM(LastErrorMessage
)), Stream(Buf
, SM
), YAMLIt(Stream
.begin()) {}
170 Error
YAMLRemarkParser::error(StringRef Message
, yaml::Node
&Node
) {
171 return make_error
<YAMLParseError
>(Message
, SM
, Stream
, Node
);
174 Error
YAMLRemarkParser::error() {
175 if (LastErrorMessage
.empty())
176 return Error::success();
177 Error E
= make_error
<YAMLParseError
>(LastErrorMessage
);
178 LastErrorMessage
.clear();
182 Expected
<std::unique_ptr
<Remark
>>
183 YAMLRemarkParser::parseRemark(yaml::Document
&RemarkEntry
) {
184 if (Error E
= error())
187 yaml::Node
*YAMLRoot
= RemarkEntry
.getRoot();
189 return createStringError(std::make_error_code(std::errc::invalid_argument
),
190 "not a valid YAML file.");
193 auto *Root
= dyn_cast
<yaml::MappingNode
>(YAMLRoot
);
195 return error("document root is not of mapping type.", *YAMLRoot
);
197 std::unique_ptr
<Remark
> Result
= std::make_unique
<Remark
>();
198 Remark
&TheRemark
= *Result
;
200 // First, the type. It needs special handling since is not part of the
202 Expected
<Type
> T
= parseType(*Root
);
204 return T
.takeError();
206 TheRemark
.RemarkType
= *T
;
208 // Then, parse the fields, one by one.
209 for (yaml::KeyValueNode
&RemarkField
: *Root
) {
210 Expected
<StringRef
> MaybeKey
= parseKey(RemarkField
);
212 return MaybeKey
.takeError();
213 StringRef KeyName
= *MaybeKey
;
215 if (KeyName
== "Pass") {
216 if (Expected
<StringRef
> MaybeStr
= parseStr(RemarkField
))
217 TheRemark
.PassName
= *MaybeStr
;
219 return MaybeStr
.takeError();
220 } else if (KeyName
== "Name") {
221 if (Expected
<StringRef
> MaybeStr
= parseStr(RemarkField
))
222 TheRemark
.RemarkName
= *MaybeStr
;
224 return MaybeStr
.takeError();
225 } else if (KeyName
== "Function") {
226 if (Expected
<StringRef
> MaybeStr
= parseStr(RemarkField
))
227 TheRemark
.FunctionName
= *MaybeStr
;
229 return MaybeStr
.takeError();
230 } else if (KeyName
== "Hotness") {
231 if (Expected
<unsigned> MaybeU
= parseUnsigned(RemarkField
))
232 TheRemark
.Hotness
= *MaybeU
;
234 return MaybeU
.takeError();
235 } else if (KeyName
== "DebugLoc") {
236 if (Expected
<RemarkLocation
> MaybeLoc
= parseDebugLoc(RemarkField
))
237 TheRemark
.Loc
= *MaybeLoc
;
239 return MaybeLoc
.takeError();
240 } else if (KeyName
== "Args") {
241 auto *Args
= dyn_cast
<yaml::SequenceNode
>(RemarkField
.getValue());
243 return error("wrong value type for key.", RemarkField
);
245 for (yaml::Node
&Arg
: *Args
) {
246 if (Expected
<Argument
> MaybeArg
= parseArg(Arg
))
247 TheRemark
.Args
.push_back(*MaybeArg
);
249 return MaybeArg
.takeError();
252 return error("unknown key.", RemarkField
);
256 // Check if any of the mandatory fields are missing.
257 if (TheRemark
.RemarkType
== Type::Unknown
|| TheRemark
.PassName
.empty() ||
258 TheRemark
.RemarkName
.empty() || TheRemark
.FunctionName
.empty())
259 return error("Type, Pass, Name or Function missing.",
260 *RemarkEntry
.getRoot());
262 return std::move(Result
);
265 Expected
<Type
> YAMLRemarkParser::parseType(yaml::MappingNode
&Node
) {
266 auto Type
= StringSwitch
<remarks::Type
>(Node
.getRawTag())
267 .Case("!Passed", remarks::Type::Passed
)
268 .Case("!Missed", remarks::Type::Missed
)
269 .Case("!Analysis", remarks::Type::Analysis
)
270 .Case("!AnalysisFPCommute", remarks::Type::AnalysisFPCommute
)
271 .Case("!AnalysisAliasing", remarks::Type::AnalysisAliasing
)
272 .Case("!Failure", remarks::Type::Failure
)
273 .Default(remarks::Type::Unknown
);
274 if (Type
== remarks::Type::Unknown
)
275 return error("expected a remark tag.", Node
);
279 Expected
<StringRef
> YAMLRemarkParser::parseKey(yaml::KeyValueNode
&Node
) {
280 if (auto *Key
= dyn_cast
<yaml::ScalarNode
>(Node
.getKey()))
281 return Key
->getRawValue();
283 return error("key is not a string.", Node
);
286 Expected
<StringRef
> YAMLRemarkParser::parseStr(yaml::KeyValueNode
&Node
) {
287 auto *Value
= dyn_cast
<yaml::ScalarNode
>(Node
.getValue());
289 return error("expected a value of scalar type.", Node
);
290 StringRef Result
= Value
->getRawValue();
292 if (Result
.front() == '\'')
293 Result
= Result
.drop_front();
295 if (Result
.back() == '\'')
296 Result
= Result
.drop_back();
301 Expected
<unsigned> YAMLRemarkParser::parseUnsigned(yaml::KeyValueNode
&Node
) {
302 SmallVector
<char, 4> Tmp
;
303 auto *Value
= dyn_cast
<yaml::ScalarNode
>(Node
.getValue());
305 return error("expected a value of scalar type.", Node
);
306 unsigned UnsignedValue
= 0;
307 if (Value
->getValue(Tmp
).getAsInteger(10, UnsignedValue
))
308 return error("expected a value of integer type.", *Value
);
309 return UnsignedValue
;
312 Expected
<RemarkLocation
>
313 YAMLRemarkParser::parseDebugLoc(yaml::KeyValueNode
&Node
) {
314 auto *DebugLoc
= dyn_cast
<yaml::MappingNode
>(Node
.getValue());
316 return error("expected a value of mapping type.", Node
);
318 Optional
<StringRef
> File
;
319 Optional
<unsigned> Line
;
320 Optional
<unsigned> Column
;
322 for (yaml::KeyValueNode
&DLNode
: *DebugLoc
) {
323 Expected
<StringRef
> MaybeKey
= parseKey(DLNode
);
325 return MaybeKey
.takeError();
326 StringRef KeyName
= *MaybeKey
;
328 if (KeyName
== "File") {
329 if (Expected
<StringRef
> MaybeStr
= parseStr(DLNode
))
332 return MaybeStr
.takeError();
333 } else if (KeyName
== "Column") {
334 if (Expected
<unsigned> MaybeU
= parseUnsigned(DLNode
))
337 return MaybeU
.takeError();
338 } else if (KeyName
== "Line") {
339 if (Expected
<unsigned> MaybeU
= parseUnsigned(DLNode
))
342 return MaybeU
.takeError();
344 return error("unknown entry in DebugLoc map.", DLNode
);
348 // If any of the debug loc fields is missing, return an error.
349 if (!File
|| !Line
|| !Column
)
350 return error("DebugLoc node incomplete.", Node
);
352 return RemarkLocation
{*File
, *Line
, *Column
};
355 Expected
<Argument
> YAMLRemarkParser::parseArg(yaml::Node
&Node
) {
356 auto *ArgMap
= dyn_cast
<yaml::MappingNode
>(&Node
);
358 return error("expected a value of mapping type.", Node
);
360 Optional
<StringRef
> KeyStr
;
361 Optional
<StringRef
> ValueStr
;
362 Optional
<RemarkLocation
> Loc
;
364 for (yaml::KeyValueNode
&ArgEntry
: *ArgMap
) {
365 Expected
<StringRef
> MaybeKey
= parseKey(ArgEntry
);
367 return MaybeKey
.takeError();
368 StringRef KeyName
= *MaybeKey
;
370 // Try to parse debug locs.
371 if (KeyName
== "DebugLoc") {
372 // Can't have multiple DebugLoc entries per argument.
374 return error("only one DebugLoc entry is allowed per argument.",
377 if (Expected
<RemarkLocation
> MaybeLoc
= parseDebugLoc(ArgEntry
)) {
381 return MaybeLoc
.takeError();
384 // If we already have a string, error out.
386 return error("only one string entry is allowed per argument.", ArgEntry
);
388 // Try to parse the value.
389 if (Expected
<StringRef
> MaybeStr
= parseStr(ArgEntry
))
390 ValueStr
= *MaybeStr
;
392 return MaybeStr
.takeError();
394 // Keep the key from the string.
399 return error("argument key is missing.", *ArgMap
);
401 return error("argument value is missing.", *ArgMap
);
403 return Argument
{*KeyStr
, *ValueStr
, Loc
};
406 Expected
<std::unique_ptr
<Remark
>> YAMLRemarkParser::next() {
407 if (YAMLIt
== Stream
.end())
408 return make_error
<EndOfFileError
>();
410 Expected
<std::unique_ptr
<Remark
>> MaybeResult
= parseRemark(*YAMLIt
);
412 // Avoid garbage input, set the iterator to the end.
413 YAMLIt
= Stream
.end();
414 return MaybeResult
.takeError();
419 return std::move(*MaybeResult
);
422 Expected
<StringRef
> YAMLStrTabRemarkParser::parseStr(yaml::KeyValueNode
&Node
) {
423 auto *Value
= dyn_cast
<yaml::ScalarNode
>(Node
.getValue());
425 return error("expected a value of scalar type.", Node
);
427 // If we have a string table, parse it as an unsigned.
429 if (Expected
<unsigned> MaybeStrID
= parseUnsigned(Node
))
432 return MaybeStrID
.takeError();
434 if (Expected
<StringRef
> Str
= (*StrTab
)[StrID
])
437 return Str
.takeError();
439 if (Result
.front() == '\'')
440 Result
= Result
.drop_front();
442 if (Result
.back() == '\'')
443 Result
= Result
.drop_back();