blob: ef81a441cea26978aaa0e645f299fa9822277c8d [file] [log] [blame]
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <string>
#include "src/debug/wasm/gdb-server/packet.h"
#include "src/debug/wasm/gdb-server/session.h"
#include "src/debug/wasm/gdb-server/transport.h"
#include "test/unittests/test-utils.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace v8 {
namespace internal {
namespace wasm {
namespace gdb_server {
using ::testing::_;
using ::testing::Return;
using ::testing::SetArrayArgument;
using ::testing::StrEq;
class WasmGdbRemoteTest : public ::testing::Test {};
TEST_F(WasmGdbRemoteTest, GdbRemotePacketAddChars) {
Packet packet;
// Read empty packet
bool end_of_packet = packet.EndOfPacket();
EXPECT_TRUE(end_of_packet);
// Add raw chars
packet.AddRawChar('4');
packet.AddRawChar('2');
std::string str;
packet.GetString(&str);
EXPECT_EQ("42", str);
}
TEST_F(WasmGdbRemoteTest, GdbRemotePacketAddBlock) {
static const uint8_t block[] = {0x01, 0x02, 0x03, 0x04, 0x05,
0x06, 0x07, 0x08, 0x09};
static const size_t kLen = sizeof(block) / sizeof(uint8_t);
Packet packet;
packet.AddBlock(block, kLen);
uint8_t buffer[kLen];
bool ok = packet.GetBlock(buffer, kLen);
EXPECT_TRUE(ok);
EXPECT_EQ(0, memcmp(block, buffer, kLen));
packet.Rewind();
std::string str;
ok = packet.GetString(&str);
EXPECT_TRUE(ok);
EXPECT_EQ("010203040506070809", str);
}
TEST_F(WasmGdbRemoteTest, GdbRemotePacketAddString) {
Packet packet;
packet.AddHexString("foobar");
std::string str;
bool ok = packet.GetString(&str);
EXPECT_TRUE(ok);
EXPECT_EQ("666f6f626172", str);
packet.Clear();
packet.AddHexString("GDB");
ok = packet.GetString(&str);
EXPECT_TRUE(ok);
EXPECT_EQ("474442", str);
}
TEST_F(WasmGdbRemoteTest, GdbRemotePacketAddNumbers) {
Packet packet;
static const uint64_t u64_val = 0xdeadbeef89abcdef;
static const uint8_t u8_val = 0x42;
packet.AddNumberSep(u64_val, ';');
packet.AddWord8(u8_val);
std::string str;
packet.GetString(&str);
EXPECT_EQ("deadbeef89abcdef;42", str);
packet.Rewind();
uint64_t val = 0;
char sep = '\0';
bool ok = packet.GetNumberSep(&val, &sep);
EXPECT_TRUE(ok);
EXPECT_EQ(u64_val, val);
uint8_t b = 0;
ok = packet.GetWord8(&b);
EXPECT_TRUE(ok);
EXPECT_EQ(u8_val, b);
}
TEST_F(WasmGdbRemoteTest, GdbRemotePacketSequenceNumber) {
Packet packet_with_sequence_num;
packet_with_sequence_num.AddWord8(42);
packet_with_sequence_num.AddRawChar(':');
packet_with_sequence_num.AddHexString("foobar");
int32_t sequence_num = 0;
packet_with_sequence_num.ParseSequence();
bool ok = packet_with_sequence_num.GetSequence(&sequence_num);
EXPECT_TRUE(ok);
EXPECT_EQ(42, sequence_num);
Packet packet_without_sequence_num;
packet_without_sequence_num.AddHexString("foobar");
packet_without_sequence_num.ParseSequence();
ok = packet_without_sequence_num.GetSequence(&sequence_num);
EXPECT_FALSE(ok);
}
TEST_F(WasmGdbRemoteTest, GdbRemotePacketRunLengthEncoded) {
Packet packet1;
packet1.AddRawChar('0');
packet1.AddRawChar('*');
packet1.AddRawChar(' ');
std::string str1;
bool ok = packet1.GetHexString(&str1);
EXPECT_TRUE(ok);
EXPECT_EQ("0000", std::string(packet1.GetPayload()));
Packet packet2;
packet2.AddRawChar('1');
packet2.AddRawChar('2');
packet2.AddRawChar('3');
packet2.AddRawChar('*');
packet2.AddRawChar(' ');
packet2.AddRawChar('a');
packet2.AddRawChar('b');
std::string str2;
ok = packet2.GetHexString(&str2);
EXPECT_TRUE(ok);
EXPECT_EQ("123333ab", std::string(packet2.GetPayload()));
}
TEST_F(WasmGdbRemoteTest, GdbRemoteUtilStringSplit) {
std::vector<std::string> parts1 = StringSplit({}, ",");
EXPECT_EQ(size_t(0), parts1.size());
auto parts2 = StringSplit("a", nullptr);
EXPECT_EQ(size_t(1), parts2.size());
EXPECT_EQ("a", parts2[0]);
auto parts3 = StringSplit(";a;bc;def;", ",");
EXPECT_EQ(size_t(1), parts3.size());
EXPECT_EQ(";a;bc;def;", parts3[0]);
auto parts4 = StringSplit(";a;bc;def;", ";");
EXPECT_EQ(size_t(3), parts4.size());
EXPECT_EQ("a", parts4[0]);
EXPECT_EQ("bc", parts4[1]);
EXPECT_EQ("def", parts4[2]);
}
class MockTransport : public TransportBase {
public:
MOCK_METHOD(bool, AcceptConnection, (), (override));
MOCK_METHOD(bool, Read, (char*, int32_t), (override));
MOCK_METHOD(bool, Write, (const char*, int32_t), (override));
MOCK_METHOD(bool, IsDataAvailable, (), (override));
MOCK_METHOD(bool, IsDataAvailable, (), (const, override));
MOCK_METHOD(void, Disconnect, (), (override));
MOCK_METHOD(void, Close, (), (override));
MOCK_METHOD(void, WaitForDebugStubEvent, (), (override));
MOCK_METHOD(bool, SignalThreadEvent, (), (override));
};
TEST_F(WasmGdbRemoteTest, GdbRemoteSessionSendPacket) {
const char* ack_buffer = "+";
MockTransport mock_transport;
EXPECT_CALL(mock_transport, Write(StrEq("$474442#39"), 10))
.WillOnce(Return(true));
EXPECT_CALL(mock_transport, Read(_, _))
.Times(1)
.WillOnce(
DoAll(SetArrayArgument<0>(ack_buffer, ack_buffer + 1), Return(true)));
Session session(&mock_transport);
Packet packet;
packet.AddHexString("GDB");
bool ok = session.SendPacket(&packet);
EXPECT_TRUE(ok);
}
TEST_F(WasmGdbRemoteTest, GdbRemoteSessionSendPacketDisconnectOnNoAck) {
MockTransport mock_transport;
EXPECT_CALL(mock_transport, Write(StrEq("$474442#39"), 10))
.Times(1)
.WillOnce(Return(true));
EXPECT_CALL(mock_transport, Read(_, _)).Times(1).WillOnce(Return(false));
EXPECT_CALL(mock_transport, Disconnect()).Times(1);
Session session(&mock_transport);
Packet packet;
packet.AddHexString("GDB");
bool ok = session.SendPacket(&packet);
EXPECT_FALSE(ok);
}
TEST_F(WasmGdbRemoteTest, GdbRemoteSessionGetPacketCheckChecksum) {
const char* buffer_bad = "$47#00";
const char* buffer_ok = "$47#6b";
MockTransport mock_transport;
EXPECT_CALL(mock_transport, Read(_, _))
.WillOnce(
DoAll(SetArrayArgument<0>(buffer_bad, buffer_bad + 1), Return(true)))
.WillOnce(DoAll(SetArrayArgument<0>(buffer_bad + 1, buffer_bad + 2),
Return(true)))
.WillOnce(DoAll(SetArrayArgument<0>(buffer_bad + 2, buffer_bad + 3),
Return(true)))
.WillOnce(DoAll(SetArrayArgument<0>(buffer_bad + 3, buffer_bad + 4),
Return(true)))
.WillOnce(DoAll(SetArrayArgument<0>(buffer_bad + 4, buffer_bad + 5),
Return(true)))
.WillOnce(DoAll(SetArrayArgument<0>(buffer_bad + 5, buffer_bad + 6),
Return(true)))
.WillOnce(
DoAll(SetArrayArgument<0>(buffer_ok, buffer_ok + 1), Return(true)))
.WillOnce(DoAll(SetArrayArgument<0>(buffer_ok + 1, buffer_ok + 2),
Return(true)))
.WillOnce(DoAll(SetArrayArgument<0>(buffer_ok + 2, buffer_ok + 3),
Return(true)))
.WillOnce(DoAll(SetArrayArgument<0>(buffer_ok + 3, buffer_ok + 4),
Return(true)))
.WillOnce(DoAll(SetArrayArgument<0>(buffer_ok + 4, buffer_ok + 5),
Return(true)))
.WillOnce(DoAll(SetArrayArgument<0>(buffer_ok + 5, buffer_ok + 6),
Return(true)));
EXPECT_CALL(mock_transport, Write(StrEq("-"), 1)) // Signal bad packet
.Times(1)
.WillOnce(Return(true));
EXPECT_CALL(mock_transport, Write(StrEq("+"), 1)) // Signal ack
.Times(1)
.WillOnce(Return(true));
Session session(&mock_transport);
Packet packet;
bool ok = session.GetPacket(&packet);
EXPECT_TRUE(ok);
char ch;
ok = packet.GetBlock(&ch, 1);
EXPECT_TRUE(ok);
EXPECT_EQ('G', ch);
}
TEST_F(WasmGdbRemoteTest, GdbRemoteSessionGetPacketDisconnectOnReadFailure) {
MockTransport mock_transport;
EXPECT_CALL(mock_transport, Read(_, _)).Times(1).WillOnce(Return(false));
EXPECT_CALL(mock_transport, Disconnect()).Times(1);
Session session(&mock_transport);
Packet packet;
bool ok = session.GetPacket(&packet);
EXPECT_FALSE(ok);
}
} // namespace gdb_server
} // namespace wasm
} // namespace internal
} // namespace v8