blob: ada7930e37c537c3e21876d927fe43967454e6ea [file] [log] [blame]
// Copyright 2022 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 <errno.h>
#include <fcntl.h>
#include <fidl/fuchsia.boot/cpp/markers.h>
#include <fidl/fuchsia.boot/cpp/wire.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/fdio/directory.h>
#include <lib/fidl/cpp/interface_request.h>
#include <lib/fidl/cpp/wire/client.h>
#include <lib/fidl/cpp/wire/connect_service.h>
#include <lib/fidl/cpp/wire/internal/transport_channel.h>
#include <lib/sys/cpp/component_context.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/vfs/cpp/pseudo_dir.h>
#include <lib/zx/channel.h>
#include <string.h>
#include <zircon/errors.h>
#include <zircon/status.h>
#include <memory>
#include <fbl/unique_fd.h>
#include "src/lib/fxl/command_line.h"
#include "src/lib/fxl/log_settings_command_line.h"
#include "src/sys/early_boot_instrumentation/coverage_source.h"
int main(int argc, char** argv) {
static const std::string static_dir_name(early_boot_instrumentation::kStaticDir);
static const std::string dynamic_dir_name(early_boot_instrumentation::kDynamicDir);
const auto command_line = fxl::CommandLineFromArgcArgv(argc, argv);
fxl::SetLogSettingsFromCommandLine(command_line, {"early-boot-instrumentation"});
async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
auto context = sys::ComponentContext::CreateAndServeOutgoingDirectory();
// Add prof_data dir.
early_boot_instrumentation::SinkDirMap sink_map;
// All but llvm-profile data until its unified.
auto debug_data = context->outgoing()->GetOrCreateDirectory("debugdata");
// Get the SvcStash server end.
zx::channel provider_client, provider_server;
if (auto res = zx::channel::create(0, &provider_client, &provider_server); res != ZX_OK) {
FX_LOGS(ERROR) << "Could not create channel for fuchsia.boot.SvcStashProvider. "
<< zx_status_get_string(res);
} else if (auto res = fdio_service_connect(
fidl::DiscoverableProtocolDefaultPath<fuchsia_boot::SvcStashProvider>,
provider_server.release());
res != ZX_OK) {
FX_LOGS(ERROR) << "Could not obtain handle to fuchsia.boot.SvcStashProvider. "
<< zx_status_get_string(res);
} else { // Successfully connected to the service.
fidl::WireSyncClient<fuchsia_boot::SvcStashProvider> provider_fidl_client;
fidl::ClientEnd<fuchsia_boot::SvcStashProvider> provider_client_end(std::move(provider_client));
provider_fidl_client.Bind(std::move(provider_client_end));
auto get_response = provider_fidl_client->Get();
if (get_response->is_ok()) {
auto& stash_svc = get_response->value()->resource;
sink_map = early_boot_instrumentation::ExtractDebugData(stash_svc.channel().borrow());
}
}
// Even if we fail to populate from the sources, we expose empty directories,
// such that the contract remains.
fbl::unique_fd kernel_data_dir(open("/boot/kernel/data", O_RDONLY));
if (!kernel_data_dir) {
const char* err = strerror(errno);
FX_LOGS(ERROR) << "Could not obtain handle to '/boot/kernel/data'. " << err;
}
if (auto res = early_boot_instrumentation::ExposeKernelProfileData(kernel_data_dir, sink_map);
res.is_error()) {
FX_LOGS(ERROR) << "Could not expose kernel profile data. " << res.status_value();
}
fbl::unique_fd phys_data_dir(open("/boot/kernel/data/phys", O_RDONLY));
if (!phys_data_dir) {
const char* err = strerror(errno);
FX_LOGS(ERROR) << "Could not obtain handle to '/boot/kernel/data/phys'. " << err;
}
if (auto res = early_boot_instrumentation::ExposePhysbootProfileData(phys_data_dir, sink_map);
res.is_error()) {
FX_LOGS(ERROR) << "Could not expose physboot profile data. " << res.status_value();
}
for (auto& [sink, root] : sink_map) {
debug_data->AddEntry(sink, std::move(root));
}
sink_map.clear();
loop.Run();
return 0;
}