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