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