labath created this revision. labath added reviewers: eugene, davide. Right now the test client is not parsing register values correctly, which is manifesting itself in one test failing on 32-bit architectures (pr36013). This parses the information from the qRegisterInfo packets and stores it in the client, which will enable fixing the parsing in a follow up commit.
I am also adding a new templated SendMessage overload, which enables one to send a message get a parsed response in a single call. https://reviews.llvm.org/D43076 Files: unittests/tools/lldb-server/tests/MessageObjects.cpp unittests/tools/lldb-server/tests/MessageObjects.h unittests/tools/lldb-server/tests/TestClient.cpp unittests/tools/lldb-server/tests/TestClient.h unittests/tools/lldb-server/tests/ThreadIdsInJstopinfoTest.cpp
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; } } Index: unittests/tools/lldb-server/tests/TestClient.h =================================================================== --- unittests/tools/lldb-server/tests/TestClient.h +++ unittests/tools/lldb-server/tests/TestClient.h @@ -74,23 +74,38 @@ std::string &response_string); llvm::Error SendMessage(llvm::StringRef message, std::string &response_string, PacketResult expected_result); + + template <typename P> + llvm::Expected<typename P::result_type> SendMessage(llvm::StringRef Message); unsigned int GetPcRegisterId(); private: TestClient(std::unique_ptr<lldb_private::Connection> 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, lldb_private::process_gdb_remote::GDBRemoteCommunication::PacketResult result); llvm::Optional<ProcessInfo> m_process_info; std::unique_ptr<StopReply> m_stop_reply; - unsigned int m_pc_register = UINT_MAX; + std::vector<lldb_private::RegisterInfo> m_register_infos; + unsigned int m_pc_register = LLDB_INVALID_REGNUM; }; +template <typename P> +llvm::Expected<typename P::result_type> +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<Connection> Conn) { SetConnection(Conn.release()); @@ -103,7 +102,7 @@ auto Client = std::unique_ptr<TestClient>(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<JThreadsInfo> 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<ProcessInfo>("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<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; } - - 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/MessageObjects.h =================================================================== --- unittests/tools/lldb-server/tests/MessageObjects.h +++ unittests/tools/lldb-server/tests/MessageObjects.h @@ -25,9 +25,11 @@ typedef llvm::DenseMap<uint64_t, uint64_t> U64Map; typedef llvm::DenseMap<unsigned int, std::string> RegisterMap; -class ProcessInfo { +template <typename T> struct Parser { using result_type = T; }; + +class ProcessInfo : public Parser<ProcessInfo> { public: - static llvm::Expected<ProcessInfo> Create(llvm::StringRef response); + static llvm::Expected<ProcessInfo> 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<lldb_private::RegisterInfo> { + static llvm::Expected<lldb_private::RegisterInfo> + 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> ProcessInfo::Create(StringRef response) { +Expected<ProcessInfo> 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<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); +} + //====== StopReply ============================================================= Expected<std::unique_ptr<StopReply>> StopReply::create(StringRef Response, llvm::support::endianness Endian) {
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits