diff options
author | Pavel Labath <labath@google.com> | 2017-06-06 13:40:18 +0000 |
---|---|---|
committer | Pavel Labath <labath@google.com> | 2017-06-06 13:40:18 +0000 |
commit | 015f17d3cc85cb3491df680dfc89eb66422e969b (patch) | |
tree | fa88cffb95cf9fb2d9f23ac75438ce9d282b7c67 /lldb/unittests/tools/lldb-server/tests/MessageObjects.cpp | |
parent | aaeada6c755e64cd3611e4476a2f97fb81b7f3cb (diff) | |
download | bcm5719-llvm-015f17d3cc85cb3491df680dfc89eb66422e969b.tar.gz bcm5719-llvm-015f17d3cc85cb3491df680dfc89eb66422e969b.zip |
New framework for lldb client-server communication tests.
Summary:
This is a new C++ test framework based on Google Test, and one working
example test.
The intention is to replace the existing tests in
packages/Python/lldbsuite/test/tools/lldb-server/ with this suite
and use this framework for all new client server tests.
Reviewers: labath, beanz
Reviewed By: labath, beanz
Subscribers: beanz, emaste, zturner, tberghammer, takuto.ikuta, krytarowski, mgorny, lldb-commits
Differential Revision: https://reviews.llvm.org/D32930
Patch by Jason Majors <jmajors@google.com>
llvm-svn: 304793
Diffstat (limited to 'lldb/unittests/tools/lldb-server/tests/MessageObjects.cpp')
-rw-r--r-- | lldb/unittests/tools/lldb-server/tests/MessageObjects.cpp | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/lldb/unittests/tools/lldb-server/tests/MessageObjects.cpp b/lldb/unittests/tools/lldb-server/tests/MessageObjects.cpp new file mode 100644 index 00000000000..fd44bf6b23a --- /dev/null +++ b/lldb/unittests/tools/lldb-server/tests/MessageObjects.cpp @@ -0,0 +1,207 @@ +//===-- MessageObjects.cpp --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MessageObjects.h" +#include "lldb/Core/StructuredData.h" +#include "llvm/ADT/StringExtras.h" +#include "gtest/gtest.h" + +using namespace lldb_private; +using namespace llvm; +using namespace llvm::support; +namespace llgs_tests { + +Expected<ProcessInfo> ProcessInfo::Create(StringRef response) { + ProcessInfo process_info; + auto elements_or_error = SplitPairList("ProcessInfo", response); + if (!elements_or_error) + return elements_or_error.takeError(); + + auto &elements = *elements_or_error; + if (elements["pid"].getAsInteger(16, process_info.m_pid)) + return make_parsing_error("ProcessInfo: pid"); + if (elements["parent-pid"].getAsInteger(16, process_info.m_parent_pid)) + return make_parsing_error("ProcessInfo: parent-pid"); + if (elements["real-uid"].getAsInteger(16, process_info.m_real_uid)) + return make_parsing_error("ProcessInfo: real-uid"); + if (elements["real-gid"].getAsInteger(16, process_info.m_real_gid)) + return make_parsing_error("ProcessInfo: real-uid"); + if (elements["effective-uid"].getAsInteger(16, process_info.m_effective_uid)) + return make_parsing_error("ProcessInfo: effective-uid"); + if (elements["effective-gid"].getAsInteger(16, process_info.m_effective_gid)) + return make_parsing_error("ProcessInfo: effective-gid"); + if (elements["ptrsize"].getAsInteger(10, process_info.m_ptrsize)) + return make_parsing_error("ProcessInfo: ptrsize"); + + process_info.m_triple = fromHex(elements["triple"]); + StringRef endian_str = elements["endian"]; + if (endian_str == "little") + process_info.m_endian = support::little; + else if (endian_str == "big") + process_info.m_endian = support::big; + else + return make_parsing_error("ProcessInfo: endian"); + + return process_info; +} + +lldb::pid_t ProcessInfo::GetPid() const { return m_pid; } + +endianness ProcessInfo::GetEndian() const { return m_endian; } + +//====== ThreadInfo ============================================================ +ThreadInfo::ThreadInfo(StringRef name, StringRef reason, + const RegisterMap ®isters, unsigned int signal) + : m_name(name.str()), m_reason(reason.str()), m_registers(registers), + m_signal(signal) {} + +StringRef ThreadInfo::ReadRegister(unsigned int register_id) const { + return m_registers.lookup(register_id); +} + +bool ThreadInfo::ReadRegisterAsUint64(unsigned int register_id, + uint64_t &value) const { + StringRef value_str(m_registers.lookup(register_id)); + if (value_str.getAsInteger(16, value)) { + GTEST_LOG_(ERROR) + << formatv("ThreadInfo: Unable to parse register value at {0}.", + register_id) + .str(); + return false; + } + + sys::swapByteOrder(value); + return true; +} + +//====== JThreadsInfo ========================================================== +Expected<JThreadsInfo> JThreadsInfo::Create(StringRef response, + endianness endian) { + JThreadsInfo jthreads_info; + + StructuredData::ObjectSP json = StructuredData::ParseJSON(response); + StructuredData::Array *array = json->GetAsArray(); + if (!array) + return make_parsing_error("JThreadsInfo: JSON array"); + + for (size_t i = 0; i < array->GetSize(); i++) { + StructuredData::Dictionary *thread_info; + array->GetItemAtIndexAsDictionary(i, thread_info); + if (!thread_info) + return make_parsing_error("JThreadsInfo: JSON obj at {0}", i); + + StringRef name, reason; + thread_info->GetValueForKeyAsString("name", name); + thread_info->GetValueForKeyAsString("reason", reason); + uint64_t signal; + thread_info->GetValueForKeyAsInteger("signal", signal); + uint64_t tid; + thread_info->GetValueForKeyAsInteger("tid", tid); + + StructuredData::Dictionary *register_dict; + thread_info->GetValueForKeyAsDictionary("registers", register_dict); + if (!register_dict) + return make_parsing_error("JThreadsInfo: registers JSON obj"); + + RegisterMap registers; + + auto keys_obj = register_dict->GetKeys(); + auto keys = keys_obj->GetAsArray(); + for (size_t i = 0; i < keys->GetSize(); i++) { + StringRef key_str, value_str; + keys->GetItemAtIndexAsString(i, key_str); + register_dict->GetValueForKeyAsString(key_str, value_str); + unsigned int register_id; + if (key_str.getAsInteger(10, register_id)) + return make_parsing_error("JThreadsInfo: register key[{0}]", i); + + registers[register_id] = value_str.str(); + } + + jthreads_info.m_thread_infos[tid] = + ThreadInfo(name, reason, registers, signal); + } + + return jthreads_info; +} + +const ThreadInfoMap &JThreadsInfo::GetThreadInfos() const { + return m_thread_infos; +} + +//====== StopReply ============================================================= +const U64Map &StopReply::GetThreadPcs() const { return m_thread_pcs; } + +Expected<StopReply> StopReply::Create(StringRef response, + llvm::support::endianness endian) { + StopReply stop_reply; + + auto elements_or_error = SplitPairList("StopReply", response); + if (auto split_error = elements_or_error.takeError()) { + return std::move(split_error); + } + + auto elements = *elements_or_error; + stop_reply.m_name = elements["name"]; + stop_reply.m_reason = elements["reason"]; + + SmallVector<StringRef, 20> threads; + SmallVector<StringRef, 20> pcs; + elements["threads"].split(threads, ','); + elements["thread-pcs"].split(pcs, ','); + if (threads.size() != pcs.size()) + return make_parsing_error("StopReply: thread/PC count mismatch"); + + for (size_t i = 0; i < threads.size(); i++) { + lldb::tid_t thread_id; + uint64_t pc; + if (threads[i].getAsInteger(16, thread_id)) + return make_parsing_error("StopReply: thread ID at [{0}].", i); + if (pcs[i].getAsInteger(16, pc)) + return make_parsing_error("StopReply: thread PC at [{0}].", i); + + stop_reply.m_thread_pcs[thread_id] = pc; + } + + for (auto i = elements.begin(); i != elements.end(); i++) { + StringRef key = i->getKey(); + StringRef val = i->getValue(); + if (key.size() >= 9 && key[0] == 'T' && key.substr(3, 6) == "thread") { + if (val.getAsInteger(16, stop_reply.m_thread)) + return make_parsing_error("StopReply: thread id"); + if (key.substr(1, 2).getAsInteger(16, stop_reply.m_signal)) + return make_parsing_error("StopReply: stop signal"); + } else if (key.size() == 2) { + unsigned int reg; + if (!key.getAsInteger(16, reg)) { + stop_reply.m_registers[reg] = val.str(); + } + } + } + + return stop_reply; +} + +//====== Globals =============================================================== +Expected<StringMap<StringRef>> SplitPairList(StringRef caller, StringRef str) { + SmallVector<StringRef, 20> elements; + str.split(elements, ';'); + + StringMap<StringRef> pairs; + for (StringRef s : elements) { + std::pair<StringRef, StringRef> pair = s.split(':'); + if (pairs.count(pair.first)) + return make_parsing_error("{0}: Duplicate Key: {1}", caller, pair.first); + + pairs.insert(s.split(':')); + } + + return pairs; +} +} // namespace llgs_tests |