1 //===-- MessageObjects.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 "MessageObjects.h" 10 #include "lldb/Utility/Args.h" 11 #include "lldb/Utility/StringExtractor.h" 12 #include "llvm/ADT/StringExtras.h" 13 #include "gtest/gtest.h" 14 15 using namespace lldb_private; 16 using namespace lldb; 17 using namespace llvm; 18 namespace llgs_tests { 19 20 Expected<ProcessInfo> ProcessInfo::create(StringRef response) { 21 ProcessInfo process_info; 22 auto elements_or_error = SplitUniquePairList("ProcessInfo", response); 23 if (!elements_or_error) 24 return elements_or_error.takeError(); 25 26 auto &elements = *elements_or_error; 27 if (elements["pid"].getAsInteger(16, process_info.m_pid)) 28 return make_parsing_error("ProcessInfo: pid"); 29 if (elements["parent-pid"].getAsInteger(16, process_info.m_parent_pid)) 30 return make_parsing_error("ProcessInfo: parent-pid"); 31 if (elements["real-uid"].getAsInteger(16, process_info.m_real_uid)) 32 return make_parsing_error("ProcessInfo: real-uid"); 33 if (elements["real-gid"].getAsInteger(16, process_info.m_real_gid)) 34 return make_parsing_error("ProcessInfo: real-uid"); 35 if (elements["effective-uid"].getAsInteger(16, process_info.m_effective_uid)) 36 return make_parsing_error("ProcessInfo: effective-uid"); 37 if (elements["effective-gid"].getAsInteger(16, process_info.m_effective_gid)) 38 return make_parsing_error("ProcessInfo: effective-gid"); 39 if (elements["ptrsize"].getAsInteger(10, process_info.m_ptrsize)) 40 return make_parsing_error("ProcessInfo: ptrsize"); 41 42 process_info.m_triple = fromHex(elements["triple"]); 43 StringRef endian_str = elements["endian"]; 44 if (endian_str == "little") 45 process_info.m_endian = support::little; 46 else if (endian_str == "big") 47 process_info.m_endian = support::big; 48 else 49 return make_parsing_error("ProcessInfo: endian"); 50 51 return process_info; 52 } 53 54 lldb::pid_t ProcessInfo::GetPid() const { return m_pid; } 55 56 support::endianness ProcessInfo::GetEndian() const { return m_endian; } 57 58 //====== ThreadInfo ============================================================ 59 ThreadInfo::ThreadInfo(StringRef name, StringRef reason, RegisterMap registers, 60 unsigned int) 61 : m_name(name.str()), m_reason(reason.str()), 62 m_registers(std::move(registers)) {} 63 64 const RegisterValue *ThreadInfo::ReadRegister(unsigned int Id) const { 65 auto Iter = m_registers.find(Id); 66 return Iter == m_registers.end() ? nullptr : &Iter->getSecond(); 67 } 68 69 //====== JThreadsInfo ========================================================== 70 71 Expected<RegisterMap> 72 JThreadsInfo::parseRegisters(const StructuredData::Dictionary &Dict, 73 ArrayRef<RegisterInfo> RegInfos) { 74 RegisterMap Result; 75 76 auto KeysObj = Dict.GetKeys(); 77 auto Keys = KeysObj->GetAsArray(); 78 for (size_t i = 0; i < Keys->GetSize(); i++) { 79 StringRef KeyStr, ValueStr; 80 Keys->GetItemAtIndexAsString(i, KeyStr); 81 Dict.GetValueForKeyAsString(KeyStr, ValueStr); 82 unsigned int Register; 83 if (!llvm::to_integer(KeyStr, Register, 10)) 84 return make_parsing_error("JThreadsInfo: register key[{0}]", i); 85 86 auto RegValOr = 87 parseRegisterValue(RegInfos[Register], ValueStr, support::big); 88 if (!RegValOr) 89 return RegValOr.takeError(); 90 Result[Register] = std::move(*RegValOr); 91 } 92 return std::move(Result); 93 } 94 95 Expected<JThreadsInfo> JThreadsInfo::create(StringRef Response, 96 ArrayRef<RegisterInfo> RegInfos) { 97 JThreadsInfo jthreads_info; 98 99 StructuredData::ObjectSP json = StructuredData::ParseJSON(Response); 100 StructuredData::Array *array = json->GetAsArray(); 101 if (!array) 102 return make_parsing_error("JThreadsInfo: JSON array"); 103 104 for (size_t i = 0; i < array->GetSize(); i++) { 105 StructuredData::Dictionary *thread_info; 106 array->GetItemAtIndexAsDictionary(i, thread_info); 107 if (!thread_info) 108 return make_parsing_error("JThreadsInfo: JSON obj at {0}", i); 109 110 StringRef name, reason; 111 thread_info->GetValueForKeyAsString("name", name); 112 thread_info->GetValueForKeyAsString("reason", reason); 113 uint64_t signal; 114 thread_info->GetValueForKeyAsInteger("signal", signal); 115 uint64_t tid; 116 thread_info->GetValueForKeyAsInteger("tid", tid); 117 118 StructuredData::Dictionary *register_dict; 119 thread_info->GetValueForKeyAsDictionary("registers", register_dict); 120 if (!register_dict) 121 return make_parsing_error("JThreadsInfo: registers JSON obj"); 122 123 auto RegsOr = parseRegisters(*register_dict, RegInfos); 124 if (!RegsOr) 125 return RegsOr.takeError(); 126 jthreads_info.m_thread_infos[tid] = 127 ThreadInfo(name, reason, std::move(*RegsOr), 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 nullptr, 158 nullptr, 159 nullptr, // 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 Expected<RegisterValue> parseRegisterValue(const RegisterInfo &Info, 204 StringRef HexValue, 205 llvm::support::endianness Endian, 206 bool ZeroPad) { 207 SmallString<128> Storage; 208 if (ZeroPad && HexValue.size() < Info.byte_size * 2) { 209 Storage.insert(Storage.begin(), Info.byte_size * 2 - HexValue.size(), '0'); 210 Storage += HexValue; 211 HexValue = Storage; 212 } 213 214 SmallVector<uint8_t, 64> Bytes(HexValue.size() / 2); 215 StringExtractor(HexValue).GetHexBytes(Bytes, '\xcc'); 216 RegisterValue Value; 217 Status ST; 218 Value.SetFromMemoryData( 219 &Info, Bytes.data(), Bytes.size(), 220 Endian == support::little ? eByteOrderLittle : eByteOrderBig, ST); 221 if (ST.Fail()) 222 return ST.ToError(); 223 return Value; 224 } 225 226 //====== StopReply ============================================================= 227 Expected<std::unique_ptr<StopReply>> 228 StopReply::create(StringRef Response, llvm::support::endianness Endian, 229 ArrayRef<RegisterInfo> RegInfos) { 230 if (Response.size() < 3) 231 return make_parsing_error("StopReply: Invalid packet"); 232 if (Response.consume_front("T")) 233 return StopReplyStop::create(Response, Endian, RegInfos); 234 if (Response.consume_front("W")) 235 return StopReplyExit::create(Response); 236 return make_parsing_error("StopReply: Invalid packet"); 237 } 238 239 Expected<RegisterMap> StopReplyStop::parseRegisters( 240 const StringMap<SmallVector<StringRef, 2>> &Elements, 241 support::endianness Endian, ArrayRef<lldb_private::RegisterInfo> RegInfos) { 242 243 RegisterMap Result; 244 for (const auto &E : Elements) { 245 StringRef Key = E.getKey(); 246 const auto &Val = E.getValue(); 247 if (Key.size() != 2) 248 continue; 249 250 unsigned int Reg; 251 if (!to_integer(Key, Reg, 16)) 252 continue; 253 254 if (Val.size() != 1) 255 return make_parsing_error( 256 "StopReplyStop: multiple entries for register field [{0:x}]", Reg); 257 258 auto RegValOr = parseRegisterValue(RegInfos[Reg], Val[0], Endian); 259 if (!RegValOr) 260 return RegValOr.takeError(); 261 Result[Reg] = std::move(*RegValOr); 262 } 263 return std::move(Result); 264 } 265 266 Expected<std::unique_ptr<StopReplyStop>> 267 StopReplyStop::create(StringRef Response, support::endianness Endian, 268 ArrayRef<RegisterInfo> RegInfos) { 269 unsigned int Signal; 270 StringRef SignalStr = Response.take_front(2); 271 Response = Response.drop_front(2); 272 if (!to_integer(SignalStr, Signal, 16)) 273 return make_parsing_error("StopReply: stop signal"); 274 275 auto Elements = SplitPairList(Response); 276 for (StringRef Field : 277 {"name", "reason", "thread", "threads", "thread-pcs"}) { 278 // This will insert an empty field if there is none. In the future, we 279 // should probably differentiate between these fields not being present and 280 // them being empty, but right now no tests depends on this. 281 if (Elements.insert({Field, {""}}).first->second.size() != 1) 282 return make_parsing_error( 283 "StopReply: got multiple responses for the {0} field", Field); 284 } 285 StringRef Name = Elements["name"][0]; 286 StringRef Reason = Elements["reason"][0]; 287 288 lldb::tid_t Thread; 289 if (!to_integer(Elements["thread"][0], Thread, 16)) 290 return make_parsing_error("StopReply: thread"); 291 292 SmallVector<StringRef, 20> Threads; 293 SmallVector<StringRef, 20> Pcs; 294 Elements["threads"][0].split(Threads, ','); 295 Elements["thread-pcs"][0].split(Pcs, ','); 296 if (Threads.size() != Pcs.size()) 297 return make_parsing_error("StopReply: thread/PC count mismatch"); 298 299 RegisterMap ThreadPcs; 300 const RegisterInfo *PcInfo = find_if(RegInfos, [](const RegisterInfo &Info) { 301 return Info.kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_PC; 302 }); 303 assert(PcInfo); 304 305 for (auto ThreadPc : zip(Threads, Pcs)) { 306 lldb::tid_t Id; 307 if (!to_integer(std::get<0>(ThreadPc), Id, 16)) 308 return make_parsing_error("StopReply: Thread id '{0}'", 309 std::get<0>(ThreadPc)); 310 311 auto PcOr = parseRegisterValue(*PcInfo, std::get<1>(ThreadPc), Endian, 312 /*ZeroPad*/ true); 313 if (!PcOr) 314 return PcOr.takeError(); 315 ThreadPcs[Id] = std::move(*PcOr); 316 } 317 318 auto RegistersOr = parseRegisters(Elements, Endian, RegInfos); 319 if (!RegistersOr) 320 return RegistersOr.takeError(); 321 322 return std::make_unique<StopReplyStop>(Signal, Thread, Name, 323 std::move(ThreadPcs), 324 std::move(*RegistersOr), Reason); 325 } 326 327 Expected<std::unique_ptr<StopReplyExit>> 328 StopReplyExit::create(StringRef Response) { 329 uint8_t Status; 330 if (!to_integer(Response, Status, 16)) 331 return make_parsing_error("StopReply: exit status"); 332 return std::make_unique<StopReplyExit>(Status); 333 } 334 335 //====== Globals =============================================================== 336 Expected<StringMap<StringRef>> SplitUniquePairList(StringRef caller, 337 StringRef str) { 338 SmallVector<StringRef, 20> elements; 339 str.split(elements, ';'); 340 341 StringMap<StringRef> pairs; 342 for (StringRef s : elements) { 343 std::pair<StringRef, StringRef> pair = s.split(':'); 344 if (pairs.count(pair.first)) 345 return make_parsing_error("{0}: Duplicate Key: {1}", caller, pair.first); 346 347 pairs.insert(pair); 348 } 349 350 return pairs; 351 } 352 353 StringMap<SmallVector<StringRef, 2>> SplitPairList(StringRef str) { 354 SmallVector<StringRef, 20> elements; 355 str.split(elements, ';'); 356 357 StringMap<SmallVector<StringRef, 2>> pairs; 358 for (StringRef s : elements) { 359 std::pair<StringRef, StringRef> pair = s.split(':'); 360 pairs[pair.first].push_back(pair.second); 361 } 362 363 return pairs; 364 } 365 } // namespace llgs_tests 366 367 std::ostream &lldb_private::operator<<(std::ostream &OS, 368 const RegisterValue &RegVal) { 369 ArrayRef<uint8_t> Bytes(static_cast<const uint8_t *>(RegVal.GetBytes()), 370 RegVal.GetByteSize()); 371 return OS << formatv("RegisterValue[{0}]: {1:@[x-2]}", RegVal.GetByteSize(), 372 make_range(Bytes.begin(), Bytes.end())) 373 .str(); 374 } 375