]> git.saurik.com Git - apple/xnu.git/blame_incremental - bsd/dev/dtrace/systrace.c
xnu-1228.9.59.tar.gz
[apple/xnu.git] / bsd / dev / dtrace / systrace.c
... / ...
CommitLineData
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/*
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26/* #pragma ident "@(#)systrace.c 1.5 06/03/24 SMI" */
27
28#if !defined(__APPLE__)
29#include <sys/dtrace.h>
30#include <sys/systrace.h>
31#include <sys/stat.h>
32#include <sys/systm.h>
33#include <sys/conf.h>
34#include <sys/ddi.h>
35#include <sys/sunddi.h>
36#include <sys/atomic.h>
37#define SYSTRACE_ARTIFICIAL_FRAMES 1
38#else
39
40#ifdef KERNEL
41#ifndef _KERNEL
42#define _KERNEL /* Solaris vs. Darwin */
43#endif
44#endif
45
46#define MACH__POSIX_C_SOURCE_PRIVATE 1 /* pulls in suitable savearea from mach/ppc/thread_status.h */
47#include <kern/thread.h>
48#include <mach/thread_status.h>
49/* XXX All of these should really be derived from syscall_sw.h */
50#if defined(__i386__) || defined (__x86_64__)
51#define SYSCALL_CLASS_SHIFT 24
52#define SYSCALL_CLASS_MASK (0xFF << SYSCALL_CLASS_SHIFT)
53#define SYSCALL_NUMBER_MASK (~SYSCALL_CLASS_MASK)
54#define I386_SYSCALL_NUMBER_MASK (0xFFFF)
55
56typedef x86_saved_state_t savearea_t;
57#endif
58
59#include <sys/param.h>
60#include <sys/systm.h>
61#include <sys/proc.h>
62#include <sys/errno.h>
63#include <sys/ioctl.h>
64#include <sys/conf.h>
65#include <sys/fcntl.h>
66#include <miscfs/devfs/devfs.h>
67
68#include <sys/dtrace.h>
69#include <sys/dtrace_impl.h>
70#include "systrace.h"
71#include <sys/stat.h>
72#include <sys/systm.h>
73#include <sys/conf.h>
74#include <sys/user.h>
75
76#if defined (__ppc__) || defined (__ppc64__)
77#define SYSTRACE_ARTIFICIAL_FRAMES 3
78#define MACHTRACE_ARTIFICIAL_FRAMES 4
79#elif defined(__i386__) || defined (__x86_64__)
80#define SYSTRACE_ARTIFICIAL_FRAMES 2
81#define MACHTRACE_ARTIFICIAL_FRAMES 3
82#else
83#error Unknown Architecture
84#endif
85
86#include <sys/sysent.h>
87#define sy_callc sy_call /* Map Solaris slot name to Darwin's */
88#define NSYSCALL nsysent /* and is less than 500 or so */
89
90extern const char *syscallnames[];
91
92#include <sys/dtrace_glue.h>
93#define casptr dtrace_casptr
94#define membar_enter dtrace_membar_producer
95
96#define LOADABLE_SYSCALL(a) 0 /* Not pertinent to Darwin. */
97#define LOADED_SYSCALL(a) 1 /* Not pertinent to Darwin. */
98
99systrace_sysent_t *systrace_sysent = NULL;
100void (*systrace_probe)(dtrace_id_t, uint64_t, uint64_t,
101 uint64_t, uint64_t, uint64_t);
102
103void
104systrace_stub(dtrace_id_t id, uint64_t arg0, uint64_t arg1,
105 uint64_t arg2, uint64_t arg3, uint64_t arg4)
106{
107#pragma unused(id,arg0,arg1,arg2,arg3,arg4)
108}
109
110int32_t
111dtrace_systrace_syscall(struct proc *pp, void *uap, int *rv)
112{
113 boolean_t flavor;
114 unsigned short code;
115
116 systrace_sysent_t *sy;
117 dtrace_id_t id;
118 int32_t rval;
119#if 0 /* XXX */
120 proc_t *p;
121#endif
122 syscall_arg_t *ip = (syscall_arg_t *)uap;
123
124#if defined (__ppc__) || defined (__ppc64__)
125 {
126 savearea_t *regs = (savearea_t *)find_user_regs(current_thread());
127
128 flavor = (((unsigned int)regs->save_r0) == 0)? 1: 0;
129
130 if (flavor)
131 code = regs->save_r3;
132 else
133 code = regs->save_r0;
134 }
135#elif defined(__i386__) || defined (__x86_64__)
136#pragma unused(flavor)
137 {
138 x86_saved_state_t *tagged_regs = (x86_saved_state_t *)find_user_regs(current_thread());
139
140 if (is_saved_state64(tagged_regs)) {
141 x86_saved_state64_t *regs = saved_state64(tagged_regs);
142 code = regs->rax & SYSCALL_NUMBER_MASK;
143 /*
144 * Check for indirect system call... system call number
145 * passed as 'arg0'
146 */
147 if (code == 0) {
148 code = regs->rdi;
149 }
150 } else {
151 code = saved_state32(tagged_regs)->eax & I386_SYSCALL_NUMBER_MASK;
152 /*
153 * TODO: handle indirect system calls
154 */
155 }
156 }
157#else
158#error Unknown Architecture
159#endif
160
161 // Bounds "check" the value of code a la unix_syscall
162 sy = (code >= NUM_SYSENT) ? &systrace_sysent[63] : &systrace_sysent[code];
163
164 if ((id = sy->stsy_entry) != DTRACE_IDNONE)
165 (*systrace_probe)(id, *ip, *(ip+1), *(ip+2), *(ip+3), *(ip+4));
166
167#if 0 /* XXX */
168 /*
169 * We want to explicitly allow DTrace consumers to stop a process
170 * before it actually executes the meat of the syscall.
171 */
172 p = ttoproc(curthread);
173 mutex_enter(&p->p_lock);
174 if (curthread->t_dtrace_stop && !curthread->t_lwp->lwp_nostop) {
175 curthread->t_dtrace_stop = 0;
176 stop(PR_REQUESTED, 0);
177 }
178 mutex_exit(&p->p_lock);
179#endif
180
181 rval = (*sy->stsy_underlying)(pp, uap, rv);
182
183 if ((id = sy->stsy_return) != DTRACE_IDNONE) {
184 uint64_t munged_rv;
185 uthread_t uthread = (uthread_t)get_bsdthread_info(current_thread());
186
187 if (uthread)
188 uthread->t_dtrace_errno = rval; /* Establish t_dtrace_errno now in case this enabling refers to it. */
189
190 /*
191 * "Decode" rv for use in the call to dtrace_probe()
192 */
193 if (rval == ERESTART) {
194 munged_rv = -1LL; /* System call will be reissued in user mode. Make DTrace report a -1 return. */
195 } else if (rval != EJUSTRETURN) {
196 if (rval) {
197 munged_rv = -1LL; /* Mimic what libc will do. */
198 } else {
199 switch (sy->stsy_return_type) {
200 case _SYSCALL_RET_INT_T:
201 munged_rv = rv[0];
202 break;
203 case _SYSCALL_RET_UINT_T:
204 munged_rv = ((u_int)rv[0]);
205 break;
206 case _SYSCALL_RET_OFF_T:
207 munged_rv = *(u_int64_t *)rv;
208 break;
209 case _SYSCALL_RET_ADDR_T:
210 case _SYSCALL_RET_SIZE_T:
211 case _SYSCALL_RET_SSIZE_T:
212 munged_rv = *(user_addr_t *)rv;
213 break;
214 case _SYSCALL_RET_NONE:
215 munged_rv = 0LL;
216 break;
217 default:
218 munged_rv = 0LL;
219 break;
220 }
221 }
222 } else
223 munged_rv = 0LL;
224
225 (*systrace_probe)(id, munged_rv, munged_rv, (uint64_t)rval, 0, 0);
226 }
227
228 return (rval);
229}
230
231void
232dtrace_systrace_syscall_return(unsigned short code, int rval, int *rv)
233{
234 systrace_sysent_t *sy;
235 dtrace_id_t id;
236
237 // Bounds "check" the value of code a la unix_syscall_return
238 sy = (code >= NUM_SYSENT) ? &systrace_sysent[63] : &systrace_sysent[code];
239
240 if ((id = sy->stsy_return) != DTRACE_IDNONE) {
241 uint64_t munged_rv;
242 uthread_t uthread = (uthread_t)get_bsdthread_info(current_thread());
243
244 if (uthread)
245 uthread->t_dtrace_errno = rval; /* Establish t_dtrace_errno now in case this enabling refers to it. */
246
247 /*
248 * "Decode" rv for use in the call to dtrace_probe()
249 */
250 if (rval == ERESTART) {
251 munged_rv = -1LL; /* System call will be reissued in user mode. Make DTrace report a -1 return. */
252 } else if (rval != EJUSTRETURN) {
253 if (rval) {
254 munged_rv = -1LL; /* Mimic what libc will do. */
255 } else {
256 switch (sy->stsy_return_type) {
257 case _SYSCALL_RET_INT_T:
258 munged_rv = rv[0];
259 break;
260 case _SYSCALL_RET_UINT_T:
261 munged_rv = ((u_int)rv[0]);
262 break;
263 case _SYSCALL_RET_OFF_T:
264 munged_rv = *(u_int64_t *)rv;
265 break;
266 case _SYSCALL_RET_ADDR_T:
267 case _SYSCALL_RET_SIZE_T:
268 case _SYSCALL_RET_SSIZE_T:
269 munged_rv = *(user_addr_t *)rv;
270 break;
271 case _SYSCALL_RET_NONE:
272 munged_rv = 0LL;
273 break;
274 default:
275 munged_rv = 0LL;
276 break;
277 }
278 }
279 } else
280 munged_rv = 0LL;
281
282 (*systrace_probe)(id, munged_rv, munged_rv, (uint64_t)rval, 0, 0);
283 }
284}
285#endif /* __APPLE__ */
286
287#define SYSTRACE_SHIFT 16
288#define SYSTRACE_ISENTRY(x) ((int)(x) >> SYSTRACE_SHIFT)
289#define SYSTRACE_SYSNUM(x) ((int)(x) & ((1 << SYSTRACE_SHIFT) - 1))
290#define SYSTRACE_ENTRY(id) ((1 << SYSTRACE_SHIFT) | (id))
291#define SYSTRACE_RETURN(id) (id)
292
293#if ((1 << SYSTRACE_SHIFT) <= NSYSCALL)
294#error 1 << SYSTRACE_SHIFT must exceed number of system calls
295#endif
296
297static dev_info_t *systrace_devi;
298static dtrace_provider_id_t systrace_id;
299
300#if defined(__APPLE__)
301#define systrace_init _systrace_init /* Avoid name clash with Darwin automagic conf symbol */
302#endif
303static void
304systrace_init(struct sysent *actual, systrace_sysent_t **interposed)
305{
306 systrace_sysent_t *sysent = *interposed;
307 int i;
308
309 if (sysent == NULL) {
310 *interposed = sysent = kmem_zalloc(sizeof (systrace_sysent_t) *
311 NSYSCALL, KM_SLEEP);
312 }
313
314 for (i = 0; i < NSYSCALL; i++) {
315 struct sysent *a = &actual[i];
316 systrace_sysent_t *s = &sysent[i];
317
318 if (LOADABLE_SYSCALL(a) && !LOADED_SYSCALL(a))
319 continue;
320
321 if (a->sy_callc == dtrace_systrace_syscall)
322 continue;
323
324#ifdef _SYSCALL32_IMPL
325 if (a->sy_callc == dtrace_systrace_syscall32)
326 continue;
327#endif
328
329 s->stsy_underlying = a->sy_callc;
330#if defined(__APPLE__)
331 s->stsy_return_type = a->sy_return_type;
332#endif
333 }
334}
335
336/*ARGSUSED*/
337static void
338systrace_provide(void *arg, const dtrace_probedesc_t *desc)
339{
340 int i;
341
342 if (desc != NULL)
343 return;
344
345 systrace_init(sysent, &systrace_sysent);
346#ifdef _SYSCALL32_IMPL
347 systrace_init(sysent32, &systrace_sysent32);
348#endif
349
350 for (i = 0; i < NSYSCALL; i++) {
351 if (systrace_sysent[i].stsy_underlying == NULL)
352 continue;
353
354 if (dtrace_probe_lookup(systrace_id, NULL,
355 syscallnames[i], "entry") != 0)
356 continue;
357
358 (void) dtrace_probe_create(systrace_id, NULL, syscallnames[i],
359 "entry", SYSTRACE_ARTIFICIAL_FRAMES,
360 (void *)((uintptr_t)SYSTRACE_ENTRY(i)));
361 (void) dtrace_probe_create(systrace_id, NULL, syscallnames[i],
362 "return", SYSTRACE_ARTIFICIAL_FRAMES,
363 (void *)((uintptr_t)SYSTRACE_RETURN(i)));
364
365 systrace_sysent[i].stsy_entry = DTRACE_IDNONE;
366 systrace_sysent[i].stsy_return = DTRACE_IDNONE;
367#ifdef _SYSCALL32_IMPL
368 systrace_sysent32[i].stsy_entry = DTRACE_IDNONE;
369 systrace_sysent32[i].stsy_return = DTRACE_IDNONE;
370#endif
371 }
372}
373#if defined(__APPLE__)
374#undef systrace_init
375#endif
376
377/*ARGSUSED*/
378static void
379systrace_destroy(void *arg, dtrace_id_t id, void *parg)
380{
381 int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg);
382
383 /*
384 * There's nothing to do here but assert that we have actually been
385 * disabled.
386 */
387 if (SYSTRACE_ISENTRY((uintptr_t)parg)) {
388 ASSERT(systrace_sysent[sysnum].stsy_entry == DTRACE_IDNONE);
389#ifdef _SYSCALL32_IMPL
390 ASSERT(systrace_sysent32[sysnum].stsy_entry == DTRACE_IDNONE);
391#endif
392 } else {
393 ASSERT(systrace_sysent[sysnum].stsy_return == DTRACE_IDNONE);
394#ifdef _SYSCALL32_IMPL
395 ASSERT(systrace_sysent32[sysnum].stsy_return == DTRACE_IDNONE);
396#endif
397 }
398}
399
400/*ARGSUSED*/
401static void
402systrace_enable(void *arg, dtrace_id_t id, void *parg)
403{
404 int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg);
405 int enabled = (systrace_sysent[sysnum].stsy_entry != DTRACE_IDNONE ||
406 systrace_sysent[sysnum].stsy_return != DTRACE_IDNONE);
407
408 if (SYSTRACE_ISENTRY((uintptr_t)parg)) {
409 systrace_sysent[sysnum].stsy_entry = id;
410#ifdef _SYSCALL32_IMPL
411 systrace_sysent32[sysnum].stsy_entry = id;
412#endif
413 } else {
414 systrace_sysent[sysnum].stsy_return = id;
415#ifdef _SYSCALL32_IMPL
416 systrace_sysent32[sysnum].stsy_return = id;
417#endif
418 }
419
420 if (enabled) {
421 ASSERT(sysent[sysnum].sy_callc == dtrace_systrace_syscall);
422 return;
423 }
424
425 (void) casptr(&sysent[sysnum].sy_callc,
426 (void *)systrace_sysent[sysnum].stsy_underlying,
427 (void *)dtrace_systrace_syscall);
428#ifdef _SYSCALL32_IMPL
429 (void) casptr(&sysent32[sysnum].sy_callc,
430 (void *)systrace_sysent32[sysnum].stsy_underlying,
431 (void *)dtrace_systrace_syscall32);
432#endif
433}
434
435/*ARGSUSED*/
436static void
437systrace_disable(void *arg, dtrace_id_t id, void *parg)
438{
439 int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg);
440 int disable = (systrace_sysent[sysnum].stsy_entry == DTRACE_IDNONE ||
441 systrace_sysent[sysnum].stsy_return == DTRACE_IDNONE);
442
443 if (disable) {
444 (void) casptr(&sysent[sysnum].sy_callc,
445 (void *)dtrace_systrace_syscall,
446 (void *)systrace_sysent[sysnum].stsy_underlying);
447
448#ifdef _SYSCALL32_IMPL
449 (void) casptr(&sysent32[sysnum].sy_callc,
450 (void *)dtrace_systrace_syscall32,
451 (void *)systrace_sysent32[sysnum].stsy_underlying);
452#endif
453 }
454
455 if (SYSTRACE_ISENTRY((uintptr_t)parg)) {
456 systrace_sysent[sysnum].stsy_entry = DTRACE_IDNONE;
457#ifdef _SYSCALL32_IMPL
458 systrace_sysent32[sysnum].stsy_entry = DTRACE_IDNONE;
459#endif
460 } else {
461 systrace_sysent[sysnum].stsy_return = DTRACE_IDNONE;
462#ifdef _SYSCALL32_IMPL
463 systrace_sysent32[sysnum].stsy_return = DTRACE_IDNONE;
464#endif
465 }
466}
467
468static dtrace_pattr_t systrace_attr = {
469{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
470{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
471{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
472{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
473{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
474};
475
476static dtrace_pops_t systrace_pops = {
477 systrace_provide,
478 NULL,
479 systrace_enable,
480 systrace_disable,
481 NULL,
482 NULL,
483 NULL,
484 NULL,
485 NULL,
486 systrace_destroy
487};
488
489static int
490systrace_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
491{
492 switch (cmd) {
493 case DDI_ATTACH:
494 break;
495 case DDI_RESUME:
496 return (DDI_SUCCESS);
497 default:
498 return (DDI_FAILURE);
499 }
500
501 systrace_probe = dtrace_probe;
502 membar_enter();
503
504 if (ddi_create_minor_node(devi, "systrace", S_IFCHR, 0,
505 DDI_PSEUDO, NULL) == DDI_FAILURE ||
506 dtrace_register("syscall", &systrace_attr, DTRACE_PRIV_USER, NULL,
507 &systrace_pops, NULL, &systrace_id) != 0) {
508 systrace_probe = systrace_stub;
509 ddi_remove_minor_node(devi, NULL);
510 return (DDI_FAILURE);
511 }
512
513 ddi_report_dev(devi);
514 systrace_devi = devi;
515
516 return (DDI_SUCCESS);
517}
518
519#if !defined(__APPLE__)
520static int
521systrace_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
522{
523 switch (cmd) {
524 case DDI_DETACH:
525 break;
526 case DDI_SUSPEND:
527 return (DDI_SUCCESS);
528 default:
529 return (DDI_FAILURE);
530 }
531
532 if (dtrace_unregister(systrace_id) != 0)
533 return (DDI_FAILURE);
534
535 ddi_remove_minor_node(devi, NULL);
536 systrace_probe = systrace_stub;
537 return (DDI_SUCCESS);
538}
539
540/*ARGSUSED*/
541static int
542systrace_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
543{
544 int error;
545
546 switch (infocmd) {
547 case DDI_INFO_DEVT2DEVINFO:
548 *result = (void *)systrace_devi;
549 error = DDI_SUCCESS;
550 break;
551 case DDI_INFO_DEVT2INSTANCE:
552 *result = (void *)0;
553 error = DDI_SUCCESS;
554 break;
555 default:
556 error = DDI_FAILURE;
557 }
558 return (error);
559}
560
561/*ARGSUSED*/
562static int
563systrace_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
564{
565 return (0);
566}
567
568static struct cb_ops systrace_cb_ops = {
569 systrace_open, /* open */
570 nodev, /* close */
571 nulldev, /* strategy */
572 nulldev, /* print */
573 nodev, /* dump */
574 nodev, /* read */
575 nodev, /* write */
576 nodev, /* ioctl */
577 nodev, /* devmap */
578 nodev, /* mmap */
579 nodev, /* segmap */
580 nochpoll, /* poll */
581 ddi_prop_op, /* cb_prop_op */
582 0, /* streamtab */
583 D_NEW | D_MP /* Driver compatibility flag */
584};
585
586static struct dev_ops systrace_ops = {
587 DEVO_REV, /* devo_rev, */
588 0, /* refcnt */
589 systrace_info, /* get_dev_info */
590 nulldev, /* identify */
591 nulldev, /* probe */
592 systrace_attach, /* attach */
593 systrace_detach, /* detach */
594 nodev, /* reset */
595 &systrace_cb_ops, /* driver operations */
596 NULL, /* bus operations */
597 nodev /* dev power */
598};
599
600/*
601 * Module linkage information for the kernel.
602 */
603static struct modldrv modldrv = {
604 &mod_driverops, /* module type (this is a pseudo driver) */
605 "System Call Tracing", /* name of module */
606 &systrace_ops, /* driver ops */
607};
608
609static struct modlinkage modlinkage = {
610 MODREV_1,
611 (void *)&modldrv,
612 NULL
613};
614
615int
616_init(void)
617{
618 return (mod_install(&modlinkage));
619}
620
621int
622_info(struct modinfo *modinfop)
623{
624 return (mod_info(&modlinkage, modinfop));
625}
626
627int
628_fini(void)
629{
630 return (mod_remove(&modlinkage));
631}
632#else
633typedef kern_return_t (*mach_call_t)(void *);
634
635/* XXX From #include <kern/syscall_sw.h> which may be changed for 64 bit! */
636typedef void mach_munge_t(const void *, void *);
637
638typedef struct {
639 int mach_trap_arg_count;
640 int (*mach_trap_function)(void);
641#if defined(__i386__)
642 boolean_t mach_trap_stack;
643#else
644 mach_munge_t *mach_trap_arg_munge32; /* system call arguments for 32-bit */
645 mach_munge_t *mach_trap_arg_munge64; /* system call arguments for 64-bit */
646#endif
647#if !MACH_ASSERT
648 int mach_trap_unused;
649#else
650 const char* mach_trap_name;
651#endif /* !MACH_ASSERT */
652} mach_trap_t;
653
654#define MACH_TRAP_TABLE_COUNT 128
655
656extern mach_trap_t mach_trap_table[];
657extern int mach_trap_count;
658
659#define MACH_TRAP(name, foo, bar, baz) #name
660
661/* XXX From osfmk/kern/syscall_sw.c */
662static const char * mach_name_table[MACH_TRAP_TABLE_COUNT] = {
663/* 0 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
664/* 1 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
665/* 2 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
666/* 3 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
667/* 4 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
668/* 5 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
669/* 6 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
670/* 7 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
671/* 8 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
672/* 9 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
673/* 10 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
674/* 11 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
675/* 12 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
676/* 13 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
677/* 14 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
678/* 15 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
679/* 16 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
680/* 17 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
681/* 18 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
682/* 19 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
683/* 20 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
684/* 21 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
685/* 22 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
686/* 23 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
687/* 24 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
688/* 25 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
689/* 26 */ MACH_TRAP(mach_reply_port, 0, NULL, NULL),
690/* 27 */ MACH_TRAP(thread_self_trap, 0, NULL, NULL),
691/* 28 */ MACH_TRAP(task_self_trap, 0, NULL, NULL),
692/* 29 */ MACH_TRAP(host_self_trap, 0, NULL, NULL),
693/* 30 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
694/* 31 */ MACH_TRAP(mach_msg_trap, 7, munge_wwwwwww, munge_ddddddd),
695/* 32 */ MACH_TRAP(mach_msg_overwrite_trap, 8, munge_wwwwwwww, munge_dddddddd),
696/* 33 */ MACH_TRAP(semaphore_signal_trap, 1, munge_w, munge_d),
697/* 34 */ MACH_TRAP(semaphore_signal_all_trap, 1, munge_w, munge_d),
698/* 35 */ MACH_TRAP(semaphore_signal_thread_trap, 2, munge_ww, munge_dd),
699/* 36 */ MACH_TRAP(semaphore_wait_trap, 1, munge_w, munge_d),
700/* 37 */ MACH_TRAP(semaphore_wait_signal_trap, 2, munge_ww, munge_dd),
701/* 38 */ MACH_TRAP(semaphore_timedwait_trap, 3, munge_www, munge_ddd),
702/* 39 */ MACH_TRAP(semaphore_timedwait_signal_trap, 4, munge_wwww, munge_dddd),
703/* 40 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
704/* 41 */ MACH_TRAP(init_process, 0, NULL, NULL),
705/* 42 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
706/* 43 */ MACH_TRAP(map_fd, 5, munge_wwwww, munge_ddddd),
707/* 44 */ MACH_TRAP(task_name_for_pid, 3, munge_www, munge_ddd),
708/* 45 */ MACH_TRAP(task_for_pid, 3, munge_www, munge_ddd),
709/* 46 */ MACH_TRAP(pid_for_task, 2, munge_ww,munge_dd),
710/* 47 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
711/* 48 */ MACH_TRAP(macx_swapon, 4, munge_wwww, munge_dddd),
712/* 49 */ MACH_TRAP(macx_swapoff, 2, munge_ww, munge_dd),
713/* 50 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
714/* 51 */ MACH_TRAP(macx_triggers, 4, munge_wwww, munge_dddd),
715/* 52 */ MACH_TRAP(macx_backing_store_suspend, 1, munge_w, munge_d),
716/* 53 */ MACH_TRAP(macx_backing_store_recovery, 1, munge_w, munge_d),
717/* 54 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
718/* 55 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
719/* 56 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
720/* 57 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
721/* 58 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
722/* 59 */ MACH_TRAP(swtch_pri, 0, NULL, NULL),
723/* 60 */ MACH_TRAP(swtch, 0, NULL, NULL),
724/* 61 */ MACH_TRAP(thread_switch, 3, munge_www, munge_ddd),
725/* 62 */ MACH_TRAP(clock_sleep_trap, 5, munge_wwwww, munge_ddddd),
726/* 63 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
727/* traps 64 - 95 reserved (debo) */
728/* 64 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
729/* 65 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
730/* 66 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
731/* 67 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
732/* 68 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
733/* 69 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
734/* 70 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
735/* 71 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
736/* 72 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
737/* 73 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
738/* 74 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
739/* 75 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
740/* 76 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
741/* 77 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
742/* 78 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
743/* 79 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
744/* 80 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
745/* 81 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
746/* 82 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
747/* 83 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
748/* 84 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
749/* 85 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
750/* 86 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
751/* 87 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
752/* 88 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
753/* 89 */ MACH_TRAP(mach_timebase_info_trap, 1, munge_w, munge_d),
754/* 90 */ MACH_TRAP(mach_wait_until_trap, 2, munge_l, munge_d),
755/* 91 */ MACH_TRAP(mk_timer_create_trap, 0, NULL, NULL),
756/* 92 */ MACH_TRAP(mk_timer_destroy_trap, 1, munge_w, munge_d),
757/* 93 */ MACH_TRAP(mk_timer_arm_trap, 3, munge_wl, munge_dd),
758/* 94 */ MACH_TRAP(mk_timer_cancel_trap, 2, munge_ww, munge_dd),
759/* 95 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
760/* traps 64 - 95 reserved (debo) */
761/* 96 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
762/* 97 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
763/* 98 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
764/* 99 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
765/* traps 100-107 reserved for iokit (esb) */
766/* 100 */ MACH_TRAP(iokit_user_client_trap, 8, munge_wwwwwwww, munge_dddddddd),
767/* 101 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
768/* 102 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
769/* 103 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
770/* 104 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
771/* 105 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
772/* 106 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
773/* 107 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
774/* traps 108-127 unused */
775/* 108 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
776/* 109 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
777/* 110 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
778/* 111 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
779/* 112 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
780/* 113 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
781/* 114 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
782/* 115 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
783/* 116 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
784/* 117 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
785/* 118 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
786/* 119 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
787/* 120 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
788/* 121 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
789/* 122 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
790/* 123 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
791/* 124 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
792/* 125 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
793/* 126 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
794/* 127 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
795};
796
797/* XXX From osfmk/i386/bsd_i386.c */
798struct mach_call_args {
799 syscall_arg_t arg1;
800 syscall_arg_t arg2;
801 syscall_arg_t arg3;
802 syscall_arg_t arg4;
803 syscall_arg_t arg5;
804 syscall_arg_t arg6;
805 syscall_arg_t arg7;
806 syscall_arg_t arg8;
807 syscall_arg_t arg9;
808};
809
810#undef NSYSCALL
811#define NSYSCALL mach_trap_count
812
813#if ((1 << SYSTRACE_SHIFT) <= NSYSCALL)
814#error 1 << SYSTRACE_SHIFT must exceed number of Mach traps
815#endif
816
817typedef systrace_sysent_t machtrace_sysent_t;
818
819static machtrace_sysent_t *machtrace_sysent = NULL;
820
821void (*machtrace_probe)(dtrace_id_t, uint64_t, uint64_t,
822 uint64_t, uint64_t, uint64_t);
823
824static dev_info_t *machtrace_devi;
825static dtrace_provider_id_t machtrace_id;
826
827static kern_return_t
828dtrace_machtrace_syscall(struct mach_call_args *args)
829{
830 boolean_t flavor;
831 unsigned short code;
832
833 machtrace_sysent_t *sy;
834 dtrace_id_t id;
835 kern_return_t rval;
836#if 0 /* XXX */
837 proc_t *p;
838#endif
839 syscall_arg_t *ip = (syscall_arg_t *)args;
840 mach_call_t mach_call;
841
842#if defined (__ppc__) || defined (__ppc64__)
843 {
844 savearea_t *regs = (savearea_t *)find_user_regs(current_thread());
845
846 flavor = (((unsigned int)regs->save_r0) == 0)? 1: 0;
847
848 if (flavor)
849 code = -regs->save_r3;
850 else
851 code = -regs->save_r0;
852 }
853#elif defined(__i386__) || defined (__x86_64__)
854#pragma unused(flavor)
855 {
856 x86_saved_state_t *tagged_regs = (x86_saved_state_t *)find_user_regs(current_thread());
857
858 if (is_saved_state64(tagged_regs)) {
859 code = saved_state64(tagged_regs)->rax & SYSCALL_NUMBER_MASK;
860 } else {
861 code = -saved_state32(tagged_regs)->eax;
862 }
863 }
864#else
865#error Unknown Architecture
866#endif
867
868 sy = &machtrace_sysent[code];
869
870 if ((id = sy->stsy_entry) != DTRACE_IDNONE)
871 (*machtrace_probe)(id, *ip, *(ip+1), *(ip+2), *(ip+3), *(ip+4));
872
873#if 0 /* XXX */
874 /*
875 * We want to explicitly allow DTrace consumers to stop a process
876 * before it actually executes the meat of the syscall.
877 */
878 p = ttoproc(curthread);
879 mutex_enter(&p->p_lock);
880 if (curthread->t_dtrace_stop && !curthread->t_lwp->lwp_nostop) {
881 curthread->t_dtrace_stop = 0;
882 stop(PR_REQUESTED, 0);
883 }
884 mutex_exit(&p->p_lock);
885#endif
886
887 mach_call = (mach_call_t)(*sy->stsy_underlying);
888 rval = mach_call(args);
889
890 if ((id = sy->stsy_return) != DTRACE_IDNONE)
891 (*machtrace_probe)(id, (uint64_t)rval, 0, 0, 0, 0);
892
893 return (rval);
894}
895
896static void
897machtrace_init(mach_trap_t *actual, machtrace_sysent_t **interposed)
898{
899 machtrace_sysent_t *msysent = *interposed;
900 int i;
901
902 if (msysent == NULL) {
903 *interposed = msysent = kmem_zalloc(sizeof (machtrace_sysent_t) *
904 NSYSCALL, KM_SLEEP);
905 }
906
907 for (i = 0; i < NSYSCALL; i++) {
908 mach_trap_t *a = &actual[i];
909 machtrace_sysent_t *s = &msysent[i];
910
911 if (LOADABLE_SYSCALL(a) && !LOADED_SYSCALL(a))
912 continue;
913
914 if ((mach_call_t)(a->mach_trap_function) == (mach_call_t)(dtrace_machtrace_syscall))
915 continue;
916
917 s->stsy_underlying = a->mach_trap_function;
918 }
919}
920
921/*ARGSUSED*/
922static void
923machtrace_provide(void *arg, const dtrace_probedesc_t *desc)
924{
925 int i;
926
927 if (desc != NULL)
928 return;
929
930 machtrace_init(mach_trap_table, &machtrace_sysent);
931
932 for (i = 0; i < NSYSCALL; i++) {
933
934 if (machtrace_sysent[i].stsy_underlying == NULL)
935 continue;
936
937 if (dtrace_probe_lookup(machtrace_id, NULL,
938 mach_name_table[i], "entry") != 0)
939 continue;
940
941 (void) dtrace_probe_create(machtrace_id, NULL, mach_name_table[i],
942 "entry", MACHTRACE_ARTIFICIAL_FRAMES,
943 (void *)((uintptr_t)SYSTRACE_ENTRY(i)));
944 (void) dtrace_probe_create(machtrace_id, NULL, mach_name_table[i],
945 "return", MACHTRACE_ARTIFICIAL_FRAMES,
946 (void *)((uintptr_t)SYSTRACE_RETURN(i)));
947
948 machtrace_sysent[i].stsy_entry = DTRACE_IDNONE;
949 machtrace_sysent[i].stsy_return = DTRACE_IDNONE;
950 }
951}
952
953/*ARGSUSED*/
954static void
955machtrace_destroy(void *arg, dtrace_id_t id, void *parg)
956{
957 int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg);
958
959 /*
960 * There's nothing to do here but assert that we have actually been
961 * disabled.
962 */
963 if (SYSTRACE_ISENTRY((uintptr_t)parg)) {
964 ASSERT(machtrace_sysent[sysnum].stsy_entry == DTRACE_IDNONE);
965 } else {
966 ASSERT(machtrace_sysent[sysnum].stsy_return == DTRACE_IDNONE);
967 }
968}
969
970/*ARGSUSED*/
971static void
972machtrace_enable(void *arg, dtrace_id_t id, void *parg)
973{
974 int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg);
975 int enabled = (machtrace_sysent[sysnum].stsy_entry != DTRACE_IDNONE ||
976 machtrace_sysent[sysnum].stsy_return != DTRACE_IDNONE);
977
978 if (SYSTRACE_ISENTRY((uintptr_t)parg)) {
979 machtrace_sysent[sysnum].stsy_entry = id;
980 } else {
981 machtrace_sysent[sysnum].stsy_return = id;
982 }
983
984 if (enabled) {
985 ASSERT(sysent[sysnum].sy_callc == dtrace_machtrace_syscall);
986 return;
987 }
988
989 (void) casptr(&mach_trap_table[sysnum].mach_trap_function,
990 (void *)machtrace_sysent[sysnum].stsy_underlying,
991 (void *)dtrace_machtrace_syscall);
992}
993
994/*ARGSUSED*/
995static void
996machtrace_disable(void *arg, dtrace_id_t id, void *parg)
997{
998 int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg);
999 int disable = (machtrace_sysent[sysnum].stsy_entry == DTRACE_IDNONE ||
1000 machtrace_sysent[sysnum].stsy_return == DTRACE_IDNONE);
1001
1002 if (disable) {
1003 (void) casptr(&mach_trap_table[sysnum].mach_trap_function,
1004 (void *)dtrace_machtrace_syscall,
1005 (void *)machtrace_sysent[sysnum].stsy_underlying);
1006
1007 }
1008
1009 if (SYSTRACE_ISENTRY((uintptr_t)parg)) {
1010 machtrace_sysent[sysnum].stsy_entry = DTRACE_IDNONE;
1011 } else {
1012 machtrace_sysent[sysnum].stsy_return = DTRACE_IDNONE;
1013 }
1014}
1015
1016static dtrace_pattr_t machtrace_attr = {
1017{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
1018{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
1019{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
1020{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
1021{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
1022};
1023
1024static dtrace_pops_t machtrace_pops = {
1025 machtrace_provide,
1026 NULL,
1027 machtrace_enable,
1028 machtrace_disable,
1029 NULL,
1030 NULL,
1031 NULL,
1032 NULL,
1033 NULL,
1034 machtrace_destroy
1035};
1036
1037static int
1038machtrace_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
1039{
1040 switch (cmd) {
1041 case DDI_ATTACH:
1042 break;
1043 case DDI_RESUME:
1044 return (DDI_SUCCESS);
1045 default:
1046 return (DDI_FAILURE);
1047 }
1048
1049 machtrace_probe = dtrace_probe;
1050 membar_enter();
1051
1052 if (ddi_create_minor_node(devi, "machtrace", S_IFCHR, 0,
1053 DDI_PSEUDO, NULL) == DDI_FAILURE ||
1054 dtrace_register("mach_trap", &machtrace_attr, DTRACE_PRIV_USER, NULL,
1055 &machtrace_pops, NULL, &machtrace_id) != 0) {
1056 machtrace_probe = systrace_stub;
1057 ddi_remove_minor_node(devi, NULL);
1058 return (DDI_FAILURE);
1059 }
1060
1061 ddi_report_dev(devi);
1062 machtrace_devi = devi;
1063
1064 return (DDI_SUCCESS);
1065}
1066
1067d_open_t _systrace_open;
1068
1069int _systrace_open(dev_t dev, int flags, int devtype, struct proc *p)
1070{
1071#pragma unused(dev,flags,devtype,p)
1072 return 0;
1073}
1074
1075#define SYSTRACE_MAJOR -24 /* let the kernel pick the device number */
1076
1077/*
1078 * A struct describing which functions will get invoked for certain
1079 * actions.
1080 */
1081static struct cdevsw systrace_cdevsw =
1082{
1083 _systrace_open, /* open */
1084 eno_opcl, /* close */
1085 eno_rdwrt, /* read */
1086 eno_rdwrt, /* write */
1087 eno_ioctl, /* ioctl */
1088 (stop_fcn_t *)nulldev, /* stop */
1089 (reset_fcn_t *)nulldev, /* reset */
1090 NULL, /* tty's */
1091 eno_select, /* select */
1092 eno_mmap, /* mmap */
1093 eno_strat, /* strategy */
1094 eno_getc, /* getc */
1095 eno_putc, /* putc */
1096 0 /* type */
1097};
1098
1099static int gSysTraceInited = 0;
1100
1101void systrace_init( void );
1102
1103void systrace_init( void )
1104{
1105 if (0 == gSysTraceInited) {
1106 int majdevno = cdevsw_add(SYSTRACE_MAJOR, &systrace_cdevsw);
1107
1108 if (majdevno < 0) {
1109 printf("systrace_init: failed to allocate a major number!\n");
1110 gSysTraceInited = 0;
1111 return;
1112 }
1113
1114 systrace_attach( (dev_info_t *)majdevno, DDI_ATTACH );
1115 machtrace_attach( (dev_info_t *)majdevno, DDI_ATTACH );
1116
1117 gSysTraceInited = 1;
1118 } else
1119 panic("systrace_init: called twice!\n");
1120}
1121#undef SYSTRACE_MAJOR
1122#endif /* __APPLE__ */