1 //===- BitstreamRemarkParser.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 "llvm/Remarks/BitstreamRemarkParser.h" 15 #include "BitstreamRemarkParser.h" 16 #include "llvm/Remarks/BitstreamRemarkContainer.h" 17 #include "llvm/Support/MemoryBuffer.h" 18 19 using namespace llvm; 20 using namespace llvm::remarks; 21 22 static Error unknownRecord(const char *BlockName, unsigned RecordID) { 23 return createStringError( 24 std::make_error_code(std::errc::illegal_byte_sequence), 25 "Error while parsing %s: unknown record entry (%lu).", BlockName, 26 RecordID); 27 } 28 29 static Error malformedRecord(const char *BlockName, const char *RecordName) { 30 return createStringError( 31 std::make_error_code(std::errc::illegal_byte_sequence), 32 "Error while parsing %s: malformed record entry (%s).", BlockName, 33 RecordName); 34 } 35 36 BitstreamMetaParserHelper::BitstreamMetaParserHelper( 37 BitstreamCursor &Stream, BitstreamBlockInfo &BlockInfo) 38 : Stream(Stream), BlockInfo(BlockInfo) {} 39 40 /// Parse a record and fill in the fields in the parser. 41 static Error parseRecord(BitstreamMetaParserHelper &Parser, unsigned Code) { 42 BitstreamCursor &Stream = Parser.Stream; 43 // Note: 2 is used here because it's the max number of fields we have per 44 // record. 45 SmallVector<uint64_t, 2> Record; 46 StringRef Blob; 47 Expected<unsigned> RecordID = Stream.readRecord(Code, Record, &Blob); 48 if (!RecordID) 49 return RecordID.takeError(); 50 51 switch (*RecordID) { 52 case RECORD_META_CONTAINER_INFO: { 53 if (Record.size() != 2) 54 return malformedRecord("BLOCK_META", "RECORD_META_CONTAINER_INFO"); 55 Parser.ContainerVersion = Record[0]; 56 Parser.ContainerType = Record[1]; 57 break; 58 } 59 case RECORD_META_REMARK_VERSION: { 60 if (Record.size() != 1) 61 return malformedRecord("BLOCK_META", "RECORD_META_REMARK_VERSION"); 62 Parser.RemarkVersion = Record[0]; 63 break; 64 } 65 case RECORD_META_STRTAB: { 66 if (Record.size() != 0) 67 return malformedRecord("BLOCK_META", "RECORD_META_STRTAB"); 68 Parser.StrTabBuf = Blob; 69 break; 70 } 71 case RECORD_META_EXTERNAL_FILE: { 72 if (Record.size() != 0) 73 return malformedRecord("BLOCK_META", "RECORD_META_EXTERNAL_FILE"); 74 Parser.ExternalFilePath = Blob; 75 break; 76 } 77 default: 78 return unknownRecord("BLOCK_META", *RecordID); 79 } 80 return Error::success(); 81 } 82 83 BitstreamRemarkParserHelper::BitstreamRemarkParserHelper( 84 BitstreamCursor &Stream) 85 : Stream(Stream) {} 86 87 /// Parse a record and fill in the fields in the parser. 88 static Error parseRecord(BitstreamRemarkParserHelper &Parser, unsigned Code) { 89 BitstreamCursor &Stream = Parser.Stream; 90 // Note: 5 is used here because it's the max number of fields we have per 91 // record. 92 SmallVector<uint64_t, 5> Record; 93 StringRef Blob; 94 Expected<unsigned> RecordID = Stream.readRecord(Code, Record, &Blob); 95 if (!RecordID) 96 return RecordID.takeError(); 97 98 switch (*RecordID) { 99 case RECORD_REMARK_HEADER: { 100 if (Record.size() != 4) 101 return malformedRecord("BLOCK_REMARK", "RECORD_REMARK_HEADER"); 102 Parser.Type = Record[0]; 103 Parser.RemarkNameIdx = Record[1]; 104 Parser.PassNameIdx = Record[2]; 105 Parser.FunctionNameIdx = Record[3]; 106 break; 107 } 108 case RECORD_REMARK_DEBUG_LOC: { 109 if (Record.size() != 3) 110 return malformedRecord("BLOCK_REMARK", "RECORD_REMARK_DEBUG_LOC"); 111 Parser.SourceFileNameIdx = Record[0]; 112 Parser.SourceLine = Record[1]; 113 Parser.SourceColumn = Record[2]; 114 break; 115 } 116 case RECORD_REMARK_HOTNESS: { 117 if (Record.size() != 1) 118 return malformedRecord("BLOCK_REMARK", "RECORD_REMARK_HOTNESS"); 119 Parser.Hotness = Record[0]; 120 break; 121 } 122 case RECORD_REMARK_ARG_WITH_DEBUGLOC: { 123 if (Record.size() != 5) 124 return malformedRecord("BLOCK_REMARK", "RECORD_REMARK_ARG_WITH_DEBUGLOC"); 125 // Create a temporary argument. Use that as a valid memory location for this 126 // argument entry. 127 Parser.TmpArgs.emplace_back(); 128 Parser.TmpArgs.back().KeyIdx = Record[0]; 129 Parser.TmpArgs.back().ValueIdx = Record[1]; 130 Parser.TmpArgs.back().SourceFileNameIdx = Record[2]; 131 Parser.TmpArgs.back().SourceLine = Record[3]; 132 Parser.TmpArgs.back().SourceColumn = Record[4]; 133 Parser.Args = 134 ArrayRef<BitstreamRemarkParserHelper::Argument>(Parser.TmpArgs); 135 break; 136 } 137 case RECORD_REMARK_ARG_WITHOUT_DEBUGLOC: { 138 if (Record.size() != 2) 139 return malformedRecord("BLOCK_REMARK", 140 "RECORD_REMARK_ARG_WITHOUT_DEBUGLOC"); 141 // Create a temporary argument. Use that as a valid memory location for this 142 // argument entry. 143 Parser.TmpArgs.emplace_back(); 144 Parser.TmpArgs.back().KeyIdx = Record[0]; 145 Parser.TmpArgs.back().ValueIdx = Record[1]; 146 Parser.Args = 147 ArrayRef<BitstreamRemarkParserHelper::Argument>(Parser.TmpArgs); 148 break; 149 } 150 default: 151 return unknownRecord("BLOCK_REMARK", *RecordID); 152 } 153 return Error::success(); 154 } 155 156 template <typename T> 157 static Error parseBlock(T &ParserHelper, unsigned BlockID, 158 const char *BlockName) { 159 BitstreamCursor &Stream = ParserHelper.Stream; 160 Expected<BitstreamEntry> Next = Stream.advance(); 161 if (!Next) 162 return Next.takeError(); 163 if (Next->Kind != BitstreamEntry::SubBlock || Next->ID != BlockID) 164 return createStringError( 165 std::make_error_code(std::errc::illegal_byte_sequence), 166 "Error while parsing %s: expecting [ENTER_SUBBLOCK, %s, ...].", 167 BlockName, BlockName); 168 if (Stream.EnterSubBlock(BlockID)) 169 return createStringError( 170 std::make_error_code(std::errc::illegal_byte_sequence), 171 "Error while entering %s.", BlockName); 172 173 // Stop when there is nothing to read anymore or when we encounter an 174 // END_BLOCK. 175 while (!Stream.AtEndOfStream()) { 176 Expected<BitstreamEntry> Next = Stream.advance(); 177 if (!Next) 178 return Next.takeError(); 179 switch (Next->Kind) { 180 case BitstreamEntry::EndBlock: 181 return Error::success(); 182 case BitstreamEntry::Error: 183 case BitstreamEntry::SubBlock: 184 return createStringError( 185 std::make_error_code(std::errc::illegal_byte_sequence), 186 "Error while parsing %s: expecting records.", BlockName); 187 case BitstreamEntry::Record: 188 if (Error E = parseRecord(ParserHelper, Next->ID)) 189 return E; 190 continue; 191 } 192 } 193 // If we're here, it means we didn't get an END_BLOCK yet, but we're at the 194 // end of the stream. In this case, error. 195 return createStringError( 196 std::make_error_code(std::errc::illegal_byte_sequence), 197 "Error while parsing %s: unterminated block.", BlockName); 198 } 199 200 Error BitstreamMetaParserHelper::parse() { 201 return parseBlock(*this, META_BLOCK_ID, "META_BLOCK"); 202 } 203 204 Error BitstreamRemarkParserHelper::parse() { 205 return parseBlock(*this, REMARK_BLOCK_ID, "REMARK_BLOCK"); 206 } 207 208 BitstreamParserHelper::BitstreamParserHelper(StringRef Buffer) 209 : Stream(Buffer) {} 210 211 Expected<std::array<char, 4>> BitstreamParserHelper::parseMagic() { 212 std::array<char, 4> Result; 213 for (unsigned i = 0; i < 4; ++i) 214 if (Expected<unsigned> R = Stream.Read(8)) 215 Result[i] = *R; 216 else 217 return R.takeError(); 218 return Result; 219 } 220 221 Error BitstreamParserHelper::parseBlockInfoBlock() { 222 Expected<BitstreamEntry> Next = Stream.advance(); 223 if (!Next) 224 return Next.takeError(); 225 if (Next->Kind != BitstreamEntry::SubBlock || 226 Next->ID != llvm::bitc::BLOCKINFO_BLOCK_ID) 227 return createStringError( 228 std::make_error_code(std::errc::illegal_byte_sequence), 229 "Error while parsing BLOCKINFO_BLOCK: expecting [ENTER_SUBBLOCK, " 230 "BLOCKINFO_BLOCK, ...]."); 231 232 Expected<Optional<BitstreamBlockInfo>> MaybeBlockInfo = 233 Stream.ReadBlockInfoBlock(); 234 if (!MaybeBlockInfo) 235 return MaybeBlockInfo.takeError(); 236 237 if (!*MaybeBlockInfo) 238 return createStringError( 239 std::make_error_code(std::errc::illegal_byte_sequence), 240 "Error while parsing BLOCKINFO_BLOCK."); 241 242 BlockInfo = **MaybeBlockInfo; 243 244 Stream.setBlockInfo(&BlockInfo); 245 return Error::success(); 246 } 247 248 static Expected<bool> isBlock(BitstreamCursor &Stream, unsigned BlockID) { 249 bool Result = false; 250 uint64_t PreviousBitNo = Stream.GetCurrentBitNo(); 251 Expected<BitstreamEntry> Next = Stream.advance(); 252 if (!Next) 253 return Next.takeError(); 254 switch (Next->Kind) { 255 case BitstreamEntry::SubBlock: 256 // Check for the block id. 257 Result = Next->ID == BlockID; 258 break; 259 case BitstreamEntry::Error: 260 return createStringError( 261 std::make_error_code(std::errc::illegal_byte_sequence), 262 "Unexpected error while parsing bitstream."); 263 default: 264 Result = false; 265 break; 266 } 267 if (Error E = Stream.JumpToBit(PreviousBitNo)) 268 return std::move(E); 269 return Result; 270 } 271 272 Expected<bool> BitstreamParserHelper::isMetaBlock() { 273 return isBlock(Stream, META_BLOCK_ID); 274 } 275 276 Expected<bool> BitstreamParserHelper::isRemarkBlock() { 277 return isBlock(Stream, META_BLOCK_ID); 278 } 279 280 static Error validateMagicNumber(StringRef Magic) { 281 if (Magic != remarks::ContainerMagic) 282 return createStringError(std::make_error_code(std::errc::invalid_argument), 283 "Unknown magic number: expecting %s, got %.4s.", 284 remarks::ContainerMagic.data(), Magic.data()); 285 return Error::success(); 286 } 287 288 static Error advanceToMetaBlock(BitstreamParserHelper &Helper) { 289 Expected<std::array<char, 4>> Magic = Helper.parseMagic(); 290 if (!Magic) 291 return Magic.takeError(); 292 if (Error E = validateMagicNumber(StringRef(Magic->data(), Magic->size()))) 293 return E; 294 if (Error E = Helper.parseBlockInfoBlock()) 295 return E; 296 Expected<bool> isMetaBlock = Helper.isMetaBlock(); 297 if (!isMetaBlock) 298 return isMetaBlock.takeError(); 299 if (!*isMetaBlock) 300 return createStringError( 301 std::make_error_code(std::errc::illegal_byte_sequence), 302 "Expecting META_BLOCK after the BLOCKINFO_BLOCK."); 303 return Error::success(); 304 } 305 306 Expected<std::unique_ptr<BitstreamRemarkParser>> 307 remarks::createBitstreamParserFromMeta(StringRef Buf, 308 Optional<ParsedStringTable> StrTab) { 309 BitstreamParserHelper Helper(Buf); 310 Expected<std::array<char, 4>> Magic = Helper.parseMagic(); 311 if (!Magic) 312 return Magic.takeError(); 313 314 if (Error E = validateMagicNumber(StringRef(Magic->data(), Magic->size()))) 315 return std::move(E); 316 317 return StrTab 318 ? std::make_unique<BitstreamRemarkParser>(Buf, std::move(*StrTab)) 319 : std::make_unique<BitstreamRemarkParser>(Buf); 320 } 321 322 Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::next() { 323 if (ParserHelper.atEndOfStream()) 324 return make_error<EndOfFileError>(); 325 326 if (!ReadyToParseRemarks) { 327 if (Error E = parseMeta()) 328 return std::move(E); 329 ReadyToParseRemarks = true; 330 } 331 332 return parseRemark(); 333 } 334 335 Error BitstreamRemarkParser::parseMeta() { 336 // Advance and to the meta block. 337 if (Error E = advanceToMetaBlock(ParserHelper)) 338 return E; 339 340 BitstreamMetaParserHelper MetaHelper(ParserHelper.Stream, 341 ParserHelper.BlockInfo); 342 if (Error E = MetaHelper.parse()) 343 return E; 344 345 if (Error E = processCommonMeta(MetaHelper)) 346 return E; 347 348 switch (ContainerType) { 349 case BitstreamRemarkContainerType::Standalone: 350 return processStandaloneMeta(MetaHelper); 351 case BitstreamRemarkContainerType::SeparateRemarksFile: 352 return processSeparateRemarksFileMeta(MetaHelper); 353 case BitstreamRemarkContainerType::SeparateRemarksMeta: 354 return processSeparateRemarksMetaMeta(MetaHelper); 355 } 356 llvm_unreachable("Unknown BitstreamRemarkContainerType enum"); 357 } 358 359 Error BitstreamRemarkParser::processCommonMeta( 360 BitstreamMetaParserHelper &MetaHelper) { 361 if (Optional<uint64_t> Version = MetaHelper.ContainerVersion) 362 ContainerVersion = *Version; 363 else 364 return createStringError( 365 std::make_error_code(std::errc::illegal_byte_sequence), 366 "Error while parsing BLOCK_META: missing container version."); 367 368 if (Optional<uint8_t> Type = MetaHelper.ContainerType) { 369 // Always >= BitstreamRemarkContainerType::First since it's unsigned. 370 if (*Type > static_cast<uint8_t>(BitstreamRemarkContainerType::Last)) 371 return createStringError( 372 std::make_error_code(std::errc::illegal_byte_sequence), 373 "Error while parsing BLOCK_META: invalid container type."); 374 375 ContainerType = static_cast<BitstreamRemarkContainerType>(*Type); 376 } else 377 return createStringError( 378 std::make_error_code(std::errc::illegal_byte_sequence), 379 "Error while parsing BLOCK_META: missing container type."); 380 381 return Error::success(); 382 } 383 384 static Error processStrTab(BitstreamRemarkParser &P, 385 Optional<StringRef> StrTabBuf) { 386 if (!StrTabBuf) 387 return createStringError( 388 std::make_error_code(std::errc::illegal_byte_sequence), 389 "Error while parsing BLOCK_META: missing string table."); 390 // Parse and assign the string table. 391 P.StrTab.emplace(*StrTabBuf); 392 return Error::success(); 393 } 394 395 static Error processRemarkVersion(BitstreamRemarkParser &P, 396 Optional<uint64_t> RemarkVersion) { 397 if (!RemarkVersion) 398 return createStringError( 399 std::make_error_code(std::errc::illegal_byte_sequence), 400 "Error while parsing BLOCK_META: missing remark version."); 401 P.RemarkVersion = *RemarkVersion; 402 return Error::success(); 403 } 404 405 Error BitstreamRemarkParser::processExternalFilePath( 406 Optional<StringRef> ExternalFilePath) { 407 if (!ExternalFilePath) 408 return createStringError( 409 std::make_error_code(std::errc::illegal_byte_sequence), 410 "Error while parsing BLOCK_META: missing external file path."); 411 412 // External file: open the external file, parse it, check if its metadata 413 // matches the one from the separate metadata, then replace the current parser 414 // with the one parsing the remarks. 415 ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = 416 MemoryBuffer::getFile(*ExternalFilePath); 417 if (std::error_code EC = BufferOrErr.getError()) 418 return errorCodeToError(EC); 419 TmpRemarkBuffer = std::move(*BufferOrErr); 420 421 // Create a separate parser used for parsing the separate file. 422 ParserHelper = BitstreamParserHelper(TmpRemarkBuffer->getBuffer()); 423 // Advance and check until we can parse the meta block. 424 if (Error E = advanceToMetaBlock(ParserHelper)) 425 return E; 426 // Parse the meta from the separate file. 427 // Note: here we overwrite the BlockInfo with the one from the file. This will 428 // be used to parse the rest of the file. 429 BitstreamMetaParserHelper SeparateMetaHelper(ParserHelper.Stream, 430 ParserHelper.BlockInfo); 431 if (Error E = SeparateMetaHelper.parse()) 432 return E; 433 434 uint64_t PreviousContainerVersion = ContainerVersion; 435 if (Error E = processCommonMeta(SeparateMetaHelper)) 436 return E; 437 438 if (ContainerType != BitstreamRemarkContainerType::SeparateRemarksFile) 439 return createStringError( 440 std::make_error_code(std::errc::illegal_byte_sequence), 441 "Error while parsing external file's BLOCK_META: wrong container " 442 "type."); 443 444 if (PreviousContainerVersion != ContainerVersion) 445 return createStringError( 446 std::make_error_code(std::errc::illegal_byte_sequence), 447 "Error while parsing external file's BLOCK_META: mismatching versions: " 448 "original meta: %lu, external file meta: %lu.", 449 PreviousContainerVersion, ContainerVersion); 450 451 // Process the meta from the separate file. 452 return processSeparateRemarksFileMeta(SeparateMetaHelper); 453 } 454 455 Error BitstreamRemarkParser::processStandaloneMeta( 456 BitstreamMetaParserHelper &Helper) { 457 if (Error E = processStrTab(*this, Helper.StrTabBuf)) 458 return E; 459 return processRemarkVersion(*this, Helper.RemarkVersion); 460 } 461 462 Error BitstreamRemarkParser::processSeparateRemarksFileMeta( 463 BitstreamMetaParserHelper &Helper) { 464 return processRemarkVersion(*this, Helper.RemarkVersion); 465 } 466 467 Error BitstreamRemarkParser::processSeparateRemarksMetaMeta( 468 BitstreamMetaParserHelper &Helper) { 469 if (Error E = processStrTab(*this, Helper.StrTabBuf)) 470 return E; 471 return processExternalFilePath(Helper.ExternalFilePath); 472 } 473 474 Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::parseRemark() { 475 BitstreamRemarkParserHelper RemarkHelper(ParserHelper.Stream); 476 if (Error E = RemarkHelper.parse()) 477 return std::move(E); 478 479 return processRemark(RemarkHelper); 480 } 481 482 Expected<std::unique_ptr<Remark>> 483 BitstreamRemarkParser::processRemark(BitstreamRemarkParserHelper &Helper) { 484 std::unique_ptr<Remark> Result = std::make_unique<Remark>(); 485 Remark &R = *Result; 486 487 if (StrTab == None) 488 return createStringError( 489 std::make_error_code(std::errc::invalid_argument), 490 "Error while parsing BLOCK_REMARK: missing string table."); 491 492 if (!Helper.Type) 493 return createStringError( 494 std::make_error_code(std::errc::illegal_byte_sequence), 495 "Error while parsing BLOCK_REMARK: missing remark type."); 496 497 // Always >= Type::First since it's unsigned. 498 if (*Helper.Type > static_cast<uint8_t>(Type::Last)) 499 return createStringError( 500 std::make_error_code(std::errc::illegal_byte_sequence), 501 "Error while parsing BLOCK_REMARK: unknown remark type."); 502 503 R.RemarkType = static_cast<Type>(*Helper.Type); 504 505 if (!Helper.RemarkNameIdx) 506 return createStringError( 507 std::make_error_code(std::errc::illegal_byte_sequence), 508 "Error while parsing BLOCK_REMARK: missing remark name."); 509 510 if (Expected<StringRef> RemarkName = (*StrTab)[*Helper.RemarkNameIdx]) 511 R.RemarkName = *RemarkName; 512 else 513 return RemarkName.takeError(); 514 515 if (!Helper.PassNameIdx) 516 return createStringError( 517 std::make_error_code(std::errc::illegal_byte_sequence), 518 "Error while parsing BLOCK_REMARK: missing remark pass."); 519 520 if (Expected<StringRef> PassName = (*StrTab)[*Helper.PassNameIdx]) 521 R.PassName = *PassName; 522 else 523 return PassName.takeError(); 524 525 if (!Helper.FunctionNameIdx) 526 return createStringError( 527 std::make_error_code(std::errc::illegal_byte_sequence), 528 "Error while parsing BLOCK_REMARK: missing remark function name."); 529 if (Expected<StringRef> FunctionName = (*StrTab)[*Helper.FunctionNameIdx]) 530 R.FunctionName = *FunctionName; 531 else 532 return FunctionName.takeError(); 533 534 if (Helper.SourceFileNameIdx && Helper.SourceLine && Helper.SourceColumn) { 535 Expected<StringRef> SourceFileName = (*StrTab)[*Helper.SourceFileNameIdx]; 536 if (!SourceFileName) 537 return SourceFileName.takeError(); 538 R.Loc.emplace(); 539 R.Loc->SourceFilePath = *SourceFileName; 540 R.Loc->SourceLine = *Helper.SourceLine; 541 R.Loc->SourceColumn = *Helper.SourceColumn; 542 } 543 544 if (Helper.Hotness) 545 R.Hotness = *Helper.Hotness; 546 547 if (!Helper.Args) 548 return std::move(Result); 549 550 for (const BitstreamRemarkParserHelper::Argument &Arg : *Helper.Args) { 551 if (!Arg.KeyIdx) 552 return createStringError( 553 std::make_error_code(std::errc::illegal_byte_sequence), 554 "Error while parsing BLOCK_REMARK: missing key in remark argument."); 555 if (!Arg.ValueIdx) 556 return createStringError( 557 std::make_error_code(std::errc::illegal_byte_sequence), 558 "Error while parsing BLOCK_REMARK: missing value in remark " 559 "argument."); 560 561 // We have at least a key and a value, create an entry. 562 R.Args.emplace_back(); 563 564 if (Expected<StringRef> Key = (*StrTab)[*Arg.KeyIdx]) 565 R.Args.back().Key = *Key; 566 else 567 return Key.takeError(); 568 569 if (Expected<StringRef> Value = (*StrTab)[*Arg.ValueIdx]) 570 R.Args.back().Val = *Value; 571 else 572 return Value.takeError(); 573 574 if (Arg.SourceFileNameIdx && Arg.SourceLine && Arg.SourceColumn) { 575 if (Expected<StringRef> SourceFileName = 576 (*StrTab)[*Arg.SourceFileNameIdx]) { 577 R.Args.back().Loc.emplace(); 578 R.Args.back().Loc->SourceFilePath = *SourceFileName; 579 R.Args.back().Loc->SourceLine = *Arg.SourceLine; 580 R.Args.back().Loc->SourceColumn = *Arg.SourceColumn; 581 } else 582 return SourceFileName.takeError(); 583 } 584 } 585 586 return std::move(Result); 587 } 588