blob: 7232a33594dab549a3681b40a1df6a178c7f7a58 [file] [log] [blame]
// Copyright 2018 The Fuchsia 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 "garnet/lib/debug_ipc/agent_protocol.h"
#include "garnet/lib/debug_ipc/client_protocol.h"
#include "garnet/lib/debug_ipc/message_reader.h"
#include "garnet/lib/debug_ipc/message_writer.h"
#include "garnet/lib/debug_ipc/protocol_helpers.h"
#include "gtest/gtest.h"
namespace debug_ipc {
namespace {
template<typename RequestType>
bool SerializeDeserializeRequest(const RequestType& in, RequestType* out) {
MessageWriter writer;
uint32_t in_transaction_id = 32;
WriteRequest(in, in_transaction_id, &writer);
std::vector<char> serialized = writer.MessageComplete();
MessageReader reader(std::move(serialized));
uint32_t out_transaction_id = 0;
if (!ReadRequest(&reader, out, &out_transaction_id))
return false;
EXPECT_EQ(in_transaction_id, out_transaction_id);
return true;
}
template<typename ReplyType>
bool SerializeDeserializeReply(const ReplyType& in, ReplyType* out) {
MessageWriter writer;
uint32_t in_transaction_id = 32;
WriteReply(in, in_transaction_id, &writer);
std::vector<char> serialized = writer.MessageComplete();
MessageReader reader(std::move(serialized));
uint32_t out_transaction_id = 0;
if (!ReadReply(&reader, out, &out_transaction_id))
return false;
EXPECT_EQ(in_transaction_id, out_transaction_id);
return true;
}
template<typename NotificationType>
bool SerializeDeserializeNotification(
const NotificationType& in,
NotificationType* out,
void (*write_fn)(const NotificationType&, MessageWriter*),
bool (*read_fn)(MessageReader*, NotificationType*)) {
MessageWriter writer;
write_fn(in, &writer);
MessageReader reader(writer.MessageComplete());
return read_fn(&reader, out);
}
} // namespace
// Hello -----------------------------------------------------------------------
TEST(Protocol, HelloRequest) {
HelloRequest initial;
HelloRequest second;
ASSERT_TRUE(SerializeDeserializeRequest(initial, &second));
}
TEST(Protocol, HelloReply) {
HelloReply initial;
initial.version = 12345678;
HelloReply second;
ASSERT_TRUE(SerializeDeserializeReply(initial, &second));
EXPECT_EQ(initial.version, second.version);
}
// Launch ----------------------------------------------------------------------
TEST(Protocol, LaunchRequest) {
LaunchRequest initial;
initial.argv.push_back("/usr/bin/WINWORD.EXE");
initial.argv.push_back("--dosmode");
LaunchRequest second;
ASSERT_TRUE(SerializeDeserializeRequest(initial, &second));
ASSERT_EQ(initial.argv.size(), second.argv.size());
for (size_t i = 0; i < initial.argv.size(); i++)
EXPECT_EQ(initial.argv[i], second.argv[i]);
}
TEST(Protocol, LaunchReply) {
LaunchReply initial;
initial.status = 67;
initial.process_koid = 0x1234;
initial.process_name = "winword.exe";
LaunchReply second;
ASSERT_TRUE(SerializeDeserializeReply(initial, &second));
EXPECT_EQ(initial.status, second.status);
EXPECT_EQ(initial.process_koid, second.process_koid);
EXPECT_EQ(initial.process_name, second.process_name);
}
// Kill ----------------------------------------------------------------------
TEST(Protocol, KillRequest) {
KillRequest initial;
initial.process_koid = 5678;
KillRequest second;
ASSERT_TRUE(SerializeDeserializeRequest(initial, &second));
EXPECT_EQ(initial.process_koid, second.process_koid);
}
TEST(Protocol, KillReply) {
KillReply initial;
initial.status = 67;
KillReply second;
ASSERT_TRUE(SerializeDeserializeReply(initial, &second));
EXPECT_EQ(initial.status, second.status);
}
// Attach ----------------------------------------------------------------------
TEST(Protocol, AttachRequest) {
AttachRequest initial;
initial.koid = 5678;
AttachRequest second;
ASSERT_TRUE(SerializeDeserializeRequest(initial, &second));
EXPECT_EQ(initial.koid, second.koid);
}
TEST(Protocol, AttachReply) {
AttachReply initial;
initial.status = 67;
initial.process_name = "virtual console";
AttachReply second;
ASSERT_TRUE(SerializeDeserializeReply(initial, &second));
EXPECT_EQ(initial.status, second.status);
EXPECT_EQ(initial.process_name, second.process_name);
}
// Detach ----------------------------------------------------------------------
TEST(Protocol, DetachRequest) {
DetachRequest initial;
initial.process_koid = 5678;
DetachRequest second;
ASSERT_TRUE(SerializeDeserializeRequest(initial, &second));
EXPECT_EQ(initial.process_koid, second.process_koid);
}
TEST(Protocol, DetachReply) {
DetachReply initial;
initial.status = 67;
DetachReply second;
ASSERT_TRUE(SerializeDeserializeReply(initial, &second));
EXPECT_EQ(initial.status, second.status);
}
// Pause ---------------------------------------------------------------------
TEST(Protocol, PauseRequest) {
PauseRequest initial;
initial.process_koid = 3746234;
initial.thread_koid = 123523;
PauseRequest second;
ASSERT_TRUE(SerializeDeserializeRequest(initial, &second));
EXPECT_EQ(initial.process_koid, second.process_koid);
EXPECT_EQ(initial.thread_koid, second.thread_koid);
}
// Resume --------------------------------------------------------------------
TEST(Protocol, ResumeRequest) {
ResumeRequest initial;
initial.process_koid = 3746234;
initial.thread_koid = 123523;
initial.how = ResumeRequest::How::kStepInstruction;
ResumeRequest second;
ASSERT_TRUE(SerializeDeserializeRequest(initial, &second));
EXPECT_EQ(initial.process_koid, second.process_koid);
EXPECT_EQ(initial.thread_koid, second.thread_koid);
EXPECT_EQ(initial.how, second.how);
}
// ProcessTree -----------------------------------------------------------------
TEST(Protocol, ProcessTreeRequest) {
ProcessTreeRequest initial;
ProcessTreeRequest second;
ASSERT_TRUE(SerializeDeserializeRequest(initial, &second));
}
TEST(Protocol, ProcessTreeReply) {
ProcessTreeReply initial;
initial.root.type = ProcessTreeRecord::Type::kJob;
initial.root.koid = 1234;
initial.root.name = "root";
initial.root.children.resize(1);
initial.root.children[0].type = ProcessTreeRecord::Type::kProcess;
initial.root.children[0].koid = 3456;
initial.root.children[0].name = "hello";
ProcessTreeReply second;
ASSERT_TRUE(SerializeDeserializeReply(initial, &second));
EXPECT_EQ(initial.root.type, second.root.type);
EXPECT_EQ(initial.root.koid, second.root.koid);
EXPECT_EQ(initial.root.name, second.root.name);
ASSERT_EQ(initial.root.children.size(), second.root.children.size());
EXPECT_EQ(initial.root.children[0].type, second.root.children[0].type);
EXPECT_EQ(initial.root.children[0].koid, second.root.children[0].koid);
EXPECT_EQ(initial.root.children[0].name, second.root.children[0].name);
}
// Threads ---------------------------------------------------------------------
TEST(Protocol, ThreadsRequest) {
ThreadsRequest initial;
initial.process_koid = 36473476;
ThreadsRequest second;
ASSERT_TRUE(SerializeDeserializeRequest(initial, &second));
EXPECT_EQ(initial.process_koid, second.process_koid);
}
TEST(Protocol, ThreadsReply) {
ThreadsReply initial;
initial.threads.resize(2);
initial.threads[0].koid = 1234;
initial.threads[0].name = "one";
initial.threads[1].koid = 7634;
initial.threads[1].name = "two";
ThreadsReply second;
ASSERT_TRUE(SerializeDeserializeReply(initial, &second));
ASSERT_EQ(initial.threads.size(), second.threads.size());
EXPECT_EQ(initial.threads[0].koid, second.threads[0].koid);
EXPECT_EQ(initial.threads[0].name, second.threads[0].name);
EXPECT_EQ(initial.threads[1].koid, second.threads[1].koid);
EXPECT_EQ(initial.threads[1].name, second.threads[1].name);
}
// ReadMemory ------------------------------------------------------------------
TEST(Protocol, ReadMemoryRequest) {
ReadMemoryRequest initial;
initial.process_koid = 91823765;
initial.address = 983462384;
initial.size = 93453926;
ReadMemoryRequest second;
ASSERT_TRUE(SerializeDeserializeRequest(initial, &second));
EXPECT_EQ(initial.process_koid, second.process_koid);
EXPECT_EQ(initial.address, second.address);
EXPECT_EQ(initial.size, second.size);
}
TEST(Protocol, ReadMemoryReply) {
ReadMemoryReply initial;
initial.blocks.resize(2);
initial.blocks[0].address = 876234;
initial.blocks[0].valid = true;
initial.blocks[0].size = 12;
for (uint64_t i = 0; i < initial.blocks[0].size; i++)
initial.blocks[0].data.push_back(static_cast<uint8_t>(i));
initial.blocks[1].address = 89362454;
initial.blocks[1].valid = false;
initial.blocks[1].size = 0;
ReadMemoryReply second;
ASSERT_TRUE(SerializeDeserializeReply(initial, &second));
ASSERT_EQ(initial.blocks.size(), second.blocks.size());
EXPECT_EQ(initial.blocks[0].address, second.blocks[0].address);
EXPECT_EQ(initial.blocks[0].valid, second.blocks[0].valid);
EXPECT_EQ(initial.blocks[0].size, second.blocks[0].size);
EXPECT_EQ(second.blocks[0].size, second.blocks[0].data.size());
for (uint64_t i = 0; i < second.blocks[0].size; i++)
EXPECT_EQ(static_cast<uint8_t>(i), second.blocks[0].data[i]);
EXPECT_EQ(initial.blocks[1].address, second.blocks[1].address);
EXPECT_EQ(initial.blocks[1].valid, second.blocks[1].valid);
EXPECT_EQ(initial.blocks[1].size, second.blocks[1].size);
EXPECT_TRUE(second.blocks[1].data.empty());
}
// AddOrChangeBreakpoint -------------------------------------------------------
TEST(Protocol, AddOrChangeBreakpointRequest) {
AddOrChangeBreakpointRequest initial;
initial.process_koid = 1234;
initial.breakpoint.breakpoint_id = 8976;
initial.breakpoint.thread_koid = 14612;
initial.breakpoint.address = 0x723456234;
initial.breakpoint.stop = debug_ipc::Stop::kProcess;
AddOrChangeBreakpointRequest second;
ASSERT_TRUE(SerializeDeserializeRequest(initial, &second));
EXPECT_EQ(initial.process_koid, second.process_koid);
EXPECT_EQ(initial.breakpoint.breakpoint_id, second.breakpoint.breakpoint_id);
EXPECT_EQ(initial.breakpoint.thread_koid, second.breakpoint.thread_koid);
EXPECT_EQ(initial.breakpoint.address, second.breakpoint.address);
EXPECT_EQ(initial.breakpoint.stop, second.breakpoint.stop);
}
TEST(Protocol, AddOrChangeBreakpointReply) {
AddOrChangeBreakpointReply initial;
initial.status = 78;
initial.error_message = "foo bar";
AddOrChangeBreakpointReply second;
ASSERT_TRUE(SerializeDeserializeReply(initial, &second));
EXPECT_EQ(initial.status, second.status);
EXPECT_EQ(initial.error_message, second.error_message);
}
// RemoveBreakpoint ------------------------------------------------------------
TEST(Protocol, RemoveBreakpointRequest) {
RemoveBreakpointRequest initial;
initial.process_koid = 1234;
initial.breakpoint_id = 8976;
RemoveBreakpointRequest second;
ASSERT_TRUE(SerializeDeserializeRequest(initial, &second));
EXPECT_EQ(initial.process_koid, second.process_koid);
EXPECT_EQ(initial.breakpoint_id, second.breakpoint_id);
}
TEST(Protocol, RemoveBreakpointReply) {
RemoveBreakpointReply initial;
RemoveBreakpointReply second;
ASSERT_TRUE(SerializeDeserializeReply(initial, &second));
}
// Backtrace -------------------------------------------------------------------
TEST(Protocol, BacktraceRequest) {
BacktraceRequest initial;
initial.process_koid = 1234;
initial.thread_koid = 8976;
BacktraceRequest second;
ASSERT_TRUE(SerializeDeserializeRequest(initial, &second));
EXPECT_EQ(initial.process_koid, second.process_koid);
EXPECT_EQ(initial.thread_koid, second.thread_koid);
}
TEST(Protocol, BacktraceReply) {
BacktraceReply initial;
initial.frames.resize(2);
initial.frames[0].ip = 1234;
initial.frames[0].sp = 9875;
initial.frames[1].ip = 71562341;
initial.frames[1].sp = 89236413;
BacktraceReply second;
ASSERT_TRUE(SerializeDeserializeReply(initial, &second));
EXPECT_EQ(2u, second.frames.size());
EXPECT_EQ(initial.frames[0].ip, second.frames[0].ip);
EXPECT_EQ(initial.frames[0].sp, second.frames[0].sp);
EXPECT_EQ(initial.frames[1].ip, second.frames[1].ip);
EXPECT_EQ(initial.frames[1].sp, second.frames[1].sp);
}
// Modules ---------------------------------------------------------------------
TEST(Protocol, ModulesRequest) {
ModulesRequest initial;
initial.process_koid = 1234;
ModulesRequest second;
ASSERT_TRUE(SerializeDeserializeRequest(initial, &second));
EXPECT_EQ(initial.process_koid, second.process_koid);
}
TEST(Protocol, ModulesReply) {
ModulesReply initial;
initial.modules.resize(2);
initial.modules[0].name = "winnt.dll";
initial.modules[0].base = 0x1234567890;
initial.modules[1].name = "libncurses.so.1.0.0";
initial.modules[1].base = 0x1000;
ModulesReply second;
ASSERT_TRUE(SerializeDeserializeReply(initial, &second));
EXPECT_EQ(2u, second.modules.size());
EXPECT_EQ(initial.modules[0].name, second.modules[0].name);
EXPECT_EQ(initial.modules[0].base, second.modules[0].base);
EXPECT_EQ(initial.modules[1].name, second.modules[1].name);
EXPECT_EQ(initial.modules[1].base, second.modules[1].base);
}
// Notifications ---------------------------------------------------------------
TEST(Protocol, NotifyThread) {
NotifyThread initial;
initial.process_koid = 9887;
initial.record.koid = 1234;
initial.record.name = "Wolfgang";
initial.record.state = ThreadRecord::State::kDying;
MessageWriter writer;
WriteNotifyThread(MsgHeader::Type::kNotifyThreadStarting, initial, &writer);
MessageReader reader(writer.MessageComplete());
NotifyThread second;
ASSERT_TRUE(ReadNotifyThread(&reader, &second));
EXPECT_EQ(initial.process_koid, second.process_koid);
EXPECT_EQ(initial.record.koid, second.record.koid);
EXPECT_EQ(initial.record.name, second.record.name);
EXPECT_EQ(initial.record.state, second.record.state);
}
TEST(Protocol, NotifyException) {
NotifyException initial;
initial.process_koid = 23;
initial.thread.name = "foo";
initial.type = NotifyException::Type::kHardware;
initial.frame.ip = 0x7647342634;
initial.frame.sp = 0x9861238251;
NotifyException second;
ASSERT_TRUE(SerializeDeserializeNotification(
initial, &second, &WriteNotifyException, &ReadNotifyException));
EXPECT_EQ(initial.process_koid, second.process_koid);
EXPECT_EQ(initial.thread.name, second.thread.name);
EXPECT_EQ(initial.type, second.type);
EXPECT_EQ(initial.frame.ip, second.frame.ip);
EXPECT_EQ(initial.frame.sp, second.frame.sp);
}
} // namespace debug_ipc