| // 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/user_copy/user_ptr.h> |
| #include <lib/ktrace.h> |
| #include <lib/mtrace.h> |
| #include <lib/io.h> |
| #include <object/handle_owner.h> |
| #include <object/process_dispatcher.h> |
| #include <object/resources.h> |
| |
| #include <platform/debug.h> |
| |
| #include <zircon/syscalls/debug.h> |
| |
| #include "syscalls_priv.h" |
| |
| #define LOCAL_TRACE 0 |
| |
| constexpr uint32_t kMaxDebugWriteSize = 256u; |
| |
| zx_status_t sys_debug_read(zx_handle_t handle, user_ptr<void> ptr, uint32_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; |
| } |
| |
| // TODO: remove this cast. |
| auto uptr = ptr.reinterpret<uint8_t>(); |
| |
| uint32_t idx = 0; |
| for (; idx < len; ++idx) { |
| int c = getchar(); |
| if (c < 0) |
| break; |
| |
| if (c == '\r') |
| c = '\n'; |
| |
| auto cur = uptr.byte_offset(idx); |
| if (cur.copy_to_user(static_cast<uint8_t>(c)) != ZX_OK) |
| break; |
| } |
| // TODO: fix this cast, which can overflow. |
| return static_cast<zx_status_t>(idx); |
| } |
| |
| zx_status_t sys_debug_write(user_ptr<const void> ptr, uint32_t len) { |
| LTRACEF("ptr %p, len %u\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; |
| |
| __kernel_serial_write(buf, len); |
| |
| return len; |
| } |
| |
| zx_status_t sys_debug_send_command(zx_handle_t handle, user_ptr<const void> ptr, uint32_t len) { |
| LTRACEF("ptr %p, len %u\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 sys_ktrace_read(zx_handle_t handle, user_ptr<void> _data, |
| uint32_t offset, uint32_t len, |
| user_ptr<uint32_t> _actual) { |
| // TODO(ZX-971): finer grained validation |
| zx_status_t status; |
| if ((status = validate_resource(handle, ZX_RSRC_KIND_ROOT)) < 0) { |
| return status; |
| } |
| |
| int result = ktrace_read_user(_data.get(), offset, len); |
| if (result < 0) |
| return result; |
| |
| return _actual.copy_to_user(static_cast<uint32_t>(result)); |
| } |
| |
| zx_status_t sys_ktrace_control( |
| zx_handle_t handle, uint32_t action, uint32_t options, user_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 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 sys_mtrace_control(zx_handle_t handle, |
| uint32_t kind, uint32_t action, uint32_t options, |
| user_ptr<void> ptr, uint32_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); |
| } |