Index: unittests/tools/lldb-server/tests/MessageObjects.h =================================================================== --- unittests/tools/lldb-server/tests/MessageObjects.h +++ unittests/tools/lldb-server/tests/MessageObjects.h @@ -25,9 +25,11 @@ typedef llvm::DenseMap U64Map; typedef llvm::DenseMap RegisterMap; -class ProcessInfo { +template struct Parser { using result_type = T; }; + +class ProcessInfo : public Parser { public: - static llvm::Expected Create(llvm::StringRef response); + static llvm::Expected create(llvm::StringRef response); lldb::pid_t GetPid() const; llvm::support::endianness GetEndian() const; @@ -73,6 +75,11 @@ ThreadInfoMap m_thread_infos; }; +struct RegisterInfoParser : public Parser { + static llvm::Expected + create(llvm::StringRef Response); +}; + class StopReply { public: StopReply() = default; Index: unittests/tools/lldb-server/tests/MessageObjects.cpp =================================================================== --- unittests/tools/lldb-server/tests/MessageObjects.cpp +++ unittests/tools/lldb-server/tests/MessageObjects.cpp @@ -8,16 +8,18 @@ //===----------------------------------------------------------------------===// #include "MessageObjects.h" +#include "lldb/Interpreter/Args.h" #include "lldb/Utility/StructuredData.h" #include "llvm/ADT/StringExtras.h" #include "gtest/gtest.h" using namespace lldb_private; +using namespace lldb; using namespace llvm; using namespace llvm::support; namespace llgs_tests { -Expected ProcessInfo::Create(StringRef response) { +Expected ProcessInfo::create(StringRef response) { ProcessInfo process_info; auto elements_or_error = SplitUniquePairList("ProcessInfo", response); if (!elements_or_error) @@ -132,6 +134,72 @@ return m_thread_infos; } +Expected 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(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); +} + //====== StopReply ============================================================= Expected> StopReply::create(StringRef Response, llvm::support::endianness Endian) { Index: unittests/tools/lldb-server/tests/TestClient.h =================================================================== --- unittests/tools/lldb-server/tests/TestClient.h +++ unittests/tools/lldb-server/tests/TestClient.h @@ -74,12 +74,17 @@ std::string &response_string); llvm::Error SendMessage(llvm::StringRef message, std::string &response_string, PacketResult expected_result); + + template + llvm::Expected SendMessage(llvm::StringRef Message); unsigned int GetPcRegisterId(); private: TestClient(std::unique_ptr Conn); - llvm::Error QueryProcessInfo(); + llvm::Error qProcessInfo(); + llvm::Error qRegisterInfos(); + llvm::Error queryProcess(); llvm::Error Continue(llvm::StringRef message); std::string FormatFailedResult( const std::string &message, @@ -88,9 +93,19 @@ llvm::Optional m_process_info; std::unique_ptr m_stop_reply; - unsigned int m_pc_register = UINT_MAX; + std::vector m_register_infos; + unsigned int m_pc_register = LLDB_INVALID_REGNUM; }; +template +llvm::Expected +TestClient::SendMessage(llvm::StringRef Message) { + std::string ResponseText; + if (llvm::Error E = SendMessage(Message, ResponseText)) + return std::move(E); + return P::create(ResponseText); +} + } // namespace llgs_tests #endif // LLDB_SERVER_TESTS_TESTCLIENT_H Index: unittests/tools/lldb-server/tests/TestClient.cpp =================================================================== --- unittests/tools/lldb-server/tests/TestClient.cpp +++ unittests/tools/lldb-server/tests/TestClient.cpp @@ -25,8 +25,7 @@ using namespace lldb; using namespace lldb_private; using namespace llvm; - -namespace llgs_tests { +using namespace llgs_tests; TestClient::TestClient(std::unique_ptr Conn) { SetConnection(Conn.release()); @@ -103,7 +102,7 @@ auto Client = std::unique_ptr(new TestClient(std::move(Conn))); if (!InferiorArgs.empty()) { - if (Error E = Client->QueryProcessInfo()) + if (Error E = Client->queryProcess()) return std::move(E); } @@ -128,7 +127,7 @@ return E; if (Error E = SendMessage("qLaunchSuccess")) return E; - if (Error E = QueryProcessInfo()) + if (Error E = queryProcess()) return E; return Error::success(); } @@ -147,7 +146,9 @@ return Continue(formatv("vCont;c:{0:x-}", thread_id).str()); } -const ProcessInfo &TestClient::GetProcessInfo() { return *m_process_info; } +const llgs_tests::ProcessInfo &TestClient::GetProcessInfo() { + return *m_process_info; +} Optional TestClient::GetJThreadsInfo() { std::string response; @@ -201,42 +202,42 @@ } unsigned int TestClient::GetPcRegisterId() { - if (m_pc_register != UINT_MAX) - return m_pc_register; - - for (unsigned int register_id = 0;; register_id++) { - std::string message = formatv("qRegisterInfo{0:x-}", register_id).str(); - std::string response; - if (SendMessage(message, response)) { - GTEST_LOG_(ERROR) << "Unable to query register ID for PC register."; - return UINT_MAX; - } + assert(m_pc_register != LLDB_INVALID_REGNUM); + return m_pc_register; +} - auto elements_or_error = SplitUniquePairList("GetPcRegisterId", response); - if (auto split_error = elements_or_error.takeError()) { - GTEST_LOG_(ERROR) << "GetPcRegisterId: Error splitting response: " - << response; - return UINT_MAX; - } +Error TestClient::qProcessInfo() { + m_process_info = None; + auto InfoOr = SendMessage("qProcessInfo"); + if (!InfoOr) + return InfoOr.takeError(); + m_process_info = std::move(*InfoOr); + return Error::success(); +} - auto elements = *elements_or_error; - if (elements["alt-name"] == "pc" || elements["generic"] == "pc") { - m_pc_register = register_id; +Error TestClient::qRegisterInfos() { + for (unsigned int Reg = 0;; ++Reg) { + std::string Message = formatv("qRegisterInfo{0:x-}", Reg).str(); + Expected InfoOr = SendMessage(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; } - - return m_pc_register; + if (m_pc_register == LLDB_INVALID_REGNUM) + return make_parsing_error("qRegisterInfo: generic"); + return Error::success(); } -llvm::Error TestClient::QueryProcessInfo() { - std::string response; - if (Error E = SendMessage("qProcessInfo", response)) +Error TestClient::queryProcess() { + if (Error E = qProcessInfo()) + return E; + if (Error E = qRegisterInfos()) return E; - auto create_or_error = ProcessInfo::Create(response); - if (!create_or_error) - return create_or_error.takeError(); - m_process_info = *create_or_error; return Error::success(); } @@ -265,5 +266,3 @@ } return Error::success(); } - -} // namespace llgs_tests Index: unittests/tools/lldb-server/tests/ThreadIdsInJstopinfoTest.cpp =================================================================== --- unittests/tools/lldb-server/tests/ThreadIdsInJstopinfoTest.cpp +++ unittests/tools/lldb-server/tests/ThreadIdsInJstopinfoTest.cpp @@ -44,7 +44,7 @@ << "Thread ID: " << tid << " not in JThreadsInfo."; auto pc_value = thread_infos[tid].ReadRegisterAsUint64(pc_reg); ASSERT_THAT_EXPECTED(pc_value, Succeeded()); - ASSERT_EQ(stop_reply_pcs[tid], *pc_value) + ASSERT_EQ(stop_reply_pc.second, *pc_value) << "Mismatched PC for thread: " << tid; } }