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 = SplitPairList("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 StringRef value_str(m_registers.lookup(register_id)); 71 if (value_str.getAsInteger(16, value)) { 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 StopReply stop_reply; 144 145 auto elements_or_error = SplitPairList("StopReply", response); 146 if (auto split_error = elements_or_error.takeError()) { 147 return std::move(split_error); 148 } 149 150 auto elements = *elements_or_error; 151 stop_reply.m_name = elements["name"]; 152 stop_reply.m_reason = elements["reason"]; 153 154 SmallVector<StringRef, 20> threads; 155 SmallVector<StringRef, 20> pcs; 156 elements["threads"].split(threads, ','); 157 elements["thread-pcs"].split(pcs, ','); 158 if (threads.size() != pcs.size()) 159 return make_parsing_error("StopReply: thread/PC count mismatch"); 160 161 for (size_t i = 0; i < threads.size(); i++) { 162 lldb::tid_t thread_id; 163 uint64_t pc; 164 if (threads[i].getAsInteger(16, thread_id)) 165 return make_parsing_error("StopReply: thread ID at [{0}].", i); 166 if (pcs[i].getAsInteger(16, pc)) 167 return make_parsing_error("StopReply: thread PC at [{0}].", i); 168 169 stop_reply.m_thread_pcs[thread_id] = pc; 170 } 171 172 for (auto i = elements.begin(); i != elements.end(); i++) { 173 StringRef key = i->getKey(); 174 StringRef val = i->getValue(); 175 if (key.size() >= 9 && key[0] == 'T' && key.substr(3, 6) == "thread") { 176 if (val.getAsInteger(16, stop_reply.m_thread)) 177 return make_parsing_error("StopReply: thread id"); 178 if (key.substr(1, 2).getAsInteger(16, stop_reply.m_signal)) 179 return make_parsing_error("StopReply: stop signal"); 180 } else if (key.size() == 2) { 181 unsigned int reg; 182 if (!key.getAsInteger(16, reg)) { 183 stop_reply.m_registers[reg] = val.str(); 184 } 185 } 186 } 187 188 return stop_reply; 189 } 190 191 //====== Globals =============================================================== 192 Expected<StringMap<StringRef>> SplitPairList(StringRef caller, StringRef str) { 193 SmallVector<StringRef, 20> elements; 194 str.split(elements, ';'); 195 196 StringMap<StringRef> pairs; 197 for (StringRef s : elements) { 198 std::pair<StringRef, StringRef> pair = s.split(':'); 199 if (pairs.count(pair.first)) 200 return make_parsing_error("{0}: Duplicate Key: {1}", caller, pair.first); 201 202 pairs.insert(s.split(':')); 203 } 204 205 return pairs; 206 } 207 } // namespace llgs_tests 208