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