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 ®isters, 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 Expected<std::unique_ptr<StopReply>> 137 StopReply::create(StringRef Response, llvm::support::endianness Endian) { 138 if (Response.size() < 3) 139 return make_parsing_error("StopReply: Invalid packet"); 140 if (Response.consume_front("T")) 141 return StopReplyStop::create(Response, Endian); 142 if (Response.consume_front("W")) 143 return StopReplyExit::create(Response); 144 return make_parsing_error("StopReply: Invalid packet"); 145 } 146 147 Expected<std::unique_ptr<StopReplyStop>> 148 StopReplyStop::create(StringRef Response, llvm::support::endianness Endian) { 149 unsigned int Signal; 150 StringRef SignalStr = Response.take_front(2); 151 Response = Response.drop_front(2); 152 if (!to_integer(SignalStr, Signal, 16)) 153 return make_parsing_error("StopReply: stop signal"); 154 155 auto Elements = SplitPairList(Response); 156 for (StringRef Field : 157 {"name", "reason", "thread", "threads", "thread-pcs"}) { 158 // This will insert an empty field if there is none. In the future, we 159 // should probably differentiate between these fields not being present and 160 // them being empty, but right now no tests depends on this. 161 if (Elements.insert({Field, {""}}).first->second.size() != 1) 162 return make_parsing_error( 163 "StopReply: got multiple responses for the {0} field", Field); 164 } 165 StringRef Name = Elements["name"][0]; 166 StringRef Reason = Elements["reason"][0]; 167 168 lldb::tid_t Thread; 169 if (!to_integer(Elements["thread"][0], Thread, 16)) 170 return make_parsing_error("StopReply: thread"); 171 172 SmallVector<StringRef, 20> Threads; 173 SmallVector<StringRef, 20> Pcs; 174 Elements["threads"][0].split(Threads, ','); 175 Elements["thread-pcs"][0].split(Pcs, ','); 176 if (Threads.size() != Pcs.size()) 177 return make_parsing_error("StopReply: thread/PC count mismatch"); 178 179 U64Map ThreadPcs; 180 for (auto ThreadPc : zip(Threads, Pcs)) { 181 lldb::tid_t Id; 182 uint64_t Pc; 183 if (!to_integer(std::get<0>(ThreadPc), Id, 16)) 184 return make_parsing_error("StopReply: Thread id '{0}'", 185 std::get<0>(ThreadPc)); 186 if (!to_integer(std::get<1>(ThreadPc), Pc, 16)) 187 return make_parsing_error("StopReply Thread Pc '{0}'", 188 std::get<1>(ThreadPc)); 189 190 ThreadPcs[Id] = Pc; 191 } 192 193 RegisterMap Registers; 194 for (const auto &E : Elements) { 195 StringRef Key = E.getKey(); 196 const auto &Val = E.getValue(); 197 if (Key.size() != 2) 198 continue; 199 200 unsigned int Reg; 201 if (!to_integer(Key, Reg, 16)) 202 continue; 203 204 if (Val.size() != 1) 205 return make_parsing_error( 206 "StopReply: multiple entries for register field [{0:x}]", Reg); 207 208 Registers[Reg] = Val[0].str(); 209 } 210 211 return llvm::make_unique<StopReplyStop>(Signal, Thread, Name, ThreadPcs, 212 Registers, Reason); 213 } 214 215 Expected<std::unique_ptr<StopReplyExit>> 216 StopReplyExit::create(StringRef Response) { 217 uint8_t Status; 218 if (!to_integer(Response, Status, 16)) 219 return make_parsing_error("StopReply: exit status"); 220 return llvm::make_unique<StopReplyExit>(Status); 221 } 222 223 //====== Globals =============================================================== 224 Expected<StringMap<StringRef>> SplitUniquePairList(StringRef caller, 225 StringRef str) { 226 SmallVector<StringRef, 20> elements; 227 str.split(elements, ';'); 228 229 StringMap<StringRef> pairs; 230 for (StringRef s : elements) { 231 std::pair<StringRef, StringRef> pair = s.split(':'); 232 if (pairs.count(pair.first)) 233 return make_parsing_error("{0}: Duplicate Key: {1}", caller, pair.first); 234 235 pairs.insert(pair); 236 } 237 238 return pairs; 239 } 240 241 StringMap<SmallVector<StringRef, 2>> SplitPairList(StringRef str) { 242 SmallVector<StringRef, 20> elements; 243 str.split(elements, ';'); 244 245 StringMap<SmallVector<StringRef, 2>> pairs; 246 for (StringRef s : elements) { 247 std::pair<StringRef, StringRef> pair = s.split(':'); 248 pairs[pair.first].push_back(pair.second); 249 } 250 251 return pairs; 252 } 253 } // namespace llgs_tests 254