summaryrefslogtreecommitdiff
path: root/unittests/tools/lldb-server/tests/TestClient.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2018-07-28 11:09:23 +0000
committerDimitry Andric <dim@FreeBSD.org>2018-07-28 11:09:23 +0000
commitf73363f1dd94996356cefbf24388f561891acf0b (patch)
treee3c31248bdb36eaec5fd833490d4278162dba2a0 /unittests/tools/lldb-server/tests/TestClient.cpp
parent160ee69dd7ae18978f4068116777639ea98dc951 (diff)
Notes
Diffstat (limited to 'unittests/tools/lldb-server/tests/TestClient.cpp')
-rw-r--r--unittests/tools/lldb-server/tests/TestClient.cpp156
1 files changed, 73 insertions, 83 deletions
diff --git a/unittests/tools/lldb-server/tests/TestClient.cpp b/unittests/tools/lldb-server/tests/TestClient.cpp
index 4653c2df1ce9..3dd5be2c6e8e 100644
--- a/unittests/tools/lldb-server/tests/TestClient.cpp
+++ b/unittests/tools/lldb-server/tests/TestClient.cpp
@@ -11,8 +11,8 @@
#include "lldb/Host/HostInfo.h"
#include "lldb/Host/common/TCPSocket.h"
#include "lldb/Host/posix/ConnectionFileDescriptorPosix.h"
-#include "lldb/Interpreter/Args.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"
@@ -25,25 +25,30 @@
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());
-
- SendAck(); // Send this as a handshake.
+ SetPacketTimeout(std::chrono::seconds(10));
}
TestClient::~TestClient() {
if (!IsConnected())
return;
- std::string response;
- // Debugserver (non-conformingly?) sends a reply to the k packet instead of
- // simply closing the connection.
- PacketResult result =
- IsDebugServer() ? PacketResult::Success : PacketResult::ErrorDisconnected;
- EXPECT_THAT_ERROR(SendMessage("k", response, result), Succeeded());
+ 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) {
@@ -91,10 +96,12 @@ Expected<std::unique_ptr<TestClient>> TestClient::launchCustom(StringRef Log, Ar
ProcessLaunchInfo Info;
Info.SetArchitecture(arch_spec);
Info.SetArguments(args, true);
-
- StringList Env;
- Host::GetEnvironment(Env);
- Info.GetEnvironmentEntries() = Args(Env);
+ 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())
@@ -105,8 +112,11 @@ Expected<std::unique_ptr<TestClient>> TestClient::launchCustom(StringRef Log, Ar
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->QueryProcessInfo())
+ if (Error E = Client->queryProcess())
return std::move(E);
}
@@ -114,14 +124,9 @@ Expected<std::unique_ptr<TestClient>> TestClient::launchCustom(StringRef Log, Ar
}
Error TestClient::SetInferior(llvm::ArrayRef<std::string> inferior_args) {
- StringList env;
- Host::GetEnvironment(env);
- for (size_t i = 0; i < env.GetSize(); ++i) {
- if (SendEnvironmentPacket(env[i].c_str()) != 0) {
- return make_error<StringError>(
- formatv("Failed to set environment variable: {0}", env[i]).str(),
- inconvertibleErrorCode());
- }
+ if (SendEnvironment(Host::GetEnvironment()) != 0) {
+ return make_error<StringError>("Failed to set launch environment",
+ inconvertibleErrorCode());
}
std::stringstream command;
command << "A";
@@ -136,7 +141,7 @@ Error TestClient::SetInferior(llvm::ArrayRef<std::string> inferior_args) {
return E;
if (Error E = SendMessage("qLaunchSuccess"))
return E;
- if (Error E = QueryProcessInfo())
+ if (Error E = queryProcess())
return E;
return Error::success();
}
@@ -155,19 +160,12 @@ Error TestClient::ContinueThread(unsigned long thread_id) {
return Continue(formatv("vCont;c:{0:x-}", thread_id).str());
}
-const ProcessInfo &TestClient::GetProcessInfo() { return *m_process_info; }
-
-Optional<JThreadsInfo> TestClient::GetJThreadsInfo() {
- std::string response;
- if (SendMessage("jThreadsInfo", response))
- return llvm::None;
- auto creation = JThreadsInfo::Create(response, m_process_info->GetEndian());
- if (auto create_error = creation.takeError()) {
- GTEST_LOG_(ERROR) << toString(std::move(create_error));
- return llvm::None;
- }
+const llgs_tests::ProcessInfo &TestClient::GetProcessInfo() {
+ return *m_process_info;
+}
- return std::move(*creation);
+Expected<JThreadsInfo> TestClient::GetJThreadsInfo() {
+ return SendMessage<JThreadsInfo>("jThreadsInfo", m_register_infos);
}
const StopReply &TestClient::GetLatestStopReply() {
@@ -183,13 +181,9 @@ Error TestClient::SendMessage(StringRef message) {
Error TestClient::SendMessage(StringRef message, std::string &response_string) {
if (Error E = SendMessage(message, response_string, PacketResult::Success))
return E;
- if (response_string[0] == 'E') {
- return make_error<StringError>(
- formatv("Error `{0}` while sending message: {1}", response_string,
- message)
- .str(),
- inconvertibleErrorCode());
- }
+ StringExtractorGDBRemote Extractor(response_string);
+ if (Extractor.IsErrorResponse())
+ return Extractor.GetStatus().ToError();
return Error::success();
}
@@ -209,69 +203,65 @@ Error TestClient::SendMessage(StringRef message, std::string &response_string,
}
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();
}
Error TestClient::Continue(StringRef message) {
assert(m_process_info.hasValue());
- std::string response;
- if (Error E = SendMessage(message, response))
- return E;
- auto creation = StopReply::create(response, m_process_info->GetEndian());
- if (Error E = creation.takeError())
- return E;
+ auto StopReplyOr = SendMessage<StopReply>(
+ message, m_process_info->GetEndian(), m_register_infos);
+ if (!StopReplyOr)
+ return StopReplyOr.takeError();
- m_stop_reply = std::move(*creation);
+ 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 receiving {0}. Got {1}/{2} "
+ formatv("Expected connection close after sending {0}. Got {1}/{2} "
"instead.",
- response, result, R.GetStringRef())
+ message, result, R.GetStringRef())
.str(),
inconvertibleErrorCode());
}
}
return Error::success();
}
-
-} // namespace llgs_tests