1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <ddk/binding.h>
6 #include <ddk/device.h>
7 #include <ddk/driver.h>
8 
9 #include <lib/zircon-internal/ktrace.h>
10 #include <zircon/syscalls.h>
11 #include <zircon/types.h>
12 
13 #include <zircon/device/ktrace.h>
14 
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <threads.h>
19 
ktrace_read(void * ctx,void * buf,size_t count,zx_off_t off,size_t * actual)20 static zx_status_t ktrace_read(void* ctx, void* buf, size_t count, zx_off_t off, size_t* actual) {
21     size_t length;
22     zx_status_t status = zx_ktrace_read(get_root_resource(), buf, off, count, &length);
23     if (status == ZX_OK) {
24         *actual = length;
25     }
26     return status;
27 }
28 
ktrace_get_size(void * ctx)29 static zx_off_t ktrace_get_size(void* ctx) {
30     size_t size;
31     zx_status_t status = zx_ktrace_read(get_root_resource(), NULL, 0, 0, &size);
32     return status != ZX_OK ? (zx_off_t)status : (zx_off_t)size;
33 }
34 
ktrace_ioctl(void * ctx,uint32_t op,const void * cmd,size_t cmdlen,void * reply,size_t max,size_t * out_actual)35 static zx_status_t ktrace_ioctl(void* ctx, uint32_t op,
36                             const void* cmd, size_t cmdlen,
37                             void* reply, size_t max, size_t* out_actual) {
38     switch (op) {
39     case IOCTL_KTRACE_GET_HANDLE: {
40         if (max < sizeof(zx_handle_t)) {
41             return ZX_ERR_BUFFER_TOO_SMALL;
42         }
43         //TODO: ktrace-only handle once resources are further along
44         zx_handle_t h;
45         zx_status_t status = zx_handle_duplicate(get_root_resource(), ZX_RIGHT_SAME_RIGHTS, &h);
46         if (status < 0) {
47             return status;
48         }
49         *((zx_handle_t*) reply) = h;
50         *out_actual = sizeof(zx_handle_t);
51         return ZX_OK;
52     }
53     case IOCTL_KTRACE_ADD_PROBE: {
54         char name[ZX_MAX_NAME_LEN];
55         if ((cmdlen >= ZX_MAX_NAME_LEN) || (cmdlen < 1) || (max != sizeof(uint32_t))) {
56             return ZX_ERR_INVALID_ARGS;
57         }
58         memcpy(name, cmd, cmdlen);
59         name[cmdlen] = 0;
60         zx_status_t status = zx_ktrace_control(get_root_resource(), KTRACE_ACTION_NEW_PROBE, 0, name);
61         if (status < 0) {
62             return status;
63         }
64         *((uint32_t*) reply) = status;
65         *out_actual = sizeof(uint32_t);
66         return ZX_OK;
67     }
68     case IOCTL_KTRACE_START: {
69         if (cmdlen != sizeof(uint32_t)) {
70             return ZX_ERR_INVALID_ARGS;
71         }
72         uint32_t group_mask = *(uint32_t *)cmd;
73         return zx_ktrace_control(get_root_resource(), KTRACE_ACTION_START, group_mask, NULL);
74     }
75     case IOCTL_KTRACE_STOP: {
76         zx_ktrace_control(get_root_resource(), KTRACE_ACTION_STOP, 0, NULL);
77         zx_ktrace_control(get_root_resource(), KTRACE_ACTION_REWIND, 0, NULL);
78         return ZX_OK;
79     }
80     default:
81         return ZX_ERR_INVALID_ARGS;
82     }
83 }
84 
85 static zx_protocol_device_t ktrace_device_proto = {
86     .version = DEVICE_OPS_VERSION,
87     .read = ktrace_read,
88     .ioctl = ktrace_ioctl,
89     .get_size = ktrace_get_size,
90 };
91 
ktrace_bind(void * ctx,zx_device_t * parent)92 static zx_status_t ktrace_bind(void* ctx, zx_device_t* parent) {
93     device_add_args_t args = {
94         .version = DEVICE_ADD_ARGS_VERSION,
95         .name = "ktrace",
96         .ops = &ktrace_device_proto,
97     };
98 
99     zx_device_t* dev;
100     return device_add(parent, &args, &dev);
101 }
102 
103 static zx_driver_ops_t ktrace_driver_ops = {
104     .version = DRIVER_OPS_VERSION,
105     .bind = ktrace_bind,
106 };
107 
108 ZIRCON_DRIVER_BEGIN(ktrace, ktrace_driver_ops, "zircon", "0.1", 1)
109     BI_MATCH_IF(EQ, BIND_PROTOCOL, ZX_PROTOCOL_MISC_PARENT),
110 ZIRCON_DRIVER_END(ktrace)
111