diff options
Diffstat (limited to 'unittests/tools/lldb-server')
-rw-r--r-- | unittests/tools/lldb-server/CMakeLists.txt | 25 | ||||
-rw-r--r-- | unittests/tools/lldb-server/inferior/environment_check.cpp | 20 | ||||
-rw-r--r-- | unittests/tools/lldb-server/inferior/thread_inferior.cpp | 41 | ||||
-rw-r--r-- | unittests/tools/lldb-server/tests/CMakeLists.txt | 21 | ||||
-rw-r--r-- | unittests/tools/lldb-server/tests/LLGSTest.cpp | 70 | ||||
-rw-r--r-- | unittests/tools/lldb-server/tests/MessageObjects.cpp | 375 | ||||
-rw-r--r-- | unittests/tools/lldb-server/tests/MessageObjects.h | 187 | ||||
-rw-r--r-- | unittests/tools/lldb-server/tests/TestBase.cpp | 36 | ||||
-rw-r--r-- | unittests/tools/lldb-server/tests/TestBase.h | 52 | ||||
-rw-r--r-- | unittests/tools/lldb-server/tests/TestClient.cpp | 267 | ||||
-rw-r--r-- | unittests/tools/lldb-server/tests/TestClient.h | 113 | ||||
-rw-r--r-- | unittests/tools/lldb-server/tests/ThreadIdsInJstopinfoTest.cpp | 54 |
12 files changed, 0 insertions, 1261 deletions
diff --git a/unittests/tools/lldb-server/CMakeLists.txt b/unittests/tools/lldb-server/CMakeLists.txt deleted file mode 100644 index 60616c93153f..000000000000 --- a/unittests/tools/lldb-server/CMakeLists.txt +++ /dev/null @@ -1,25 +0,0 @@ -set(ALL_LLDB_TEST_EXECUTABLES) - -function(add_lldb_test_executable test_name) - set(EXCLUDE_FROM_ALL ON) - add_llvm_executable(${test_name} NO_INSTALL_RPATH ${ARGN}) - set(outdir ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}) - set_output_directory(${test_name} BINARY_DIR ${outdir} LIBRARY_DIR ${outdir}) - list(APPEND ALL_LLDB_TEST_EXECUTABLES ${test_name}) - set(ALL_LLDB_TEST_EXECUTABLES ${ALL_LLDB_TEST_EXECUTABLES} PARENT_SCOPE) -endfunction() - -add_lldb_test_executable(thread_inferior inferior/thread_inferior.cpp) -add_lldb_test_executable(environment_check inferior/environment_check.cpp) - -if(DEBUGSERVER_PATH) - add_definitions(-DLLDB_SERVER="${DEBUGSERVER_PATH}" -DLLDB_SERVER_IS_DEBUGSERVER=1) -else() - add_definitions(-DLLDB_SERVER="$<TARGET_FILE:lldb-server>" -DLLDB_SERVER_IS_DEBUGSERVER=0) -endif() - -add_definitions( - -DLLDB_TEST_INFERIOR_PATH="${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}" - -DLLDB_TEST_INFERIOR_SUFFIX="${CMAKE_EXECUTABLE_SUFFIX}" - ) -add_subdirectory(tests) diff --git a/unittests/tools/lldb-server/inferior/environment_check.cpp b/unittests/tools/lldb-server/inferior/environment_check.cpp deleted file mode 100644 index d2a5ede0cabf..000000000000 --- a/unittests/tools/lldb-server/inferior/environment_check.cpp +++ /dev/null @@ -1,20 +0,0 @@ -//===-- thread_inferior.cpp -------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include <string> -#include <cstdlib> - -int main() { - const char *value = std::getenv("LLDB_TEST_MAGIC_VARIABLE"); - if (!value) - return 1; - if (std::string(value) != "LLDB_TEST_MAGIC_VALUE") - return 2; - return 0; -} diff --git a/unittests/tools/lldb-server/inferior/thread_inferior.cpp b/unittests/tools/lldb-server/inferior/thread_inferior.cpp deleted file mode 100644 index d968e9ef71ea..000000000000 --- a/unittests/tools/lldb-server/inferior/thread_inferior.cpp +++ /dev/null @@ -1,41 +0,0 @@ -//===-- thread_inferior.cpp -------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include <atomic> -#include <chrono> -#include <string> -#include <thread> -#include <vector> - -int main(int argc, char* argv[]) { - int thread_count = 2; - if (argc > 1) { - thread_count = std::stoi(argv[1], nullptr, 10); - } - - std::atomic<bool> delay(true); - std::vector<std::thread> threads; - for (int i = 0; i < thread_count; i++) { - threads.push_back(std::thread([&delay] { - while (delay.load()) - std::this_thread::sleep_for(std::chrono::seconds(1)); - })); - } - - // Cause a break. - volatile char *p = NULL; - *p = 'a'; - - delay.store(false); - for (std::thread& t : threads) { - t.join(); - } - - return 0; -} diff --git a/unittests/tools/lldb-server/tests/CMakeLists.txt b/unittests/tools/lldb-server/tests/CMakeLists.txt deleted file mode 100644 index ed5eb88ba527..000000000000 --- a/unittests/tools/lldb-server/tests/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -add_lldb_unittest(LLDBServerTests - LLGSTest.cpp - MessageObjects.cpp - TestBase.cpp - TestClient.cpp - ThreadIdsInJstopinfoTest.cpp - - LINK_LIBS - lldbHost - lldbCore - lldbInterpreter - lldbTarget - lldbPluginPlatformLinux - lldbPluginProcessGDBRemote - - LLVMTestingSupport - LINK_COMPONENTS - Support - ) - -add_dependencies(LLDBServerTests lldb-server ${ALL_LLDB_TEST_EXECUTABLES}) diff --git a/unittests/tools/lldb-server/tests/LLGSTest.cpp b/unittests/tools/lldb-server/tests/LLGSTest.cpp deleted file mode 100644 index fab84f7dd6b5..000000000000 --- a/unittests/tools/lldb-server/tests/LLGSTest.cpp +++ /dev/null @@ -1,70 +0,0 @@ -//===-- LLGSTest.cpp --------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "TestBase.h" -#include "lldb/Host/Host.h" -#include "llvm/Testing/Support/Error.h" - -using namespace llgs_tests; -using namespace lldb_private; -using namespace llvm; - -TEST_F(TestBase, LaunchModePreservesEnvironment) { - putenv(const_cast<char *>("LLDB_TEST_MAGIC_VARIABLE=LLDB_TEST_MAGIC_VALUE")); - - auto ClientOr = TestClient::launch(getLogFileName(), - {getInferiorPath("environment_check")}); - ASSERT_THAT_EXPECTED(ClientOr, Succeeded()); - auto &Client = **ClientOr; - - ASSERT_THAT_ERROR(Client.ContinueAll(), Succeeded()); - ASSERT_THAT_EXPECTED( - Client.GetLatestStopReplyAs<StopReplyExit>(), - HasValue(testing::Property(&StopReply::getKind, - WaitStatus{WaitStatus::Exit, 0}))); -} - -TEST_F(TestBase, DS_TEST(DebugserverEnv)) { - // Test that --env takes precedence over inherited environment variables. - putenv(const_cast<char *>("LLDB_TEST_MAGIC_VARIABLE=foobar")); - - auto ClientOr = TestClient::launchCustom(getLogFileName(), - { "--env", "LLDB_TEST_MAGIC_VARIABLE=LLDB_TEST_MAGIC_VALUE" }, - {getInferiorPath("environment_check")}); - ASSERT_THAT_EXPECTED(ClientOr, Succeeded()); - auto &Client = **ClientOr; - - ASSERT_THAT_ERROR(Client.ContinueAll(), Succeeded()); - ASSERT_THAT_EXPECTED( - Client.GetLatestStopReplyAs<StopReplyExit>(), - HasValue(testing::Property(&StopReply::getKind, - WaitStatus{WaitStatus::Exit, 0}))); -} - -TEST_F(TestBase, LLGS_TEST(vAttachRichError)) { - auto ClientOr = TestClient::launch(getLogFileName(), - {getInferiorPath("environment_check")}); - ASSERT_THAT_EXPECTED(ClientOr, Succeeded()); - auto &Client = **ClientOr; - - // Until we enable error strings we should just get the error code. - ASSERT_THAT_ERROR(Client.SendMessage("vAttach;1"), - Failed<ErrorInfoBase>(testing::Property( - &ErrorInfoBase::message, "Error 255"))); - - ASSERT_THAT_ERROR(Client.SendMessage("QEnableErrorStrings"), Succeeded()); - - // Now, we expect the full error message. - ASSERT_THAT_ERROR( - Client.SendMessage("vAttach;1"), - Failed<ErrorInfoBase>(testing::Property( - &ErrorInfoBase::message, - testing::StartsWith( - "cannot attach to process 1 when another process with pid")))); -} diff --git a/unittests/tools/lldb-server/tests/MessageObjects.cpp b/unittests/tools/lldb-server/tests/MessageObjects.cpp deleted file mode 100644 index 27fd78ec4bde..000000000000 --- a/unittests/tools/lldb-server/tests/MessageObjects.cpp +++ /dev/null @@ -1,375 +0,0 @@ -//===-- 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/Utility/Args.h" -#include "lldb/Utility/StringExtractor.h" -#include "llvm/ADT/StringExtras.h" -#include "gtest/gtest.h" - -using namespace lldb_private; -using namespace lldb; -using namespace llvm; -namespace llgs_tests { - -Expected<ProcessInfo> ProcessInfo::create(StringRef response) { - ProcessInfo process_info; - auto elements_or_error = SplitUniquePairList("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; } - -support::endianness ProcessInfo::GetEndian() const { return m_endian; } - -//====== ThreadInfo ============================================================ -ThreadInfo::ThreadInfo(StringRef name, StringRef reason, RegisterMap registers, - unsigned int) - : m_name(name.str()), m_reason(reason.str()), - m_registers(std::move(registers)) {} - -const RegisterValue *ThreadInfo::ReadRegister(unsigned int Id) const { - auto Iter = m_registers.find(Id); - return Iter == m_registers.end() ? nullptr : &Iter->getSecond(); -} - -//====== JThreadsInfo ========================================================== - -Expected<RegisterMap> -JThreadsInfo::parseRegisters(const StructuredData::Dictionary &Dict, - ArrayRef<RegisterInfo> RegInfos) { - RegisterMap Result; - - auto KeysObj = Dict.GetKeys(); - auto Keys = KeysObj->GetAsArray(); - for (size_t i = 0; i < Keys->GetSize(); i++) { - StringRef KeyStr, ValueStr; - Keys->GetItemAtIndexAsString(i, KeyStr); - Dict.GetValueForKeyAsString(KeyStr, ValueStr); - unsigned int Register; - if (!llvm::to_integer(KeyStr, Register, 10)) - return make_parsing_error("JThreadsInfo: register key[{0}]", i); - - auto RegValOr = - parseRegisterValue(RegInfos[Register], ValueStr, support::big); - if (!RegValOr) - return RegValOr.takeError(); - Result[Register] = std::move(*RegValOr); - } - return std::move(Result); -} - -Expected<JThreadsInfo> JThreadsInfo::create(StringRef Response, - ArrayRef<RegisterInfo> RegInfos) { - 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"); - - auto RegsOr = parseRegisters(*register_dict, RegInfos); - if (!RegsOr) - return RegsOr.takeError(); - jthreads_info.m_thread_infos[tid] = - ThreadInfo(name, reason, std::move(*RegsOr), signal); - } - - return jthreads_info; -} - -const ThreadInfoMap &JThreadsInfo::GetThreadInfos() const { - return m_thread_infos; -} - -Expected<RegisterInfo> RegisterInfoParser::create(StringRef Response) { - auto ElementsOr = SplitUniquePairList("RegisterInfoParser", Response); - if (!ElementsOr) - return ElementsOr.takeError(); - auto &Elements = *ElementsOr; - - RegisterInfo Info = { - nullptr, // Name - nullptr, // Alt name - 0, // byte size - 0, // offset - eEncodingUint, // encoding - eFormatHex, // format - { - LLDB_INVALID_REGNUM, // eh_frame reg num - LLDB_INVALID_REGNUM, // DWARF reg num - LLDB_INVALID_REGNUM, // generic reg num - LLDB_INVALID_REGNUM, // process plugin reg num - LLDB_INVALID_REGNUM // native register number - }, - NULL, - NULL, - NULL, // Dwarf expression opcode bytes pointer - 0 // Dwarf expression opcode bytes length - }; - Info.name = ConstString(Elements["name"]).GetCString(); - if (!Info.name) - return make_parsing_error("qRegisterInfo: name"); - - Info.alt_name = ConstString(Elements["alt-name"]).GetCString(); - - if (!to_integer(Elements["bitsize"], Info.byte_size, 10)) - return make_parsing_error("qRegisterInfo: bit-size"); - Info.byte_size /= CHAR_BIT; - - if (!to_integer(Elements["offset"], Info.byte_offset, 10)) - return make_parsing_error("qRegisterInfo: offset"); - - Info.encoding = Args::StringToEncoding(Elements["encoding"]); - if (Info.encoding == eEncodingInvalid) - return make_parsing_error("qRegisterInfo: encoding"); - - Info.format = StringSwitch<Format>(Elements["format"]) - .Case("binary", eFormatBinary) - .Case("decimal", eFormatDecimal) - .Case("hex", eFormatHex) - .Case("float", eFormatFloat) - .Case("vector-sint8", eFormatVectorOfSInt8) - .Case("vector-uint8", eFormatVectorOfUInt8) - .Case("vector-sint16", eFormatVectorOfSInt16) - .Case("vector-uint16", eFormatVectorOfUInt16) - .Case("vector-sint32", eFormatVectorOfSInt32) - .Case("vector-uint32", eFormatVectorOfUInt32) - .Case("vector-float32", eFormatVectorOfFloat32) - .Case("vector-uint64", eFormatVectorOfUInt64) - .Case("vector-uint128", eFormatVectorOfUInt128) - .Default(eFormatInvalid); - if (Info.format == eFormatInvalid) - return make_parsing_error("qRegisterInfo: format"); - - Info.kinds[eRegisterKindGeneric] = - Args::StringToGenericRegister(Elements["generic"]); - - return std::move(Info); -} - -Expected<RegisterValue> parseRegisterValue(const RegisterInfo &Info, - StringRef HexValue, - llvm::support::endianness Endian, - bool ZeroPad) { - SmallString<128> Storage; - if (ZeroPad && HexValue.size() < Info.byte_size * 2) { - Storage.insert(Storage.begin(), Info.byte_size * 2 - HexValue.size(), '0'); - Storage += HexValue; - HexValue = Storage; - } - - SmallVector<uint8_t, 64> Bytes(HexValue.size() / 2); - StringExtractor(HexValue).GetHexBytes(Bytes, '\xcc'); - RegisterValue Value; - Status ST; - Value.SetFromMemoryData( - &Info, Bytes.data(), Bytes.size(), - Endian == support::little ? eByteOrderLittle : eByteOrderBig, ST); - if (ST.Fail()) - return ST.ToError(); - return Value; -} - -//====== StopReply ============================================================= -Expected<std::unique_ptr<StopReply>> -StopReply::create(StringRef Response, llvm::support::endianness Endian, - ArrayRef<RegisterInfo> RegInfos) { - if (Response.size() < 3) - return make_parsing_error("StopReply: Invalid packet"); - if (Response.consume_front("T")) - return StopReplyStop::create(Response, Endian, RegInfos); - if (Response.consume_front("W")) - return StopReplyExit::create(Response); - return make_parsing_error("StopReply: Invalid packet"); -} - -Expected<RegisterMap> StopReplyStop::parseRegisters( - const StringMap<SmallVector<StringRef, 2>> &Elements, - support::endianness Endian, ArrayRef<lldb_private::RegisterInfo> RegInfos) { - - RegisterMap Result; - for (const auto &E : Elements) { - StringRef Key = E.getKey(); - const auto &Val = E.getValue(); - if (Key.size() != 2) - continue; - - unsigned int Reg; - if (!to_integer(Key, Reg, 16)) - continue; - - if (Val.size() != 1) - return make_parsing_error( - "StopReplyStop: multiple entries for register field [{0:x}]", Reg); - - auto RegValOr = parseRegisterValue(RegInfos[Reg], Val[0], Endian); - if (!RegValOr) - return RegValOr.takeError(); - Result[Reg] = std::move(*RegValOr); - } - return std::move(Result); -} - -Expected<std::unique_ptr<StopReplyStop>> -StopReplyStop::create(StringRef Response, support::endianness Endian, - ArrayRef<RegisterInfo> RegInfos) { - unsigned int Signal; - StringRef SignalStr = Response.take_front(2); - Response = Response.drop_front(2); - if (!to_integer(SignalStr, Signal, 16)) - return make_parsing_error("StopReply: stop signal"); - - auto Elements = SplitPairList(Response); - for (StringRef Field : - {"name", "reason", "thread", "threads", "thread-pcs"}) { - // This will insert an empty field if there is none. In the future, we - // should probably differentiate between these fields not being present and - // them being empty, but right now no tests depends on this. - if (Elements.insert({Field, {""}}).first->second.size() != 1) - return make_parsing_error( - "StopReply: got multiple responses for the {0} field", Field); - } - StringRef Name = Elements["name"][0]; - StringRef Reason = Elements["reason"][0]; - - lldb::tid_t Thread; - if (!to_integer(Elements["thread"][0], Thread, 16)) - return make_parsing_error("StopReply: thread"); - - SmallVector<StringRef, 20> Threads; - SmallVector<StringRef, 20> Pcs; - Elements["threads"][0].split(Threads, ','); - Elements["thread-pcs"][0].split(Pcs, ','); - if (Threads.size() != Pcs.size()) - return make_parsing_error("StopReply: thread/PC count mismatch"); - - RegisterMap ThreadPcs; - const RegisterInfo *PcInfo = find_if(RegInfos, [](const RegisterInfo &Info) { - return Info.kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_PC; - }); - assert(PcInfo); - - for (auto ThreadPc : zip(Threads, Pcs)) { - lldb::tid_t Id; - if (!to_integer(std::get<0>(ThreadPc), Id, 16)) - return make_parsing_error("StopReply: Thread id '{0}'", - std::get<0>(ThreadPc)); - - auto PcOr = parseRegisterValue(*PcInfo, std::get<1>(ThreadPc), Endian, - /*ZeroPad*/ true); - if (!PcOr) - return PcOr.takeError(); - ThreadPcs[Id] = std::move(*PcOr); - } - - auto RegistersOr = parseRegisters(Elements, Endian, RegInfos); - if (!RegistersOr) - return RegistersOr.takeError(); - - return llvm::make_unique<StopReplyStop>(Signal, Thread, Name, - std::move(ThreadPcs), - std::move(*RegistersOr), Reason); -} - -Expected<std::unique_ptr<StopReplyExit>> -StopReplyExit::create(StringRef Response) { - uint8_t Status; - if (!to_integer(Response, Status, 16)) - return make_parsing_error("StopReply: exit status"); - return llvm::make_unique<StopReplyExit>(Status); -} - -//====== Globals =============================================================== -Expected<StringMap<StringRef>> SplitUniquePairList(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(pair); - } - - return pairs; -} - -StringMap<SmallVector<StringRef, 2>> SplitPairList(StringRef str) { - SmallVector<StringRef, 20> elements; - str.split(elements, ';'); - - StringMap<SmallVector<StringRef, 2>> pairs; - for (StringRef s : elements) { - std::pair<StringRef, StringRef> pair = s.split(':'); - pairs[pair.first].push_back(pair.second); - } - - return pairs; -} -} // namespace llgs_tests - -std::ostream &lldb_private::operator<<(std::ostream &OS, - const RegisterValue &RegVal) { - ArrayRef<uint8_t> Bytes(static_cast<const uint8_t *>(RegVal.GetBytes()), - RegVal.GetByteSize()); - return OS << formatv("RegisterValue[{0}]: {1:@[x-2]}", RegVal.GetByteSize(), - make_range(Bytes.begin(), Bytes.end())) - .str(); -} diff --git a/unittests/tools/lldb-server/tests/MessageObjects.h b/unittests/tools/lldb-server/tests/MessageObjects.h deleted file mode 100644 index e8d5ba94580e..000000000000 --- a/unittests/tools/lldb-server/tests/MessageObjects.h +++ /dev/null @@ -1,187 +0,0 @@ -//===-- MessageObjects.h ----------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_SERVER_TESTS_MESSAGEOBJECTS_H -#define LLDB_SERVER_TESTS_MESSAGEOBJECTS_H - -#include "lldb/Host/Host.h" -#include "lldb/Utility/RegisterValue.h" -#include "lldb/Utility/StructuredData.h" -#include "lldb/lldb-types.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/FormatVariadic.h" -#include <string> - -namespace llgs_tests { -class ThreadInfo; -typedef llvm::DenseMap<uint64_t, ThreadInfo> ThreadInfoMap; -typedef llvm::DenseMap<unsigned int, lldb_private::RegisterValue> RegisterMap; - -template <typename T> struct Parser { using result_type = T; }; - -class ProcessInfo : public Parser<ProcessInfo> { -public: - static llvm::Expected<ProcessInfo> create(llvm::StringRef response); - lldb::pid_t GetPid() const; - llvm::support::endianness GetEndian() const; - -private: - ProcessInfo() = default; - lldb::pid_t m_pid; - lldb::pid_t m_parent_pid; - uint32_t m_real_uid; - uint32_t m_real_gid; - uint32_t m_effective_uid; - uint32_t m_effective_gid; - std::string m_triple; - llvm::SmallString<16> m_ostype; - llvm::support::endianness m_endian; - unsigned int m_ptrsize; -}; - -class ThreadInfo { -public: - ThreadInfo() = default; - ThreadInfo(llvm::StringRef name, llvm::StringRef reason, - RegisterMap registers, unsigned int signal); - - const lldb_private::RegisterValue *ReadRegister(unsigned int Id) const; - -private: - std::string m_name; - std::string m_reason; - RegisterMap m_registers; -}; - -class JThreadsInfo : public Parser<JThreadsInfo> { -public: - static llvm::Expected<JThreadsInfo> - create(llvm::StringRef Response, - llvm::ArrayRef<lldb_private::RegisterInfo> RegInfos); - - const ThreadInfoMap &GetThreadInfos() const; - -private: - static llvm::Expected<RegisterMap> - parseRegisters(const lldb_private::StructuredData::Dictionary &Dict, - llvm::ArrayRef<lldb_private::RegisterInfo> RegInfos); - - JThreadsInfo() = default; - ThreadInfoMap m_thread_infos; -}; - -struct RegisterInfoParser : public Parser<lldb_private::RegisterInfo> { - static llvm::Expected<lldb_private::RegisterInfo> - create(llvm::StringRef Response); -}; - -llvm::Expected<lldb_private::RegisterValue> -parseRegisterValue(const lldb_private::RegisterInfo &Info, - llvm::StringRef HexValue, llvm::support::endianness Endian, - bool ZeroPad = false); - -class StopReply : public Parser<std::unique_ptr<StopReply>> { -public: - StopReply() = default; - virtual ~StopReply() = default; - - static llvm::Expected<std::unique_ptr<StopReply>> - create(llvm::StringRef Response, llvm::support::endianness Endian, - llvm::ArrayRef<lldb_private::RegisterInfo> RegInfos); - - // for llvm::cast<> - virtual lldb_private::WaitStatus getKind() const = 0; - - StopReply(const StopReply &) = delete; - void operator=(const StopReply &) = delete; -}; - -class StopReplyStop : public StopReply { -public: - StopReplyStop(uint8_t Signal, lldb::tid_t ThreadId, llvm::StringRef Name, - RegisterMap ThreadPcs, RegisterMap Registers, - llvm::StringRef Reason) - : Signal(Signal), ThreadId(ThreadId), Name(Name), - ThreadPcs(std::move(ThreadPcs)), Registers(std::move(Registers)), - Reason(Reason) {} - - static llvm::Expected<std::unique_ptr<StopReplyStop>> - create(llvm::StringRef Response, llvm::support::endianness Endian, - llvm::ArrayRef<lldb_private::RegisterInfo> RegInfos); - - const RegisterMap &getThreadPcs() const { return ThreadPcs; } - lldb::tid_t getThreadId() const { return ThreadId; } - - // for llvm::cast<> - lldb_private::WaitStatus getKind() const override { - return lldb_private::WaitStatus{lldb_private::WaitStatus::Stop, Signal}; - } - static bool classof(const StopReply *R) { - return R->getKind().type == lldb_private::WaitStatus::Stop; - } - -private: - static llvm::Expected<RegisterMap> parseRegisters( - const llvm::StringMap<llvm::SmallVector<llvm::StringRef, 2>> &Elements, - llvm::support::endianness Endian, - llvm::ArrayRef<lldb_private::RegisterInfo> RegInfos); - - uint8_t Signal; - lldb::tid_t ThreadId; - std::string Name; - RegisterMap ThreadPcs; - RegisterMap Registers; - std::string Reason; -}; - -class StopReplyExit : public StopReply { -public: - explicit StopReplyExit(uint8_t Status) : Status(Status) {} - - static llvm::Expected<std::unique_ptr<StopReplyExit>> - create(llvm::StringRef response); - - // for llvm::cast<> - lldb_private::WaitStatus getKind() const override { - return lldb_private::WaitStatus{lldb_private::WaitStatus::Exit, Status}; - } - static bool classof(const StopReply *R) { - return R->getKind().type == lldb_private::WaitStatus::Exit; - } - -private: - uint8_t Status; -}; - -// Common functions for parsing packet data. -llvm::Expected<llvm::StringMap<llvm::StringRef>> -SplitUniquePairList(llvm::StringRef caller, llvm::StringRef s); - -llvm::StringMap<llvm::SmallVector<llvm::StringRef, 2>> -SplitPairList(llvm::StringRef s); - -template <typename... Args> -llvm::Error make_parsing_error(llvm::StringRef format, Args &&... args) { - std::string error = - "Unable to parse " + - llvm::formatv(format.data(), std::forward<Args>(args)...).str(); - return llvm::make_error<llvm::StringError>(error, - llvm::inconvertibleErrorCode()); -} - -} // namespace llgs_tests - -namespace lldb_private { -std::ostream &operator<<(std::ostream &OS, const RegisterValue &RegVal); -} - -#endif // LLDB_SERVER_TESTS_MESSAGEOBJECTS_H diff --git a/unittests/tools/lldb-server/tests/TestBase.cpp b/unittests/tools/lldb-server/tests/TestBase.cpp deleted file mode 100644 index b901249dbf4c..000000000000 --- a/unittests/tools/lldb-server/tests/TestBase.cpp +++ /dev/null @@ -1,36 +0,0 @@ -//===-- TestBase.cpp --------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "TestBase.h" -#include <cstdlib> - -using namespace llgs_tests; -using namespace llvm; - -std::string TestBase::getLogFileName() { - const auto *test_info = - ::testing::UnitTest::GetInstance()->current_test_info(); - assert(test_info); - - const char *Dir = getenv("LOG_FILE_DIRECTORY"); - if (!Dir) - return ""; - - if (!llvm::sys::fs::is_directory(Dir)) { - GTEST_LOG_(WARNING) << "Cannot access log directory: " << Dir; - return ""; - } - - SmallString<64> DirStr(Dir); - sys::path::append(DirStr, std::string("server-") + - test_info->test_case_name() + "-" + - test_info->name() + ".log"); - return DirStr.str(); -} - diff --git a/unittests/tools/lldb-server/tests/TestBase.h b/unittests/tools/lldb-server/tests/TestBase.h deleted file mode 100644 index 7ca1c1a975a8..000000000000 --- a/unittests/tools/lldb-server/tests/TestBase.h +++ /dev/null @@ -1,52 +0,0 @@ -//===-- TestBase.h ----------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_SERVER_TESTS_TESTBASE_H -#define LLDB_SERVER_TESTS_TESTBASE_H - -#include "TestClient.h" -#include "lldb/Host/FileSystem.h" -#include "lldb/Host/HostInfo.h" -#include "llvm/Support/Path.h" -#include "llvm/Testing/Support/Error.h" -#include "gtest/gtest.h" - -namespace llgs_tests { - -class TestBase: public ::testing::Test { -public: - static void SetUpTestCase() { - lldb_private::FileSystem::Initialize(); - lldb_private::HostInfo::Initialize(); - } - - static std::string getInferiorPath(llvm::StringRef Name) { - llvm::SmallString<64> Path(LLDB_TEST_INFERIOR_PATH); - llvm::sys::path::append(Path, Name + LLDB_TEST_INFERIOR_SUFFIX); - return Path.str(); - } - - static std::string getLogFileName(); -}; - -class StandardStartupTest: public TestBase { -public: - void SetUp() override { - auto ClientOr = TestClient::launch(getLogFileName()); - ASSERT_THAT_EXPECTED(ClientOr, llvm::Succeeded()); - Client = std::move(*ClientOr); - } - -protected: - std::unique_ptr<TestClient> Client; -}; - -} // namespace llgs_tests - -#endif // LLDB_SERVER_TESTS_TESTBASE_H diff --git a/unittests/tools/lldb-server/tests/TestClient.cpp b/unittests/tools/lldb-server/tests/TestClient.cpp deleted file mode 100644 index 3dd5be2c6e8e..000000000000 --- a/unittests/tools/lldb-server/tests/TestClient.cpp +++ /dev/null @@ -1,267 +0,0 @@ -//===-- TestClient.cpp ------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "TestClient.h" -#include "lldb/Host/HostInfo.h" -#include "lldb/Host/common/TCPSocket.h" -#include "lldb/Host/posix/ConnectionFileDescriptorPosix.h" -#include "lldb/Target/ProcessLaunchInfo.h" -#include "lldb/Utility/Args.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Support/Path.h" -#include "llvm/Testing/Support/Error.h" -#include "gtest/gtest.h" -#include <cstdlib> -#include <future> -#include <sstream> -#include <string> - -using namespace lldb; -using namespace lldb_private; -using namespace llvm; -using namespace llgs_tests; - -TestClient::TestClient(std::unique_ptr<Connection> Conn) { - SetConnection(Conn.release()); - SetPacketTimeout(std::chrono::seconds(10)); -} - -TestClient::~TestClient() { - if (!IsConnected()) - return; - - EXPECT_THAT_ERROR(SendMessage("k"), Succeeded()); -} - -Error TestClient::initializeConnection() { - if (SendAck() == 0) - return make_error<StringError>("Sending initial ACK failed.", - inconvertibleErrorCode()); - - if (Error E = SendMessage("QStartNoAckMode")) - return E; - - m_send_acks = false; - return Error::success(); -} - -Expected<std::unique_ptr<TestClient>> TestClient::launch(StringRef Log) { - return launch(Log, {}); -} - -Expected<std::unique_ptr<TestClient>> TestClient::launch(StringRef Log, ArrayRef<StringRef> InferiorArgs) { - return launchCustom(Log, {}, InferiorArgs); -} - -Expected<std::unique_ptr<TestClient>> TestClient::launchCustom(StringRef Log, ArrayRef<StringRef> ServerArgs, ArrayRef<StringRef> InferiorArgs) { - const ArchSpec &arch_spec = HostInfo::GetArchitecture(); - Args args; - args.AppendArgument(LLDB_SERVER); - if (IsLldbServer()) - args.AppendArgument("gdbserver"); - args.AppendArgument("--reverse-connect"); - - if (!Log.empty()) { - args.AppendArgument(("--log-file=" + Log).str()); - if (IsLldbServer()) - args.AppendArgument("--log-channels=gdb-remote packets"); - else - args.AppendArgument("--log-flags=0x800000"); - } - - Status status; - TCPSocket listen_socket(true, false); - status = listen_socket.Listen("127.0.0.1:0", 5); - if (status.Fail()) - return status.ToError(); - - args.AppendArgument( - ("localhost:" + Twine(listen_socket.GetLocalPortNumber())).str()); - - for (StringRef arg : ServerArgs) - args.AppendArgument(arg); - - if (!InferiorArgs.empty()) { - args.AppendArgument("--"); - for (StringRef arg : InferiorArgs) - args.AppendArgument(arg); - } - - ProcessLaunchInfo Info; - Info.SetArchitecture(arch_spec); - Info.SetArguments(args, true); - Info.GetEnvironment() = Host::GetEnvironment(); - // TODO: Use this callback to detect botched launches. If lldb-server does not - // start, we can print a nice error message here instead of hanging in - // Accept(). - Info.SetMonitorProcessCallback(&ProcessLaunchInfo::NoOpMonitorCallback, - false); - - status = Host::LaunchProcess(Info); - if (status.Fail()) - return status.ToError(); - - Socket *accept_socket; - listen_socket.Accept(accept_socket); - auto Conn = llvm::make_unique<ConnectionFileDescriptor>(accept_socket); - auto Client = std::unique_ptr<TestClient>(new TestClient(std::move(Conn))); - - if (Error E = Client->initializeConnection()) - return std::move(E); - - if (!InferiorArgs.empty()) { - if (Error E = Client->queryProcess()) - return std::move(E); - } - - return std::move(Client); -} - -Error TestClient::SetInferior(llvm::ArrayRef<std::string> inferior_args) { - if (SendEnvironment(Host::GetEnvironment()) != 0) { - return make_error<StringError>("Failed to set launch environment", - inconvertibleErrorCode()); - } - std::stringstream command; - command << "A"; - for (size_t i = 0; i < inferior_args.size(); i++) { - if (i > 0) - command << ','; - std::string hex_encoded = toHex(inferior_args[i]); - command << hex_encoded.size() << ',' << i << ',' << hex_encoded; - } - - if (Error E = SendMessage(command.str())) - return E; - if (Error E = SendMessage("qLaunchSuccess")) - return E; - if (Error E = queryProcess()) - return E; - return Error::success(); -} - -Error TestClient::ListThreadsInStopReply() { - return SendMessage("QListThreadsInStopReply"); -} - -Error TestClient::SetBreakpoint(unsigned long address) { - return SendMessage(formatv("Z0,{0:x-},1", address).str()); -} - -Error TestClient::ContinueAll() { return Continue("vCont;c"); } - -Error TestClient::ContinueThread(unsigned long thread_id) { - return Continue(formatv("vCont;c:{0:x-}", thread_id).str()); -} - -const llgs_tests::ProcessInfo &TestClient::GetProcessInfo() { - return *m_process_info; -} - -Expected<JThreadsInfo> TestClient::GetJThreadsInfo() { - return SendMessage<JThreadsInfo>("jThreadsInfo", m_register_infos); -} - -const StopReply &TestClient::GetLatestStopReply() { - assert(m_stop_reply); - return *m_stop_reply; -} - -Error TestClient::SendMessage(StringRef message) { - std::string dummy_string; - return SendMessage(message, dummy_string); -} - -Error TestClient::SendMessage(StringRef message, std::string &response_string) { - if (Error E = SendMessage(message, response_string, PacketResult::Success)) - return E; - StringExtractorGDBRemote Extractor(response_string); - if (Extractor.IsErrorResponse()) - return Extractor.GetStatus().ToError(); - return Error::success(); -} - -Error TestClient::SendMessage(StringRef message, std::string &response_string, - PacketResult expected_result) { - StringExtractorGDBRemote response; - GTEST_LOG_(INFO) << "Send Packet: " << message.str(); - PacketResult result = SendPacketAndWaitForResponse(message, response, false); - response.GetEscapedBinaryData(response_string); - GTEST_LOG_(INFO) << "Read Packet: " << response_string; - if (result != expected_result) - return make_error<StringError>( - formatv("Error sending message `{0}`: {1}", message, result).str(), - inconvertibleErrorCode()); - - return Error::success(); -} - -unsigned int TestClient::GetPcRegisterId() { - assert(m_pc_register != LLDB_INVALID_REGNUM); - return m_pc_register; -} - -Error TestClient::qProcessInfo() { - m_process_info = None; - auto InfoOr = SendMessage<ProcessInfo>("qProcessInfo"); - if (!InfoOr) - return InfoOr.takeError(); - m_process_info = std::move(*InfoOr); - return Error::success(); -} - -Error TestClient::qRegisterInfos() { - for (unsigned int Reg = 0;; ++Reg) { - std::string Message = formatv("qRegisterInfo{0:x-}", Reg).str(); - Expected<RegisterInfo> InfoOr = SendMessage<RegisterInfoParser>(Message); - if (!InfoOr) { - consumeError(InfoOr.takeError()); - break; - } - m_register_infos.emplace_back(std::move(*InfoOr)); - if (m_register_infos[Reg].kinds[eRegisterKindGeneric] == - LLDB_REGNUM_GENERIC_PC) - m_pc_register = Reg; - } - if (m_pc_register == LLDB_INVALID_REGNUM) - return make_parsing_error("qRegisterInfo: generic"); - return Error::success(); -} - -Error TestClient::queryProcess() { - if (Error E = qProcessInfo()) - return E; - if (Error E = qRegisterInfos()) - return E; - return Error::success(); -} - -Error TestClient::Continue(StringRef message) { - assert(m_process_info.hasValue()); - - auto StopReplyOr = SendMessage<StopReply>( - message, m_process_info->GetEndian(), m_register_infos); - if (!StopReplyOr) - return StopReplyOr.takeError(); - - m_stop_reply = std::move(*StopReplyOr); - if (!isa<StopReplyStop>(m_stop_reply)) { - StringExtractorGDBRemote R; - PacketResult result = ReadPacket(R, GetPacketTimeout(), false); - if (result != PacketResult::ErrorDisconnected) { - return make_error<StringError>( - formatv("Expected connection close after sending {0}. Got {1}/{2} " - "instead.", - message, result, R.GetStringRef()) - .str(), - inconvertibleErrorCode()); - } - } - return Error::success(); -} diff --git a/unittests/tools/lldb-server/tests/TestClient.h b/unittests/tools/lldb-server/tests/TestClient.h deleted file mode 100644 index 286c871f4735..000000000000 --- a/unittests/tools/lldb-server/tests/TestClient.h +++ /dev/null @@ -1,113 +0,0 @@ -//===-- TestClient.h --------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_SERVER_TESTS_TESTCLIENT_H -#define LLDB_SERVER_TESTS_TESTCLIENT_H - -#include "MessageObjects.h" -#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h" -#include "lldb/Target/ProcessLaunchInfo.h" -#include "lldb/Utility/ArchSpec.h" -#include "lldb/Utility/Connection.h" -#include "llvm/ADT/Optional.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/FormatVariadic.h" -#include <memory> -#include <string> - -#if LLDB_SERVER_IS_DEBUGSERVER -#define LLGS_TEST(x) DISABLED_ ## x -#define DS_TEST(x) x -#else -#define LLGS_TEST(x) x -#define DS_TEST(x) DISABLED_ ## x -#endif - -namespace llgs_tests { -class TestClient - : public lldb_private::process_gdb_remote::GDBRemoteCommunicationClient { -public: - static bool IsDebugServer() { return LLDB_SERVER_IS_DEBUGSERVER; } - static bool IsLldbServer() { return !IsDebugServer(); } - - /// Launches the server, connects it to the client and returns the client. If - /// Log is non-empty, the server will write it's log to this file. - static llvm::Expected<std::unique_ptr<TestClient>> launch(llvm::StringRef Log); - - /// Launches the server, while specifying the inferior on its command line. - /// When the client connects, it already has a process ready. - static llvm::Expected<std::unique_ptr<TestClient>> - launch(llvm::StringRef Log, llvm::ArrayRef<llvm::StringRef> InferiorArgs); - - /// Allows user to pass additional arguments to the server. Be careful when - /// using this for generic tests, as the two stubs have different - /// command-line interfaces. - static llvm::Expected<std::unique_ptr<TestClient>> - launchCustom(llvm::StringRef Log, llvm::ArrayRef<llvm::StringRef> ServerArgs, llvm::ArrayRef<llvm::StringRef> InferiorArgs); - - - ~TestClient() override; - llvm::Error SetInferior(llvm::ArrayRef<std::string> inferior_args); - llvm::Error ListThreadsInStopReply(); - llvm::Error SetBreakpoint(unsigned long address); - llvm::Error ContinueAll(); - llvm::Error ContinueThread(unsigned long thread_id); - const ProcessInfo &GetProcessInfo(); - llvm::Expected<JThreadsInfo> GetJThreadsInfo(); - const StopReply &GetLatestStopReply(); - template <typename T> llvm::Expected<const T &> GetLatestStopReplyAs() { - assert(m_stop_reply); - if (const auto *Reply = llvm::dyn_cast<T>(m_stop_reply.get())) - return *Reply; - return llvm::make_error<llvm::StringError>( - llvm::formatv("Unexpected Stop Reply {0}", m_stop_reply->getKind()), - llvm::inconvertibleErrorCode()); - } - llvm::Error SendMessage(llvm::StringRef message); - llvm::Error SendMessage(llvm::StringRef message, - std::string &response_string); - llvm::Error SendMessage(llvm::StringRef message, std::string &response_string, - PacketResult expected_result); - - template <typename P, typename... CreateArgs> - llvm::Expected<typename P::result_type> SendMessage(llvm::StringRef Message, - CreateArgs &&... Args); - unsigned int GetPcRegisterId(); - -private: - TestClient(std::unique_ptr<lldb_private::Connection> Conn); - - llvm::Error initializeConnection(); - llvm::Error qProcessInfo(); - llvm::Error qRegisterInfos(); - llvm::Error queryProcess(); - llvm::Error Continue(llvm::StringRef message); - std::string FormatFailedResult( - const std::string &message, - lldb_private::process_gdb_remote::GDBRemoteCommunication::PacketResult - result); - - llvm::Optional<ProcessInfo> m_process_info; - std::unique_ptr<StopReply> m_stop_reply; - std::vector<lldb_private::RegisterInfo> m_register_infos; - unsigned int m_pc_register = LLDB_INVALID_REGNUM; -}; - -template <typename P, typename... CreateArgs> -llvm::Expected<typename P::result_type> -TestClient::SendMessage(llvm::StringRef Message, CreateArgs &&... Args) { - std::string ResponseText; - if (llvm::Error E = SendMessage(Message, ResponseText)) - return std::move(E); - return P::create(ResponseText, std::forward<CreateArgs>(Args)...); -} - -} // namespace llgs_tests - -#endif // LLDB_SERVER_TESTS_TESTCLIENT_H diff --git a/unittests/tools/lldb-server/tests/ThreadIdsInJstopinfoTest.cpp b/unittests/tools/lldb-server/tests/ThreadIdsInJstopinfoTest.cpp deleted file mode 100644 index efc9517bc4b4..000000000000 --- a/unittests/tools/lldb-server/tests/ThreadIdsInJstopinfoTest.cpp +++ /dev/null @@ -1,54 +0,0 @@ -//===-- ThreadsInJstopinfoTest.cpp ------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "TestBase.h" -#include "TestClient.h" -#include "lldb/Utility/DataExtractor.h" -#include "llvm/Support/FormatVariadic.h" -#include "llvm/Support/Path.h" -#include "llvm/Testing/Support/Error.h" -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include <string> - -using namespace llgs_tests; -using namespace lldb_private; -using namespace llvm; -using namespace lldb; -using namespace testing; - -TEST_F(StandardStartupTest, TestStopReplyContainsThreadPcs) { - // This inferior spawns 4 threads, then forces a break. - ASSERT_THAT_ERROR( - Client->SetInferior({getInferiorPath("thread_inferior"), "4"}), - Succeeded()); - - ASSERT_THAT_ERROR(Client->ListThreadsInStopReply(), Succeeded()); - ASSERT_THAT_ERROR(Client->ContinueAll(), Succeeded()); - unsigned int pc_reg = Client->GetPcRegisterId(); - ASSERT_NE(pc_reg, UINT_MAX); - - auto jthreads_info = Client->GetJThreadsInfo(); - ASSERT_THAT_EXPECTED(jthreads_info, Succeeded()); - - auto stop_reply = Client->GetLatestStopReplyAs<StopReplyStop>(); - ASSERT_THAT_EXPECTED(stop_reply, Succeeded()); - auto stop_reply_pcs = stop_reply->getThreadPcs(); - auto thread_infos = jthreads_info->GetThreadInfos(); - ASSERT_EQ(stop_reply_pcs.size(), thread_infos.size()) - << "Thread count mismatch."; - - for (auto stop_reply_pc : stop_reply_pcs) { - unsigned long tid = stop_reply_pc.first; - ASSERT_TRUE(thread_infos.find(tid) != thread_infos.end()) - << "Thread ID: " << tid << " not in JThreadsInfo."; - EXPECT_THAT(thread_infos[tid].ReadRegister(pc_reg), - Pointee(Eq(stop_reply_pc.second))); - } -} |