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