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 #ifdef __x86_64__ // entire file
8
9 #include <assert.h>
10 #include <inttypes.h>
11
12 #include "lib/mtrace.h"
13 #include "trace.h"
14
15 #include <object/process_dispatcher.h>
16 #include <lib/zircon-internal/mtrace.h>
17 #include <lib/zircon-internal/device/cpu-trace/intel-pt.h>
18
19 #include "arch/x86/proc_trace.h"
20
21 #define LOCAL_TRACE 0
22
23 static_assert(IPT_MAX_NUM_TRACES >= SMP_MAX_CPUS, "");
24
mtrace_insntrace_control(uint32_t action,uint32_t options,user_inout_ptr<void> arg,size_t size)25 zx_status_t mtrace_insntrace_control(uint32_t action, uint32_t options,
26 user_inout_ptr<void> arg, size_t size) {
27 TRACEF("action %u, options 0x%x, arg %p, size 0x%zx\n",
28 action, options, arg.get(), size);
29
30 switch (action) {
31 case MTRACE_INSNTRACE_ALLOC_TRACE: {
32 if (options != 0)
33 return ZX_ERR_INVALID_ARGS;
34 ioctl_insntrace_trace_config_t config;
35 if (size != sizeof(config))
36 return ZX_ERR_INVALID_ARGS;
37 zx_status_t status = arg.reinterpret<ioctl_insntrace_trace_config_t>().copy_from_user(&config);
38 if (status != ZX_OK)
39 return status;
40 TRACEF("action %u, mode %u, num traces %u\n", action, config.mode, config.num_traces);
41 if (config.num_traces > IPT_MAX_NUM_TRACES)
42 return ZX_ERR_INVALID_ARGS;
43 switch (config.mode) {
44 case IPT_MODE_CPUS:
45 if (config.num_traces != arch_max_num_cpus())
46 return ZX_ERR_INVALID_ARGS;
47 return x86_ipt_alloc_trace(IPT_TRACE_CPUS, config.num_traces);
48 case IPT_MODE_THREADS:
49 return x86_ipt_alloc_trace(IPT_TRACE_THREADS, config.num_traces);
50 default:
51 return ZX_ERR_INVALID_ARGS;
52 }
53 }
54
55 case MTRACE_INSNTRACE_FREE_TRACE:
56 if (options != 0 || size != 0)
57 return ZX_ERR_INVALID_ARGS;
58 return x86_ipt_free_trace();
59
60 case MTRACE_INSNTRACE_STAGE_TRACE_DATA: {
61 zx_x86_pt_regs_t regs;
62 if (size != sizeof(regs))
63 return ZX_ERR_INVALID_ARGS;
64 zx_status_t status = arg.reinterpret<zx_x86_pt_regs_t>().copy_from_user(®s);
65 if (status != ZX_OK)
66 return status;
67 zx_itrace_buffer_descriptor_t descriptor = options;
68 TRACEF("action %u, descriptor %u, ctl 0x%" PRIx64 ", output_base 0x%" PRIx64 "\n",
69 action, descriptor, regs.ctl, regs.output_base);
70 return x86_ipt_stage_trace_data(descriptor, ®s);
71 }
72
73 case MTRACE_INSNTRACE_GET_TRACE_DATA: {
74 zx_x86_pt_regs_t regs;
75 if (size != sizeof(regs))
76 return ZX_ERR_INVALID_ARGS;
77 zx_itrace_buffer_descriptor_t descriptor = options;
78 auto status = x86_ipt_get_trace_data(descriptor, ®s);
79 if (status != ZX_OK)
80 return status;
81 TRACEF("action %u, descriptor %u, ctl 0x%" PRIx64 ", output_base 0x%" PRIx64 "\n",
82 action, descriptor, regs.ctl, regs.output_base);
83 status = arg.reinterpret<zx_x86_pt_regs_t>().copy_to_user(regs);
84 if (status != ZX_OK)
85 return status;
86 return ZX_OK;
87 }
88
89 case MTRACE_INSNTRACE_START:
90 if (options != 0 || size != 0)
91 return ZX_ERR_INVALID_ARGS;
92 return x86_ipt_start();
93
94 case MTRACE_INSNTRACE_STOP:
95 if (options != 0 || size != 0)
96 return ZX_ERR_INVALID_ARGS;
97 return x86_ipt_stop();
98
99 default:
100 return ZX_ERR_INVALID_ARGS;
101 }
102 }
103
104 #endif
105