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