1//===-- GDBRemoteClientBaseTest.cpp ---------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "Plugins/Process/gdb-remote/GDBRemoteClientBase.h"
10#include "GDBRemoteTestUtils.h"
11#include "Plugins/Process/Utility/LinuxSignals.h"
12#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h"
13#include "lldb/Utility/GDBRemote.h"
14#include "lldb/Utility/Listener.h"
15#include "llvm/ADT/StringRef.h"
16#include "llvm/Testing/Support/Error.h"
17#include "gtest/gtest.h"
18#include <chrono>
19#include <future>
20#include <string>
21#include <vector>
22
23using namespace lldb_private::process_gdb_remote;
24using namespace lldb_private;
25using namespace lldb;
26typedef GDBRemoteCommunication::PacketResult PacketResult;
27
28namespace {
29
30struct MockDelegate : public GDBRemoteClientBase::ContinueDelegate {
31 std::string output;
32 std::string misc_data;
33 unsigned stop_reply_called = 0;
34 std::vector<std::string> structured_data_packets;
35
36 void HandleAsyncStdout(llvm::StringRef out) override { output += out; }
37 void HandleAsyncMisc(llvm::StringRef data) override { misc_data += data; }
38 void HandleStopReply() override { ++stop_reply_called; }
39
40 void HandleAsyncStructuredDataPacket(llvm::StringRef data) override {
41 structured_data_packets.push_back(x: std::string(data));
42 }
43};
44
45struct TestClient : public GDBRemoteClientBase {
46 TestClient() : GDBRemoteClientBase("test.client") {
47 m_send_acks = false;
48 }
49};
50
51class GDBRemoteClientBaseTest : public GDBRemoteTest {
52public:
53 void SetUp() override {
54 ASSERT_THAT_ERROR(GDBRemoteCommunication::ConnectLocally(client, server),
55 llvm::Succeeded());
56 ASSERT_EQ(TestClient::eBroadcastBitRunPacketSent,
57 listener_sp->StartListeningForEvents(
58 &client, TestClient::eBroadcastBitRunPacketSent));
59 }
60
61protected:
62 // We don't have a process to get the interrupt timeout from, so make one up.
63 static std::chrono::seconds g_timeout;
64 TestClient client;
65 MockServer server;
66 MockDelegate delegate;
67 ListenerSP listener_sp = Listener::MakeListener(name: "listener");
68
69 StateType SendCPacket(StringExtractorGDBRemote &response) {
70 return client.SendContinuePacketAndWaitForResponse(delegate, signals: LinuxSignals(),
71 payload: "c", interrupt_timeout: g_timeout,
72 response);
73 }
74
75 void WaitForRunEvent() {
76 EventSP event_sp;
77 listener_sp->GetEventForBroadcasterWithType(
78 broadcaster: &client, event_type_mask: TestClient::eBroadcastBitRunPacketSent, event_sp,
79 timeout: std::nullopt);
80 }
81};
82
83std::chrono::seconds GDBRemoteClientBaseTest::g_timeout(10);
84
85} // end anonymous namespace
86
87TEST_F(GDBRemoteClientBaseTest, SendContinueAndWait) {
88 StringExtractorGDBRemote response;
89
90 // Continue. The inferior will stop with a signal.
91 ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
92 ASSERT_EQ(eStateStopped, SendCPacket(response));
93 ASSERT_EQ("T01", response.GetStringRef());
94 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
95 ASSERT_EQ("c", response.GetStringRef());
96
97 // Continue. The inferior will exit.
98 ASSERT_EQ(PacketResult::Success, server.SendPacket("W01"));
99 ASSERT_EQ(eStateExited, SendCPacket(response));
100 ASSERT_EQ("W01", response.GetStringRef());
101 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
102 ASSERT_EQ("c", response.GetStringRef());
103
104 // Continue. The inferior will get killed.
105 ASSERT_EQ(PacketResult::Success, server.SendPacket("X01"));
106 ASSERT_EQ(eStateExited, SendCPacket(response));
107 ASSERT_EQ("X01", response.GetStringRef());
108 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
109 ASSERT_EQ("c", response.GetStringRef());
110}
111
112TEST_F(GDBRemoteClientBaseTest, SendContinueAndAsyncSignal) {
113 StringExtractorGDBRemote continue_response, response;
114
115 // SendAsyncSignal should do nothing when we are not running.
116 ASSERT_FALSE(client.SendAsyncSignal(0x47, g_timeout));
117
118 // Continue. After the run packet is sent, send an async signal.
119 std::future<StateType> continue_state = std::async(
120 policy: std::launch::async, fn: [&] { return SendCPacket(response&: continue_response); });
121 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
122 ASSERT_EQ("c", response.GetStringRef());
123 WaitForRunEvent();
124
125 std::future<bool> async_result = std::async(policy: std::launch::async, fn: [&] {
126 return client.SendAsyncSignal(signo: 0x47, interrupt_timeout: g_timeout);
127 });
128
129 // First we'll get interrupted.
130 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
131 ASSERT_EQ("\x03", response.GetStringRef());
132 ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));
133
134 // Then we get the signal packet.
135 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
136 ASSERT_EQ("C47", response.GetStringRef());
137 ASSERT_TRUE(async_result.get());
138
139 // And we report back a signal stop.
140 ASSERT_EQ(PacketResult::Success, server.SendPacket("T47"));
141 ASSERT_EQ(eStateStopped, continue_state.get());
142 ASSERT_EQ("T47", continue_response.GetStringRef());
143}
144
145TEST_F(GDBRemoteClientBaseTest, SendContinueAndAsyncPacket) {
146 StringExtractorGDBRemote continue_response, async_response, response;
147
148 // Continue. After the run packet is sent, send an async packet.
149 std::future<StateType> continue_state = std::async(
150 policy: std::launch::async, fn: [&] { return SendCPacket(response&: continue_response); });
151 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
152 ASSERT_EQ("c", response.GetStringRef());
153 WaitForRunEvent();
154
155 // Sending without async enabled should fail.
156 ASSERT_EQ(PacketResult::ErrorSendFailed,
157 client.SendPacketAndWaitForResponse("qTest1", response));
158
159 std::future<PacketResult> async_result = std::async(policy: std::launch::async, fn: [&] {
160 return client.SendPacketAndWaitForResponse(payload: "qTest2", response&: async_response,
161 interrupt_timeout: g_timeout);
162 });
163
164 // First we'll get interrupted.
165 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
166 ASSERT_EQ("\x03", response.GetStringRef());
167 ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));
168
169 // Then we get the async packet.
170 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
171 ASSERT_EQ("qTest2", response.GetStringRef());
172
173 // Send the response and receive it.
174 ASSERT_EQ(PacketResult::Success, server.SendPacket("QTest2"));
175 ASSERT_EQ(PacketResult::Success, async_result.get());
176 ASSERT_EQ("QTest2", async_response.GetStringRef());
177
178 // And we get resumed again.
179 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
180 ASSERT_EQ("c", response.GetStringRef());
181 ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
182 ASSERT_EQ(eStateStopped, continue_state.get());
183 ASSERT_EQ("T01", continue_response.GetStringRef());
184}
185
186TEST_F(GDBRemoteClientBaseTest, SendContinueAndInterrupt) {
187 StringExtractorGDBRemote continue_response, response;
188
189 // Interrupt should do nothing when we're not running.
190 ASSERT_FALSE(client.Interrupt(g_timeout));
191
192 // Continue. After the run packet is sent, send an interrupt.
193 std::future<StateType> continue_state = std::async(
194 policy: std::launch::async, fn: [&] { return SendCPacket(response&: continue_response); });
195 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
196 ASSERT_EQ("c", response.GetStringRef());
197 WaitForRunEvent();
198
199 std::future<bool> async_result = std::async(
200 policy: std::launch::async, fn: [&] { return client.Interrupt(interrupt_timeout: g_timeout); });
201
202 // We get interrupted.
203 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
204 ASSERT_EQ("\x03", response.GetStringRef());
205 ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));
206
207 // And that's it.
208 ASSERT_EQ(eStateStopped, continue_state.get());
209 ASSERT_EQ("T13", continue_response.GetStringRef());
210 ASSERT_TRUE(async_result.get());
211}
212
213TEST_F(GDBRemoteClientBaseTest, SendContinueAndLateInterrupt) {
214 StringExtractorGDBRemote continue_response, response;
215
216 // Continue. After the run packet is sent, send an interrupt.
217 std::future<StateType> continue_state = std::async(
218 policy: std::launch::async, fn: [&] { return SendCPacket(response&: continue_response); });
219 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
220 ASSERT_EQ("c", response.GetStringRef());
221 WaitForRunEvent();
222
223 std::future<bool> async_result = std::async(
224 policy: std::launch::async, fn: [&] { return client.Interrupt(interrupt_timeout: g_timeout); });
225
226 // However, the target stops due to a different reason than the original
227 // interrupt.
228 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
229 ASSERT_EQ("\x03", response.GetStringRef());
230 ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
231 ASSERT_EQ(eStateStopped, continue_state.get());
232 ASSERT_EQ("T01", continue_response.GetStringRef());
233 ASSERT_TRUE(async_result.get());
234
235 // The subsequent continue packet should work normally.
236 ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
237 ASSERT_EQ(eStateStopped, SendCPacket(response));
238 ASSERT_EQ("T01", response.GetStringRef());
239 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
240 ASSERT_EQ("c", response.GetStringRef());
241}
242
243TEST_F(GDBRemoteClientBaseTest, SendContinueAndInterrupt2PacketBug) {
244 StringExtractorGDBRemote continue_response, async_response, response;
245
246 // Interrupt should do nothing when we're not running.
247 ASSERT_FALSE(client.Interrupt(g_timeout));
248
249 // Continue. After the run packet is sent, send an async signal.
250 std::future<StateType> continue_state = std::async(
251 policy: std::launch::async, fn: [&] { return SendCPacket(response&: continue_response); });
252 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
253 ASSERT_EQ("c", response.GetStringRef());
254 WaitForRunEvent();
255
256 std::future<bool> interrupt_result = std::async(
257 policy: std::launch::async, fn: [&] { return client.Interrupt(interrupt_timeout: g_timeout); });
258
259 // We get interrupted. We'll send two packets to simulate a buggy stub.
260 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
261 ASSERT_EQ("\x03", response.GetStringRef());
262 ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));
263 ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));
264
265 // We should stop.
266 ASSERT_EQ(eStateStopped, continue_state.get());
267 ASSERT_EQ("T13", continue_response.GetStringRef());
268 ASSERT_TRUE(interrupt_result.get());
269
270 // Packet stream should remain synchronized.
271 std::future<PacketResult> send_result = std::async(policy: std::launch::async, fn: [&] {
272 return client.SendPacketAndWaitForResponse(payload: "qTest", response&: async_response);
273 });
274 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
275 ASSERT_EQ("qTest", response.GetStringRef());
276 ASSERT_EQ(PacketResult::Success, server.SendPacket("QTest"));
277 ASSERT_EQ(PacketResult::Success, send_result.get());
278 ASSERT_EQ("QTest", async_response.GetStringRef());
279}
280
281TEST_F(GDBRemoteClientBaseTest, SendContinueDelegateInterface) {
282 StringExtractorGDBRemote response;
283
284 // Continue. We'll have the server send a bunch of async packets before it
285 // stops.
286 ASSERT_EQ(PacketResult::Success, server.SendPacket("O4142"));
287 ASSERT_EQ(PacketResult::Success, server.SendPacket("Apro"));
288 ASSERT_EQ(PacketResult::Success, server.SendPacket("O4344"));
289 ASSERT_EQ(PacketResult::Success, server.SendPacket("Afile"));
290 ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
291 ASSERT_EQ(eStateStopped, SendCPacket(response));
292 ASSERT_EQ("T01", response.GetStringRef());
293 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
294 ASSERT_EQ("c", response.GetStringRef());
295
296 EXPECT_EQ("ABCD", delegate.output);
297 EXPECT_EQ("profile", delegate.misc_data);
298 EXPECT_EQ(1u, delegate.stop_reply_called);
299}
300
301TEST_F(GDBRemoteClientBaseTest, SendContinueDelegateStructuredDataReceipt) {
302 // Build the plain-text version of the JSON data we will have the
303 // server send.
304 const std::string json_payload =
305 "{ \"type\": \"MyFeatureType\", "
306 " \"elements\": [ \"entry1\", \"entry2\" ] }";
307 const std::string json_packet = "JSON-async:" + json_payload;
308
309 // Escape it properly for transit.
310 StreamGDBRemote stream;
311 stream.PutEscapedBytes(s: json_packet.c_str(), src_len: json_packet.length());
312 stream.Flush();
313
314 StringExtractorGDBRemote response;
315
316 // Send async structured data packet, then stop.
317 ASSERT_EQ(PacketResult::Success, server.SendPacket(stream.GetData()));
318 ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
319 ASSERT_EQ(eStateStopped, SendCPacket(response));
320 ASSERT_EQ("T01", response.GetStringRef());
321 ASSERT_EQ(1ul, delegate.structured_data_packets.size());
322
323 // Verify the packet contents. It should have been unescaped upon packet
324 // reception.
325 ASSERT_EQ(json_packet, delegate.structured_data_packets[0]);
326}
327
328TEST_F(GDBRemoteClientBaseTest, InterruptNoResponse) {
329 StringExtractorGDBRemote continue_response, response;
330
331 // Continue. After the run packet is sent, send an interrupt.
332 std::future<StateType> continue_state = std::async(
333 policy: std::launch::async, fn: [&] { return SendCPacket(response&: continue_response); });
334 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
335 ASSERT_EQ("c", response.GetStringRef());
336 WaitForRunEvent();
337
338 std::future<bool> async_result = std::async(
339 policy: std::launch::async, fn: [&] { return client.Interrupt(interrupt_timeout: g_timeout); });
340
341 // We get interrupted, but we don't send a stop packet.
342 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
343 ASSERT_EQ("\x03", response.GetStringRef());
344
345 // The functions should still terminate (after a timeout).
346 ASSERT_TRUE(async_result.get());
347 ASSERT_EQ(eStateInvalid, continue_state.get());
348}
349
350TEST_F(GDBRemoteClientBaseTest, SendPacketAndReceiveResponseWithOutputSupport) {
351 StringExtractorGDBRemote response;
352 StreamString command_output;
353
354 ASSERT_EQ(PacketResult::Success, server.SendPacket("O"));
355 ASSERT_EQ(PacketResult::Success, server.SendPacket("O48656c6c6f2c"));
356 ASSERT_EQ(PacketResult::Success, server.SendPacket("O20"));
357 ASSERT_EQ(PacketResult::Success, server.SendPacket("O"));
358 ASSERT_EQ(PacketResult::Success, server.SendPacket("O776f726c64"));
359 ASSERT_EQ(PacketResult::Success, server.SendPacket("OK"));
360
361 PacketResult result = client.SendPacketAndReceiveResponseWithOutputSupport(
362 payload: "qRcmd,test", response, interrupt_timeout: g_timeout,
363 output_callback: [&command_output](llvm::StringRef output) { command_output << output; });
364
365 ASSERT_EQ(PacketResult::Success, result);
366 ASSERT_EQ("OK", response.GetStringRef());
367 ASSERT_EQ("Hello, world", command_output.GetString().str());
368}
369

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of lldb/unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp