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/Utility/StructuredData.h"
12 #include "llvm/ADT/StringExtras.h"
13 #include "gtest/gtest.h"
14 
15 using namespace lldb_private;
16 using namespace llvm;
17 using namespace llvm::support;
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 endianness ProcessInfo::GetEndian() const { return m_endian; }
57 
58 //====== ThreadInfo ============================================================
59 ThreadInfo::ThreadInfo(StringRef name, StringRef reason,
60                        const RegisterMap &registers, unsigned int signal)
61     : m_name(name.str()), m_reason(reason.str()), m_registers(registers),
62       m_signal(signal) {}
63 
64 StringRef ThreadInfo::ReadRegister(unsigned int register_id) const {
65   return m_registers.lookup(register_id);
66 }
67 
68 Expected<uint64_t>
69 ThreadInfo::ReadRegisterAsUint64(unsigned int register_id) const {
70   uint64_t value;
71   std::string value_str(m_registers.lookup(register_id));
72   if (!llvm::to_integer(value_str, value, 16))
73     return make_parsing_error("ThreadInfo value for register {0}: {1}",
74                               register_id, value_str);
75 
76   sys::swapByteOrder(value);
77   return value;
78 }
79 
80 //====== JThreadsInfo ==========================================================
81 Expected<JThreadsInfo> JThreadsInfo::Create(StringRef response,
82                                             endianness endian) {
83   JThreadsInfo jthreads_info;
84 
85   StructuredData::ObjectSP json = StructuredData::ParseJSON(response);
86   StructuredData::Array *array = json->GetAsArray();
87   if (!array)
88     return make_parsing_error("JThreadsInfo: JSON array");
89 
90   for (size_t i = 0; i < array->GetSize(); i++) {
91     StructuredData::Dictionary *thread_info;
92     array->GetItemAtIndexAsDictionary(i, thread_info);
93     if (!thread_info)
94       return make_parsing_error("JThreadsInfo: JSON obj at {0}", i);
95 
96     StringRef name, reason;
97     thread_info->GetValueForKeyAsString("name", name);
98     thread_info->GetValueForKeyAsString("reason", reason);
99     uint64_t signal;
100     thread_info->GetValueForKeyAsInteger("signal", signal);
101     uint64_t tid;
102     thread_info->GetValueForKeyAsInteger("tid", tid);
103 
104     StructuredData::Dictionary *register_dict;
105     thread_info->GetValueForKeyAsDictionary("registers", register_dict);
106     if (!register_dict)
107       return make_parsing_error("JThreadsInfo: registers JSON obj");
108 
109     RegisterMap registers;
110 
111     auto keys_obj = register_dict->GetKeys();
112     auto keys = keys_obj->GetAsArray();
113     for (size_t i = 0; i < keys->GetSize(); i++) {
114       StringRef key_str, value_str;
115       keys->GetItemAtIndexAsString(i, key_str);
116       register_dict->GetValueForKeyAsString(key_str, value_str);
117       unsigned int register_id;
118       if (key_str.getAsInteger(10, register_id))
119         return make_parsing_error("JThreadsInfo: register key[{0}]", i);
120 
121       registers[register_id] = value_str.str();
122     }
123 
124     jthreads_info.m_thread_infos[tid] =
125         ThreadInfo(name, reason, registers, signal);
126   }
127 
128   return jthreads_info;
129 }
130 
131 const ThreadInfoMap &JThreadsInfo::GetThreadInfos() const {
132   return m_thread_infos;
133 }
134 
135 //====== StopReply =============================================================
136 const U64Map &StopReply::GetThreadPcs() const { return m_thread_pcs; }
137 
138 Expected<StopReply> StopReply::Create(StringRef response,
139                                       llvm::support::endianness endian) {
140   if (response.size() < 3 || !response.consume_front("T"))
141     return make_parsing_error("StopReply: Invalid packet");
142 
143   StopReply stop_reply;
144 
145   StringRef signal = response.take_front(2);
146   response = response.drop_front(2);
147   if (!llvm::to_integer(signal, stop_reply.m_signal, 16))
148     return make_parsing_error("StopReply: stop signal");
149 
150   auto elements = SplitPairList(response);
151   for (StringRef field :
152        {"name", "reason", "thread", "threads", "thread-pcs"}) {
153     // This will insert an empty field if there is none. In the future, we
154     // should probably differentiate between these fields not being present and
155     // them being empty, but right now no tests depends on this.
156     if (elements.insert({field, {""}}).first->second.size() != 1)
157       return make_parsing_error(
158           "StopReply: got multiple responses for the {0} field", field);
159   }
160   stop_reply.m_name = elements["name"][0];
161   stop_reply.m_reason = elements["reason"][0];
162 
163   if (!llvm::to_integer(elements["thread"][0], stop_reply.m_thread, 16))
164     return make_parsing_error("StopReply: thread");
165 
166   SmallVector<StringRef, 20> threads;
167   SmallVector<StringRef, 20> pcs;
168   elements["threads"][0].split(threads, ',');
169   elements["thread-pcs"][0].split(pcs, ',');
170   if (threads.size() != pcs.size())
171     return make_parsing_error("StopReply: thread/PC count mismatch");
172 
173   for (size_t i = 0; i < threads.size(); i++) {
174     lldb::tid_t thread_id;
175     uint64_t pc;
176     if (threads[i].getAsInteger(16, thread_id))
177       return make_parsing_error("StopReply: thread ID at [{0}].", i);
178     if (pcs[i].getAsInteger(16, pc))
179       return make_parsing_error("StopReply: thread PC at [{0}].", i);
180 
181     stop_reply.m_thread_pcs[thread_id] = pc;
182   }
183 
184   for (auto i = elements.begin(); i != elements.end(); i++) {
185     StringRef key = i->getKey();
186     const auto &val = i->getValue();
187     if (key.size() == 2) {
188       unsigned int reg;
189       if (key.getAsInteger(16, reg))
190         continue;
191       if (val.size() != 1)
192         return make_parsing_error(
193             "StopReply: multiple entries for register field [{0:x}]", reg);
194 
195       stop_reply.m_registers[reg] = val[0].str();
196     }
197   }
198 
199   return stop_reply;
200 }
201 
202 //====== Globals ===============================================================
203 Expected<StringMap<StringRef>> SplitUniquePairList(StringRef caller,
204                                                    StringRef str) {
205   SmallVector<StringRef, 20> elements;
206   str.split(elements, ';');
207 
208   StringMap<StringRef> pairs;
209   for (StringRef s : elements) {
210     std::pair<StringRef, StringRef> pair = s.split(':');
211     if (pairs.count(pair.first))
212       return make_parsing_error("{0}: Duplicate Key: {1}", caller, pair.first);
213 
214     pairs.insert(pair);
215   }
216 
217   return pairs;
218 }
219 
220 StringMap<SmallVector<StringRef, 2>> SplitPairList(StringRef str) {
221   SmallVector<StringRef, 20> elements;
222   str.split(elements, ';');
223 
224   StringMap<SmallVector<StringRef, 2>> pairs;
225   for (StringRef s : elements) {
226     std::pair<StringRef, StringRef> pair = s.split(':');
227     pairs[pair.first].push_back(pair.second);
228   }
229 
230   return pairs;
231 }
232 } // namespace llgs_tests
233