OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 The Native Client Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 #include "debugger/rsp/rsp_packet.h" | |
5 #include <deque> | |
6 #include <map> | |
7 #include "debugger/base/debug_blob.h" | |
8 #include "gtest/gtest.h" | |
9 | |
10 namespace { | |
11 rsp::Packet* kNullPacketPtr = NULL; | |
12 | |
13 // RspPacket test fixture. | |
14 class RspPacketTest : public ::testing::Test { | |
15 public: | |
16 rsp::Packet* ParseMsg(const char* msg_str, const char* hint=NULL) { | |
17 debug::Blob msg(msg_str); | |
18 return rsp::Packet::CreateFromBlob(&msg, hint); | |
19 } | |
20 | |
21 template <class T> | |
22 bool TestParseAndPrintout(T* dummy, const char* message) { | |
23 delete dummy; | |
24 rsp::Packet* obj = ParseMsg(message); | |
25 if (NULL == obj) | |
26 return false; | |
27 | |
28 T* pack = rsp::packet_cast<T>(obj); | |
29 if (pack != obj) { | |
30 delete obj; | |
31 return false; | |
32 } | |
33 | |
34 debug::Blob blob; | |
35 pack->ToBlob(&blob); | |
36 delete pack; | |
37 std::string s = blob.ToString(); | |
38 return (s == message); | |
39 } | |
40 }; | |
41 | |
42 //#define TestParseAndPrintout(message) | |
43 | |
44 | |
45 | |
46 // Unit tests start here. | |
47 TEST_F(RspPacketTest, EmptyPacket) { | |
48 rsp::Packet* obj = ParseMsg(""); | |
49 ASSERT_NE(kNullPacketPtr, obj); | |
50 | |
51 rsp::EmptyPacket* ep = rsp::packet_cast<rsp::EmptyPacket>(obj); | |
52 EXPECT_EQ(obj, ep); | |
53 ASSERT_NE(kNullPacketPtr, ep); | |
54 | |
55 debug::Blob blob; | |
56 ep->ToBlob(&blob); | |
57 EXPECT_EQ(0, blob.size()); | |
58 delete obj; | |
59 } | |
60 | |
61 TEST_F(RspPacketTest, TypingPacketVisitor) { | |
62 std::deque<rsp::Packet*> packs; | |
63 packs.push_back(new rsp::Packet); | |
64 packs.push_back(new rsp::EmptyPacket); | |
65 packs.push_back(new rsp::QuerySupportedCommand); | |
66 packs.push_back(new rsp::QuerySupportedReply); | |
67 packs.push_back(new rsp::GetStopReasonCommand); | |
68 packs.push_back(new rsp::StopReply); | |
69 packs.push_back(new rsp::ReadMemoryCommand); | |
70 packs.push_back(new rsp::WriteMemoryCommand); | |
71 packs.push_back(new rsp::BlobReply); | |
72 packs.push_back(new rsp::ReadRegistersCommand); | |
73 packs.push_back(new rsp::WriteRegistersCommand); | |
74 packs.push_back(new rsp::ErrorReply); | |
75 packs.push_back(new rsp::OkReply); | |
76 packs.push_back(new rsp::SetCurrentThread); | |
77 packs.push_back(new rsp::GetCurrentThreadCommand); | |
78 packs.push_back(new rsp::GetCurrentThreadReply); | |
79 packs.push_back(new rsp::ContinueCommand); | |
80 packs.push_back(new rsp::StepCommand); | |
81 packs.push_back(new rsp::IsThreadAliveCommand); | |
82 packs.push_back(new rsp::QXferFeaturesReadCommand); | |
83 packs.push_back(new rsp::QXferReply); | |
84 packs.push_back(new rsp::GetThreadInfoCommand); | |
85 packs.push_back(new rsp::GetThreadInfoReply); | |
86 | |
87 std::map<int, int> type_ids; | |
88 for (size_t i = 0; i < packs.size(); i++) { | |
89 rsp::TypingPacketVisitor vis; | |
90 rsp::Packet* packet = packs[i]; | |
91 packet->AcceptVisitor(&vis); | |
92 | |
93 bool found = type_ids.end() != type_ids.find(vis.type_); | |
94 EXPECT_FALSE(found); | |
95 | |
96 int type0 = vis.type_; | |
97 rsp::Packet* packet2 = packet->Create(); | |
98 packet2->AcceptVisitor(&vis); | |
99 EXPECT_EQ(type0, vis.type_); | |
100 | |
101 type_ids[type0] = 1; | |
102 delete packet; | |
103 delete packet2; | |
104 } | |
105 } | |
106 | |
107 TEST_F(RspPacketTest, QuerySupportedCommand) { | |
108 const char* kMsg = "qSupported:xmlRegisters=i386;qRelocInsn+"; | |
109 rsp::Packet* obj = ParseMsg(kMsg); | |
110 ASSERT_NE(kNullPacketPtr, obj); | |
111 | |
112 rsp::QuerySupportedCommand* pack = | |
113 rsp::packet_cast<rsp::QuerySupportedCommand>(obj); | |
114 EXPECT_EQ(obj, pack); | |
115 ASSERT_NE(kNullPacketPtr, pack); | |
116 | |
117 EXPECT_EQ(2, pack->GetFeaturesNum()); | |
118 EXPECT_STREQ("i386", pack->GetFeature("xmlRegisters").c_str()); | |
119 EXPECT_STREQ("+", pack->GetFeature("qRelocInsn").c_str()); | |
120 EXPECT_STREQ("xmlRegisters", pack->GetFeatureName(0).c_str()); | |
121 EXPECT_STREQ("qRelocInsn", pack->GetFeatureName(1).c_str()); | |
122 EXPECT_STREQ("", pack->GetFeatureName(2).c_str()); | |
123 | |
124 debug::Blob blob; | |
125 pack->ToBlob(&blob); | |
126 EXPECT_STREQ(kMsg, blob.ToString().c_str()); | |
127 delete obj; | |
128 } | |
129 | |
130 TEST_F(RspPacketTest, QuerySupportedReply) { | |
131 const char* kMsg = "PacketSize=7cf;qXfer:libraries:read+;qXfer:features:read+"
; | |
132 rsp::Packet* obj = ParseMsg(kMsg, "qSupported$Reply"); | |
133 ASSERT_NE(kNullPacketPtr, obj); | |
134 | |
135 rsp::QuerySupportedReply* pack = | |
136 rsp::packet_cast<rsp::QuerySupportedReply>(obj); | |
137 EXPECT_EQ(obj, pack); | |
138 ASSERT_NE(kNullPacketPtr, pack); | |
139 | |
140 EXPECT_EQ(3, pack->GetFeaturesNum()); | |
141 EXPECT_STREQ("PacketSize", pack->GetFeatureName(0).c_str()); | |
142 EXPECT_STREQ("qXfer:libraries:read", pack->GetFeatureName(1).c_str()); | |
143 EXPECT_STREQ("qXfer:features:read", pack->GetFeatureName(2).c_str()); | |
144 | |
145 EXPECT_STREQ("7cf", pack->GetFeature("PacketSize").c_str()); | |
146 EXPECT_STREQ("+", pack->GetFeature("qXfer:libraries:read").c_str()); | |
147 EXPECT_STREQ("+", pack->GetFeature("qXfer:features:read").c_str()); | |
148 | |
149 debug::Blob blob; | |
150 pack->ToBlob(&blob); | |
151 EXPECT_STREQ(kMsg, blob.ToString().c_str()); | |
152 delete obj; | |
153 } | |
154 | |
155 TEST_F(RspPacketTest, StopReply1) { | |
156 const char* kMsg = "S15"; | |
157 rsp::Packet* obj = ParseMsg(kMsg); | |
158 ASSERT_NE(kNullPacketPtr, obj); | |
159 | |
160 rsp::StopReply* pack = rsp::packet_cast<rsp::StopReply>(obj); | |
161 EXPECT_EQ(obj, pack); | |
162 ASSERT_NE(kNullPacketPtr, pack); | |
163 | |
164 EXPECT_EQ(21, pack->signal_number()); | |
165 EXPECT_EQ(rsp::StopReply::SIGNALED, pack->stop_reason()); | |
166 EXPECT_EQ(0, pack->pid()); | |
167 | |
168 debug::Blob blob; | |
169 pack->ToBlob(&blob); | |
170 EXPECT_STREQ(kMsg, blob.ToString().c_str()); | |
171 | |
172 pack->set_signal_number(5); | |
173 pack->ToBlob(&blob); | |
174 EXPECT_STREQ("S05", blob.ToString().c_str()); | |
175 delete obj; | |
176 } | |
177 | |
178 TEST_F(RspPacketTest, StopReply2) { | |
179 const char* kMsg = "W21;process:138c"; | |
180 rsp::Packet* obj = ParseMsg(kMsg); | |
181 ASSERT_NE(kNullPacketPtr, obj); | |
182 | |
183 rsp::StopReply* pack = rsp::packet_cast<rsp::StopReply>(obj); | |
184 EXPECT_EQ(obj, pack); | |
185 ASSERT_NE(kNullPacketPtr, pack); | |
186 | |
187 EXPECT_EQ(33, pack->exit_code()); | |
188 EXPECT_EQ(rsp::StopReply::EXITED, pack->stop_reason()); | |
189 EXPECT_EQ(0x138c, pack->pid()); | |
190 | |
191 debug::Blob blob; | |
192 pack->ToBlob(&blob); | |
193 EXPECT_STREQ(kMsg, blob.ToString().c_str()); | |
194 | |
195 pack->set_exit_code(5); | |
196 pack->ToBlob(&blob); | |
197 EXPECT_STREQ("W05;process:138c", blob.ToString().c_str()); | |
198 | |
199 pack->set_pid(10); | |
200 pack->ToBlob(&blob); | |
201 EXPECT_STREQ("W05;process:a", blob.ToString().c_str()); | |
202 | |
203 delete obj; | |
204 } | |
205 | |
206 TEST_F(RspPacketTest, StopReply3) { | |
207 const char* kMsg = "X21;process:138c"; | |
208 rsp::Packet* obj = ParseMsg(kMsg); | |
209 ASSERT_NE(kNullPacketPtr, obj); | |
210 | |
211 rsp::StopReply* pack = rsp::packet_cast<rsp::StopReply>(obj); | |
212 EXPECT_EQ(obj, pack); | |
213 ASSERT_NE(kNullPacketPtr, pack); | |
214 | |
215 EXPECT_EQ(33, pack->signal_number()); | |
216 EXPECT_EQ(rsp::StopReply::TERMINATED, pack->stop_reason()); | |
217 EXPECT_EQ(0x138c, pack->pid()); | |
218 | |
219 debug::Blob blob; | |
220 pack->ToBlob(&blob); | |
221 EXPECT_STREQ(kMsg, blob.ToString().c_str()); | |
222 | |
223 pack->set_signal_number(5); | |
224 pack->ToBlob(&blob); | |
225 EXPECT_STREQ("X05;process:138c", blob.ToString().c_str()); | |
226 | |
227 pack->set_pid(10); | |
228 pack->ToBlob(&blob); | |
229 EXPECT_STREQ("X05;process:a", blob.ToString().c_str()); | |
230 | |
231 delete obj; | |
232 } | |
233 | |
234 TEST_F(RspPacketTest, ReadMemoryCommand) { | |
235 const char* kMsg = "mcffffff80,40"; | |
236 rsp::Packet* obj = ParseMsg(kMsg); | |
237 ASSERT_NE(kNullPacketPtr, obj); | |
238 | |
239 rsp::ReadMemoryCommand* pack = rsp::packet_cast<rsp::ReadMemoryCommand>(obj); | |
240 EXPECT_EQ(obj, pack); | |
241 ASSERT_NE(kNullPacketPtr, pack); | |
242 | |
243 u_int64_t kAddr = 0xcffffff80LL; | |
244 u_int64_t addr = pack->addr(); | |
245 | |
246 EXPECT_EQ(kAddr, addr); | |
247 EXPECT_EQ(64, pack->num_of_bytes()); | |
248 | |
249 debug::Blob blob; | |
250 pack->ToBlob(&blob); | |
251 std::string s = blob.ToString(); | |
252 EXPECT_STREQ(kMsg, blob.ToString().c_str()); | |
253 delete obj; | |
254 } | |
255 | |
256 TEST_F(RspPacketTest, WriteMemoryCommand) { | |
257 const char* kMsg = "Mcffffff80,1:cc"; | |
258 rsp::Packet* obj = ParseMsg(kMsg); | |
259 ASSERT_NE(kNullPacketPtr, obj); | |
260 | |
261 rsp::WriteMemoryCommand* pack = | |
262 rsp::packet_cast<rsp::WriteMemoryCommand>(obj); | |
263 EXPECT_EQ(obj, pack); | |
264 ASSERT_NE(kNullPacketPtr, pack); | |
265 | |
266 u_int64_t kAddr = 0xcffffff80LL; | |
267 u_int64_t addr = pack->addr(); | |
268 EXPECT_EQ(kAddr, addr); | |
269 EXPECT_EQ(1, pack->data().size()); | |
270 EXPECT_STREQ("cc", pack->data().ToHexString().c_str()); | |
271 delete obj; | |
272 } | |
273 | |
274 TEST_F(RspPacketTest, BlobReply) { | |
275 const char* kMsgs[] = { | |
276 "", | |
277 "0b00cdcd2b00cdcd5300cdcd2b00cdcd", | |
278 "cc", | |
279 "00000000", | |
280 "123456789abcdeff" }; | |
281 | |
282 size_t num = sizeof(kMsgs) / sizeof(kMsgs[0]); | |
283 for (size_t i = 0; i < num; i++) { | |
284 const char* kMsg = kMsgs[i]; | |
285 rsp::Packet* obj = ParseMsg(kMsg, "blob$Reply"); | |
286 ASSERT_NE(kNullPacketPtr, obj) << "msg=[" << kMsg << "]"; | |
287 | |
288 rsp::BlobReply* pack = | |
289 rsp::packet_cast<rsp::BlobReply>(obj); | |
290 EXPECT_EQ(obj, pack) << "msg=[" << kMsg << "]"; | |
291 ASSERT_NE(kNullPacketPtr, pack) << "msg=[" << kMsg << "]"; | |
292 | |
293 size_t expected_bytes = strlen(kMsg) / 2; | |
294 EXPECT_EQ(expected_bytes, pack->data().size()) << "msg=[" << kMsg << "]"; | |
295 | |
296 debug::Blob blob; | |
297 pack->ToBlob(&blob); | |
298 std::string s = blob.ToString(); | |
299 EXPECT_STREQ(kMsg, blob.ToString().c_str()); | |
300 delete obj; | |
301 } | |
302 } | |
303 | |
304 TEST_F(RspPacketTest, SingleWordCommands) { | |
305 EXPECT_TRUE(TestParseAndPrintout(new rsp::ReadRegistersCommand, "g")); | |
306 EXPECT_TRUE(TestParseAndPrintout( | |
307 new rsp::WriteRegistersCommand, | |
308 "G00a500000000000c0ffffff00000000d85123020")); | |
309 EXPECT_TRUE(TestParseAndPrintout(new rsp::WriteMemoryCommand, | |
310 "Mcffffff80,1:cc")); | |
311 EXPECT_TRUE(TestParseAndPrintout(new rsp::GetStopReasonCommand, "?")); | |
312 EXPECT_TRUE(TestParseAndPrintout(new rsp::ErrorReply, "E02")); | |
313 EXPECT_TRUE(TestParseAndPrintout(new rsp::ErrorReply, "E15")); | |
314 EXPECT_TRUE(TestParseAndPrintout(new rsp::OkReply, "OK")); | |
315 EXPECT_TRUE(TestParseAndPrintout(new rsp::SetCurrentThread, "Hc-1")); | |
316 EXPECT_TRUE(TestParseAndPrintout(new rsp::SetCurrentThread, "Hc0")); | |
317 EXPECT_TRUE(TestParseAndPrintout(new rsp::SetCurrentThread, "Hg-1")); | |
318 EXPECT_TRUE(TestParseAndPrintout(new rsp::SetCurrentThread, "Hg0")); | |
319 EXPECT_TRUE(TestParseAndPrintout(new rsp::SetCurrentThread, "Hg138c")); | |
320 EXPECT_TRUE(TestParseAndPrintout(new rsp::SetCurrentThread, "Hc138c")); | |
321 EXPECT_TRUE(TestParseAndPrintout(new rsp::GetCurrentThreadCommand, "qC")); | |
322 EXPECT_TRUE(TestParseAndPrintout(new rsp::GetCurrentThreadReply, "QC138c")); | |
323 EXPECT_TRUE(TestParseAndPrintout(new rsp::ContinueCommand, "c")); | |
324 EXPECT_TRUE(TestParseAndPrintout(new rsp::StepCommand, "s")); | |
325 EXPECT_TRUE(TestParseAndPrintout(new rsp::IsThreadAliveCommand, "T138c")); | |
326 EXPECT_TRUE(TestParseAndPrintout(new rsp::QXferFeaturesReadCommand, | |
327 "qXfer:features:read:target.xml:0,7ca")); | |
328 EXPECT_TRUE(TestParseAndPrintout(new rsp::GetThreadInfoCommand, | |
329 "qfThreadInfo")); | |
330 EXPECT_TRUE(TestParseAndPrintout(new rsp::GetThreadInfoCommand, | |
331 "qsThreadInfo")); | |
332 } | |
333 | |
334 TEST_F(RspPacketTest, WriteRegistersCommand) { | |
335 rsp::Packet* obj = ParseMsg("G00a500000000000c0ffffff00000000d85123020"); | |
336 ASSERT_NE(kNullPacketPtr, obj); | |
337 | |
338 rsp::WriteRegistersCommand* pack = | |
339 rsp::packet_cast<rsp::WriteRegistersCommand>(obj); | |
340 ASSERT_NE(kNullPacketPtr, pack); | |
341 | |
342 EXPECT_EQ(20, pack->data().size()); | |
343 EXPECT_EQ(0x00, pack->data().GetAt(0)); | |
344 EXPECT_EQ(0xa5, pack->data().GetAt(1)); | |
345 EXPECT_EQ(0x20, pack->data().GetAt(19)); | |
346 delete obj; | |
347 } | |
348 | |
349 TEST_F(RspPacketTest, SetCurrentThread) { | |
350 rsp::SetCurrentThread* obj = | |
351 rsp::packet_cast<rsp::SetCurrentThread>(ParseMsg("Hc-1")); | |
352 ASSERT_NE(kNullPacketPtr, obj); | |
353 EXPECT_EQ(rsp::SetCurrentThread::FOR_CONTINUE, obj->subtype()); | |
354 EXPECT_EQ(-1, obj->thread_id()); | |
355 delete obj; | |
356 | |
357 obj = rsp::packet_cast<rsp::SetCurrentThread>(ParseMsg("Hc0")); | |
358 ASSERT_NE(kNullPacketPtr, obj); | |
359 EXPECT_EQ(rsp::SetCurrentThread::FOR_CONTINUE, obj->subtype()); | |
360 EXPECT_EQ(0, obj->thread_id()); | |
361 delete obj; | |
362 | |
363 obj = rsp::packet_cast<rsp::SetCurrentThread>(ParseMsg("Hg-1")); | |
364 ASSERT_NE(kNullPacketPtr, obj); | |
365 EXPECT_EQ(rsp::SetCurrentThread::FOR_READ, obj->subtype()); | |
366 EXPECT_EQ(-1, obj->thread_id()); | |
367 delete obj; | |
368 | |
369 obj = rsp::packet_cast<rsp::SetCurrentThread>(ParseMsg("Hg0")); | |
370 ASSERT_NE(kNullPacketPtr, obj); | |
371 EXPECT_EQ(rsp::SetCurrentThread::FOR_READ, obj->subtype()); | |
372 EXPECT_EQ(0, obj->thread_id()); | |
373 delete obj; | |
374 | |
375 obj = rsp::packet_cast<rsp::SetCurrentThread>(ParseMsg("Hg138c")); | |
376 ASSERT_NE(kNullPacketPtr, obj); | |
377 EXPECT_EQ(rsp::SetCurrentThread::FOR_READ, obj->subtype()); | |
378 EXPECT_EQ(0x138c, obj->thread_id()); | |
379 delete obj; | |
380 | |
381 obj = rsp::packet_cast<rsp::SetCurrentThread>(ParseMsg("Hc138c")); | |
382 ASSERT_NE(kNullPacketPtr, obj); | |
383 EXPECT_EQ(rsp::SetCurrentThread::FOR_CONTINUE, obj->subtype()); | |
384 EXPECT_EQ(0x138c, obj->thread_id()); | |
385 delete obj; | |
386 } | |
387 | |
388 TEST_F(RspPacketTest, IsThreadAliveCommand) { | |
389 rsp::IsThreadAliveCommand* obj = | |
390 rsp::packet_cast<rsp::IsThreadAliveCommand>(ParseMsg("T2e0")); | |
391 ASSERT_NE(kNullPacketPtr, obj); | |
392 EXPECT_EQ(0x2e0, obj->value()); | |
393 } | |
394 | |
395 TEST_F(RspPacketTest, QXferFeaturesReadCommand) { | |
396 rsp::QXferFeaturesReadCommand* obj = | |
397 rsp::packet_cast<rsp::QXferFeaturesReadCommand>( | |
398 ParseMsg("qXfer:features:read:target.xml:0,7ca")); | |
399 ASSERT_NE(kNullPacketPtr, obj); | |
400 EXPECT_STREQ("target.xml", obj->file_name().c_str()); | |
401 EXPECT_EQ(0, obj->offset()); | |
402 EXPECT_EQ(0x7ca, obj->length()); | |
403 } | |
404 | |
405 TEST_F(RspPacketTest, QXferReply) { | |
406 const char* kMsg = | |
407 "l<target><architecture>i386:x86-64</architecture></target>"; | |
408 rsp::QXferReply* obj = | |
409 rsp::packet_cast<rsp::QXferReply>(ParseMsg(kMsg, "qXfer$Reply")); | |
410 ASSERT_NE(kNullPacketPtr, obj); | |
411 EXPECT_STREQ("<target><architecture>i386:x86-64</architecture></target>", | |
412 obj->body().c_str()); | |
413 EXPECT_TRUE(obj->eom()); | |
414 | |
415 debug::Blob blob; | |
416 obj->ToBlob(&blob); | |
417 EXPECT_STREQ(kMsg, blob.ToString().c_str()); | |
418 delete obj; | |
419 } | |
420 | |
421 TEST_F(RspPacketTest, GetThreadInfoReply) { | |
422 const char* kMsg = "m1598,138c"; | |
423 rsp::GetThreadInfoReply* obj = | |
424 rsp::packet_cast<rsp::GetThreadInfoReply>(ParseMsg(kMsg, "GetThreadInfo$Re
ply")); | |
425 ASSERT_NE(kNullPacketPtr, obj); | |
426 EXPECT_FALSE(obj->eom()); | |
427 EXPECT_EQ(2, obj->threads_ids().size()); | |
428 EXPECT_EQ(0x1598, obj->threads_ids()[0]); | |
429 EXPECT_EQ(0x138c, obj->threads_ids()[1]); | |
430 | |
431 debug::Blob blob; | |
432 obj->ToBlob(&blob); | |
433 EXPECT_STREQ(kMsg, blob.ToString().c_str()); | |
434 delete obj; | |
435 } | |
436 | |
437 TEST_F(RspPacketTest, GetThreadInfoReply2) { | |
438 const char* kMsg = "l138c"; | |
439 rsp::GetThreadInfoReply* obj = | |
440 rsp::packet_cast<rsp::GetThreadInfoReply>(ParseMsg(kMsg, "GetThreadInfo$Re
ply")); | |
441 ASSERT_NE(kNullPacketPtr, obj); | |
442 EXPECT_TRUE(obj->eom()); | |
443 EXPECT_EQ(1, obj->threads_ids().size()); | |
444 EXPECT_EQ(0x138c, obj->threads_ids()[0]); | |
445 | |
446 debug::Blob blob; | |
447 obj->ToBlob(&blob); | |
448 EXPECT_STREQ(kMsg, blob.ToString().c_str()); | |
449 delete obj; | |
450 } | |
451 | |
452 } // namespace | |
OLD | NEW |