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 | |
23 | using namespace lldb_private::process_gdb_remote; |
24 | using namespace lldb_private; |
25 | using namespace lldb; |
26 | typedef GDBRemoteCommunication::PacketResult PacketResult; |
27 | |
28 | namespace { |
29 | |
30 | struct 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 | |
45 | struct TestClient : public GDBRemoteClientBase { |
46 | TestClient() : GDBRemoteClientBase("test.client" ) { |
47 | m_send_acks = false; |
48 | } |
49 | }; |
50 | |
51 | class GDBRemoteClientBaseTest : public GDBRemoteTest { |
52 | public: |
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 | |
61 | protected: |
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 (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 | |
83 | std::chrono::seconds GDBRemoteClientBaseTest::g_timeout(10); |
84 | |
85 | } // end anonymous namespace |
86 | |
87 | TEST_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 | |
112 | TEST_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 | |
145 | TEST_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 | |
186 | TEST_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 | |
213 | TEST_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 | |
243 | TEST_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 | |
281 | TEST_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 | |
301 | TEST_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 | |
328 | TEST_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 | |
350 | TEST_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 | |