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