Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/cddl/dev/systrace/systrace.c
48266 views
1
/*
2
* CDDL HEADER START
3
*
4
* The contents of this file are subject to the terms of the
5
* Common Development and Distribution License (the "License").
6
* You may not use this file except in compliance with the License.
7
*
8
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9
* or http://www.opensolaris.org/os/licensing.
10
* See the License for the specific language governing permissions
11
* and limitations under the License.
12
*
13
* When distributing Covered Code, include this CDDL HEADER in each
14
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15
* If applicable, add the following below this CDDL HEADER, with the
16
* fields enclosed by brackets "[]" replaced with your own identifying
17
* information: Portions Copyright [yyyy] [name of copyright owner]
18
*
19
* CDDL HEADER END
20
*
21
* Portions Copyright 2006-2008 John Birrell [email protected]
22
*/
23
24
/*
25
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
26
* Use is subject to license terms.
27
*/
28
29
#include <sys/param.h>
30
#include <sys/systm.h>
31
#include <sys/conf.h>
32
#include <sys/cpuvar.h>
33
#include <sys/dtrace.h>
34
#include <sys/fcntl.h>
35
#include <sys/filio.h>
36
#include <sys/kdb.h>
37
#include <sys/kernel.h>
38
#include <sys/kmem.h>
39
#include <sys/kthread.h>
40
#include <sys/limits.h>
41
#include <sys/linker.h>
42
#include <sys/lock.h>
43
#include <sys/malloc.h>
44
#include <sys/module.h>
45
#include <sys/mutex.h>
46
#include <sys/poll.h>
47
#include <sys/proc.h>
48
#include <sys/selinfo.h>
49
#include <sys/smp.h>
50
#include <sys/stdarg.h>
51
#include <sys/sysent.h>
52
#include <sys/sysproto.h>
53
#include <sys/uio.h>
54
#include <sys/unistd.h>
55
56
#include <cddl/dev/dtrace/dtrace_cddl.h>
57
58
#ifdef LINUX_SYSTRACE
59
#if defined(__amd64__)
60
#include <amd64/linux/linux.h>
61
#include <amd64/linux/linux_proto.h>
62
#include <amd64/linux/linux_syscalls.c>
63
#include <amd64/linux/linux_systrace_args.c>
64
#elif defined(__i386__)
65
#include <i386/linux/linux.h>
66
#include <i386/linux/linux_proto.h>
67
#include <i386/linux/linux_syscalls.c>
68
#include <i386/linux/linux_systrace_args.c>
69
#else
70
#error Only i386 and amd64 are supported.
71
#endif
72
#define MODNAME "linux"
73
extern struct sysent linux_sysent[];
74
#define MAXSYSCALL LINUX_SYS_MAXSYSCALL
75
#define SYSCALLNAMES linux_syscallnames
76
#define SYSENT linux_sysent
77
#elif defined(LINUX32_SYSTRACE)
78
#if defined(__amd64__)
79
#include <amd64/linux32/linux.h>
80
#include <amd64/linux32/linux32_proto.h>
81
#include <amd64/linux32/linux32_syscalls.c>
82
#include <amd64/linux32/linux32_systrace_args.c>
83
#else
84
#error Only amd64 is supported.
85
#endif
86
#define MODNAME "linux32"
87
extern struct sysent linux32_sysent[];
88
#define MAXSYSCALL LINUX32_SYS_MAXSYSCALL
89
#define SYSCALLNAMES linux32_syscallnames
90
#define SYSENT linux32_sysent
91
#elif defined(FREEBSD32_SYSTRACE)
92
/*
93
* The syscall arguments are processed into a DTrace argument array
94
* using a generated function. See sys/tools/syscalls/README.md.
95
*/
96
#include <compat/freebsd32/freebsd32_proto.h>
97
#include <compat/freebsd32/freebsd32_util.h>
98
#include <compat/freebsd32/freebsd32_syscall.h>
99
#include <compat/freebsd32/freebsd32_systrace_args.c>
100
extern const char *freebsd32_syscallnames[];
101
#define MODNAME "freebsd32"
102
#define MAXSYSCALL FREEBSD32_SYS_MAXSYSCALL
103
#define SYSCALLNAMES freebsd32_syscallnames
104
#define SYSENT freebsd32_sysent
105
#else
106
/*
107
* The syscall arguments are processed into a DTrace argument array
108
* using a generated function. See sys/tools/syscalls/README.md.
109
*/
110
#include <sys/syscall.h>
111
#include <kern/systrace_args.c>
112
#define MODNAME "freebsd"
113
#define MAXSYSCALL SYS_MAXSYSCALL
114
#define SYSCALLNAMES syscallnames
115
#define SYSENT sysent
116
#define NATIVE_ABI
117
#endif
118
119
#define PROVNAME "syscall"
120
#define DEVNAME "dtrace/systrace/" MODNAME
121
122
#define SYSTRACE_ARTIFICIAL_FRAMES 1
123
124
#define SYSTRACE_SHIFT 16
125
#define SYSTRACE_ISENTRY(x) ((int)(x) >> SYSTRACE_SHIFT)
126
#define SYSTRACE_SYSNUM(x) ((int)(x) & ((1 << SYSTRACE_SHIFT) - 1))
127
#define SYSTRACE_ENTRY(id) ((1 << SYSTRACE_SHIFT) | (id))
128
#define SYSTRACE_RETURN(id) (id)
129
130
#if ((1 << SYSTRACE_SHIFT) <= MAXSYSCALL)
131
#error 1 << SYSTRACE_SHIFT must exceed number of system calls
132
#endif
133
134
static int systrace_enabled_count;
135
136
static void systrace_load(void *);
137
static void systrace_unload(void *);
138
139
static void systrace_getargdesc(void *, dtrace_id_t, void *,
140
dtrace_argdesc_t *);
141
static uint64_t systrace_getargval(void *, dtrace_id_t, void *, int, int);
142
static void systrace_provide(void *, dtrace_probedesc_t *);
143
static void systrace_destroy(void *, dtrace_id_t, void *);
144
static void systrace_enable(void *, dtrace_id_t, void *);
145
static void systrace_disable(void *, dtrace_id_t, void *);
146
147
static union {
148
const char **p_constnames;
149
char **pp_syscallnames;
150
} uglyhack = { SYSCALLNAMES };
151
152
static dtrace_pattr_t systrace_attr = {
153
{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
154
{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
155
{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
156
{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
157
{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
158
};
159
160
static dtrace_pops_t systrace_pops = {
161
.dtps_provide = systrace_provide,
162
.dtps_provide_module = NULL,
163
.dtps_enable = systrace_enable,
164
.dtps_disable = systrace_disable,
165
.dtps_suspend = NULL,
166
.dtps_resume = NULL,
167
.dtps_getargdesc = systrace_getargdesc,
168
.dtps_getargval = systrace_getargval,
169
.dtps_usermode = NULL,
170
.dtps_destroy = systrace_destroy
171
};
172
173
static dtrace_provider_id_t systrace_id;
174
175
#ifdef NATIVE_ABI
176
/*
177
* Probe callback function.
178
*
179
* Note: This function is called for _all_ syscalls, regardless of which sysent
180
* array the syscall comes from. It could be a standard syscall or a
181
* compat syscall from something like Linux.
182
*/
183
static void
184
systrace_probe(struct syscall_args *sa, enum systrace_probe_t type, int retval)
185
{
186
uint64_t uargs[nitems(sa->args)];
187
dtrace_id_t id;
188
int n_args, sysnum;
189
190
sysnum = sa->code;
191
memset(uargs, 0, sizeof(uargs));
192
193
if (type == SYSTRACE_ENTRY) {
194
if ((id = sa->callp->sy_entry) == DTRACE_IDNONE)
195
return;
196
197
if (sa->callp->sy_systrace_args_func != NULL)
198
/*
199
* Convert the syscall parameters using the registered
200
* function.
201
*/
202
(*sa->callp->sy_systrace_args_func)(sysnum, sa->args,
203
uargs, &n_args);
204
else
205
/*
206
* Use the built-in system call argument conversion
207
* function to translate the syscall structure fields
208
* into the array of 64-bit values that DTrace expects.
209
*/
210
systrace_args(sysnum, sa->args, uargs, &n_args);
211
/*
212
* Save probe arguments now so that we can retrieve them if
213
* the getargval method is called from further down the stack.
214
*/
215
curthread->t_dtrace_systrace_args = uargs;
216
} else {
217
if ((id = sa->callp->sy_return) == DTRACE_IDNONE)
218
return;
219
220
curthread->t_dtrace_systrace_args = NULL;
221
/* Set arg0 and arg1 as the return value of this syscall. */
222
uargs[0] = uargs[1] = retval;
223
}
224
225
/* Process the probe using the converted argments. */
226
dtrace_probe(id, uargs[0], uargs[1], uargs[2], uargs[3], uargs[4]);
227
}
228
#endif
229
230
static void
231
systrace_getargdesc(void *arg, dtrace_id_t id, void *parg,
232
dtrace_argdesc_t *desc)
233
{
234
int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg);
235
236
if (SYSTRACE_ISENTRY((uintptr_t)parg))
237
systrace_entry_setargdesc(sysnum, desc->dtargd_ndx,
238
desc->dtargd_native, sizeof(desc->dtargd_native));
239
else
240
systrace_return_setargdesc(sysnum, desc->dtargd_ndx,
241
desc->dtargd_native, sizeof(desc->dtargd_native));
242
243
if (desc->dtargd_native[0] == '\0')
244
desc->dtargd_ndx = DTRACE_ARGNONE;
245
}
246
247
static uint64_t
248
systrace_getargval(void *arg __unused, dtrace_id_t id __unused,
249
void *parg __unused, int argno, int aframes __unused)
250
{
251
uint64_t *uargs;
252
253
uargs = curthread->t_dtrace_systrace_args;
254
if (uargs == NULL)
255
/* This is a return probe. */
256
return (0);
257
if (argno >= nitems(((struct syscall_args *)NULL)->args))
258
return (0);
259
return (uargs[argno]);
260
}
261
262
static void
263
systrace_provide(void *arg, dtrace_probedesc_t *desc)
264
{
265
int i;
266
267
if (desc != NULL)
268
return;
269
270
for (i = 0; i < MAXSYSCALL; i++) {
271
if (dtrace_probe_lookup(systrace_id, MODNAME,
272
uglyhack.pp_syscallnames[i], "entry") != 0)
273
continue;
274
275
(void)dtrace_probe_create(systrace_id, MODNAME,
276
uglyhack.pp_syscallnames[i], "entry",
277
SYSTRACE_ARTIFICIAL_FRAMES,
278
(void *)((uintptr_t)SYSTRACE_ENTRY(i)));
279
(void)dtrace_probe_create(systrace_id, MODNAME,
280
uglyhack.pp_syscallnames[i], "return",
281
SYSTRACE_ARTIFICIAL_FRAMES,
282
(void *)((uintptr_t)SYSTRACE_RETURN(i)));
283
}
284
}
285
286
static void
287
systrace_destroy(void *arg, dtrace_id_t id, void *parg)
288
{
289
#ifdef SYSTRACE_DEBUG
290
int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg);
291
292
/*
293
* There's nothing to do here but assert that we have actually been
294
* disabled.
295
*/
296
if (SYSTRACE_ISENTRY((uintptr_t)parg)) {
297
ASSERT(sysent[sysnum].sy_entry == DTRACE_IDNONE);
298
} else {
299
ASSERT(sysent[sysnum].sy_return == DTRACE_IDNONE);
300
}
301
#endif
302
}
303
304
static void
305
systrace_enable(void *arg, dtrace_id_t id, void *parg)
306
{
307
int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg);
308
309
SYSENT[sysnum].sy_systrace_args_func = systrace_args;
310
311
if (SYSTRACE_ISENTRY((uintptr_t)parg))
312
SYSENT[sysnum].sy_entry = id;
313
else
314
SYSENT[sysnum].sy_return = id;
315
systrace_enabled_count++;
316
if (systrace_enabled_count == 1)
317
systrace_enabled = true;
318
}
319
320
static void
321
systrace_disable(void *arg, dtrace_id_t id, void *parg)
322
{
323
int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg);
324
325
SYSENT[sysnum].sy_systrace_args_func = NULL;
326
SYSENT[sysnum].sy_entry = DTRACE_IDNONE;
327
SYSENT[sysnum].sy_return = DTRACE_IDNONE;
328
systrace_enabled_count--;
329
if (systrace_enabled_count == 0)
330
systrace_enabled = false;
331
}
332
333
static void
334
systrace_load(void *dummy __unused)
335
{
336
337
if (dtrace_register(PROVNAME, &systrace_attr, DTRACE_PRIV_USER, NULL,
338
&systrace_pops, NULL, &systrace_id) != 0)
339
return;
340
341
#ifdef NATIVE_ABI
342
systrace_probe_func = systrace_probe;
343
#endif
344
}
345
346
static void
347
systrace_unload(void *dummy __unused)
348
{
349
350
#ifdef NATIVE_ABI
351
systrace_probe_func = NULL;
352
#endif
353
354
if (dtrace_unregister(systrace_id) != 0)
355
return;
356
}
357
358
static int
359
systrace_modevent(module_t mod __unused, int type, void *data __unused)
360
{
361
int error;
362
363
error = 0;
364
switch (type) {
365
case MOD_LOAD:
366
break;
367
368
case MOD_UNLOAD:
369
break;
370
371
case MOD_SHUTDOWN:
372
break;
373
374
default:
375
error = EOPNOTSUPP;
376
break;
377
378
}
379
return (error);
380
}
381
382
SYSINIT(systrace_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY,
383
systrace_load, NULL);
384
SYSUNINIT(systrace_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY,
385
systrace_unload, NULL);
386
387
#ifdef LINUX_SYSTRACE
388
DEV_MODULE(systrace_linux, systrace_modevent, NULL);
389
MODULE_VERSION(systrace_linux, 1);
390
#ifdef __amd64__
391
MODULE_DEPEND(systrace_linux, linux64, 1, 1, 1);
392
#else
393
MODULE_DEPEND(systrace_linux, linux, 1, 1, 1);
394
#endif
395
MODULE_DEPEND(systrace_linux, dtrace, 1, 1, 1);
396
MODULE_DEPEND(systrace_linux, opensolaris, 1, 1, 1);
397
#elif defined(LINUX32_SYSTRACE)
398
DEV_MODULE(systrace_linux32, systrace_modevent, NULL);
399
MODULE_VERSION(systrace_linux32, 1);
400
MODULE_DEPEND(systrace_linux32, linux, 1, 1, 1);
401
MODULE_DEPEND(systrace_linux32, dtrace, 1, 1, 1);
402
MODULE_DEPEND(systrace_linux32, opensolaris, 1, 1, 1);
403
#elif defined(FREEBSD32_SYSTRACE)
404
DEV_MODULE(systrace_freebsd32, systrace_modevent, NULL);
405
MODULE_VERSION(systrace_freebsd32, 1);
406
MODULE_DEPEND(systrace_freebsd32, dtrace, 1, 1, 1);
407
MODULE_DEPEND(systrace_freebsd32, opensolaris, 1, 1, 1);
408
#else
409
DEV_MODULE(systrace, systrace_modevent, NULL);
410
MODULE_VERSION(systrace, 1);
411
MODULE_DEPEND(systrace, dtrace, 1, 1, 1);
412
MODULE_DEPEND(systrace, opensolaris, 1, 1, 1);
413
#endif
414
415