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