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 } 357 358 Error BitstreamRemarkParser::processCommonMeta( 359 BitstreamMetaParserHelper &MetaHelper) { 360 if (Optional<uint64_t> Version = MetaHelper.ContainerVersion) 361 ContainerVersion = *Version; 362 else 363 return createStringError( 364 std::make_error_code(std::errc::illegal_byte_sequence), 365 "Error while parsing BLOCK_META: missing container version."); 366 367 if (Optional<uint8_t> Type = MetaHelper.ContainerType) { 368 // Always >= BitstreamRemarkContainerType::First since it's unsigned. 369 if (*Type > static_cast<uint8_t>(BitstreamRemarkContainerType::Last)) 370 return createStringError( 371 std::make_error_code(std::errc::illegal_byte_sequence), 372 "Error while parsing BLOCK_META: invalid container type."); 373 374 ContainerType = static_cast<BitstreamRemarkContainerType>(*Type); 375 } else 376 return createStringError( 377 std::make_error_code(std::errc::illegal_byte_sequence), 378 "Error while parsing BLOCK_META: missing container type."); 379 380 return Error::success(); 381 } 382 383 static Error processStrTab(BitstreamRemarkParser &P, 384 Optional<StringRef> StrTabBuf) { 385 if (!StrTabBuf) 386 return createStringError( 387 std::make_error_code(std::errc::illegal_byte_sequence), 388 "Error while parsing BLOCK_META: missing string table."); 389 // Parse and assign the string table. 390 P.StrTab.emplace(*StrTabBuf); 391 return Error::success(); 392 } 393 394 static Error processRemarkVersion(BitstreamRemarkParser &P, 395 Optional<uint64_t> RemarkVersion) { 396 if (!RemarkVersion) 397 return createStringError( 398 std::make_error_code(std::errc::illegal_byte_sequence), 399 "Error while parsing BLOCK_META: missing remark version."); 400 P.RemarkVersion = *RemarkVersion; 401 return Error::success(); 402 } 403 404 Error BitstreamRemarkParser::processExternalFilePath( 405 Optional<StringRef> ExternalFilePath) { 406 if (!ExternalFilePath) 407 return createStringError( 408 std::make_error_code(std::errc::illegal_byte_sequence), 409 "Error while parsing BLOCK_META: missing external file path."); 410 411 // External file: open the external file, parse it, check if its metadata 412 // matches the one from the separate metadata, then replace the current parser 413 // with the one parsing the remarks. 414 ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = 415 MemoryBuffer::getFile(*ExternalFilePath); 416 if (std::error_code EC = BufferOrErr.getError()) 417 return errorCodeToError(EC); 418 TmpRemarkBuffer = std::move(*BufferOrErr); 419 420 // Create a separate parser used for parsing the separate file. 421 ParserHelper = BitstreamParserHelper(TmpRemarkBuffer->getBuffer()); 422 // Advance and check until we can parse the meta block. 423 if (Error E = advanceToMetaBlock(ParserHelper)) 424 return E; 425 // Parse the meta from the separate file. 426 // Note: here we overwrite the BlockInfo with the one from the file. This will 427 // be used to parse the rest of the file. 428 BitstreamMetaParserHelper SeparateMetaHelper(ParserHelper.Stream, 429 ParserHelper.BlockInfo); 430 if (Error E = SeparateMetaHelper.parse()) 431 return E; 432 433 uint64_t PreviousContainerVersion = ContainerVersion; 434 if (Error E = processCommonMeta(SeparateMetaHelper)) 435 return E; 436 437 if (ContainerType != BitstreamRemarkContainerType::SeparateRemarksFile) 438 return createStringError( 439 std::make_error_code(std::errc::illegal_byte_sequence), 440 "Error while parsing external file's BLOCK_META: wrong container " 441 "type."); 442 443 if (PreviousContainerVersion != ContainerVersion) 444 return createStringError( 445 std::make_error_code(std::errc::illegal_byte_sequence), 446 "Error while parsing external file's BLOCK_META: mismatching versions: " 447 "original meta: %lu, external file meta: %lu.", 448 PreviousContainerVersion, ContainerVersion); 449 450 // Process the meta from the separate file. 451 return processSeparateRemarksFileMeta(SeparateMetaHelper); 452 } 453 454 Error BitstreamRemarkParser::processStandaloneMeta( 455 BitstreamMetaParserHelper &Helper) { 456 if (Error E = processStrTab(*this, Helper.StrTabBuf)) 457 return E; 458 return processRemarkVersion(*this, Helper.RemarkVersion); 459 } 460 461 Error BitstreamRemarkParser::processSeparateRemarksFileMeta( 462 BitstreamMetaParserHelper &Helper) { 463 return processRemarkVersion(*this, Helper.RemarkVersion); 464 } 465 466 Error BitstreamRemarkParser::processSeparateRemarksMetaMeta( 467 BitstreamMetaParserHelper &Helper) { 468 if (Error E = processStrTab(*this, Helper.StrTabBuf)) 469 return E; 470 return processExternalFilePath(Helper.ExternalFilePath); 471 } 472 473 Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::parseRemark() { 474 BitstreamRemarkParserHelper RemarkHelper(ParserHelper.Stream); 475 if (Error E = RemarkHelper.parse()) 476 return std::move(E); 477 478 return processRemark(RemarkHelper); 479 } 480 481 Expected<std::unique_ptr<Remark>> 482 BitstreamRemarkParser::processRemark(BitstreamRemarkParserHelper &Helper) { 483 std::unique_ptr<Remark> Result = std::make_unique<Remark>(); 484 Remark &R = *Result; 485 486 if (StrTab == None) 487 return createStringError( 488 std::make_error_code(std::errc::invalid_argument), 489 "Error while parsing BLOCK_REMARK: missing string table."); 490 491 if (!Helper.Type) 492 return createStringError( 493 std::make_error_code(std::errc::illegal_byte_sequence), 494 "Error while parsing BLOCK_REMARK: missing remark type."); 495 496 // Always >= Type::First since it's unsigned. 497 if (*Helper.Type > static_cast<uint8_t>(Type::Last)) 498 return createStringError( 499 std::make_error_code(std::errc::illegal_byte_sequence), 500 "Error while parsing BLOCK_REMARK: unknown remark type."); 501 502 R.RemarkType = static_cast<Type>(*Helper.Type); 503 504 if (!Helper.RemarkNameIdx) 505 return createStringError( 506 std::make_error_code(std::errc::illegal_byte_sequence), 507 "Error while parsing BLOCK_REMARK: missing remark name."); 508 509 if (Expected<StringRef> RemarkName = (*StrTab)[*Helper.RemarkNameIdx]) 510 R.RemarkName = *RemarkName; 511 else 512 return RemarkName.takeError(); 513 514 if (!Helper.PassNameIdx) 515 return createStringError( 516 std::make_error_code(std::errc::illegal_byte_sequence), 517 "Error while parsing BLOCK_REMARK: missing remark pass."); 518 519 if (Expected<StringRef> PassName = (*StrTab)[*Helper.PassNameIdx]) 520 R.PassName = *PassName; 521 else 522 return PassName.takeError(); 523 524 if (!Helper.FunctionNameIdx) 525 return createStringError( 526 std::make_error_code(std::errc::illegal_byte_sequence), 527 "Error while parsing BLOCK_REMARK: missing remark function name."); 528 if (Expected<StringRef> FunctionName = (*StrTab)[*Helper.FunctionNameIdx]) 529 R.FunctionName = *FunctionName; 530 else 531 return FunctionName.takeError(); 532 533 if (Helper.SourceFileNameIdx && Helper.SourceLine && Helper.SourceColumn) { 534 Expected<StringRef> SourceFileName = (*StrTab)[*Helper.SourceFileNameIdx]; 535 if (!SourceFileName) 536 return SourceFileName.takeError(); 537 R.Loc.emplace(); 538 R.Loc->SourceFilePath = *SourceFileName; 539 R.Loc->SourceLine = *Helper.SourceLine; 540 R.Loc->SourceColumn = *Helper.SourceColumn; 541 } 542 543 if (Helper.Hotness) 544 R.Hotness = *Helper.Hotness; 545 546 if (!Helper.Args) 547 return std::move(Result); 548 549 for (const BitstreamRemarkParserHelper::Argument &Arg : *Helper.Args) { 550 if (!Arg.KeyIdx) 551 return createStringError( 552 std::make_error_code(std::errc::illegal_byte_sequence), 553 "Error while parsing BLOCK_REMARK: missing key in remark argument."); 554 if (!Arg.ValueIdx) 555 return createStringError( 556 std::make_error_code(std::errc::illegal_byte_sequence), 557 "Error while parsing BLOCK_REMARK: missing value in remark " 558 "argument."); 559 560 // We have at least a key and a value, create an entry. 561 R.Args.emplace_back(); 562 563 if (Expected<StringRef> Key = (*StrTab)[*Arg.KeyIdx]) 564 R.Args.back().Key = *Key; 565 else 566 return Key.takeError(); 567 568 if (Expected<StringRef> Value = (*StrTab)[*Arg.ValueIdx]) 569 R.Args.back().Val = *Value; 570 else 571 return Value.takeError(); 572 573 if (Arg.SourceFileNameIdx && Arg.SourceLine && Arg.SourceColumn) { 574 if (Expected<StringRef> SourceFileName = 575 (*StrTab)[*Arg.SourceFileNameIdx]) { 576 R.Args.back().Loc.emplace(); 577 R.Args.back().Loc->SourceFilePath = *SourceFileName; 578 R.Args.back().Loc->SourceLine = *Arg.SourceLine; 579 R.Args.back().Loc->SourceColumn = *Arg.SourceColumn; 580 } else 581 return SourceFileName.takeError(); 582 } 583 } 584 585 return std::move(Result); 586 } 587