xref: /llvm-project/lldb/unittests/tools/lldb-server/tests/MessageObjects.cpp (revision 133bcacecfb70e8b1692f9c2c0a44ec640a0422a)
180814287SRaphael Isemann //===-- MessageObjects.cpp ------------------------------------------------===//
2015f17d3SPavel Labath //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6015f17d3SPavel Labath //
7015f17d3SPavel Labath //===----------------------------------------------------------------------===//
8015f17d3SPavel Labath 
9015f17d3SPavel Labath #include "MessageObjects.h"
10145d95c9SPavel Labath #include "lldb/Utility/Args.h"
119a9556f0SPavel Labath #include "lldb/Utility/StringExtractor.h"
12015f17d3SPavel Labath #include "llvm/ADT/StringExtras.h"
13015f17d3SPavel Labath #include "gtest/gtest.h"
14015f17d3SPavel Labath 
15015f17d3SPavel Labath using namespace lldb_private;
16a1181312SPavel Labath using namespace lldb;
17015f17d3SPavel Labath using namespace llvm;
18015f17d3SPavel Labath namespace llgs_tests {
19015f17d3SPavel Labath 
create(StringRef response)20a1181312SPavel Labath Expected<ProcessInfo> ProcessInfo::create(StringRef response) {
21015f17d3SPavel Labath   ProcessInfo process_info;
22c596e908SPavel Labath   auto elements_or_error = SplitUniquePairList("ProcessInfo", response);
23015f17d3SPavel Labath   if (!elements_or_error)
24015f17d3SPavel Labath     return elements_or_error.takeError();
25015f17d3SPavel Labath 
26015f17d3SPavel Labath   auto &elements = *elements_or_error;
27015f17d3SPavel Labath   if (elements["pid"].getAsInteger(16, process_info.m_pid))
28015f17d3SPavel Labath     return make_parsing_error("ProcessInfo: pid");
29015f17d3SPavel Labath   if (elements["parent-pid"].getAsInteger(16, process_info.m_parent_pid))
30015f17d3SPavel Labath     return make_parsing_error("ProcessInfo: parent-pid");
31015f17d3SPavel Labath   if (elements["real-uid"].getAsInteger(16, process_info.m_real_uid))
32015f17d3SPavel Labath     return make_parsing_error("ProcessInfo: real-uid");
33015f17d3SPavel Labath   if (elements["real-gid"].getAsInteger(16, process_info.m_real_gid))
34015f17d3SPavel Labath     return make_parsing_error("ProcessInfo: real-uid");
35015f17d3SPavel Labath   if (elements["effective-uid"].getAsInteger(16, process_info.m_effective_uid))
36015f17d3SPavel Labath     return make_parsing_error("ProcessInfo: effective-uid");
37015f17d3SPavel Labath   if (elements["effective-gid"].getAsInteger(16, process_info.m_effective_gid))
38015f17d3SPavel Labath     return make_parsing_error("ProcessInfo: effective-gid");
39015f17d3SPavel Labath   if (elements["ptrsize"].getAsInteger(10, process_info.m_ptrsize))
40015f17d3SPavel Labath     return make_parsing_error("ProcessInfo: ptrsize");
41015f17d3SPavel Labath 
42015f17d3SPavel Labath   process_info.m_triple = fromHex(elements["triple"]);
43015f17d3SPavel Labath   StringRef endian_str = elements["endian"];
44015f17d3SPavel Labath   if (endian_str == "little")
454a0ccfa8SKazu Hirata     process_info.m_endian = llvm::endianness::little;
46015f17d3SPavel Labath   else if (endian_str == "big")
474a0ccfa8SKazu Hirata     process_info.m_endian = llvm::endianness::big;
48015f17d3SPavel Labath   else
49015f17d3SPavel Labath     return make_parsing_error("ProcessInfo: endian");
50015f17d3SPavel Labath 
51015f17d3SPavel Labath   return process_info;
52015f17d3SPavel Labath }
53015f17d3SPavel Labath 
GetPid() const54015f17d3SPavel Labath lldb::pid_t ProcessInfo::GetPid() const { return m_pid; }
55015f17d3SPavel Labath 
GetEndian() const56a9d50568SKazu Hirata llvm::endianness ProcessInfo::GetEndian() const { return m_endian; }
57015f17d3SPavel Labath 
58015f17d3SPavel Labath //====== ThreadInfo ============================================================
ThreadInfo(StringRef name,StringRef reason,RegisterMap registers,unsigned int)599a9556f0SPavel Labath ThreadInfo::ThreadInfo(StringRef name, StringRef reason, RegisterMap registers,
60b8603181SEric Christopher                        unsigned int)
619a9556f0SPavel Labath     : m_name(name.str()), m_reason(reason.str()),
62b8603181SEric Christopher       m_registers(std::move(registers)) {}
63015f17d3SPavel Labath 
ReadRegister(unsigned int Id) const649a9556f0SPavel Labath const RegisterValue *ThreadInfo::ReadRegister(unsigned int Id) const {
659a9556f0SPavel Labath   auto Iter = m_registers.find(Id);
669a9556f0SPavel Labath   return Iter == m_registers.end() ? nullptr : &Iter->getSecond();
67015f17d3SPavel Labath }
68015f17d3SPavel Labath 
69015f17d3SPavel Labath //====== JThreadsInfo ==========================================================
709a9556f0SPavel Labath 
719a9556f0SPavel Labath Expected<RegisterMap>
parseRegisters(const StructuredData::Dictionary & Dict,ArrayRef<RegisterInfo> RegInfos)729a9556f0SPavel Labath JThreadsInfo::parseRegisters(const StructuredData::Dictionary &Dict,
739a9556f0SPavel Labath                              ArrayRef<RegisterInfo> RegInfos) {
749a9556f0SPavel Labath   RegisterMap Result;
759a9556f0SPavel Labath 
769a9556f0SPavel Labath   auto KeysObj = Dict.GetKeys();
779a9556f0SPavel Labath   auto Keys = KeysObj->GetAsArray();
789a9556f0SPavel Labath   for (size_t i = 0; i < Keys->GetSize(); i++) {
791486264dSAlex Langford     std::optional<StringRef> MaybeKeyStr = Keys->GetItemAtIndexAsString(i);
801486264dSAlex Langford     if (!MaybeKeyStr)
811486264dSAlex Langford       return make_parsing_error("JThreadsInfo: Invalid Key at index {0}", i);
821486264dSAlex Langford 
831486264dSAlex Langford     StringRef KeyStr = *MaybeKeyStr;
841486264dSAlex Langford     StringRef ValueStr;
859a9556f0SPavel Labath     Dict.GetValueForKeyAsString(KeyStr, ValueStr);
869a9556f0SPavel Labath     unsigned int Register;
879a9556f0SPavel Labath     if (!llvm::to_integer(KeyStr, Register, 10))
889a9556f0SPavel Labath       return make_parsing_error("JThreadsInfo: register key[{0}]", i);
899a9556f0SPavel Labath 
909a9556f0SPavel Labath     auto RegValOr =
914a0ccfa8SKazu Hirata         parseRegisterValue(RegInfos[Register], ValueStr, llvm::endianness::big);
929a9556f0SPavel Labath     if (!RegValOr)
939a9556f0SPavel Labath       return RegValOr.takeError();
949a9556f0SPavel Labath     Result[Register] = std::move(*RegValOr);
959a9556f0SPavel Labath   }
969a9556f0SPavel Labath   return std::move(Result);
979a9556f0SPavel Labath }
989a9556f0SPavel Labath 
create(StringRef Response,ArrayRef<RegisterInfo> RegInfos)999a9556f0SPavel Labath Expected<JThreadsInfo> JThreadsInfo::create(StringRef Response,
1009a9556f0SPavel Labath                                             ArrayRef<RegisterInfo> RegInfos) {
101015f17d3SPavel Labath   JThreadsInfo jthreads_info;
102015f17d3SPavel Labath 
1038bddb13cSAlex Langford   StructuredData::ObjectSP json = StructuredData::ParseJSON(Response);
104015f17d3SPavel Labath   StructuredData::Array *array = json->GetAsArray();
105015f17d3SPavel Labath   if (!array)
106015f17d3SPavel Labath     return make_parsing_error("JThreadsInfo: JSON array");
107015f17d3SPavel Labath 
108015f17d3SPavel Labath   for (size_t i = 0; i < array->GetSize(); i++) {
109*133bcaceSAlex Langford     std::optional<StructuredData::Dictionary *> maybe_thread_info =
110*133bcaceSAlex Langford         array->GetItemAtIndexAsDictionary(i);
111*133bcaceSAlex Langford     if (!maybe_thread_info)
112015f17d3SPavel Labath       return make_parsing_error("JThreadsInfo: JSON obj at {0}", i);
113015f17d3SPavel Labath 
114*133bcaceSAlex Langford     StructuredData::Dictionary *thread_info = *maybe_thread_info;
115015f17d3SPavel Labath     StringRef name, reason;
116015f17d3SPavel Labath     thread_info->GetValueForKeyAsString("name", name);
117015f17d3SPavel Labath     thread_info->GetValueForKeyAsString("reason", reason);
118015f17d3SPavel Labath     uint64_t signal;
119015f17d3SPavel Labath     thread_info->GetValueForKeyAsInteger("signal", signal);
120015f17d3SPavel Labath     uint64_t tid;
121015f17d3SPavel Labath     thread_info->GetValueForKeyAsInteger("tid", tid);
122015f17d3SPavel Labath 
123015f17d3SPavel Labath     StructuredData::Dictionary *register_dict;
124015f17d3SPavel Labath     thread_info->GetValueForKeyAsDictionary("registers", register_dict);
125015f17d3SPavel Labath     if (!register_dict)
126015f17d3SPavel Labath       return make_parsing_error("JThreadsInfo: registers JSON obj");
127015f17d3SPavel Labath 
1289a9556f0SPavel Labath     auto RegsOr = parseRegisters(*register_dict, RegInfos);
1299a9556f0SPavel Labath     if (!RegsOr)
1309a9556f0SPavel Labath       return RegsOr.takeError();
131015f17d3SPavel Labath     jthreads_info.m_thread_infos[tid] =
1329a9556f0SPavel Labath         ThreadInfo(name, reason, std::move(*RegsOr), signal);
133015f17d3SPavel Labath   }
134015f17d3SPavel Labath 
135015f17d3SPavel Labath   return jthreads_info;
136015f17d3SPavel Labath }
137015f17d3SPavel Labath 
GetThreadInfos() const138015f17d3SPavel Labath const ThreadInfoMap &JThreadsInfo::GetThreadInfos() const {
139015f17d3SPavel Labath   return m_thread_infos;
140015f17d3SPavel Labath }
141015f17d3SPavel Labath 
create(StringRef Response)142a1181312SPavel Labath Expected<RegisterInfo> RegisterInfoParser::create(StringRef Response) {
143a1181312SPavel Labath   auto ElementsOr = SplitUniquePairList("RegisterInfoParser", Response);
144a1181312SPavel Labath   if (!ElementsOr)
145a1181312SPavel Labath     return ElementsOr.takeError();
146a1181312SPavel Labath   auto &Elements = *ElementsOr;
147a1181312SPavel Labath 
148a1181312SPavel Labath   RegisterInfo Info = {
149a1181312SPavel Labath       nullptr,       // Name
150a1181312SPavel Labath       nullptr,       // Alt name
151a1181312SPavel Labath       0,             // byte size
152a1181312SPavel Labath       0,             // offset
153a1181312SPavel Labath       eEncodingUint, // encoding
154a1181312SPavel Labath       eFormatHex,    // format
155a1181312SPavel Labath       {
156a1181312SPavel Labath           LLDB_INVALID_REGNUM, // eh_frame reg num
157a1181312SPavel Labath           LLDB_INVALID_REGNUM, // DWARF reg num
158a1181312SPavel Labath           LLDB_INVALID_REGNUM, // generic reg num
159a1181312SPavel Labath           LLDB_INVALID_REGNUM, // process plugin reg num
160a1181312SPavel Labath           LLDB_INVALID_REGNUM  // native register number
161a1181312SPavel Labath       },
162248a1305SKonrad Kleine       nullptr,
163248a1305SKonrad Kleine       nullptr,
16457c8fee1SDavid Spickett       nullptr,
165a1181312SPavel Labath   };
166a1181312SPavel Labath   Info.name = ConstString(Elements["name"]).GetCString();
167a1181312SPavel Labath   if (!Info.name)
168a1181312SPavel Labath     return make_parsing_error("qRegisterInfo: name");
169a1181312SPavel Labath 
170a1181312SPavel Labath   Info.alt_name = ConstString(Elements["alt-name"]).GetCString();
171a1181312SPavel Labath 
172a1181312SPavel Labath   if (!to_integer(Elements["bitsize"], Info.byte_size, 10))
173a1181312SPavel Labath     return make_parsing_error("qRegisterInfo: bit-size");
174a1181312SPavel Labath   Info.byte_size /= CHAR_BIT;
175a1181312SPavel Labath 
176a1181312SPavel Labath   if (!to_integer(Elements["offset"], Info.byte_offset, 10))
17778cb4562SMuhammad Omair Javaid     Info.byte_offset = LLDB_INVALID_INDEX32;
178a1181312SPavel Labath 
179a1181312SPavel Labath   Info.encoding = Args::StringToEncoding(Elements["encoding"]);
180a1181312SPavel Labath   if (Info.encoding == eEncodingInvalid)
181a1181312SPavel Labath     return make_parsing_error("qRegisterInfo: encoding");
182a1181312SPavel Labath 
183a1181312SPavel Labath   Info.format = StringSwitch<Format>(Elements["format"])
184a1181312SPavel Labath                     .Case("binary", eFormatBinary)
185a1181312SPavel Labath                     .Case("decimal", eFormatDecimal)
186a1181312SPavel Labath                     .Case("hex", eFormatHex)
187a1181312SPavel Labath                     .Case("float", eFormatFloat)
188a1181312SPavel Labath                     .Case("vector-sint8", eFormatVectorOfSInt8)
189a1181312SPavel Labath                     .Case("vector-uint8", eFormatVectorOfUInt8)
190a1181312SPavel Labath                     .Case("vector-sint16", eFormatVectorOfSInt16)
191a1181312SPavel Labath                     .Case("vector-uint16", eFormatVectorOfUInt16)
192a1181312SPavel Labath                     .Case("vector-sint32", eFormatVectorOfSInt32)
193a1181312SPavel Labath                     .Case("vector-uint32", eFormatVectorOfUInt32)
194a1181312SPavel Labath                     .Case("vector-float32", eFormatVectorOfFloat32)
195a1181312SPavel Labath                     .Case("vector-uint64", eFormatVectorOfUInt64)
196a1181312SPavel Labath                     .Case("vector-uint128", eFormatVectorOfUInt128)
197a1181312SPavel Labath                     .Default(eFormatInvalid);
198a1181312SPavel Labath   if (Info.format == eFormatInvalid)
199a1181312SPavel Labath     return make_parsing_error("qRegisterInfo: format");
200a1181312SPavel Labath 
201a1181312SPavel Labath   Info.kinds[eRegisterKindGeneric] =
202a1181312SPavel Labath       Args::StringToGenericRegister(Elements["generic"]);
203a1181312SPavel Labath 
204a1181312SPavel Labath   return std::move(Info);
205a1181312SPavel Labath }
206a1181312SPavel Labath 
parseRegisterValue(const RegisterInfo & Info,StringRef HexValue,llvm::endianness Endian,bool ZeroPad)2079a9556f0SPavel Labath Expected<RegisterValue> parseRegisterValue(const RegisterInfo &Info,
2089a9556f0SPavel Labath                                            StringRef HexValue,
209d7b18d50SKazu Hirata                                            llvm::endianness Endian,
2109391d98eSPavel Labath                                            bool ZeroPad) {
2119391d98eSPavel Labath   SmallString<128> Storage;
2129391d98eSPavel Labath   if (ZeroPad && HexValue.size() < Info.byte_size * 2) {
2139391d98eSPavel Labath     Storage.insert(Storage.begin(), Info.byte_size * 2 - HexValue.size(), '0');
2149391d98eSPavel Labath     Storage += HexValue;
2159391d98eSPavel Labath     HexValue = Storage;
2169391d98eSPavel Labath   }
2179391d98eSPavel Labath 
2189a9556f0SPavel Labath   SmallVector<uint8_t, 64> Bytes(HexValue.size() / 2);
2199a9556f0SPavel Labath   StringExtractor(HexValue).GetHexBytes(Bytes, '\xcc');
2209a9556f0SPavel Labath   RegisterValue Value;
2219a9556f0SPavel Labath   Status ST;
2224a0ccfa8SKazu Hirata   Value.SetFromMemoryData(Info, Bytes.data(), Bytes.size(),
2234a0ccfa8SKazu Hirata                           Endian == llvm::endianness::little ? eByteOrderLittle
2244a0ccfa8SKazu Hirata                                                              : eByteOrderBig,
2254a0ccfa8SKazu Hirata                           ST);
2269a9556f0SPavel Labath   if (ST.Fail())
2279a9556f0SPavel Labath     return ST.ToError();
2289a9556f0SPavel Labath   return Value;
2299a9556f0SPavel Labath }
2309a9556f0SPavel Labath 
231015f17d3SPavel Labath //====== StopReply =============================================================
23293a582c0SPavel Labath Expected<std::unique_ptr<StopReply>>
create(StringRef Response,llvm::endianness Endian,ArrayRef<RegisterInfo> RegInfos)233d7b18d50SKazu Hirata StopReply::create(StringRef Response, llvm::endianness Endian,
2349a9556f0SPavel Labath                   ArrayRef<RegisterInfo> RegInfos) {
23593a582c0SPavel Labath   if (Response.size() < 3)
236c596e908SPavel Labath     return make_parsing_error("StopReply: Invalid packet");
23793a582c0SPavel Labath   if (Response.consume_front("T"))
2389a9556f0SPavel Labath     return StopReplyStop::create(Response, Endian, RegInfos);
23993a582c0SPavel Labath   if (Response.consume_front("W"))
24093a582c0SPavel Labath     return StopReplyExit::create(Response);
24193a582c0SPavel Labath   return make_parsing_error("StopReply: Invalid packet");
24293a582c0SPavel Labath }
243c596e908SPavel Labath 
parseRegisters(const StringMap<SmallVector<StringRef,2>> & Elements,llvm::endianness Endian,ArrayRef<lldb_private::RegisterInfo> RegInfos)2449a9556f0SPavel Labath Expected<RegisterMap> StopReplyStop::parseRegisters(
2459a9556f0SPavel Labath     const StringMap<SmallVector<StringRef, 2>> &Elements,
246a9d50568SKazu Hirata     llvm::endianness Endian, ArrayRef<lldb_private::RegisterInfo> RegInfos) {
2479a9556f0SPavel Labath 
2489a9556f0SPavel Labath   RegisterMap Result;
2499a9556f0SPavel Labath   for (const auto &E : Elements) {
2509a9556f0SPavel Labath     StringRef Key = E.getKey();
2519a9556f0SPavel Labath     const auto &Val = E.getValue();
2529a9556f0SPavel Labath     if (Key.size() != 2)
2539a9556f0SPavel Labath       continue;
2549a9556f0SPavel Labath 
2559a9556f0SPavel Labath     unsigned int Reg;
2569a9556f0SPavel Labath     if (!to_integer(Key, Reg, 16))
2579a9556f0SPavel Labath       continue;
2589a9556f0SPavel Labath 
2599a9556f0SPavel Labath     if (Val.size() != 1)
2609a9556f0SPavel Labath       return make_parsing_error(
2619a9556f0SPavel Labath           "StopReplyStop: multiple entries for register field [{0:x}]", Reg);
2629a9556f0SPavel Labath 
2639a9556f0SPavel Labath     auto RegValOr = parseRegisterValue(RegInfos[Reg], Val[0], Endian);
2649a9556f0SPavel Labath     if (!RegValOr)
2659a9556f0SPavel Labath       return RegValOr.takeError();
2669a9556f0SPavel Labath     Result[Reg] = std::move(*RegValOr);
2679a9556f0SPavel Labath   }
2689a9556f0SPavel Labath   return std::move(Result);
2699a9556f0SPavel Labath }
2709a9556f0SPavel Labath 
27193a582c0SPavel Labath Expected<std::unique_ptr<StopReplyStop>>
create(StringRef Response,llvm::endianness Endian,ArrayRef<RegisterInfo> RegInfos)272a9d50568SKazu Hirata StopReplyStop::create(StringRef Response, llvm::endianness Endian,
2739a9556f0SPavel Labath                       ArrayRef<RegisterInfo> RegInfos) {
27493a582c0SPavel Labath   unsigned int Signal;
27593a582c0SPavel Labath   StringRef SignalStr = Response.take_front(2);
27693a582c0SPavel Labath   Response = Response.drop_front(2);
27793a582c0SPavel Labath   if (!to_integer(SignalStr, Signal, 16))
278c596e908SPavel Labath     return make_parsing_error("StopReply: stop signal");
279015f17d3SPavel Labath 
28093a582c0SPavel Labath   auto Elements = SplitPairList(Response);
28193a582c0SPavel Labath   for (StringRef Field :
282c596e908SPavel Labath        {"name", "reason", "thread", "threads", "thread-pcs"}) {
283c596e908SPavel Labath     // This will insert an empty field if there is none. In the future, we
284c596e908SPavel Labath     // should probably differentiate between these fields not being present and
285c596e908SPavel Labath     // them being empty, but right now no tests depends on this.
28693a582c0SPavel Labath     if (Elements.insert({Field, {""}}).first->second.size() != 1)
287c596e908SPavel Labath       return make_parsing_error(
28893a582c0SPavel Labath           "StopReply: got multiple responses for the {0} field", Field);
289c596e908SPavel Labath   }
29093a582c0SPavel Labath   StringRef Name = Elements["name"][0];
29193a582c0SPavel Labath   StringRef Reason = Elements["reason"][0];
292c596e908SPavel Labath 
29393a582c0SPavel Labath   lldb::tid_t Thread;
29493a582c0SPavel Labath   if (!to_integer(Elements["thread"][0], Thread, 16))
295c596e908SPavel Labath     return make_parsing_error("StopReply: thread");
296015f17d3SPavel Labath 
29793a582c0SPavel Labath   SmallVector<StringRef, 20> Threads;
29893a582c0SPavel Labath   SmallVector<StringRef, 20> Pcs;
29993a582c0SPavel Labath   Elements["threads"][0].split(Threads, ',');
30093a582c0SPavel Labath   Elements["thread-pcs"][0].split(Pcs, ',');
30193a582c0SPavel Labath   if (Threads.size() != Pcs.size())
302015f17d3SPavel Labath     return make_parsing_error("StopReply: thread/PC count mismatch");
303015f17d3SPavel Labath 
3049a9556f0SPavel Labath   RegisterMap ThreadPcs;
3059a9556f0SPavel Labath   const RegisterInfo *PcInfo = find_if(RegInfos, [](const RegisterInfo &Info) {
3069a9556f0SPavel Labath     return Info.kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_PC;
3079a9556f0SPavel Labath   });
3089a9556f0SPavel Labath   assert(PcInfo);
3099a9556f0SPavel Labath 
31093a582c0SPavel Labath   for (auto ThreadPc : zip(Threads, Pcs)) {
31193a582c0SPavel Labath     lldb::tid_t Id;
31293a582c0SPavel Labath     if (!to_integer(std::get<0>(ThreadPc), Id, 16))
31393a582c0SPavel Labath       return make_parsing_error("StopReply: Thread id '{0}'",
31493a582c0SPavel Labath                                 std::get<0>(ThreadPc));
315015f17d3SPavel Labath 
3169391d98eSPavel Labath     auto PcOr = parseRegisterValue(*PcInfo, std::get<1>(ThreadPc), Endian,
3179391d98eSPavel Labath                                    /*ZeroPad*/ true);
3189a9556f0SPavel Labath     if (!PcOr)
3199a9556f0SPavel Labath       return PcOr.takeError();
3209a9556f0SPavel Labath     ThreadPcs[Id] = std::move(*PcOr);
321015f17d3SPavel Labath   }
322015f17d3SPavel Labath 
3239a9556f0SPavel Labath   auto RegistersOr = parseRegisters(Elements, Endian, RegInfos);
3249a9556f0SPavel Labath   if (!RegistersOr)
3259a9556f0SPavel Labath     return RegistersOr.takeError();
32693a582c0SPavel Labath 
327a8f3ae7cSJonas Devlieghere   return std::make_unique<StopReplyStop>(Signal, Thread, Name,
3289a9556f0SPavel Labath                                           std::move(ThreadPcs),
3299a9556f0SPavel Labath                                           std::move(*RegistersOr), Reason);
33093a582c0SPavel Labath }
33193a582c0SPavel Labath 
33293a582c0SPavel Labath Expected<std::unique_ptr<StopReplyExit>>
create(StringRef Response)33393a582c0SPavel Labath StopReplyExit::create(StringRef Response) {
33493a582c0SPavel Labath   uint8_t Status;
33593a582c0SPavel Labath   if (!to_integer(Response, Status, 16))
33693a582c0SPavel Labath     return make_parsing_error("StopReply: exit status");
337a8f3ae7cSJonas Devlieghere   return std::make_unique<StopReplyExit>(Status);
338015f17d3SPavel Labath }
339015f17d3SPavel Labath 
340015f17d3SPavel Labath //====== Globals ===============================================================
SplitUniquePairList(StringRef caller,StringRef str)341c596e908SPavel Labath Expected<StringMap<StringRef>> SplitUniquePairList(StringRef caller,
342c596e908SPavel Labath                                                    StringRef str) {
343015f17d3SPavel Labath   SmallVector<StringRef, 20> elements;
344015f17d3SPavel Labath   str.split(elements, ';');
345015f17d3SPavel Labath 
346015f17d3SPavel Labath   StringMap<StringRef> pairs;
347015f17d3SPavel Labath   for (StringRef s : elements) {
348015f17d3SPavel Labath     std::pair<StringRef, StringRef> pair = s.split(':');
349015f17d3SPavel Labath     if (pairs.count(pair.first))
350015f17d3SPavel Labath       return make_parsing_error("{0}: Duplicate Key: {1}", caller, pair.first);
351015f17d3SPavel Labath 
352c596e908SPavel Labath     pairs.insert(pair);
353c596e908SPavel Labath   }
354c596e908SPavel Labath 
355c596e908SPavel Labath   return pairs;
356c596e908SPavel Labath }
357c596e908SPavel Labath 
SplitPairList(StringRef str)358c596e908SPavel Labath StringMap<SmallVector<StringRef, 2>> SplitPairList(StringRef str) {
359c596e908SPavel Labath   SmallVector<StringRef, 20> elements;
360c596e908SPavel Labath   str.split(elements, ';');
361c596e908SPavel Labath 
362c596e908SPavel Labath   StringMap<SmallVector<StringRef, 2>> pairs;
363c596e908SPavel Labath   for (StringRef s : elements) {
364c596e908SPavel Labath     std::pair<StringRef, StringRef> pair = s.split(':');
365c596e908SPavel Labath     pairs[pair.first].push_back(pair.second);
366015f17d3SPavel Labath   }
367015f17d3SPavel Labath 
368015f17d3SPavel Labath   return pairs;
369015f17d3SPavel Labath }
370015f17d3SPavel Labath } // namespace llgs_tests
3719a9556f0SPavel Labath 
operator <<(std::ostream & OS,const RegisterValue & RegVal)3729a9556f0SPavel Labath std::ostream &lldb_private::operator<<(std::ostream &OS,
3739a9556f0SPavel Labath                                        const RegisterValue &RegVal) {
3749a9556f0SPavel Labath   ArrayRef<uint8_t> Bytes(static_cast<const uint8_t *>(RegVal.GetBytes()),
3759a9556f0SPavel Labath                           RegVal.GetByteSize());
3769a9556f0SPavel Labath   return OS << formatv("RegisterValue[{0}]: {1:@[x-2]}", RegVal.GetByteSize(),
3779a9556f0SPavel Labath                        make_range(Bytes.begin(), Bytes.end()))
3789a9556f0SPavel Labath                    .str();
3799a9556f0SPavel Labath }
380