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/StringExtractor.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 namespace llgs_tests { 20 21 Expected<ProcessInfo> ProcessInfo::create(StringRef response) { 22 ProcessInfo process_info; 23 auto elements_or_error = SplitUniquePairList("ProcessInfo", response); 24 if (!elements_or_error) 25 return elements_or_error.takeError(); 26 27 auto &elements = *elements_or_error; 28 if (elements["pid"].getAsInteger(16, process_info.m_pid)) 29 return make_parsing_error("ProcessInfo: pid"); 30 if (elements["parent-pid"].getAsInteger(16, process_info.m_parent_pid)) 31 return make_parsing_error("ProcessInfo: parent-pid"); 32 if (elements["real-uid"].getAsInteger(16, process_info.m_real_uid)) 33 return make_parsing_error("ProcessInfo: real-uid"); 34 if (elements["real-gid"].getAsInteger(16, process_info.m_real_gid)) 35 return make_parsing_error("ProcessInfo: real-uid"); 36 if (elements["effective-uid"].getAsInteger(16, process_info.m_effective_uid)) 37 return make_parsing_error("ProcessInfo: effective-uid"); 38 if (elements["effective-gid"].getAsInteger(16, process_info.m_effective_gid)) 39 return make_parsing_error("ProcessInfo: effective-gid"); 40 if (elements["ptrsize"].getAsInteger(10, process_info.m_ptrsize)) 41 return make_parsing_error("ProcessInfo: ptrsize"); 42 43 process_info.m_triple = fromHex(elements["triple"]); 44 StringRef endian_str = elements["endian"]; 45 if (endian_str == "little") 46 process_info.m_endian = support::little; 47 else if (endian_str == "big") 48 process_info.m_endian = support::big; 49 else 50 return make_parsing_error("ProcessInfo: endian"); 51 52 return process_info; 53 } 54 55 lldb::pid_t ProcessInfo::GetPid() const { return m_pid; } 56 57 support::endianness ProcessInfo::GetEndian() const { return m_endian; } 58 59 //====== ThreadInfo ============================================================ 60 ThreadInfo::ThreadInfo(StringRef name, StringRef reason, RegisterMap registers, 61 unsigned int signal) 62 : m_name(name.str()), m_reason(reason.str()), 63 m_registers(std::move(registers)), m_signal(signal) {} 64 65 const RegisterValue *ThreadInfo::ReadRegister(unsigned int Id) const { 66 auto Iter = m_registers.find(Id); 67 return Iter == m_registers.end() ? nullptr : &Iter->getSecond(); 68 } 69 70 //====== JThreadsInfo ========================================================== 71 72 Expected<RegisterMap> 73 JThreadsInfo::parseRegisters(const StructuredData::Dictionary &Dict, 74 ArrayRef<RegisterInfo> RegInfos) { 75 RegisterMap Result; 76 77 auto KeysObj = Dict.GetKeys(); 78 auto Keys = KeysObj->GetAsArray(); 79 for (size_t i = 0; i < Keys->GetSize(); i++) { 80 StringRef KeyStr, ValueStr; 81 Keys->GetItemAtIndexAsString(i, KeyStr); 82 Dict.GetValueForKeyAsString(KeyStr, ValueStr); 83 unsigned int Register; 84 if (!llvm::to_integer(KeyStr, Register, 10)) 85 return make_parsing_error("JThreadsInfo: register key[{0}]", i); 86 87 auto RegValOr = 88 parseRegisterValue(RegInfos[Register], ValueStr, support::big); 89 if (!RegValOr) 90 return RegValOr.takeError(); 91 Result[Register] = std::move(*RegValOr); 92 } 93 return std::move(Result); 94 } 95 96 Expected<JThreadsInfo> JThreadsInfo::create(StringRef Response, 97 ArrayRef<RegisterInfo> RegInfos) { 98 JThreadsInfo jthreads_info; 99 100 StructuredData::ObjectSP json = StructuredData::ParseJSON(Response); 101 StructuredData::Array *array = json->GetAsArray(); 102 if (!array) 103 return make_parsing_error("JThreadsInfo: JSON array"); 104 105 for (size_t i = 0; i < array->GetSize(); i++) { 106 StructuredData::Dictionary *thread_info; 107 array->GetItemAtIndexAsDictionary(i, thread_info); 108 if (!thread_info) 109 return make_parsing_error("JThreadsInfo: JSON obj at {0}", i); 110 111 StringRef name, reason; 112 thread_info->GetValueForKeyAsString("name", name); 113 thread_info->GetValueForKeyAsString("reason", reason); 114 uint64_t signal; 115 thread_info->GetValueForKeyAsInteger("signal", signal); 116 uint64_t tid; 117 thread_info->GetValueForKeyAsInteger("tid", tid); 118 119 StructuredData::Dictionary *register_dict; 120 thread_info->GetValueForKeyAsDictionary("registers", register_dict); 121 if (!register_dict) 122 return make_parsing_error("JThreadsInfo: registers JSON obj"); 123 124 auto RegsOr = parseRegisters(*register_dict, RegInfos); 125 if (!RegsOr) 126 return RegsOr.takeError(); 127 jthreads_info.m_thread_infos[tid] = 128 ThreadInfo(name, reason, std::move(*RegsOr), signal); 129 } 130 131 return jthreads_info; 132 } 133 134 const ThreadInfoMap &JThreadsInfo::GetThreadInfos() const { 135 return m_thread_infos; 136 } 137 138 Expected<RegisterInfo> RegisterInfoParser::create(StringRef Response) { 139 auto ElementsOr = SplitUniquePairList("RegisterInfoParser", Response); 140 if (!ElementsOr) 141 return ElementsOr.takeError(); 142 auto &Elements = *ElementsOr; 143 144 RegisterInfo Info = { 145 nullptr, // Name 146 nullptr, // Alt name 147 0, // byte size 148 0, // offset 149 eEncodingUint, // encoding 150 eFormatHex, // format 151 { 152 LLDB_INVALID_REGNUM, // eh_frame reg num 153 LLDB_INVALID_REGNUM, // DWARF reg num 154 LLDB_INVALID_REGNUM, // generic reg num 155 LLDB_INVALID_REGNUM, // process plugin reg num 156 LLDB_INVALID_REGNUM // native register number 157 }, 158 NULL, 159 NULL, 160 NULL, // Dwarf expression opcode bytes pointer 161 0 // Dwarf expression opcode bytes length 162 }; 163 Info.name = ConstString(Elements["name"]).GetCString(); 164 if (!Info.name) 165 return make_parsing_error("qRegisterInfo: name"); 166 167 Info.alt_name = ConstString(Elements["alt-name"]).GetCString(); 168 169 if (!to_integer(Elements["bitsize"], Info.byte_size, 10)) 170 return make_parsing_error("qRegisterInfo: bit-size"); 171 Info.byte_size /= CHAR_BIT; 172 173 if (!to_integer(Elements["offset"], Info.byte_offset, 10)) 174 return make_parsing_error("qRegisterInfo: offset"); 175 176 Info.encoding = Args::StringToEncoding(Elements["encoding"]); 177 if (Info.encoding == eEncodingInvalid) 178 return make_parsing_error("qRegisterInfo: encoding"); 179 180 Info.format = StringSwitch<Format>(Elements["format"]) 181 .Case("binary", eFormatBinary) 182 .Case("decimal", eFormatDecimal) 183 .Case("hex", eFormatHex) 184 .Case("float", eFormatFloat) 185 .Case("vector-sint8", eFormatVectorOfSInt8) 186 .Case("vector-uint8", eFormatVectorOfUInt8) 187 .Case("vector-sint16", eFormatVectorOfSInt16) 188 .Case("vector-uint16", eFormatVectorOfUInt16) 189 .Case("vector-sint32", eFormatVectorOfSInt32) 190 .Case("vector-uint32", eFormatVectorOfUInt32) 191 .Case("vector-float32", eFormatVectorOfFloat32) 192 .Case("vector-uint64", eFormatVectorOfUInt64) 193 .Case("vector-uint128", eFormatVectorOfUInt128) 194 .Default(eFormatInvalid); 195 if (Info.format == eFormatInvalid) 196 return make_parsing_error("qRegisterInfo: format"); 197 198 Info.kinds[eRegisterKindGeneric] = 199 Args::StringToGenericRegister(Elements["generic"]); 200 201 return std::move(Info); 202 } 203 204 Expected<RegisterValue> parseRegisterValue(const RegisterInfo &Info, 205 StringRef HexValue, 206 llvm::support::endianness Endian, 207 bool ZeroPad) { 208 SmallString<128> Storage; 209 if (ZeroPad && HexValue.size() < Info.byte_size * 2) { 210 Storage.insert(Storage.begin(), Info.byte_size * 2 - HexValue.size(), '0'); 211 Storage += HexValue; 212 HexValue = Storage; 213 } 214 215 SmallVector<uint8_t, 64> Bytes(HexValue.size() / 2); 216 StringExtractor(HexValue).GetHexBytes(Bytes, '\xcc'); 217 RegisterValue Value; 218 Status ST; 219 Value.SetFromMemoryData( 220 &Info, Bytes.data(), Bytes.size(), 221 Endian == support::little ? eByteOrderLittle : eByteOrderBig, ST); 222 if (ST.Fail()) 223 return ST.ToError(); 224 return Value; 225 } 226 227 //====== StopReply ============================================================= 228 Expected<std::unique_ptr<StopReply>> 229 StopReply::create(StringRef Response, llvm::support::endianness Endian, 230 ArrayRef<RegisterInfo> RegInfos) { 231 if (Response.size() < 3) 232 return make_parsing_error("StopReply: Invalid packet"); 233 if (Response.consume_front("T")) 234 return StopReplyStop::create(Response, Endian, RegInfos); 235 if (Response.consume_front("W")) 236 return StopReplyExit::create(Response); 237 return make_parsing_error("StopReply: Invalid packet"); 238 } 239 240 Expected<RegisterMap> StopReplyStop::parseRegisters( 241 const StringMap<SmallVector<StringRef, 2>> &Elements, 242 support::endianness Endian, ArrayRef<lldb_private::RegisterInfo> RegInfos) { 243 244 RegisterMap Result; 245 for (const auto &E : Elements) { 246 StringRef Key = E.getKey(); 247 const auto &Val = E.getValue(); 248 if (Key.size() != 2) 249 continue; 250 251 unsigned int Reg; 252 if (!to_integer(Key, Reg, 16)) 253 continue; 254 255 if (Val.size() != 1) 256 return make_parsing_error( 257 "StopReplyStop: multiple entries for register field [{0:x}]", Reg); 258 259 auto RegValOr = parseRegisterValue(RegInfos[Reg], Val[0], Endian); 260 if (!RegValOr) 261 return RegValOr.takeError(); 262 Result[Reg] = std::move(*RegValOr); 263 } 264 return std::move(Result); 265 } 266 267 Expected<std::unique_ptr<StopReplyStop>> 268 StopReplyStop::create(StringRef Response, support::endianness Endian, 269 ArrayRef<RegisterInfo> RegInfos) { 270 unsigned int Signal; 271 StringRef SignalStr = Response.take_front(2); 272 Response = Response.drop_front(2); 273 if (!to_integer(SignalStr, Signal, 16)) 274 return make_parsing_error("StopReply: stop signal"); 275 276 auto Elements = SplitPairList(Response); 277 for (StringRef Field : 278 {"name", "reason", "thread", "threads", "thread-pcs"}) { 279 // This will insert an empty field if there is none. In the future, we 280 // should probably differentiate between these fields not being present and 281 // them being empty, but right now no tests depends on this. 282 if (Elements.insert({Field, {""}}).first->second.size() != 1) 283 return make_parsing_error( 284 "StopReply: got multiple responses for the {0} field", Field); 285 } 286 StringRef Name = Elements["name"][0]; 287 StringRef Reason = Elements["reason"][0]; 288 289 lldb::tid_t Thread; 290 if (!to_integer(Elements["thread"][0], Thread, 16)) 291 return make_parsing_error("StopReply: thread"); 292 293 SmallVector<StringRef, 20> Threads; 294 SmallVector<StringRef, 20> Pcs; 295 Elements["threads"][0].split(Threads, ','); 296 Elements["thread-pcs"][0].split(Pcs, ','); 297 if (Threads.size() != Pcs.size()) 298 return make_parsing_error("StopReply: thread/PC count mismatch"); 299 300 RegisterMap ThreadPcs; 301 const RegisterInfo *PcInfo = find_if(RegInfos, [](const RegisterInfo &Info) { 302 return Info.kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_PC; 303 }); 304 assert(PcInfo); 305 306 for (auto ThreadPc : zip(Threads, Pcs)) { 307 lldb::tid_t Id; 308 if (!to_integer(std::get<0>(ThreadPc), Id, 16)) 309 return make_parsing_error("StopReply: Thread id '{0}'", 310 std::get<0>(ThreadPc)); 311 312 auto PcOr = parseRegisterValue(*PcInfo, std::get<1>(ThreadPc), Endian, 313 /*ZeroPad*/ true); 314 if (!PcOr) 315 return PcOr.takeError(); 316 ThreadPcs[Id] = std::move(*PcOr); 317 } 318 319 auto RegistersOr = parseRegisters(Elements, Endian, RegInfos); 320 if (!RegistersOr) 321 return RegistersOr.takeError(); 322 323 return llvm::make_unique<StopReplyStop>(Signal, Thread, Name, 324 std::move(ThreadPcs), 325 std::move(*RegistersOr), Reason); 326 } 327 328 Expected<std::unique_ptr<StopReplyExit>> 329 StopReplyExit::create(StringRef Response) { 330 uint8_t Status; 331 if (!to_integer(Response, Status, 16)) 332 return make_parsing_error("StopReply: exit status"); 333 return llvm::make_unique<StopReplyExit>(Status); 334 } 335 336 //====== Globals =============================================================== 337 Expected<StringMap<StringRef>> SplitUniquePairList(StringRef caller, 338 StringRef str) { 339 SmallVector<StringRef, 20> elements; 340 str.split(elements, ';'); 341 342 StringMap<StringRef> pairs; 343 for (StringRef s : elements) { 344 std::pair<StringRef, StringRef> pair = s.split(':'); 345 if (pairs.count(pair.first)) 346 return make_parsing_error("{0}: Duplicate Key: {1}", caller, pair.first); 347 348 pairs.insert(pair); 349 } 350 351 return pairs; 352 } 353 354 StringMap<SmallVector<StringRef, 2>> SplitPairList(StringRef str) { 355 SmallVector<StringRef, 20> elements; 356 str.split(elements, ';'); 357 358 StringMap<SmallVector<StringRef, 2>> pairs; 359 for (StringRef s : elements) { 360 std::pair<StringRef, StringRef> pair = s.split(':'); 361 pairs[pair.first].push_back(pair.second); 362 } 363 364 return pairs; 365 } 366 } // namespace llgs_tests 367 368 std::ostream &lldb_private::operator<<(std::ostream &OS, 369 const RegisterValue &RegVal) { 370 ArrayRef<uint8_t> Bytes(static_cast<const uint8_t *>(RegVal.GetBytes()), 371 RegVal.GetByteSize()); 372 return OS << formatv("RegisterValue[{0}]: {1:@[x-2]}", RegVal.GetByteSize(), 373 make_range(Bytes.begin(), Bytes.end())) 374 .str(); 375 } 376