blob: f39675c13ee87c53f7d2120910cb97c1bff56391 [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 <sstream>
#include "tools/fidlcat/lib/code_generator/test_generator.h"
namespace fidlcat {
void CodeGenerator::GenerateIncludes(fidl_codec::PrettyPrinter& printer) {
printer << "#include <lib/async-loop/cpp/loop.h>\n";
printer << "#include <lib/async-loop/default.h>\n";
printer << "#include <lib/async/default.h>\n";
printer << "#include <lib/syslog/cpp/macros.h>\n";
printer << '\n';
printer << "#include <gtest/gtest.h>\n";
printer << '\n';
printer << "#include \"lib/sys/cpp/component_context.h\"\n";
printer << '\n';
GenerateFidlIncludes(printer);
printer << '\n';
}
void CodeGenerator::GenerateFidlIncludes(fidl_codec::PrettyPrinter& printer) {
for (const auto& fidl_include : fidl_headers_) {
printer << "#include <" << fidl_include << ">\n";
}
}
std::unique_ptr<FidlCallInfo> OutputEventToFidlCallInfo(OutputEvent* output_event) {
const Syscall* syscall = output_event->syscall();
SyscallKind syscall_kind = syscall->kind();
// We are only interested in FIDL calls
switch (syscall_kind) {
case SyscallKind::kChannelRead:
case SyscallKind::kChannelWrite:
case SyscallKind::kChannelCall:
break;
default:
return nullptr;
}
// We inspect the message to extract
// "interface name", "method name" and "message content".
// Based on the system call, this could be in either of output event or invoked event.
const fidl_codec::InterfaceMethod* method = nullptr;
zx_txid_t txid;
switch (syscall_kind) {
case SyscallKind::kChannelRead:
method = output_event->GetMessage()->method();
txid = output_event->GetMessage()->txid();
break;
case SyscallKind::kChannelWrite:
case SyscallKind::kChannelCall:
method = output_event->invoked_event()->GetMessage()->method();
txid = output_event->invoked_event()->GetMessage()->txid();
break;
default:
return nullptr;
break;
}
if (method == nullptr) {
// TODO(nimaj): investigate why this happens for zx_channel_read and zx_channel_write
// We will not be able to determine method name nor interface name
return nullptr;
}
const fidl_codec::PayloadableValue* decoded_input_value = nullptr;
const fidl_codec::PayloadableValue* decoded_output_value = nullptr;
switch (syscall_kind) {
case SyscallKind::kChannelWrite:
decoded_input_value = output_event->invoked_event()->GetMessage()->decoded_request();
if (!decoded_input_value) {
// monitored process is a server; event is a response sent by server
decoded_input_value = output_event->invoked_event()->GetMessage()->decoded_response();
}
break;
case SyscallKind::kChannelRead:
decoded_output_value = output_event->GetMessage()->decoded_response();
if (!decoded_output_value) {
// monitored process is a server; event is a request received by the server
decoded_output_value = output_event->GetMessage()->decoded_request();
}
break;
case SyscallKind::kChannelCall:
decoded_input_value = output_event->invoked_event()->GetMessage()->decoded_request();
if (decoded_input_value && output_event->GetMessage() != nullptr) {
decoded_output_value = output_event->GetMessage()->decoded_response();
}
break;
default:
return nullptr;
break;
}
// Extract handle information from output event in 2 steps:
// (1/2) Find handle's struct member
const fidl_codec::StructMember* handle_member = syscall->SearchInlineMember("handle", true);
// (2/2) Lookup handle's struct member in invoked_event
const fidl_codec::HandleValue* handle =
output_event->invoked_event()->GetHandleValue(handle_member);
zx_handle_t handle_id = handle->handle().handle;
bool crashed = output_event->returned_value() == ZX_ERR_PEER_CLOSED;
return std::make_unique<FidlCallInfo>(
crashed, method->enclosing_interface().name(), handle_id, txid, syscall_kind, method->name(),
method->request(), method->response(), decoded_input_value, decoded_output_value);
}
std::string FidlMethodToIncludePath(std::string_view identifier) {
std::string result = std::string(identifier.substr(0, identifier.find('/')));
std::replace(result.begin(), result.end(), '.', '/');
result.append("/cpp/fidl.h");
return result;
}
std::string ToSnakeCase(std::string_view str) {
std::ostringstream result;
std::string separator = "";
for (char c : str) {
if (c == '.' || c == '/') {
result << separator;
} else if (isupper(c)) {
result << separator << static_cast<char>(std::tolower(c));
separator = "";
} else {
result << c;
separator = "_";
}
}
return result.str();
}
} // namespace fidlcat