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/StructuredData.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 using namespace llvm::support;
20 namespace llgs_tests {
21 
22 Expected<ProcessInfo> ProcessInfo::create(StringRef response) {
23   ProcessInfo process_info;
24   auto elements_or_error = SplitUniquePairList("ProcessInfo", response);
25   if (!elements_or_error)
26     return elements_or_error.takeError();
27 
28   auto &elements = *elements_or_error;
29   if (elements["pid"].getAsInteger(16, process_info.m_pid))
30     return make_parsing_error("ProcessInfo: pid");
31   if (elements["parent-pid"].getAsInteger(16, process_info.m_parent_pid))
32     return make_parsing_error("ProcessInfo: parent-pid");
33   if (elements["real-uid"].getAsInteger(16, process_info.m_real_uid))
34     return make_parsing_error("ProcessInfo: real-uid");
35   if (elements["real-gid"].getAsInteger(16, process_info.m_real_gid))
36     return make_parsing_error("ProcessInfo: real-uid");
37   if (elements["effective-uid"].getAsInteger(16, process_info.m_effective_uid))
38     return make_parsing_error("ProcessInfo: effective-uid");
39   if (elements["effective-gid"].getAsInteger(16, process_info.m_effective_gid))
40     return make_parsing_error("ProcessInfo: effective-gid");
41   if (elements["ptrsize"].getAsInteger(10, process_info.m_ptrsize))
42     return make_parsing_error("ProcessInfo: ptrsize");
43 
44   process_info.m_triple = fromHex(elements["triple"]);
45   StringRef endian_str = elements["endian"];
46   if (endian_str == "little")
47     process_info.m_endian = support::little;
48   else if (endian_str == "big")
49     process_info.m_endian = support::big;
50   else
51     return make_parsing_error("ProcessInfo: endian");
52 
53   return process_info;
54 }
55 
56 lldb::pid_t ProcessInfo::GetPid() const { return m_pid; }
57 
58 endianness ProcessInfo::GetEndian() const { return m_endian; }
59 
60 //====== ThreadInfo ============================================================
61 ThreadInfo::ThreadInfo(StringRef name, StringRef reason,
62                        const RegisterMap &registers, unsigned int signal)
63     : m_name(name.str()), m_reason(reason.str()), m_registers(registers),
64       m_signal(signal) {}
65 
66 StringRef ThreadInfo::ReadRegister(unsigned int register_id) const {
67   return m_registers.lookup(register_id);
68 }
69 
70 Expected<uint64_t>
71 ThreadInfo::ReadRegisterAsUint64(unsigned int register_id) const {
72   uint64_t value;
73   std::string value_str(m_registers.lookup(register_id));
74   if (!llvm::to_integer(value_str, value, 16))
75     return make_parsing_error("ThreadInfo value for register {0}: {1}",
76                               register_id, value_str);
77 
78   sys::swapByteOrder(value);
79   return value;
80 }
81 
82 //====== JThreadsInfo ==========================================================
83 Expected<JThreadsInfo> JThreadsInfo::Create(StringRef response,
84                                             endianness endian) {
85   JThreadsInfo jthreads_info;
86 
87   StructuredData::ObjectSP json = StructuredData::ParseJSON(response);
88   StructuredData::Array *array = json->GetAsArray();
89   if (!array)
90     return make_parsing_error("JThreadsInfo: JSON array");
91 
92   for (size_t i = 0; i < array->GetSize(); i++) {
93     StructuredData::Dictionary *thread_info;
94     array->GetItemAtIndexAsDictionary(i, thread_info);
95     if (!thread_info)
96       return make_parsing_error("JThreadsInfo: JSON obj at {0}", i);
97 
98     StringRef name, reason;
99     thread_info->GetValueForKeyAsString("name", name);
100     thread_info->GetValueForKeyAsString("reason", reason);
101     uint64_t signal;
102     thread_info->GetValueForKeyAsInteger("signal", signal);
103     uint64_t tid;
104     thread_info->GetValueForKeyAsInteger("tid", tid);
105 
106     StructuredData::Dictionary *register_dict;
107     thread_info->GetValueForKeyAsDictionary("registers", register_dict);
108     if (!register_dict)
109       return make_parsing_error("JThreadsInfo: registers JSON obj");
110 
111     RegisterMap registers;
112 
113     auto keys_obj = register_dict->GetKeys();
114     auto keys = keys_obj->GetAsArray();
115     for (size_t i = 0; i < keys->GetSize(); i++) {
116       StringRef key_str, value_str;
117       keys->GetItemAtIndexAsString(i, key_str);
118       register_dict->GetValueForKeyAsString(key_str, value_str);
119       unsigned int register_id;
120       if (key_str.getAsInteger(10, register_id))
121         return make_parsing_error("JThreadsInfo: register key[{0}]", i);
122 
123       registers[register_id] = value_str.str();
124     }
125 
126     jthreads_info.m_thread_infos[tid] =
127         ThreadInfo(name, reason, registers, 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       NULL,
158       NULL,
159       NULL, // 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 //====== StopReply =============================================================
204 Expected<std::unique_ptr<StopReply>>
205 StopReply::create(StringRef Response, llvm::support::endianness Endian) {
206   if (Response.size() < 3)
207     return make_parsing_error("StopReply: Invalid packet");
208   if (Response.consume_front("T"))
209     return StopReplyStop::create(Response, Endian);
210   if (Response.consume_front("W"))
211     return StopReplyExit::create(Response);
212   return make_parsing_error("StopReply: Invalid packet");
213 }
214 
215 Expected<std::unique_ptr<StopReplyStop>>
216 StopReplyStop::create(StringRef Response, llvm::support::endianness Endian) {
217   unsigned int Signal;
218   StringRef SignalStr = Response.take_front(2);
219   Response = Response.drop_front(2);
220   if (!to_integer(SignalStr, Signal, 16))
221     return make_parsing_error("StopReply: stop signal");
222 
223   auto Elements = SplitPairList(Response);
224   for (StringRef Field :
225        {"name", "reason", "thread", "threads", "thread-pcs"}) {
226     // This will insert an empty field if there is none. In the future, we
227     // should probably differentiate between these fields not being present and
228     // them being empty, but right now no tests depends on this.
229     if (Elements.insert({Field, {""}}).first->second.size() != 1)
230       return make_parsing_error(
231           "StopReply: got multiple responses for the {0} field", Field);
232   }
233   StringRef Name = Elements["name"][0];
234   StringRef Reason = Elements["reason"][0];
235 
236   lldb::tid_t Thread;
237   if (!to_integer(Elements["thread"][0], Thread, 16))
238     return make_parsing_error("StopReply: thread");
239 
240   SmallVector<StringRef, 20> Threads;
241   SmallVector<StringRef, 20> Pcs;
242   Elements["threads"][0].split(Threads, ',');
243   Elements["thread-pcs"][0].split(Pcs, ',');
244   if (Threads.size() != Pcs.size())
245     return make_parsing_error("StopReply: thread/PC count mismatch");
246 
247   U64Map ThreadPcs;
248   for (auto ThreadPc : zip(Threads, Pcs)) {
249     lldb::tid_t Id;
250     uint64_t Pc;
251     if (!to_integer(std::get<0>(ThreadPc), Id, 16))
252       return make_parsing_error("StopReply: Thread id '{0}'",
253                                 std::get<0>(ThreadPc));
254     if (!to_integer(std::get<1>(ThreadPc), Pc, 16))
255       return make_parsing_error("StopReply Thread Pc '{0}'",
256                                 std::get<1>(ThreadPc));
257 
258     ThreadPcs[Id] = Pc;
259   }
260 
261   RegisterMap Registers;
262   for (const auto &E : Elements) {
263     StringRef Key = E.getKey();
264     const auto &Val = E.getValue();
265     if (Key.size() != 2)
266       continue;
267 
268     unsigned int Reg;
269     if (!to_integer(Key, Reg, 16))
270       continue;
271 
272     if (Val.size() != 1)
273       return make_parsing_error(
274           "StopReply: multiple entries for register field [{0:x}]", Reg);
275 
276     Registers[Reg] = Val[0].str();
277   }
278 
279   return llvm::make_unique<StopReplyStop>(Signal, Thread, Name, ThreadPcs,
280                                           Registers, Reason);
281 }
282 
283 Expected<std::unique_ptr<StopReplyExit>>
284 StopReplyExit::create(StringRef Response) {
285   uint8_t Status;
286   if (!to_integer(Response, Status, 16))
287     return make_parsing_error("StopReply: exit status");
288   return llvm::make_unique<StopReplyExit>(Status);
289 }
290 
291 //====== Globals ===============================================================
292 Expected<StringMap<StringRef>> SplitUniquePairList(StringRef caller,
293                                                    StringRef str) {
294   SmallVector<StringRef, 20> elements;
295   str.split(elements, ';');
296 
297   StringMap<StringRef> pairs;
298   for (StringRef s : elements) {
299     std::pair<StringRef, StringRef> pair = s.split(':');
300     if (pairs.count(pair.first))
301       return make_parsing_error("{0}: Duplicate Key: {1}", caller, pair.first);
302 
303     pairs.insert(pair);
304   }
305 
306   return pairs;
307 }
308 
309 StringMap<SmallVector<StringRef, 2>> SplitPairList(StringRef str) {
310   SmallVector<StringRef, 20> elements;
311   str.split(elements, ';');
312 
313   StringMap<SmallVector<StringRef, 2>> pairs;
314   for (StringRef s : elements) {
315     std::pair<StringRef, StringRef> pair = s.split(':');
316     pairs[pair.first].push_back(pair.second);
317   }
318 
319   return pairs;
320 }
321 } // namespace llgs_tests
322