summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/lldb/unittests/tools/lldb-server/tests/TestClient.cpp
diff options
context:
space:
mode:
authorpatrick <patrick@openbsd.org>2020-08-03 14:33:06 +0000
committerpatrick <patrick@openbsd.org>2020-08-03 14:33:06 +0000
commit061da546b983eb767bad15e67af1174fb0bcf31c (patch)
tree83c78b820819d70aa40c36d90447978b300078c5 /gnu/llvm/lldb/unittests/tools/lldb-server/tests/TestClient.cpp
parentImport LLVM 10.0.0 release including clang, lld and lldb. (diff)
downloadwireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.tar.xz
wireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.zip
Import LLVM 10.0.0 release including clang, lld and lldb.
ok hackroom tested by plenty
Diffstat (limited to 'gnu/llvm/lldb/unittests/tools/lldb-server/tests/TestClient.cpp')
-rw-r--r--gnu/llvm/lldb/unittests/tools/lldb-server/tests/TestClient.cpp269
1 files changed, 269 insertions, 0 deletions
diff --git a/gnu/llvm/lldb/unittests/tools/lldb-server/tests/TestClient.cpp b/gnu/llvm/lldb/unittests/tools/lldb-server/tests/TestClient.cpp
new file mode 100644
index 00000000000..7e51a3879ab
--- /dev/null
+++ b/gnu/llvm/lldb/unittests/tools/lldb-server/tests/TestClient.cpp
@@ -0,0 +1,269 @@
+//===-- TestClient.cpp ------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "TestClient.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/common/TCPSocket.h"
+#include "lldb/Host/posix/ConnectionFileDescriptorPosix.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;
+
+#ifdef SendMessage
+#undef SendMessage
+#endif
+
+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(
+ ("127.0.0.1:" + 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 = std::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();
+}