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 if (Result.front() == '\'') 306 Result = Result.drop_front(); 307 308 if (Result.back() == '\'') 309 Result = Result.drop_back(); 310 311 return Result; 312 } 313 314 Expected<unsigned> YAMLRemarkParser::parseUnsigned(yaml::KeyValueNode &Node) { 315 SmallVector<char, 4> Tmp; 316 auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue()); 317 if (!Value) 318 return error("expected a value of scalar type.", Node); 319 unsigned UnsignedValue = 0; 320 if (Value->getValue(Tmp).getAsInteger(10, UnsignedValue)) 321 return error("expected a value of integer type.", *Value); 322 return UnsignedValue; 323 } 324 325 Expected<RemarkLocation> 326 YAMLRemarkParser::parseDebugLoc(yaml::KeyValueNode &Node) { 327 auto *DebugLoc = dyn_cast<yaml::MappingNode>(Node.getValue()); 328 if (!DebugLoc) 329 return error("expected a value of mapping type.", Node); 330 331 std::optional<StringRef> File; 332 std::optional<unsigned> Line; 333 std::optional<unsigned> Column; 334 335 for (yaml::KeyValueNode &DLNode : *DebugLoc) { 336 Expected<StringRef> MaybeKey = parseKey(DLNode); 337 if (!MaybeKey) 338 return MaybeKey.takeError(); 339 StringRef KeyName = *MaybeKey; 340 341 if (KeyName == "File") { 342 if (Expected<StringRef> MaybeStr = parseStr(DLNode)) 343 File = *MaybeStr; 344 else 345 return MaybeStr.takeError(); 346 } else if (KeyName == "Column") { 347 if (Expected<unsigned> MaybeU = parseUnsigned(DLNode)) 348 Column = *MaybeU; 349 else 350 return MaybeU.takeError(); 351 } else if (KeyName == "Line") { 352 if (Expected<unsigned> MaybeU = parseUnsigned(DLNode)) 353 Line = *MaybeU; 354 else 355 return MaybeU.takeError(); 356 } else { 357 return error("unknown entry in DebugLoc map.", DLNode); 358 } 359 } 360 361 // If any of the debug loc fields is missing, return an error. 362 if (!File || !Line || !Column) 363 return error("DebugLoc node incomplete.", Node); 364 365 return RemarkLocation{*File, *Line, *Column}; 366 } 367 368 Expected<Argument> YAMLRemarkParser::parseArg(yaml::Node &Node) { 369 auto *ArgMap = dyn_cast<yaml::MappingNode>(&Node); 370 if (!ArgMap) 371 return error("expected a value of mapping type.", Node); 372 373 std::optional<StringRef> KeyStr; 374 std::optional<StringRef> ValueStr; 375 std::optional<RemarkLocation> Loc; 376 377 for (yaml::KeyValueNode &ArgEntry : *ArgMap) { 378 Expected<StringRef> MaybeKey = parseKey(ArgEntry); 379 if (!MaybeKey) 380 return MaybeKey.takeError(); 381 StringRef KeyName = *MaybeKey; 382 383 // Try to parse debug locs. 384 if (KeyName == "DebugLoc") { 385 // Can't have multiple DebugLoc entries per argument. 386 if (Loc) 387 return error("only one DebugLoc entry is allowed per argument.", 388 ArgEntry); 389 390 if (Expected<RemarkLocation> MaybeLoc = parseDebugLoc(ArgEntry)) { 391 Loc = *MaybeLoc; 392 continue; 393 } else 394 return MaybeLoc.takeError(); 395 } 396 397 // If we already have a string, error out. 398 if (ValueStr) 399 return error("only one string entry is allowed per argument.", ArgEntry); 400 401 // Try to parse the value. 402 if (Expected<StringRef> MaybeStr = parseStr(ArgEntry)) 403 ValueStr = *MaybeStr; 404 else 405 return MaybeStr.takeError(); 406 407 // Keep the key from the string. 408 KeyStr = KeyName; 409 } 410 411 if (!KeyStr) 412 return error("argument key is missing.", *ArgMap); 413 if (!ValueStr) 414 return error("argument value is missing.", *ArgMap); 415 416 return Argument{*KeyStr, *ValueStr, Loc}; 417 } 418 419 Expected<std::unique_ptr<Remark>> YAMLRemarkParser::next() { 420 if (YAMLIt == Stream.end()) 421 return make_error<EndOfFileError>(); 422 423 Expected<std::unique_ptr<Remark>> MaybeResult = parseRemark(*YAMLIt); 424 if (!MaybeResult) { 425 // Avoid garbage input, set the iterator to the end. 426 YAMLIt = Stream.end(); 427 return MaybeResult.takeError(); 428 } 429 430 ++YAMLIt; 431 432 return std::move(*MaybeResult); 433 } 434 435 Expected<StringRef> YAMLStrTabRemarkParser::parseStr(yaml::KeyValueNode &Node) { 436 auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue()); 437 yaml::BlockScalarNode *ValueBlock; 438 StringRef Result; 439 if (!Value) { 440 // Try to parse the value as a block node. 441 ValueBlock = dyn_cast<yaml::BlockScalarNode>(Node.getValue()); 442 if (!ValueBlock) 443 return error("expected a value of scalar type.", Node); 444 Result = ValueBlock->getValue(); 445 } else 446 Result = Value->getRawValue(); 447 // If we have a string table, parse it as an unsigned. 448 unsigned StrID = 0; 449 if (Expected<unsigned> MaybeStrID = parseUnsigned(Node)) 450 StrID = *MaybeStrID; 451 else 452 return MaybeStrID.takeError(); 453 454 if (Expected<StringRef> Str = (*StrTab)[StrID]) 455 Result = *Str; 456 else 457 return Str.takeError(); 458 459 if (Result.front() == '\'') 460 Result = Result.drop_front(); 461 462 if (Result.back() == '\'') 463 Result = Result.drop_back(); 464 465 return Result; 466 } 467