blob: 44651b08f4fb71962551a8ce9e460c12b762b936 [file] [log] [blame]
// Copyright 2019 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/bin/insntrace/ktrace_controller.h"
#include <errno.h>
#include <fcntl.h>
#include <lib/fdio/directory.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/zircon-internal/ktrace.h>
#include <lib/zx/channel.h>
#include <unistd.h>
#include <zircon/status.h>
#include <fbl/unique_fd.h>
#include "garnet/bin/insntrace/utils.h"
#include "garnet/lib/debugger_utils/util.h"
#include "src/lib/fxl/strings/string_printf.h"
namespace insntrace {
constexpr char kKtraceControllerSvc[] = "/svc/fuchsia.tracing.kernel.Controller";
constexpr char kKtraceReaderSvc[] = "/svc/fuchsia.tracing.kernel.Reader";
zx_status_t OpenKtraceControllerChannel(
fuchsia::tracing::kernel::ControllerSyncPtr* out_controller_ptr) {
zx_status_t status = fdio_service_connect(
kKtraceControllerSvc, out_controller_ptr->NewRequest().TakeChannel().release());
if (status != ZX_OK) {
FX_LOGS(ERROR) << "Error connecting to " << kKtraceControllerSvc << ": " << status;
return status;
}
return status;
}
zx_status_t OpenKtraceReaderChannel(fuchsia::tracing::kernel::ReaderSyncPtr* out_reader_ptr) {
zx_status_t status =
fdio_service_connect(kKtraceReaderSvc, out_reader_ptr->NewRequest().TakeChannel().release());
if (status != ZX_OK) {
FX_LOGS(ERROR) << "Error connecting to " << kKtraceReaderSvc << ": " << status;
return status;
}
return status;
}
bool RequestKtraceStart(const fuchsia::tracing::kernel::ControllerSyncPtr& ktrace,
uint32_t group_mask) {
zx_status_t start_status;
zx_status_t status = ktrace->Start(group_mask, &start_status);
LogFidlFailure("Ktrace start", status, start_status);
return status == ZX_OK && start_status == ZX_OK;
}
void RequestKtraceStop(const fuchsia::tracing::kernel::ControllerSyncPtr& ktrace) {
zx_status_t stop_status;
zx_status_t status = ktrace->Stop(&stop_status);
LogFidlFailure("Ktrace stop", status, stop_status);
}
void RequestKtraceRewind(const fuchsia::tracing::kernel::ControllerSyncPtr& ktrace) {
zx_status_t rewind_status;
zx_status_t status = ktrace->Rewind(&rewind_status);
LogFidlFailure("Ktrace rewind", status, rewind_status);
}
void DumpKtraceBuffer(const char* output_path_prefix, const char* output_path_suffix) {
fuchsia::tracing::kernel::ReaderSyncPtr ktrace;
if (OpenKtraceReaderChannel(&ktrace) != ZX_OK) {
return;
}
std::string ktrace_output_path =
fxl::StringPrintf("%s.%s", output_path_prefix, output_path_suffix);
const char* ktrace_c_path = ktrace_output_path.c_str();
fbl::unique_fd dest_fd(open(ktrace_c_path, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR));
if (dest_fd.is_valid()) {
std::vector<uint8_t> buf;
size_t read_size = 1024;
size_t offset = 0;
zx_status_t out_status;
zx_status_t status;
while ((status = ktrace->ReadAt(read_size, offset, &out_status, &buf)) == ZX_OK &&
out_status == ZX_OK) {
if (buf.size() == 0) {
break;
}
size_t bytes_written = write(dest_fd.get(), buf.data(), buf.size());
if (bytes_written != buf.size()) {
FX_LOGS(ERROR) << "error writing " << ktrace_c_path;
break;
}
offset += buf.size();
}
} else {
FX_LOGS(ERROR) << fxl::StringPrintf("unable to create %s", ktrace_c_path)
<< ", errno=" << debugger_utils::ErrnoString(errno);
}
}
} // namespace insntrace