blob: 3dcafd0fb7cbf1a952925439d7d859a81b814581 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include <err.h>
#include <platform.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <trace.h>
#include <lib/console.h>
#include <lib/debuglog.h>
#include <lib/user_copy/user_ptr.h>
#include <lib/ktrace.h>
#include <lib/mtrace.h>
#include <lib/io.h>
#include <object/handle.h>
#include <object/process_dispatcher.h>
#include <object/resource.h>
#include <platform/debug.h>
#include <zircon/syscalls/debug.h>
#include "priv.h"
#define LOCAL_TRACE 0
constexpr uint32_t kMaxDebugWriteSize = 256u;
// zx_status_t zx_debug_read
zx_status_t sys_debug_read(zx_handle_t handle, user_out_ptr<char> ptr, user_inout_ptr<size_t> len) {
LTRACEF("ptr %p\n", ptr.get());
// TODO(ZX-971): finer grained validation
zx_status_t status;
if ((status = validate_resource(handle, ZX_RSRC_KIND_ROOT)) < 0) {
return status;
}
// get the number of bytes the user wants us to read
size_t readlen;
status = len.copy_from_user(&readlen);
if (status != ZX_OK) {
return status;
}
size_t idx = 0;
for (; idx < readlen; ++idx) {
int intc = getchar();
if (intc < 0) {
return intc;
}
if (intc == '\r') {
intc = '\n';
}
char c = static_cast<char>(intc);
status = ptr.copy_array_to_user(&c, 1, idx);
if (status != ZX_OK) {
return status;
}
}
return len.copy_to_user(idx);
}
// zx_status_t zx_debug_write
zx_status_t sys_debug_write(user_in_ptr<const char> ptr, size_t len) {
LTRACEF("ptr %p, len %zu\n", ptr.get(), len);
if (len > kMaxDebugWriteSize)
len = kMaxDebugWriteSize;
char buf[kMaxDebugWriteSize];
if (ptr.copy_array_from_user(buf, len) != ZX_OK)
return ZX_ERR_INVALID_ARGS;
// This path to serial out arbitrates with the debug log
// drainer and/or kernel ll debug path to minimize interleaving
// of serial output between various sources
dlog_serial_write(buf, len);
return ZX_OK;
}
// zx_status_t zx_debug_send_command
zx_status_t sys_debug_send_command(zx_handle_t handle, user_in_ptr<const char> ptr, size_t len) {
LTRACEF("ptr %p, len %zu\n", ptr.get(), len);
// TODO(ZX-971): finer grained validation
zx_status_t status;
if ((status = validate_resource(handle, ZX_RSRC_KIND_ROOT)) < 0) {
return status;
}
if (len > kMaxDebugWriteSize)
return ZX_ERR_INVALID_ARGS;
char buf[kMaxDebugWriteSize + 2];
if (ptr.copy_array_from_user(buf, len) != ZX_OK)
return ZX_ERR_INVALID_ARGS;
buf[len] = '\n';
buf[len + 1] = 0;
return console_run_script(buf);
}
// zx_status_t zx_ktrace_read
zx_status_t sys_ktrace_read(zx_handle_t handle, user_out_ptr<void> _data,
uint32_t offset, size_t len,
user_out_ptr<size_t> _actual) {
// TODO(ZX-971): finer grained validation
zx_status_t status;
if ((status = validate_resource(handle, ZX_RSRC_KIND_ROOT)) < 0) {
return status;
}
ssize_t result = ktrace_read_user(_data.get(), offset, len);
if (result < 0)
return static_cast<zx_status_t>(result);
return _actual.copy_to_user(static_cast<size_t>(result));
}
// zx_status_t zx_ktrace_control
zx_status_t sys_ktrace_control(
zx_handle_t handle, uint32_t action, uint32_t options, user_inout_ptr<void> _ptr) {
// TODO(ZX-971): finer grained validation
zx_status_t status;
if ((status = validate_resource(handle, ZX_RSRC_KIND_ROOT)) < 0) {
return status;
}
switch (action) {
case KTRACE_ACTION_NEW_PROBE: {
char name[ZX_MAX_NAME_LEN];
if (_ptr.copy_array_from_user(name, sizeof(name) - 1) != ZX_OK)
return ZX_ERR_INVALID_ARGS;
name[sizeof(name) - 1] = 0;
return ktrace_control(action, options, name);
}
default:
return ktrace_control(action, options, nullptr);
}
}
// zx_status_t zx_ktrace_write
zx_status_t sys_ktrace_write(zx_handle_t handle, uint32_t event_id, uint32_t arg0, uint32_t arg1) {
// TODO(ZX-971): finer grained validation
zx_status_t status;
if ((status = validate_resource(handle, ZX_RSRC_KIND_ROOT)) < 0) {
return status;
}
if (event_id > 0x7FF) {
return ZX_ERR_INVALID_ARGS;
}
uint32_t* args = static_cast<uint32_t*>(ktrace_open(TAG_PROBE_24(event_id)));
if (!args) {
// There is not a single reason for failure. Assume it reached the end.
return ZX_ERR_UNAVAILABLE;
}
args[0] = arg0;
args[1] = arg1;
return ZX_OK;
}
// zx_status_t zx_mtrace_control
zx_status_t sys_mtrace_control(zx_handle_t handle,
uint32_t kind, uint32_t action, uint32_t options,
user_inout_ptr<void> ptr, size_t size) {
// TODO(ZX-971): finer grained validation
zx_status_t status;
if ((status = validate_resource(handle, ZX_RSRC_KIND_ROOT)) < 0) {
return status;
}
return mtrace_control(kind, action, options, ptr, size);
}