1 //===- RemarkParser.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/RemarkParser.h" 15 #include "BitstreamRemarkParser.h" 16 #include "YAMLRemarkParser.h" 17 #include "llvm-c/Remarks.h" 18 #include "llvm/Remarks/RemarkFormat.h" 19 #include "llvm/Support/CBindingWrapping.h" 20 #include <optional> 21 22 using namespace llvm; 23 using namespace llvm::remarks; 24 25 char EndOfFileError::ID = 0; 26 27 ParsedStringTable::ParsedStringTable(StringRef InBuffer) : Buffer(InBuffer) { 28 while (!InBuffer.empty()) { 29 // Strings are separated by '\0' bytes. 30 std::pair<StringRef, StringRef> Split = InBuffer.split('\0'); 31 // We only store the offset from the beginning of the buffer. 32 Offsets.push_back(Split.first.data() - Buffer.data()); 33 InBuffer = Split.second; 34 } 35 } 36 37 Expected<StringRef> ParsedStringTable::operator[](size_t Index) const { 38 if (Index >= Offsets.size()) 39 return createStringError( 40 std::make_error_code(std::errc::invalid_argument), 41 "String with index %u is out of bounds (size = %u).", Index, 42 Offsets.size()); 43 44 size_t Offset = Offsets[Index]; 45 // If it's the last offset, we can't use the next offset to know the size of 46 // the string. 47 size_t NextOffset = 48 (Index == Offsets.size() - 1) ? Buffer.size() : Offsets[Index + 1]; 49 return StringRef(Buffer.data() + Offset, NextOffset - Offset - 1); 50 } 51 52 Expected<std::unique_ptr<RemarkParser>> 53 llvm::remarks::createRemarkParser(Format ParserFormat, StringRef Buf) { 54 auto DetectedFormat = detectFormat(ParserFormat, Buf); 55 if (!DetectedFormat) 56 return DetectedFormat.takeError(); 57 58 switch (*DetectedFormat) { 59 case Format::YAML: 60 return std::make_unique<YAMLRemarkParser>(Buf); 61 case Format::Bitstream: 62 return std::make_unique<BitstreamRemarkParser>(Buf); 63 case Format::Unknown: 64 case Format::Auto: 65 break; 66 } 67 llvm_unreachable("unhandled ParseFormat"); 68 } 69 70 Expected<std::unique_ptr<RemarkParser>> 71 llvm::remarks::createRemarkParserFromMeta( 72 Format ParserFormat, StringRef Buf, 73 std::optional<StringRef> ExternalFilePrependPath) { 74 auto DetectedFormat = detectFormat(ParserFormat, Buf); 75 if (!DetectedFormat) 76 return DetectedFormat.takeError(); 77 78 switch (*DetectedFormat) { 79 case Format::YAML: 80 return createYAMLParserFromMeta(Buf, std::move(ExternalFilePrependPath)); 81 case Format::Bitstream: 82 return createBitstreamParserFromMeta(Buf, 83 std::move(ExternalFilePrependPath)); 84 case Format::Unknown: 85 case Format::Auto: 86 break; 87 } 88 llvm_unreachable("unhandled ParseFormat"); 89 } 90 91 namespace { 92 // Wrapper that holds the state needed to interact with the C API. 93 struct CParser { 94 std::unique_ptr<RemarkParser> TheParser; 95 std::optional<std::string> Err; 96 97 CParser(Format ParserFormat, StringRef Buf) 98 : TheParser(cantFail(createRemarkParser(ParserFormat, Buf))) {} 99 100 void handleError(Error E) { Err.emplace(toString(std::move(E))); } 101 bool hasError() const { return Err.has_value(); } 102 const char *getMessage() const { return Err ? Err->c_str() : nullptr; }; 103 }; 104 } // namespace 105 106 // Create wrappers for C Binding types (see CBindingWrapping.h). 107 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(CParser, LLVMRemarkParserRef) 108 109 extern "C" LLVMRemarkParserRef LLVMRemarkParserCreateYAML(const void *Buf, 110 uint64_t Size) { 111 return wrap(new CParser(Format::YAML, 112 StringRef(static_cast<const char *>(Buf), Size))); 113 } 114 115 extern "C" LLVMRemarkParserRef LLVMRemarkParserCreateBitstream(const void *Buf, 116 uint64_t Size) { 117 return wrap(new CParser(Format::Bitstream, 118 StringRef(static_cast<const char *>(Buf), Size))); 119 } 120 121 extern "C" LLVMRemarkEntryRef 122 LLVMRemarkParserGetNext(LLVMRemarkParserRef Parser) { 123 CParser &TheCParser = *unwrap(Parser); 124 remarks::RemarkParser &TheParser = *TheCParser.TheParser; 125 126 Expected<std::unique_ptr<Remark>> MaybeRemark = TheParser.next(); 127 if (Error E = MaybeRemark.takeError()) { 128 if (E.isA<EndOfFileError>()) { 129 consumeError(std::move(E)); 130 return nullptr; 131 } 132 133 // Handle the error. Allow it to be checked through HasError and 134 // GetErrorMessage. 135 TheCParser.handleError(std::move(E)); 136 return nullptr; 137 } 138 139 // Valid remark. 140 return wrap(MaybeRemark->release()); 141 } 142 143 extern "C" LLVMBool LLVMRemarkParserHasError(LLVMRemarkParserRef Parser) { 144 return unwrap(Parser)->hasError(); 145 } 146 147 extern "C" const char * 148 LLVMRemarkParserGetErrorMessage(LLVMRemarkParserRef Parser) { 149 return unwrap(Parser)->getMessage(); 150 } 151 152 extern "C" void LLVMRemarkParserDispose(LLVMRemarkParserRef Parser) { 153 delete unwrap(Parser); 154 } 155