1// Copyright 2016 The Fuchsia Authors
2//
3// Use of this source code is governed by a MIT-style
4// license that can be found in the LICENSE file or at
5// https://opensource.org/licenses/MIT
6
7#include <err.h>
8#include <platform.h>
9#include <stdint.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <trace.h>
14
15#include <lib/console.h>
16#include <lib/debuglog.h>
17#include <lib/user_copy/user_ptr.h>
18#include <lib/ktrace.h>
19#include <lib/mtrace.h>
20#include <lib/io.h>
21#include <object/handle.h>
22#include <object/process_dispatcher.h>
23#include <object/resource.h>
24
25#include <platform/debug.h>
26
27#include <zircon/syscalls/debug.h>
28
29#include "priv.h"
30
31#define LOCAL_TRACE 0
32
33constexpr uint32_t kMaxDebugWriteSize = 256u;
34
35zx_status_t sys_debug_read(zx_handle_t handle, user_out_ptr<char> ptr, user_inout_ptr<size_t> len) {
36    LTRACEF("ptr %p\n", ptr.get());
37
38    // TODO(ZX-971): finer grained validation
39    zx_status_t status;
40    if ((status = validate_resource(handle, ZX_RSRC_KIND_ROOT)) < 0) {
41        return status;
42    }
43
44    // get the number of bytes the user wants us to read
45    size_t readlen;
46    status = len.copy_from_user(&readlen);
47    if (status != ZX_OK) {
48        return status;
49    }
50
51    size_t idx = 0;
52    for (; idx < readlen; ++idx) {
53        int intc = getchar();
54        if (intc < 0) {
55            return intc;
56        }
57
58        if (intc == '\r') {
59            intc = '\n';
60        }
61
62        char c = static_cast<char>(intc);
63
64        status = ptr.copy_array_to_user(&c, 1, idx);
65        if (status != ZX_OK) {
66            return status;
67        }
68    }
69    return len.copy_to_user(idx);
70}
71
72zx_status_t sys_debug_write(user_in_ptr<const char> ptr, size_t len) {
73    LTRACEF("ptr %p, len %zu\n", ptr.get(), len);
74
75    if (len > kMaxDebugWriteSize)
76        len = kMaxDebugWriteSize;
77
78    char buf[kMaxDebugWriteSize];
79    if (ptr.copy_array_from_user(buf, len) != ZX_OK)
80        return ZX_ERR_INVALID_ARGS;
81
82    // This path to serial out arbitrates with the debug log
83    // drainer and/or kernel ll debug path to minimize interleaving
84    // of serial output between various sources
85    dlog_serial_write(buf, len);
86
87    return ZX_OK;
88}
89
90zx_status_t sys_debug_send_command(zx_handle_t handle, user_in_ptr<const char> ptr, size_t len) {
91    LTRACEF("ptr %p, len %zu\n", ptr.get(), len);
92
93    // TODO(ZX-971): finer grained validation
94    zx_status_t status;
95    if ((status = validate_resource(handle, ZX_RSRC_KIND_ROOT)) < 0) {
96        return status;
97    }
98
99    if (len > kMaxDebugWriteSize)
100        return ZX_ERR_INVALID_ARGS;
101
102    char buf[kMaxDebugWriteSize + 2];
103    if (ptr.copy_array_from_user(buf, len) != ZX_OK)
104        return ZX_ERR_INVALID_ARGS;
105
106    buf[len] = '\n';
107    buf[len + 1] = 0;
108    return console_run_script(buf);
109}
110
111zx_status_t sys_ktrace_read(zx_handle_t handle, user_out_ptr<void> _data,
112                            uint32_t offset, size_t len,
113                            user_out_ptr<size_t> _actual) {
114    // TODO(ZX-971): finer grained validation
115    zx_status_t status;
116    if ((status = validate_resource(handle, ZX_RSRC_KIND_ROOT)) < 0) {
117        return status;
118    }
119
120    ssize_t result = ktrace_read_user(_data.get(), offset, len);
121    if (result < 0)
122        return static_cast<zx_status_t>(result);
123
124    return _actual.copy_to_user(static_cast<size_t>(result));
125}
126
127zx_status_t sys_ktrace_control(
128    zx_handle_t handle, uint32_t action, uint32_t options, user_inout_ptr<void> _ptr) {
129    // TODO(ZX-971): finer grained validation
130    zx_status_t status;
131    if ((status = validate_resource(handle, ZX_RSRC_KIND_ROOT)) < 0) {
132        return status;
133    }
134
135    switch (action) {
136    case KTRACE_ACTION_NEW_PROBE: {
137        char name[ZX_MAX_NAME_LEN];
138        if (_ptr.copy_array_from_user(name, sizeof(name) - 1) != ZX_OK)
139            return ZX_ERR_INVALID_ARGS;
140        name[sizeof(name) - 1] = 0;
141        return ktrace_control(action, options, name);
142    }
143    default:
144        return ktrace_control(action, options, nullptr);
145    }
146}
147
148zx_status_t sys_ktrace_write(zx_handle_t handle, uint32_t event_id, uint32_t arg0, uint32_t arg1) {
149    // TODO(ZX-971): finer grained validation
150    zx_status_t status;
151    if ((status = validate_resource(handle, ZX_RSRC_KIND_ROOT)) < 0) {
152        return status;
153    }
154
155    if (event_id > 0x7FF) {
156        return ZX_ERR_INVALID_ARGS;
157    }
158
159    uint32_t* args = static_cast<uint32_t*>(ktrace_open(TAG_PROBE_24(event_id)));
160    if (!args) {
161        //  There is not a single reason for failure. Assume it reached the end.
162        return ZX_ERR_UNAVAILABLE;
163    }
164
165    args[0] = arg0;
166    args[1] = arg1;
167    return ZX_OK;
168}
169
170zx_status_t sys_mtrace_control(zx_handle_t handle,
171                               uint32_t kind, uint32_t action, uint32_t options,
172                               user_inout_ptr<void> ptr, size_t size) {
173    // TODO(ZX-971): finer grained validation
174    zx_status_t status;
175    if ((status = validate_resource(handle, ZX_RSRC_KIND_ROOT)) < 0) {
176        return status;
177    }
178
179    return mtrace_control(kind, action, options, ptr, size);
180}
181