1 //===---------------------StructuredData.cpp ---------------------*- C++-*-===// 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 #include "lldb/Utility/StructuredData.h" 10 #include "lldb/Utility/DataBuffer.h" 11 #include "lldb/Utility/FileSpec.h" 12 #include "lldb/Utility/JSON.h" 13 #include "lldb/Utility/Status.h" 14 #include "lldb/Utility/StreamString.h" 15 #include "llvm/ADT/STLExtras.h" 16 #include "llvm/Support/MemoryBuffer.h" 17 #include <cerrno> 18 #include <cstdlib> 19 #include <inttypes.h> 20 #include <limits> 21 22 using namespace lldb_private; 23 using namespace llvm; 24 25 // Functions that use a JSONParser to parse JSON into StructuredData 26 static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser); 27 static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser); 28 static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser); 29 30 StructuredData::ObjectSP 31 StructuredData::ParseJSONFromFile(const FileSpec &input_spec, Status &error) { 32 StructuredData::ObjectSP return_sp; 33 34 auto buffer_or_error = llvm::MemoryBuffer::getFile(input_spec.GetPath()); 35 if (!buffer_or_error) { 36 error.SetErrorStringWithFormatv("could not open input file: {0} - {1}.", 37 input_spec.GetPath(), 38 buffer_or_error.getError().message()); 39 return return_sp; 40 } 41 42 JSONParser json_parser(buffer_or_error.get()->getBuffer()); 43 return_sp = ParseJSONValue(json_parser); 44 return return_sp; 45 } 46 47 static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser) { 48 // The "JSONParser::Token::ObjectStart" token should have already been 49 // consumed by the time this function is called 50 auto dict_up = std::make_unique<StructuredData::Dictionary>(); 51 52 std::string value; 53 std::string key; 54 while (true) { 55 JSONParser::Token token = json_parser.GetToken(value); 56 57 if (token == JSONParser::Token::String) { 58 key.swap(value); 59 token = json_parser.GetToken(value); 60 if (token == JSONParser::Token::Colon) { 61 StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser); 62 if (value_sp) 63 dict_up->AddItem(key, value_sp); 64 else 65 break; 66 } 67 } else if (token == JSONParser::Token::ObjectEnd) { 68 return StructuredData::ObjectSP(dict_up.release()); 69 } else if (token == JSONParser::Token::Comma) { 70 continue; 71 } else { 72 break; 73 } 74 } 75 return StructuredData::ObjectSP(); 76 } 77 78 static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser) { 79 // The "JSONParser::Token::ObjectStart" token should have already been 80 // consumed by the time this function is called 81 auto array_up = std::make_unique<StructuredData::Array>(); 82 83 std::string value; 84 std::string key; 85 while (true) { 86 StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser); 87 if (value_sp) 88 array_up->AddItem(value_sp); 89 else 90 break; 91 92 JSONParser::Token token = json_parser.GetToken(value); 93 if (token == JSONParser::Token::Comma) { 94 continue; 95 } else if (token == JSONParser::Token::ArrayEnd) { 96 return StructuredData::ObjectSP(array_up.release()); 97 } else { 98 break; 99 } 100 } 101 return StructuredData::ObjectSP(); 102 } 103 104 static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser) { 105 std::string value; 106 const JSONParser::Token token = json_parser.GetToken(value); 107 switch (token) { 108 case JSONParser::Token::ObjectStart: 109 return ParseJSONObject(json_parser); 110 111 case JSONParser::Token::ArrayStart: 112 return ParseJSONArray(json_parser); 113 114 case JSONParser::Token::Integer: { 115 uint64_t uval; 116 if (llvm::to_integer(value, uval, 0)) 117 return std::make_shared<StructuredData::Integer>(uval); 118 } break; 119 120 case JSONParser::Token::Float: { 121 double val; 122 if (llvm::to_float(value, val)) 123 return std::make_shared<StructuredData::Float>(val); 124 } break; 125 126 case JSONParser::Token::String: 127 return std::make_shared<StructuredData::String>(value); 128 129 case JSONParser::Token::True: 130 case JSONParser::Token::False: 131 return std::make_shared<StructuredData::Boolean>(token == 132 JSONParser::Token::True); 133 134 case JSONParser::Token::Null: 135 return std::make_shared<StructuredData::Null>(); 136 137 default: 138 break; 139 } 140 return StructuredData::ObjectSP(); 141 } 142 143 StructuredData::ObjectSP StructuredData::ParseJSON(std::string json_text) { 144 JSONParser json_parser(json_text); 145 StructuredData::ObjectSP object_sp = ParseJSONValue(json_parser); 146 return object_sp; 147 } 148 149 StructuredData::ObjectSP 150 StructuredData::Object::GetObjectForDotSeparatedPath(llvm::StringRef path) { 151 if (this->GetType() == lldb::eStructuredDataTypeDictionary) { 152 std::pair<llvm::StringRef, llvm::StringRef> match = path.split('.'); 153 std::string key = match.first.str(); 154 ObjectSP value = this->GetAsDictionary()->GetValueForKey(key); 155 if (value.get()) { 156 // Do we have additional words to descend? If not, return the value 157 // we're at right now. 158 if (match.second.empty()) { 159 return value; 160 } else { 161 return value->GetObjectForDotSeparatedPath(match.second); 162 } 163 } 164 return ObjectSP(); 165 } 166 167 if (this->GetType() == lldb::eStructuredDataTypeArray) { 168 std::pair<llvm::StringRef, llvm::StringRef> match = path.split('['); 169 if (match.second.empty()) { 170 return this->shared_from_this(); 171 } 172 errno = 0; 173 uint64_t val = strtoul(match.second.str().c_str(), nullptr, 10); 174 if (errno == 0) { 175 return this->GetAsArray()->GetItemAtIndex(val); 176 } 177 return ObjectSP(); 178 } 179 180 return this->shared_from_this(); 181 } 182 183 void StructuredData::Object::DumpToStdout(bool pretty_print) const { 184 json::OStream stream(llvm::outs(), pretty_print ? 2 : 0); 185 Serialize(stream); 186 } 187 188 void StructuredData::Array::Serialize(json::OStream &s) const { 189 s.arrayBegin(); 190 for (const auto &item_sp : m_items) { 191 item_sp->Serialize(s); 192 } 193 s.arrayEnd(); 194 } 195 196 void StructuredData::Integer::Serialize(json::OStream &s) const { 197 s.value(static_cast<int64_t>(m_value)); 198 } 199 200 void StructuredData::Float::Serialize(json::OStream &s) const { 201 s.value(m_value); 202 } 203 204 void StructuredData::Boolean::Serialize(json::OStream &s) const { 205 s.value(m_value); 206 } 207 208 void StructuredData::String::Serialize(json::OStream &s) const { 209 s.value(m_value); 210 } 211 212 void StructuredData::Dictionary::Serialize(json::OStream &s) const { 213 s.objectBegin(); 214 for (const auto &pair : m_dict) { 215 s.attributeBegin(pair.first.AsCString()); 216 pair.second->Serialize(s); 217 s.attributeEnd(); 218 } 219 s.objectEnd(); 220 } 221 222 void StructuredData::Null::Serialize(json::OStream &s) const { 223 s.value(nullptr); 224 } 225 226 void StructuredData::Generic::Serialize(json::OStream &s) const { 227 s.value(llvm::formatv("{0:X}", m_object)); 228 } 229