1 //===-- GDBRemoteCommunicationClientTest.cpp --------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #if defined(_MSC_VER) && (_HAS_EXCEPTIONS == 0)
11 // Workaround for MSVC standard library bug, which fails to include <thread> when
12 // exceptions are disabled.
13 #include <eh.h>
14 #endif
15 #include <future>
16 
17 #include "GDBRemoteTestUtils.h"
18 #include "gtest/gtest.h"
19 
20 #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h"
21 #include "lldb/Core/DataBuffer.h"
22 
23 #include "llvm/ADT/ArrayRef.h"
24 
25 using namespace lldb_private::process_gdb_remote;
26 using namespace lldb_private;
27 using namespace lldb;
28 
29 namespace
30 {
31 
32 typedef GDBRemoteCommunication::PacketResult PacketResult;
33 
34 struct TestClient : public GDBRemoteCommunicationClient
35 {
36     TestClient() { m_send_acks = false; }
37 };
38 
39 void
40 Handle_QThreadSuffixSupported(MockServer &server, bool supported)
41 {
42     StringExtractorGDBRemote request;
43     ASSERT_EQ(PacketResult::Success, server.GetPacket(request));
44     ASSERT_EQ("QThreadSuffixSupported", request.GetStringRef());
45     if (supported)
46         ASSERT_EQ(PacketResult::Success, server.SendOKResponse());
47     else
48         ASSERT_EQ(PacketResult::Success, server.SendUnimplementedResponse(nullptr));
49 }
50 
51 void
52 HandlePacket(MockServer &server, llvm::StringRef expected, llvm::StringRef response)
53 {
54     StringExtractorGDBRemote request;
55     ASSERT_EQ(PacketResult::Success, server.GetPacket(request));
56     ASSERT_EQ(expected, request.GetStringRef());
57     ASSERT_EQ(PacketResult::Success, server.SendPacket(response));
58 }
59 
60 uint8_t all_registers[] = {'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O'};
61 std::string all_registers_hex = "404142434445464748494a4b4c4d4e4f";
62 uint8_t one_register[] = {'A', 'B', 'C', 'D'};
63 std::string one_register_hex = "41424344";
64 
65 } // end anonymous namespace
66 
67 class GDBRemoteCommunicationClientTest : public GDBRemoteTest
68 {
69 };
70 
71 TEST_F(GDBRemoteCommunicationClientTest, WriteRegister)
72 {
73     TestClient client;
74     MockServer server;
75     Connect(client, server);
76     if (HasFailure())
77         return;
78 
79     std::future<void> suffix_result = std::async(std::launch::async, [&] { client.ComputeThreadSuffixSupport(); });
80     Handle_QThreadSuffixSupported(server, true);
81     suffix_result.get();
82 
83     GDBRemoteCommunicationClient::Lock lock(client, false);
84     ASSERT_TRUE(bool(lock));
85 
86     const lldb::tid_t tid = 0x47;
87     const uint32_t reg_num = 4;
88     std::future<bool> write_result =
89         std::async(std::launch::async, [&] { return client.WriteRegister(tid, reg_num, one_register, lock); });
90 
91     HandlePacket(server, "P4=" + one_register_hex + ";thread:0047;", "OK");
92     ASSERT_TRUE(write_result.get());
93 
94     write_result = std::async(std::launch::async, [&] { return client.WriteAllRegisters(tid, all_registers, lock); });
95 
96     HandlePacket(server, "G" + all_registers_hex + ";thread:0047;", "OK");
97     ASSERT_TRUE(write_result.get());
98 }
99 
100 TEST_F(GDBRemoteCommunicationClientTest, WriteRegisterNoSuffix)
101 {
102     TestClient client;
103     MockServer server;
104     Connect(client, server);
105     if (HasFailure())
106         return;
107 
108     std::future<void> suffix_result = std::async(std::launch::async, [&] { client.ComputeThreadSuffixSupport(); });
109     Handle_QThreadSuffixSupported(server, false);
110     suffix_result.get();
111 
112     GDBRemoteCommunicationClient::Lock lock(client, false);
113     ASSERT_TRUE(bool(lock));
114 
115     const lldb::tid_t tid = 0x47;
116     const uint32_t reg_num = 4;
117     std::future<bool> write_result =
118         std::async(std::launch::async, [&] { return client.WriteRegister(tid, reg_num, one_register, lock); });
119 
120     HandlePacket(server, "Hg47", "OK");
121     HandlePacket(server, "P4=" + one_register_hex, "OK");
122     ASSERT_TRUE(write_result.get());
123 
124     write_result = std::async(std::launch::async, [&] { return client.WriteAllRegisters(tid, all_registers, lock); });
125 
126     HandlePacket(server, "G" + all_registers_hex, "OK");
127     ASSERT_TRUE(write_result.get());
128 }
129 
130 TEST_F(GDBRemoteCommunicationClientTest, ReadRegister)
131 {
132     TestClient client;
133     MockServer server;
134     Connect(client, server);
135     if (HasFailure())
136         return;
137 
138     std::future<void> suffix_result = std::async(std::launch::async, [&] { client.ComputeThreadSuffixSupport(); });
139     Handle_QThreadSuffixSupported(server, true);
140     suffix_result.get();
141 
142     const lldb::tid_t tid = 0x47;
143     const uint32_t reg_num = 4;
144     std::future<bool> async_result = std::async(std::launch::async, [&] { return client.GetpPacketSupported(tid); });
145     HandlePacket(server, "p0;thread:0047;", one_register_hex);
146     ASSERT_TRUE(async_result.get());
147 
148     GDBRemoteCommunicationClient::Lock lock(client, false);
149     ASSERT_TRUE(bool(lock));
150 
151     std::future<DataBufferSP> read_result =
152         std::async(std::launch::async, [&] { return client.ReadRegister(tid, reg_num, lock); });
153     HandlePacket(server, "p4;thread:0047;", "41424344");
154     auto buffer_sp = read_result.get();
155     ASSERT_TRUE(bool(buffer_sp));
156     ASSERT_EQ(0, memcmp(buffer_sp->GetBytes(), one_register, sizeof one_register));
157 
158     read_result = std::async(std::launch::async, [&] { return client.ReadAllRegisters(tid, lock); });
159     HandlePacket(server, "g;thread:0047;", all_registers_hex);
160     buffer_sp = read_result.get();
161     ASSERT_TRUE(bool(buffer_sp));
162     ASSERT_EQ(0, memcmp(buffer_sp->GetBytes(), all_registers, sizeof all_registers));
163 }
164 
165 TEST_F(GDBRemoteCommunicationClientTest, SaveRestoreRegistersNoSuffix)
166 {
167     TestClient client;
168     MockServer server;
169     Connect(client, server);
170     if (HasFailure())
171         return;
172 
173     std::future<void> suffix_result = std::async(std::launch::async, [&] { client.ComputeThreadSuffixSupport(); });
174     Handle_QThreadSuffixSupported(server, false);
175     suffix_result.get();
176 
177     const lldb::tid_t tid = 0x47;
178     uint32_t save_id;
179     std::future<bool> async_result =
180         std::async(std::launch::async, [&] { return client.SaveRegisterState(tid, save_id); });
181     HandlePacket(server, "Hg47", "OK");
182     HandlePacket(server, "QSaveRegisterState", "1");
183     ASSERT_TRUE(async_result.get());
184     EXPECT_EQ(1u, save_id);
185 
186     async_result = std::async(std::launch::async, [&] { return client.RestoreRegisterState(tid, save_id); });
187     HandlePacket(server, "QRestoreRegisterState:1", "OK");
188     ASSERT_TRUE(async_result.get());
189 }
190 
191 TEST_F(GDBRemoteCommunicationClientTest, SyncThreadState)
192 {
193     TestClient client;
194     MockServer server;
195     Connect(client, server);
196     if (HasFailure())
197         return;
198 
199     const lldb::tid_t tid = 0x47;
200     std::future<bool> async_result = std::async(std::launch::async, [&] { return client.SyncThreadState(tid); });
201     HandlePacket(server, "qSyncThreadStateSupported", "OK");
202     HandlePacket(server, "QSyncThreadState:0047;", "OK");
203     ASSERT_TRUE(async_result.get());
204 }
205