blob: 0abc04efd784731aa9458fd2c81c7cadfb7126b8 [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 "tools/fidlcat/lib/replay.h"
#include <fstream>
#include <memory>
#include <string>
#include <vector>
#include "src/lib/fidl_codec/proto_value.h"
#include "src/lib/fidl_codec/semantic.h"
#include "tools/fidlcat/lib/event.h"
#include "tools/fidlcat/lib/syscall_decoder_dispatcher.h"
#include "tools/fidlcat/proto/session.pb.h"
namespace fidlcat {
bool Replay::DumpProto(const std::string& proto_file_name) {
if (proto_file_name == "-") {
return DumpProto(std::cin);
}
std::fstream input(proto_file_name, std::ios::in | std::ios::binary);
if (input.fail()) {
FX_LOGS(ERROR) << "Can't open <" << proto_file_name << "> for reading.";
return false;
}
if (!DumpProto(input)) {
FX_LOGS(ERROR) << "Failed to parse session from file <" << proto_file_name << ">.";
return false;
}
return true;
}
bool Replay::DumpProto(std::istream& is) {
proto::Session session;
if (!session.ParseFromIstream(&is)) {
return false;
}
std::cout << session.DebugString();
return true;
}
bool Replay::ReplayProto(const std::string& proto_file_name) {
if (proto_file_name == "-") {
return ReplayProto("standard input", std::cin);
}
std::fstream input(proto_file_name, std::ios::in | std::ios::binary);
if (input.fail()) {
FX_LOGS(ERROR) << "Can't open <" << proto_file_name << "> for reading.";
return false;
}
return ReplayProto("file <" + proto_file_name + ">", input);
}
bool Replay::ReplayProto(const std::string& file_name, std::istream& is) {
proto::Session session;
if (!session.ParseFromIstream(&is)) {
FX_LOGS(ERROR) << "Failed to parse session from " << file_name << ".";
return false;
}
bool ok = true;
for (int index = 0; index < session.process_size(); ++index) {
const proto::Process& process = session.process(index);
if (dispatcher()->SearchProcess(process.koid()) != nullptr) {
FX_LOGS(INFO) << "Error reading protobuf " << file_name << ": process " << process.name()
<< " koid=" << process.koid() << " defined multiple times.";
ok = false;
} else {
dispatcher()->CreateProcess(process.name(), process.koid(), nullptr);
for (int handle_index = 0; handle_index < process.linked_handles_size(); ++handle_index) {
const proto::LinkedHandles& linked_handles = process.linked_handles(handle_index);
dispatcher()->inference().AddLinkedHandles(process.koid(), linked_handles.handle_0(),
linked_handles.handle_1());
}
}
}
for (int index = 0; index < session.thread_size(); ++index) {
const proto::Thread& thread = session.thread(index);
if (dispatcher()->SearchThread(thread.koid()) != nullptr) {
FX_LOGS(INFO) << "Error reading protobuf " << file_name << ": thread " << thread.koid()
<< " defined multiple times.";
ok = false;
} else {
Process* process = dispatcher()->SearchProcess(thread.process_koid());
if (process == nullptr) {
FX_LOGS(ERROR) << "Error reading protobuf " << file_name << ": process "
<< thread.process_koid() << " not found for thread " << thread.koid() << '.';
ok = false;
}
dispatcher()->CreateThread(thread.koid(), process);
}
}
for (int index = 0; index < session.handle_description_size(); ++index) {
const proto::HandleDescription& proto_handle_description = session.handle_description(index);
Thread* thread = dispatcher()->SearchThread(proto_handle_description.thread_koid());
if (thread == nullptr) {
FX_LOGS(ERROR) << "Error reading protobuf file " << file_name << ": thread "
<< proto_handle_description.thread_koid() << " not found for handle.";
ok = false;
} else {
HandleInfo* handle_info = dispatcher()->CreateHandleInfo(
thread, proto_handle_description.handle(), proto_handle_description.creation_time(),
proto_handle_description.startup());
handle_info->set_object_type(proto_handle_description.object_type());
handle_info->set_koid(proto_handle_description.koid());
dispatcher()->inference().AddKoidHandleInfo(proto_handle_description.koid(), handle_info);
}
auto inferred_handle_info = std::make_unique<fidl_codec::semantic::InferredHandleInfo>(
proto_handle_description.type(), proto_handle_description.fd(),
proto_handle_description.path(), proto_handle_description.attributes());
dispatcher()->inference().AddInferredHandleInfo(thread->process()->koid(),
proto_handle_description.handle(),
std::move(inferred_handle_info));
}
for (int index = 0; index < session.linked_koids_size(); ++index) {
const proto::LinkedKoids& linked_koids = session.linked_koids(index);
dispatcher()->inference().AddLinkedKoids(linked_koids.koid_0(), linked_koids.koid_1());
}
for (int index = 0; index < session.event_size(); ++index) {
const proto::Event& proto_event = session.event(index);
if (!DecodeAndDispatchEvent(proto_event)) {
ok = false;
}
}
return ok;
}
} // namespace fidlcat