1 //===- BitstreamRemarkParser.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 "llvm/Remarks/BitstreamRemarkParser.h"
15 #include "BitstreamRemarkParser.h"
16 #include "llvm/Remarks/BitstreamRemarkContainer.h"
17 #include "llvm/Support/MemoryBuffer.h"
20 using namespace llvm::remarks
;
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
,
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
,
36 BitstreamMetaParserHelper::BitstreamMetaParserHelper(
37 BitstreamCursor
&Stream
, BitstreamBlockInfo
&BlockInfo
)
38 : Stream(Stream
), BlockInfo(BlockInfo
) {}
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
45 SmallVector
<uint64_t, 2> Record
;
47 Expected
<unsigned> RecordID
= Stream
.readRecord(Code
, Record
, &Blob
);
49 return RecordID
.takeError();
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];
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];
65 case RECORD_META_STRTAB
: {
66 if (Record
.size() != 0)
67 return malformedRecord("BLOCK_META", "RECORD_META_STRTAB");
68 Parser
.StrTabBuf
= Blob
;
71 case RECORD_META_EXTERNAL_FILE
: {
72 if (Record
.size() != 0)
73 return malformedRecord("BLOCK_META", "RECORD_META_EXTERNAL_FILE");
74 Parser
.ExternalFilePath
= Blob
;
78 return unknownRecord("BLOCK_META", *RecordID
);
80 return Error::success();
83 BitstreamRemarkParserHelper::BitstreamRemarkParserHelper(
84 BitstreamCursor
&Stream
)
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
92 SmallVector
<uint64_t, 5> Record
;
94 Expected
<unsigned> RecordID
= Stream
.readRecord(Code
, Record
, &Blob
);
96 return RecordID
.takeError();
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];
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];
116 case RECORD_REMARK_HOTNESS
: {
117 if (Record
.size() != 1)
118 return malformedRecord("BLOCK_REMARK", "RECORD_REMARK_HOTNESS");
119 Parser
.Hotness
= Record
[0];
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
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];
134 ArrayRef
<BitstreamRemarkParserHelper::Argument
>(Parser
.TmpArgs
);
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
143 Parser
.TmpArgs
.emplace_back();
144 Parser
.TmpArgs
.back().KeyIdx
= Record
[0];
145 Parser
.TmpArgs
.back().ValueIdx
= Record
[1];
147 ArrayRef
<BitstreamRemarkParserHelper::Argument
>(Parser
.TmpArgs
);
151 return unknownRecord("BLOCK_REMARK", *RecordID
);
153 return Error::success();
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();
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
);
173 // Stop when there is nothing to read anymore or when we encounter an
175 while (!Stream
.AtEndOfStream()) {
176 Expected
<BitstreamEntry
> Next
= Stream
.advance();
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
))
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
);
200 Error
BitstreamMetaParserHelper::parse() {
201 return parseBlock(*this, META_BLOCK_ID
, "META_BLOCK");
204 Error
BitstreamRemarkParserHelper::parse() {
205 return parseBlock(*this, REMARK_BLOCK_ID
, "REMARK_BLOCK");
208 BitstreamParserHelper::BitstreamParserHelper(StringRef Buffer
)
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))
217 return R
.takeError();
221 Error
BitstreamParserHelper::parseBlockInfoBlock() {
222 Expected
<BitstreamEntry
> Next
= Stream
.advance();
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, ...].");
232 Expected
<Optional
<BitstreamBlockInfo
>> MaybeBlockInfo
=
233 Stream
.ReadBlockInfoBlock();
235 return MaybeBlockInfo
.takeError();
237 if (!*MaybeBlockInfo
)
238 return createStringError(
239 std::make_error_code(std::errc::illegal_byte_sequence
),
240 "Error while parsing BLOCKINFO_BLOCK.");
242 BlockInfo
= **MaybeBlockInfo
;
244 Stream
.setBlockInfo(&BlockInfo
);
245 return Error::success();
248 static Expected
<bool> isBlock(BitstreamCursor
&Stream
, unsigned BlockID
) {
250 uint64_t PreviousBitNo
= Stream
.GetCurrentBitNo();
251 Expected
<BitstreamEntry
> Next
= Stream
.advance();
253 return Next
.takeError();
254 switch (Next
->Kind
) {
255 case BitstreamEntry::SubBlock
:
256 // Check for the block id.
257 Result
= Next
->ID
== BlockID
;
259 case BitstreamEntry::Error
:
260 return createStringError(
261 std::make_error_code(std::errc::illegal_byte_sequence
),
262 "Unexpected error while parsing bitstream.");
267 if (Error E
= Stream
.JumpToBit(PreviousBitNo
))
272 Expected
<bool> BitstreamParserHelper::isMetaBlock() {
273 return isBlock(Stream
, META_BLOCK_ID
);
276 Expected
<bool> BitstreamParserHelper::isRemarkBlock() {
277 return isBlock(Stream
, META_BLOCK_ID
);
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();
288 static Error
advanceToMetaBlock(BitstreamParserHelper
&Helper
) {
289 Expected
<std::array
<char, 4>> Magic
= Helper
.parseMagic();
291 return Magic
.takeError();
292 if (Error E
= validateMagicNumber(StringRef(Magic
->data(), Magic
->size())))
294 if (Error E
= Helper
.parseBlockInfoBlock())
296 Expected
<bool> isMetaBlock
= Helper
.isMetaBlock();
298 return isMetaBlock
.takeError();
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();
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();
312 return Magic
.takeError();
314 if (Error E
= validateMagicNumber(StringRef(Magic
->data(), Magic
->size())))
318 ? std::make_unique
<BitstreamRemarkParser
>(Buf
, std::move(*StrTab
))
319 : std::make_unique
<BitstreamRemarkParser
>(Buf
);
322 Expected
<std::unique_ptr
<Remark
>> BitstreamRemarkParser::next() {
323 if (ParserHelper
.atEndOfStream())
324 return make_error
<EndOfFileError
>();
326 if (!ReadyToParseRemarks
) {
327 if (Error E
= parseMeta())
329 ReadyToParseRemarks
= true;
332 return parseRemark();
335 Error
BitstreamRemarkParser::parseMeta() {
336 // Advance and to the meta block.
337 if (Error E
= advanceToMetaBlock(ParserHelper
))
340 BitstreamMetaParserHelper
MetaHelper(ParserHelper
.Stream
,
341 ParserHelper
.BlockInfo
);
342 if (Error E
= MetaHelper
.parse())
345 if (Error E
= processCommonMeta(MetaHelper
))
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
);
356 llvm_unreachable("Unknown BitstreamRemarkContainerType enum");
359 Error
BitstreamRemarkParser::processCommonMeta(
360 BitstreamMetaParserHelper
&MetaHelper
) {
361 if (Optional
<uint64_t> Version
= MetaHelper
.ContainerVersion
)
362 ContainerVersion
= *Version
;
364 return createStringError(
365 std::make_error_code(std::errc::illegal_byte_sequence
),
366 "Error while parsing BLOCK_META: missing container version.");
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.");
375 ContainerType
= static_cast<BitstreamRemarkContainerType
>(*Type
);
377 return createStringError(
378 std::make_error_code(std::errc::illegal_byte_sequence
),
379 "Error while parsing BLOCK_META: missing container type.");
381 return Error::success();
384 static Error
processStrTab(BitstreamRemarkParser
&P
,
385 Optional
<StringRef
> 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();
395 static Error
processRemarkVersion(BitstreamRemarkParser
&P
,
396 Optional
<uint64_t> 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();
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.");
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
);
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
))
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())
434 uint64_t PreviousContainerVersion
= ContainerVersion
;
435 if (Error E
= processCommonMeta(SeparateMetaHelper
))
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 "
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
);
451 // Process the meta from the separate file.
452 return processSeparateRemarksFileMeta(SeparateMetaHelper
);
455 Error
BitstreamRemarkParser::processStandaloneMeta(
456 BitstreamMetaParserHelper
&Helper
) {
457 if (Error E
= processStrTab(*this, Helper
.StrTabBuf
))
459 return processRemarkVersion(*this, Helper
.RemarkVersion
);
462 Error
BitstreamRemarkParser::processSeparateRemarksFileMeta(
463 BitstreamMetaParserHelper
&Helper
) {
464 return processRemarkVersion(*this, Helper
.RemarkVersion
);
467 Error
BitstreamRemarkParser::processSeparateRemarksMetaMeta(
468 BitstreamMetaParserHelper
&Helper
) {
469 if (Error E
= processStrTab(*this, Helper
.StrTabBuf
))
471 return processExternalFilePath(Helper
.ExternalFilePath
);
474 Expected
<std::unique_ptr
<Remark
>> BitstreamRemarkParser::parseRemark() {
475 BitstreamRemarkParserHelper
RemarkHelper(ParserHelper
.Stream
);
476 if (Error E
= RemarkHelper
.parse())
479 return processRemark(RemarkHelper
);
482 Expected
<std::unique_ptr
<Remark
>>
483 BitstreamRemarkParser::processRemark(BitstreamRemarkParserHelper
&Helper
) {
484 std::unique_ptr
<Remark
> Result
= std::make_unique
<Remark
>();
488 return createStringError(
489 std::make_error_code(std::errc::invalid_argument
),
490 "Error while parsing BLOCK_REMARK: missing string table.");
493 return createStringError(
494 std::make_error_code(std::errc::illegal_byte_sequence
),
495 "Error while parsing BLOCK_REMARK: missing remark type.");
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.");
503 R
.RemarkType
= static_cast<Type
>(*Helper
.Type
);
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.");
510 if (Expected
<StringRef
> RemarkName
= (*StrTab
)[*Helper
.RemarkNameIdx
])
511 R
.RemarkName
= *RemarkName
;
513 return RemarkName
.takeError();
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.");
520 if (Expected
<StringRef
> PassName
= (*StrTab
)[*Helper
.PassNameIdx
])
521 R
.PassName
= *PassName
;
523 return PassName
.takeError();
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
;
532 return FunctionName
.takeError();
534 if (Helper
.SourceFileNameIdx
&& Helper
.SourceLine
&& Helper
.SourceColumn
) {
535 Expected
<StringRef
> SourceFileName
= (*StrTab
)[*Helper
.SourceFileNameIdx
];
537 return SourceFileName
.takeError();
539 R
.Loc
->SourceFilePath
= *SourceFileName
;
540 R
.Loc
->SourceLine
= *Helper
.SourceLine
;
541 R
.Loc
->SourceColumn
= *Helper
.SourceColumn
;
545 R
.Hotness
= *Helper
.Hotness
;
548 return std::move(Result
);
550 for (const BitstreamRemarkParserHelper::Argument
&Arg
: *Helper
.Args
) {
552 return createStringError(
553 std::make_error_code(std::errc::illegal_byte_sequence
),
554 "Error while parsing BLOCK_REMARK: missing key in remark argument.");
556 return createStringError(
557 std::make_error_code(std::errc::illegal_byte_sequence
),
558 "Error while parsing BLOCK_REMARK: missing value in remark "
561 // We have at least a key and a value, create an entry.
562 R
.Args
.emplace_back();
564 if (Expected
<StringRef
> Key
= (*StrTab
)[*Arg
.KeyIdx
])
565 R
.Args
.back().Key
= *Key
;
567 return Key
.takeError();
569 if (Expected
<StringRef
> Value
= (*StrTab
)[*Arg
.ValueIdx
])
570 R
.Args
.back().Val
= *Value
;
572 return Value
.takeError();
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
;
582 return SourceFileName
.takeError();
586 return std::move(Result
);