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