blob: 25e3a64de0fb129fc641e625400c44e582ab76b3 [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 <fuchsia/tracing/kernel/cpp/fidl.h>
#include <lib/fdio/directory.h>
#include <lib/fidl/cpp/binding.h>
#include <lib/ktrace/ktrace.h>
#include <lib/zircon-internal/ktrace.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <threads.h>
#include <zircon/syscalls.h>
#include <zircon/types.h>
const internal::KTraceSysCalls kKTraceSysCalls{
.ktrace_control = zx_ktrace_control,
.ktrace_read = zx_ktrace_read,
};
namespace ktrace {
class KTrace : public fuchsia::tracing::kernel::Controller,
public fuchsia::tracing::kernel::Reader {
public:
explicit KTrace(zx::resource root_resource)
: controller_(this), reader_(this), root_resource_(std::move(root_resource)) {}
// fuchsia.tracing.kernel.Controller methods
void Start(uint32_t group_mask, StartCallback callback) override;
void Stop(StopCallback callback) override;
void Rewind(RewindCallback callback) override;
zx_status_t BindController(zx::channel channel, async_dispatcher_t* dispatcher);
// fuchsia.tracing.kernel.Reader methods
void ReadAt(uint64_t count, uint64_t offset, ReadAtCallback callback) override;
void GetBytesWritten(GetBytesWrittenCallback callback) override;
zx_status_t BindReader(zx::channel channel, async_dispatcher_t* dispatcher);
void SetKTraceSysCall(internal::KTraceSysCalls sys_calls) { sys_calls_ = sys_calls; }
private:
fidl::Binding<fuchsia::tracing::kernel::Controller> controller_;
fidl::Binding<fuchsia::tracing::kernel::Reader> reader_;
zx::resource root_resource_;
internal::KTraceSysCalls sys_calls_ = kKTraceSysCalls;
};
void KTrace::Start(uint32_t group_mask, StartCallback callback) {
auto status =
sys_calls_.ktrace_control(root_resource_.get(), KTRACE_ACTION_START, group_mask, nullptr);
callback(status);
}
void KTrace::Stop(StopCallback callback) {
auto status = sys_calls_.ktrace_control(root_resource_.get(), KTRACE_ACTION_STOP, 0, nullptr);
callback(status);
}
void KTrace::Rewind(RewindCallback callback) {
auto status = sys_calls_.ktrace_control(root_resource_.get(), KTRACE_ACTION_REWIND, 0, nullptr);
callback(status);
}
zx_status_t KTrace::BindController(zx::channel channel, async_dispatcher_t* dispatcher) {
return controller_.Bind(std::move(channel), dispatcher);
}
void KTrace::GetBytesWritten(GetBytesWrittenCallback callback) {
size_t size = 0;
auto status = sys_calls_.ktrace_read(root_resource_.get(), nullptr, 0, 0, &size);
callback(status, size);
}
void KTrace::ReadAt(uint64_t count, uint64_t offset, ReadAtCallback callback) {
size_t length;
std::vector<uint8_t> buf(count);
zx_status_t status =
sys_calls_.ktrace_read(root_resource_.get(), buf.data(), offset, count, &length);
buf.resize(length);
callback(status, std::move(buf));
}
zx_status_t KTrace::BindReader(zx::channel channel, async_dispatcher_t* dispatcher) {
return reader_.Bind(std::move(channel), dispatcher);
}
} // namespace ktrace
// Method should be called only from test to override syscall
zx_status_t internal::OverrideKTraceSysCall(void* ctx, KTraceSysCalls sys_calls) {
ktrace::KTrace* ktrace = static_cast<ktrace::KTrace*>(ctx);
if (ktrace == nullptr) {
return ZX_ERR_INVALID_ARGS;
}
ktrace->SetKTraceSysCall(sys_calls);
return ZX_OK;
}
namespace {
zx_status_t Init(void** out_ctx) {
zx::resource root_resource(static_cast<zx_handle_t>(reinterpret_cast<uintptr_t>(*out_ctx)));
*out_ctx = new ktrace::KTrace(std::move(root_resource));
return ZX_OK;
}
zx_status_t Connect(void* ctx, async_dispatcher_t* dispatcher, const char* service_name,
zx_handle_t request) {
if (!strcmp(service_name, fuchsia::tracing::kernel::Controller::Name_)) {
ktrace::KTrace* ktrace = static_cast<ktrace::KTrace*>(ctx);
return ktrace->BindController(zx::channel(request), dispatcher);
}
if (!strcmp(service_name, fuchsia::tracing::kernel::Reader::Name_)) {
ktrace::KTrace* ktrace = static_cast<ktrace::KTrace*>(ctx);
return ktrace->BindReader(zx::channel(request), dispatcher);
}
zx_handle_close(request);
return ZX_ERR_NOT_SUPPORTED;
}
void Release(void* ctx) { delete static_cast<ktrace::KTrace*>(ctx); }
constexpr const char* kServices[] = {
fuchsia::tracing::kernel::Controller::Name_,
fuchsia::tracing::kernel::Reader::Name_,
nullptr,
};
constexpr zx_service_ops_t kServiceOps = {
.init = Init,
.connect = Connect,
.release = Release,
};
constexpr zx_service_provider_t kKTraceServiceProvider = {
.version = SERVICE_PROVIDER_VERSION,
.services = kServices,
.ops = &kServiceOps,
};
} // namespace
const zx_service_provider_t* ktrace_get_service_provider() { return &kKTraceServiceProvider; }