1 //===-- MessageObjects.cpp --------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "MessageObjects.h" 11 #include "lldb/Interpreter/Args.h" 12 #include "lldb/Utility/StructuredData.h" 13 #include "llvm/ADT/StringExtras.h" 14 #include "gtest/gtest.h" 15 16 using namespace lldb_private; 17 using namespace lldb; 18 using namespace llvm; 19 using namespace llvm::support; 20 namespace llgs_tests { 21 22 Expected<ProcessInfo> ProcessInfo::create(StringRef response) { 23 ProcessInfo process_info; 24 auto elements_or_error = SplitUniquePairList("ProcessInfo", response); 25 if (!elements_or_error) 26 return elements_or_error.takeError(); 27 28 auto &elements = *elements_or_error; 29 if (elements["pid"].getAsInteger(16, process_info.m_pid)) 30 return make_parsing_error("ProcessInfo: pid"); 31 if (elements["parent-pid"].getAsInteger(16, process_info.m_parent_pid)) 32 return make_parsing_error("ProcessInfo: parent-pid"); 33 if (elements["real-uid"].getAsInteger(16, process_info.m_real_uid)) 34 return make_parsing_error("ProcessInfo: real-uid"); 35 if (elements["real-gid"].getAsInteger(16, process_info.m_real_gid)) 36 return make_parsing_error("ProcessInfo: real-uid"); 37 if (elements["effective-uid"].getAsInteger(16, process_info.m_effective_uid)) 38 return make_parsing_error("ProcessInfo: effective-uid"); 39 if (elements["effective-gid"].getAsInteger(16, process_info.m_effective_gid)) 40 return make_parsing_error("ProcessInfo: effective-gid"); 41 if (elements["ptrsize"].getAsInteger(10, process_info.m_ptrsize)) 42 return make_parsing_error("ProcessInfo: ptrsize"); 43 44 process_info.m_triple = fromHex(elements["triple"]); 45 StringRef endian_str = elements["endian"]; 46 if (endian_str == "little") 47 process_info.m_endian = support::little; 48 else if (endian_str == "big") 49 process_info.m_endian = support::big; 50 else 51 return make_parsing_error("ProcessInfo: endian"); 52 53 return process_info; 54 } 55 56 lldb::pid_t ProcessInfo::GetPid() const { return m_pid; } 57 58 endianness ProcessInfo::GetEndian() const { return m_endian; } 59 60 //====== ThreadInfo ============================================================ 61 ThreadInfo::ThreadInfo(StringRef name, StringRef reason, 62 const RegisterMap ®isters, unsigned int signal) 63 : m_name(name.str()), m_reason(reason.str()), m_registers(registers), 64 m_signal(signal) {} 65 66 StringRef ThreadInfo::ReadRegister(unsigned int register_id) const { 67 return m_registers.lookup(register_id); 68 } 69 70 Expected<uint64_t> 71 ThreadInfo::ReadRegisterAsUint64(unsigned int register_id) const { 72 uint64_t value; 73 std::string value_str(m_registers.lookup(register_id)); 74 if (!llvm::to_integer(value_str, value, 16)) 75 return make_parsing_error("ThreadInfo value for register {0}: {1}", 76 register_id, value_str); 77 78 sys::swapByteOrder(value); 79 return value; 80 } 81 82 //====== JThreadsInfo ========================================================== 83 Expected<JThreadsInfo> JThreadsInfo::Create(StringRef response, 84 endianness endian) { 85 JThreadsInfo jthreads_info; 86 87 StructuredData::ObjectSP json = StructuredData::ParseJSON(response); 88 StructuredData::Array *array = json->GetAsArray(); 89 if (!array) 90 return make_parsing_error("JThreadsInfo: JSON array"); 91 92 for (size_t i = 0; i < array->GetSize(); i++) { 93 StructuredData::Dictionary *thread_info; 94 array->GetItemAtIndexAsDictionary(i, thread_info); 95 if (!thread_info) 96 return make_parsing_error("JThreadsInfo: JSON obj at {0}", i); 97 98 StringRef name, reason; 99 thread_info->GetValueForKeyAsString("name", name); 100 thread_info->GetValueForKeyAsString("reason", reason); 101 uint64_t signal; 102 thread_info->GetValueForKeyAsInteger("signal", signal); 103 uint64_t tid; 104 thread_info->GetValueForKeyAsInteger("tid", tid); 105 106 StructuredData::Dictionary *register_dict; 107 thread_info->GetValueForKeyAsDictionary("registers", register_dict); 108 if (!register_dict) 109 return make_parsing_error("JThreadsInfo: registers JSON obj"); 110 111 RegisterMap registers; 112 113 auto keys_obj = register_dict->GetKeys(); 114 auto keys = keys_obj->GetAsArray(); 115 for (size_t i = 0; i < keys->GetSize(); i++) { 116 StringRef key_str, value_str; 117 keys->GetItemAtIndexAsString(i, key_str); 118 register_dict->GetValueForKeyAsString(key_str, value_str); 119 unsigned int register_id; 120 if (key_str.getAsInteger(10, register_id)) 121 return make_parsing_error("JThreadsInfo: register key[{0}]", i); 122 123 registers[register_id] = value_str.str(); 124 } 125 126 jthreads_info.m_thread_infos[tid] = 127 ThreadInfo(name, reason, registers, signal); 128 } 129 130 return jthreads_info; 131 } 132 133 const ThreadInfoMap &JThreadsInfo::GetThreadInfos() const { 134 return m_thread_infos; 135 } 136 137 Expected<RegisterInfo> RegisterInfoParser::create(StringRef Response) { 138 auto ElementsOr = SplitUniquePairList("RegisterInfoParser", Response); 139 if (!ElementsOr) 140 return ElementsOr.takeError(); 141 auto &Elements = *ElementsOr; 142 143 RegisterInfo Info = { 144 nullptr, // Name 145 nullptr, // Alt name 146 0, // byte size 147 0, // offset 148 eEncodingUint, // encoding 149 eFormatHex, // format 150 { 151 LLDB_INVALID_REGNUM, // eh_frame reg num 152 LLDB_INVALID_REGNUM, // DWARF reg num 153 LLDB_INVALID_REGNUM, // generic reg num 154 LLDB_INVALID_REGNUM, // process plugin reg num 155 LLDB_INVALID_REGNUM // native register number 156 }, 157 NULL, 158 NULL, 159 NULL, // Dwarf expression opcode bytes pointer 160 0 // Dwarf expression opcode bytes length 161 }; 162 Info.name = ConstString(Elements["name"]).GetCString(); 163 if (!Info.name) 164 return make_parsing_error("qRegisterInfo: name"); 165 166 Info.alt_name = ConstString(Elements["alt-name"]).GetCString(); 167 168 if (!to_integer(Elements["bitsize"], Info.byte_size, 10)) 169 return make_parsing_error("qRegisterInfo: bit-size"); 170 Info.byte_size /= CHAR_BIT; 171 172 if (!to_integer(Elements["offset"], Info.byte_offset, 10)) 173 return make_parsing_error("qRegisterInfo: offset"); 174 175 Info.encoding = Args::StringToEncoding(Elements["encoding"]); 176 if (Info.encoding == eEncodingInvalid) 177 return make_parsing_error("qRegisterInfo: encoding"); 178 179 Info.format = StringSwitch<Format>(Elements["format"]) 180 .Case("binary", eFormatBinary) 181 .Case("decimal", eFormatDecimal) 182 .Case("hex", eFormatHex) 183 .Case("float", eFormatFloat) 184 .Case("vector-sint8", eFormatVectorOfSInt8) 185 .Case("vector-uint8", eFormatVectorOfUInt8) 186 .Case("vector-sint16", eFormatVectorOfSInt16) 187 .Case("vector-uint16", eFormatVectorOfUInt16) 188 .Case("vector-sint32", eFormatVectorOfSInt32) 189 .Case("vector-uint32", eFormatVectorOfUInt32) 190 .Case("vector-float32", eFormatVectorOfFloat32) 191 .Case("vector-uint64", eFormatVectorOfUInt64) 192 .Case("vector-uint128", eFormatVectorOfUInt128) 193 .Default(eFormatInvalid); 194 if (Info.format == eFormatInvalid) 195 return make_parsing_error("qRegisterInfo: format"); 196 197 Info.kinds[eRegisterKindGeneric] = 198 Args::StringToGenericRegister(Elements["generic"]); 199 200 return std::move(Info); 201 } 202 203 //====== StopReply ============================================================= 204 Expected<std::unique_ptr<StopReply>> 205 StopReply::create(StringRef Response, llvm::support::endianness Endian) { 206 if (Response.size() < 3) 207 return make_parsing_error("StopReply: Invalid packet"); 208 if (Response.consume_front("T")) 209 return StopReplyStop::create(Response, Endian); 210 if (Response.consume_front("W")) 211 return StopReplyExit::create(Response); 212 return make_parsing_error("StopReply: Invalid packet"); 213 } 214 215 Expected<std::unique_ptr<StopReplyStop>> 216 StopReplyStop::create(StringRef Response, llvm::support::endianness Endian) { 217 unsigned int Signal; 218 StringRef SignalStr = Response.take_front(2); 219 Response = Response.drop_front(2); 220 if (!to_integer(SignalStr, Signal, 16)) 221 return make_parsing_error("StopReply: stop signal"); 222 223 auto Elements = SplitPairList(Response); 224 for (StringRef Field : 225 {"name", "reason", "thread", "threads", "thread-pcs"}) { 226 // This will insert an empty field if there is none. In the future, we 227 // should probably differentiate between these fields not being present and 228 // them being empty, but right now no tests depends on this. 229 if (Elements.insert({Field, {""}}).first->second.size() != 1) 230 return make_parsing_error( 231 "StopReply: got multiple responses for the {0} field", Field); 232 } 233 StringRef Name = Elements["name"][0]; 234 StringRef Reason = Elements["reason"][0]; 235 236 lldb::tid_t Thread; 237 if (!to_integer(Elements["thread"][0], Thread, 16)) 238 return make_parsing_error("StopReply: thread"); 239 240 SmallVector<StringRef, 20> Threads; 241 SmallVector<StringRef, 20> Pcs; 242 Elements["threads"][0].split(Threads, ','); 243 Elements["thread-pcs"][0].split(Pcs, ','); 244 if (Threads.size() != Pcs.size()) 245 return make_parsing_error("StopReply: thread/PC count mismatch"); 246 247 U64Map ThreadPcs; 248 for (auto ThreadPc : zip(Threads, Pcs)) { 249 lldb::tid_t Id; 250 uint64_t Pc; 251 if (!to_integer(std::get<0>(ThreadPc), Id, 16)) 252 return make_parsing_error("StopReply: Thread id '{0}'", 253 std::get<0>(ThreadPc)); 254 if (!to_integer(std::get<1>(ThreadPc), Pc, 16)) 255 return make_parsing_error("StopReply Thread Pc '{0}'", 256 std::get<1>(ThreadPc)); 257 258 ThreadPcs[Id] = Pc; 259 } 260 261 RegisterMap Registers; 262 for (const auto &E : Elements) { 263 StringRef Key = E.getKey(); 264 const auto &Val = E.getValue(); 265 if (Key.size() != 2) 266 continue; 267 268 unsigned int Reg; 269 if (!to_integer(Key, Reg, 16)) 270 continue; 271 272 if (Val.size() != 1) 273 return make_parsing_error( 274 "StopReply: multiple entries for register field [{0:x}]", Reg); 275 276 Registers[Reg] = Val[0].str(); 277 } 278 279 return llvm::make_unique<StopReplyStop>(Signal, Thread, Name, ThreadPcs, 280 Registers, Reason); 281 } 282 283 Expected<std::unique_ptr<StopReplyExit>> 284 StopReplyExit::create(StringRef Response) { 285 uint8_t Status; 286 if (!to_integer(Response, Status, 16)) 287 return make_parsing_error("StopReply: exit status"); 288 return llvm::make_unique<StopReplyExit>(Status); 289 } 290 291 //====== Globals =============================================================== 292 Expected<StringMap<StringRef>> SplitUniquePairList(StringRef caller, 293 StringRef str) { 294 SmallVector<StringRef, 20> elements; 295 str.split(elements, ';'); 296 297 StringMap<StringRef> pairs; 298 for (StringRef s : elements) { 299 std::pair<StringRef, StringRef> pair = s.split(':'); 300 if (pairs.count(pair.first)) 301 return make_parsing_error("{0}: Duplicate Key: {1}", caller, pair.first); 302 303 pairs.insert(pair); 304 } 305 306 return pairs; 307 } 308 309 StringMap<SmallVector<StringRef, 2>> SplitPairList(StringRef str) { 310 SmallVector<StringRef, 20> elements; 311 str.split(elements, ';'); 312 313 StringMap<SmallVector<StringRef, 2>> pairs; 314 for (StringRef s : elements) { 315 std::pair<StringRef, StringRef> pair = s.split(':'); 316 pairs[pair.first].push_back(pair.second); 317 } 318 319 return pairs; 320 } 321 } // namespace llgs_tests 322