blob: 382f12e270cb2a74eb5d7f8bd8f8aa894035c101 [file] [log] [blame]
// Copyright 2020 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 <cstdint>
#include <ctime>
#include <memory>
#include <sstream>
#include <vector>
#include <gtest/gtest.h>
#include "tools/fidlcat/interception_tests/test_library.h"
#include "tools/fidlcat/lib/event.h"
#include "tools/fidlcat/lib/syscall_decoder_dispatcher.h"
#include "tools/fidlcat/proto/session.pb.h"
namespace fidlcat {
#define kPid 1234
#define kTid 5678
#define kHandle0 0xabcd
#define kHandle1 0xbeef
constexpr int64_t kEventTimestamp = 0;
constexpr int64_t kEventTimestampInvoked = 10000000;
constexpr int64_t kEventTimestampOutput = 20000000;
class ProtoEventTest : public ::testing::Test {
protected:
ProtoEventTest() {
loader_ = GetTestLibraryLoader();
EXPECT_NE(loader_, nullptr);
decode_options_.output_mode = OutputMode::kStandard;
dispatcher_ =
std::make_unique<SyscallDisplayDispatcher>(loader_, decode_options_, display_options_, ss_);
Process* process = dispatcher_->CreateProcess("my_process.cmx", kPid, nullptr);
dispatcher_->CreateThread(kTid, process);
}
fidl_codec::LibraryLoader* loader() const { return loader_; }
SyscallDisplayDispatcher* dispatcher() const { return dispatcher_.get(); }
std::string GetResult() {
std::string result = ss_.str();
ss_.str("");
return result;
}
private:
fidl_codec::LibraryLoader* loader_ = nullptr;
DecodeOptions decode_options_;
DisplayOptions display_options_;
std::stringstream ss_;
std::unique_ptr<SyscallDisplayDispatcher> dispatcher_;
};
#define TEST_PROTO_EVENT(name, event, expected) \
TEST_F(ProtoEventTest, name) { \
proto::Event proto_event; \
(event)->Write(&proto_event); \
EventDecoder decoder(dispatcher()); \
bool ok = decoder.DecodeAndDispatchEvent(proto_event); \
ASSERT_TRUE(ok); \
std::string result = GetResult(); \
ASSERT_EQ(result, expected); \
}
TEST_PROTO_EVENT(ProcessLaunchedFailed,
std::make_shared<ProcessLaunchedEvent>(kEventTimestamp, "run my_command",
"failed to run"),
"\n0 Can't launch run my_command : failed to run\n")
TEST_PROTO_EVENT(ProcessLaunchedOk,
std::make_shared<ProcessLaunchedEvent>(kEventTimestamp, "run my_command", ""),
"\n0 Launched run my_command\n")
TEST_PROTO_EVENT(ProcessMonitoredFailed,
std::make_shared<ProcessMonitoredEvent>(kEventTimestamp,
dispatcher()->SearchProcess(kPid),
"got an error"),
"\n0 Can't monitor my_process.cmx koid=1234 : got an error\n")
TEST_PROTO_EVENT(ProcessMonitoredOk,
std::make_shared<ProcessMonitoredEvent>(kEventTimestamp,
dispatcher()->SearchProcess(kPid), ""),
"\n0 Monitoring my_process.cmx koid=1234\n")
TEST_PROTO_EVENT(StopMonitoring,
std::make_shared<StopMonitoringEvent>(kEventTimestamp,
dispatcher()->SearchProcess(kPid)),
"\n0 Stop monitoring my_process.cmx koid 1234\n")
TEST_F(ProtoEventTest, InvokedAndOutputEvent) {
Syscall* syscall = dispatcher()->SearchSyscall("zx_channel_create");
auto invoked_event = std::make_shared<InvokedEvent>(kEventTimestampInvoked,
dispatcher()->SearchThread(kTid), syscall);
invoked_event->AddInlineField(syscall->SearchInlineMember("options", /*invoked=*/true),
std::make_unique<fidl_codec::IntegerValue>(0, false));
auto output_event = std::make_shared<OutputEvent>(
kEventTimestampOutput, dispatcher()->SearchThread(kTid), syscall, ZX_OK, invoked_event);
zx_handle_disposition_t handle_0 = {.operation = fidl_codec::kNoHandleDisposition,
.handle = kHandle0,
.type = ZX_OBJ_TYPE_CHANNEL,
.rights = 0,
.result = ZX_OK};
zx_handle_disposition_t handle_1 = {.operation = fidl_codec::kNoHandleDisposition,
.handle = kHandle1,
.type = ZX_OBJ_TYPE_CHANNEL,
.rights = 0,
.result = ZX_OK};
output_event->AddInlineField(syscall->SearchInlineMember("out0", /*invoked=*/false),
std::make_unique<fidl_codec::HandleValue>(handle_0));
output_event->AddInlineField(syscall->SearchInlineMember("out1", /*invoked=*/false),
std::make_unique<fidl_codec::HandleValue>(handle_1));
proto::Event proto_invoked_event;
invoked_event->Write(&proto_invoked_event);
proto::Event proto_output_event;
output_event->Write(&proto_output_event);
EventDecoder decoder(dispatcher());
bool ok = decoder.DecodeAndDispatchEvent(proto_invoked_event);
ASSERT_TRUE(ok);
ok = decoder.DecodeAndDispatchEvent(proto_output_event);
ASSERT_TRUE(ok);
std::string result = GetResult();
ASSERT_EQ(
result,
"\n"
"0.010000 my_process.cmx 1234:5678 zx_channel_create(options: uint32 = 0)\n"
"0.020000 -> ZX_OK (out0: handle = Channel:0000abcd, out1: handle = Channel:0000beef)\n");
}
TEST_F(ProtoEventTest, Exception) {
auto event = std::make_shared<ExceptionEvent>(kEventTimestamp, dispatcher()->SearchThread(kTid));
event->stack_frame().emplace_back(Location("tools/fidlcat/main.cc", 10, 20, 0x123456789, "main"));
event->stack_frame().emplace_back(
Location("tools/fidlcat/foo.cc", 100, 2, 0xabcdef012345, "foo"));
proto::Event proto_event;
event->Write(&proto_event);
EventDecoder decoder(dispatcher());
bool ok = decoder.DecodeAndDispatchEvent(proto_event);
ASSERT_TRUE(ok);
std::string result = GetResult();
ASSERT_EQ(result,
"\n"
"0.000000 my_process.cmx 1234:5678 at tools/fidlcat/main.cc:10:20 main\n"
"0.000000 my_process.cmx 1234:5678 at tools/fidlcat/foo.cc:100:2 foo\n"
"0.000000 my_process.cmx 1234:5678 thread stopped on exception\n");
}
} // namespace fidlcat