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 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