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-c/Remarks.h" 15 #include "llvm/ADT/STLExtras.h" 16 #include "llvm/Support/SourceMgr.h" 17 #include "llvm/Support/YAMLTraits.h" 18 19 using namespace llvm; 20 21 namespace { 22 struct YAMLRemarkParser { 23 /// Source manager for better error messages. 24 SourceMgr SM; 25 /// Stream for yaml parsing. 26 yaml::Stream Stream; 27 /// Storage for the error stream. 28 std::string ErrorString; 29 /// The error stream. 30 raw_string_ostream ErrorStream; 31 /// Iterator in the YAML stream. 32 yaml::document_iterator DI; 33 /// The parsed remark (if any). 34 Optional<LLVMRemarkEntry> LastRemark; 35 /// Temporary parsing buffer for the arguments. 36 SmallVector<LLVMRemarkArg, 8> TmpArgs; 37 /// The state used by the parser to parse a remark entry. Invalidated with 38 /// every call to `parseYAMLElement`. 39 struct ParseState { 40 /// Temporary parsing buffer for the arguments. 41 SmallVectorImpl<LLVMRemarkArg> *Args; 42 StringRef Type; 43 StringRef Pass; 44 StringRef Name; 45 StringRef Function; 46 /// Optional. 47 Optional<StringRef> File; 48 Optional<unsigned> Line; 49 Optional<unsigned> Column; 50 Optional<unsigned> Hotness; 51 52 ParseState(SmallVectorImpl<LLVMRemarkArg> &Args) : Args(&Args) {} 53 /// Use Args only as a **temporary** buffer. 54 ~ParseState() { Args->clear(); } 55 }; 56 57 ParseState State; 58 59 /// Set to `true` if we had any errors during parsing. 60 bool HadAnyErrors = false; 61 62 YAMLRemarkParser(StringRef Buf) 63 : SM(), Stream(Buf, SM), ErrorString(), ErrorStream(ErrorString), 64 DI(Stream.begin()), LastRemark(), TmpArgs(), State(TmpArgs) { 65 SM.setDiagHandler(YAMLRemarkParser::HandleDiagnostic, this); 66 } 67 68 /// Parse a YAML element. 69 Error parseYAMLElement(yaml::Document &Remark); 70 71 private: 72 /// Parse one key to a string. 73 /// otherwise. 74 Error parseKey(StringRef &Result, yaml::KeyValueNode &Node); 75 /// Parse one value to a string. 76 Error parseValue(StringRef &Result, yaml::KeyValueNode &Node); 77 /// Parse one value to an unsigned. 78 Error parseValue(Optional<unsigned> &Result, yaml::KeyValueNode &Node); 79 /// Parse a debug location. 80 Error parseDebugLoc(Optional<StringRef> &File, Optional<unsigned> &Line, 81 Optional<unsigned> &Column, yaml::KeyValueNode &Node); 82 /// Parse an argument. 83 Error parseArg(SmallVectorImpl<LLVMRemarkArg> &TmpArgs, yaml::Node &Node); 84 85 /// Handle a diagnostic from the YAML stream. Records the error in the 86 /// YAMLRemarkParser class. 87 static void HandleDiagnostic(const SMDiagnostic &Diag, void *Ctx) { 88 assert(Ctx && "Expected non-null Ctx in diagnostic handler."); 89 auto *Parser = static_cast<YAMLRemarkParser *>(Ctx); 90 Diag.print(/*ProgName=*/nullptr, Parser->ErrorStream, /*ShowColors*/ false, 91 /*ShowKindLabels*/ true); 92 } 93 }; 94 95 class ParseError : public ErrorInfo<ParseError> { 96 public: 97 static char ID; 98 99 ParseError(StringRef Message, yaml::Node &Node) 100 : Message(Message), Node(Node) {} 101 102 void log(raw_ostream &OS) const override { OS << Message; } 103 std::error_code convertToErrorCode() const override { 104 return inconvertibleErrorCode(); 105 } 106 107 StringRef getMessage() const { return Message; } 108 yaml::Node &getNode() const { return Node; } 109 110 private: 111 StringRef Message; // No need to hold a full copy of the buffer. 112 yaml::Node &Node; 113 }; 114 115 char ParseError::ID = 0; 116 117 static LLVMRemarkStringRef toRemarkStr(StringRef Str) { 118 return {Str.data(), static_cast<uint32_t>(Str.size())}; 119 } 120 121 Error YAMLRemarkParser::parseKey(StringRef &Result, yaml::KeyValueNode &Node) { 122 auto *Key = dyn_cast<yaml::ScalarNode>(Node.getKey()); 123 if (!Key) 124 return make_error<ParseError>("key is not a string.", Node); 125 126 Result = Key->getRawValue(); 127 return Error::success(); 128 } 129 130 Error YAMLRemarkParser::parseValue(StringRef &Result, 131 yaml::KeyValueNode &Node) { 132 auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue()); 133 if (!Value) 134 return make_error<ParseError>("expected a value of scalar type.", Node); 135 Result = Value->getRawValue(); 136 137 if (Result.front() == '\'') 138 Result = Result.drop_front(); 139 140 if (Result.back() == '\'') 141 Result = Result.drop_back(); 142 143 return Error::success(); 144 } 145 146 Error YAMLRemarkParser::parseValue(Optional<unsigned> &Result, 147 yaml::KeyValueNode &Node) { 148 SmallVector<char, 4> Tmp; 149 auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue()); 150 if (!Value) 151 return make_error<ParseError>("expected a value of scalar type.", Node); 152 unsigned UnsignedValue = 0; 153 if (Value->getValue(Tmp).getAsInteger(10, UnsignedValue)) 154 return make_error<ParseError>("expected a value of integer type.", *Value); 155 Result = UnsignedValue; 156 return Error::success(); 157 } 158 159 Error YAMLRemarkParser::parseDebugLoc(Optional<StringRef> &File, 160 Optional<unsigned> &Line, 161 Optional<unsigned> &Column, 162 yaml::KeyValueNode &Node) { 163 auto *DebugLoc = dyn_cast<yaml::MappingNode>(Node.getValue()); 164 if (!DebugLoc) 165 return make_error<ParseError>("expected a value of mapping type.", Node); 166 167 for (yaml::KeyValueNode &DLNode : *DebugLoc) { 168 StringRef KeyName; 169 if (Error E = parseKey(KeyName, DLNode)) 170 return E; 171 if (KeyName == "File") { 172 File = StringRef(); // Set the optional to contain a default constructed 173 // value, to be passed to the parsing function. 174 if (Error E = parseValue(*File, DLNode)) 175 return E; 176 } else if (KeyName == "Column") { 177 if (Error E = parseValue(Column, DLNode)) 178 return E; 179 } else if (KeyName == "Line") { 180 if (Error E = parseValue(Line, DLNode)) 181 return E; 182 } else { 183 return make_error<ParseError>("unknown entry in DebugLoc map.", DLNode); 184 } 185 } 186 187 // If any of the debug loc fields is missing, return an error. 188 if (!File || !Line || !Column) 189 return make_error<ParseError>("DebugLoc node incomplete.", Node); 190 191 return Error::success(); 192 } 193 194 Error YAMLRemarkParser::parseArg(SmallVectorImpl<LLVMRemarkArg> &Args, 195 yaml::Node &Node) { 196 auto *ArgMap = dyn_cast<yaml::MappingNode>(&Node); 197 if (!ArgMap) 198 return make_error<ParseError>("expected a value of mapping type.", Node); 199 200 StringRef ValueStr; 201 StringRef KeyStr; 202 Optional<StringRef> File; 203 Optional<unsigned> Line; 204 Optional<unsigned> Column; 205 206 for (yaml::KeyValueNode &ArgEntry : *ArgMap) { 207 StringRef KeyName; 208 if (Error E = parseKey(KeyName, ArgEntry)) 209 return E; 210 211 // Try to parse debug locs. 212 if (KeyName == "DebugLoc") { 213 // Can't have multiple DebugLoc entries per argument. 214 if (File || Line || Column) 215 return make_error<ParseError>( 216 "only one DebugLoc entry is allowed per argument.", ArgEntry); 217 218 if (Error E = parseDebugLoc(File, Line, Column, ArgEntry)) 219 return E; 220 continue; 221 } 222 223 // If we already have a string, error out. 224 if (!ValueStr.empty()) 225 return make_error<ParseError>( 226 "only one string entry is allowed per argument.", ArgEntry); 227 228 // Try to parse a string. 229 if (Error E = parseValue(ValueStr, ArgEntry)) 230 return E; 231 232 // Keep the key from the string. 233 KeyStr = KeyName; 234 } 235 236 if (KeyStr.empty()) 237 return make_error<ParseError>("argument key is missing.", *ArgMap); 238 if (ValueStr.empty()) 239 return make_error<ParseError>("argument value is missing.", *ArgMap); 240 241 Args.push_back(LLVMRemarkArg{ 242 toRemarkStr(KeyStr), toRemarkStr(ValueStr), 243 LLVMRemarkDebugLoc{toRemarkStr(File.getValueOr(StringRef())), 244 Line.getValueOr(0), Column.getValueOr(0)}}); 245 246 return Error::success(); 247 } 248 249 Error YAMLRemarkParser::parseYAMLElement(yaml::Document &Remark) { 250 // Parsing a new remark, clear the previous one. 251 LastRemark = None; 252 State = ParseState(TmpArgs); 253 254 auto *Root = dyn_cast<yaml::MappingNode>(Remark.getRoot()); 255 if (!Root) 256 return make_error<ParseError>("document root is not of mapping type.", 257 *Remark.getRoot()); 258 259 State.Type = Root->getRawTag(); 260 261 for (yaml::KeyValueNode &RemarkField : *Root) { 262 StringRef KeyName; 263 if (Error E = parseKey(KeyName, RemarkField)) 264 return E; 265 266 if (KeyName == "Pass") { 267 if (Error E = parseValue(State.Pass, RemarkField)) 268 return E; 269 } else if (KeyName == "Name") { 270 if (Error E = parseValue(State.Name, RemarkField)) 271 return E; 272 } else if (KeyName == "Function") { 273 if (Error E = parseValue(State.Function, RemarkField)) 274 return E; 275 } else if (KeyName == "Hotness") { 276 if (Error E = parseValue(State.Hotness, RemarkField)) 277 return E; 278 } else if (KeyName == "DebugLoc") { 279 if (Error E = 280 parseDebugLoc(State.File, State.Line, State.Column, RemarkField)) 281 return E; 282 } else if (KeyName == "Args") { 283 auto *Args = dyn_cast<yaml::SequenceNode>(RemarkField.getValue()); 284 if (!Args) 285 return make_error<ParseError>("wrong value type for key.", RemarkField); 286 287 for (yaml::Node &Arg : *Args) 288 if (Error E = parseArg(*State.Args, Arg)) 289 return E; 290 } else { 291 return make_error<ParseError>("unknown key.", RemarkField); 292 } 293 } 294 295 // If the YAML parsing failed, don't even continue parsing. We might 296 // encounter malformed YAML. 297 if (Stream.failed()) 298 return make_error<ParseError>("YAML parsing failed.", *Remark.getRoot()); 299 300 // Check if any of the mandatory fields are missing. 301 if (State.Type.empty() || State.Pass.empty() || State.Name.empty() || 302 State.Function.empty()) 303 return make_error<ParseError>("Type, Pass, Name or Function missing.", 304 *Remark.getRoot()); 305 306 LastRemark = LLVMRemarkEntry{ 307 toRemarkStr(State.Type), 308 toRemarkStr(State.Pass), 309 toRemarkStr(State.Name), 310 toRemarkStr(State.Function), 311 LLVMRemarkDebugLoc{toRemarkStr(State.File.getValueOr(StringRef())), 312 State.Line.getValueOr(0), State.Column.getValueOr(0)}, 313 State.Hotness.getValueOr(0), 314 static_cast<uint32_t>(State.Args->size()), 315 State.Args->data()}; 316 317 return Error::success(); 318 } 319 } // namespace 320 321 // Create wrappers for C Binding types (see CBindingWrapping.h). 322 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(YAMLRemarkParser, LLVMRemarkParserRef) 323 324 extern "C" LLVMRemarkParserRef LLVMRemarkParserCreate(const void *Buf, 325 uint64_t Size) { 326 return wrap( 327 new YAMLRemarkParser(StringRef(static_cast<const char *>(Buf), Size))); 328 } 329 330 extern "C" LLVMRemarkEntry * 331 LLVMRemarkParserGetNext(LLVMRemarkParserRef Parser) { 332 YAMLRemarkParser &TheParser = *unwrap(Parser); 333 // Check for EOF. 334 if (TheParser.HadAnyErrors || TheParser.DI == TheParser.Stream.end()) 335 return nullptr; 336 337 // Try to parse an entry. 338 if (Error E = TheParser.parseYAMLElement(*TheParser.DI)) { 339 handleAllErrors(std::move(E), [&](const ParseError &PE) { 340 TheParser.Stream.printError(&PE.getNode(), 341 Twine(PE.getMessage()) + Twine('\n')); 342 TheParser.HadAnyErrors = true; 343 }); 344 return nullptr; 345 } 346 347 // Move on. 348 ++TheParser.DI; 349 350 // Return the just-parsed remark. 351 if (Optional<LLVMRemarkEntry> &Entry = TheParser.LastRemark) 352 return &*Entry; 353 return nullptr; 354 } 355 356 extern "C" LLVMBool LLVMRemarkParserHasError(LLVMRemarkParserRef Parser) { 357 return unwrap(Parser)->HadAnyErrors; 358 } 359 360 extern "C" const char * 361 LLVMRemarkParserGetErrorMessage(LLVMRemarkParserRef Parser) { 362 return unwrap(Parser)->ErrorStream.str().c_str(); 363 } 364 365 extern "C" void LLVMRemarkParserDispose(LLVMRemarkParserRef Parser) { 366 delete unwrap(Parser); 367 } 368