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.
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.
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]
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* #pragma ident "@(#)systrace.c 1.5 06/03/24 SMI" */
28 #if !defined(__APPLE__)
29 #include <sys/dtrace.h>
30 #include <sys/systrace.h>
32 #include <sys/systm.h>
35 #include <sys/sunddi.h>
36 #include <sys/atomic.h>
37 #define SYSTRACE_ARTIFICIAL_FRAMES 1
42 #define _KERNEL /* Solaris vs. Darwin */
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)
56 typedef x86_saved_state_t savearea_t
;
59 #include <sys/param.h>
60 #include <sys/systm.h>
62 #include <sys/errno.h>
63 #include <sys/ioctl.h>
65 #include <sys/fcntl.h>
66 #include <miscfs/devfs/devfs.h>
68 #include <sys/dtrace.h>
69 #include <sys/dtrace_impl.h>
72 #include <sys/systm.h>
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
83 #error Unknown Architecture
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 */
90 extern const char *syscallnames
[];
92 #include <sys/dtrace_glue.h>
93 #define casptr dtrace_casptr
94 #define membar_enter dtrace_membar_producer
96 #define LOADABLE_SYSCALL(a) 0 /* Not pertinent to Darwin. */
97 #define LOADED_SYSCALL(a) 1 /* Not pertinent to Darwin. */
99 systrace_sysent_t
*systrace_sysent
= NULL
;
100 void (*systrace_probe
)(dtrace_id_t
, uint64_t, uint64_t,
101 uint64_t, uint64_t, uint64_t);
104 systrace_stub(dtrace_id_t id
, uint64_t arg0
, uint64_t arg1
,
105 uint64_t arg2
, uint64_t arg3
, uint64_t arg4
)
107 #pragma unused(id,arg0,arg1,arg2,arg3,arg4)
111 dtrace_systrace_syscall(struct proc
*pp
, void *uap
, int *rv
)
116 systrace_sysent_t
*sy
;
122 syscall_arg_t
*ip
= (syscall_arg_t
*)uap
;
124 #if defined (__ppc__) || defined (__ppc64__)
126 savearea_t
*regs
= (savearea_t
*)find_user_regs(current_thread());
128 flavor
= (((unsigned int)regs
->save_r0
) == 0)? 1: 0;
131 code
= regs
->save_r3
;
133 code
= regs
->save_r0
;
135 #elif defined(__i386__) || defined (__x86_64__)
136 #pragma unused(flavor)
138 x86_saved_state_t
*tagged_regs
= (x86_saved_state_t
*)find_user_regs(current_thread());
140 if (is_saved_state64(tagged_regs
)) {
141 x86_saved_state64_t
*regs
= saved_state64(tagged_regs
);
142 code
= regs
->rax
& SYSCALL_NUMBER_MASK
;
144 * Check for indirect system call... system call number
151 code
= saved_state32(tagged_regs
)->eax
& I386_SYSCALL_NUMBER_MASK
;
153 * TODO: handle indirect system calls
158 #error Unknown Architecture
161 // Bounds "check" the value of code a la unix_syscall
162 sy
= (code
>= NUM_SYSENT
) ? &systrace_sysent
[63] : &systrace_sysent
[code
];
164 if ((id
= sy
->stsy_entry
) != DTRACE_IDNONE
) {
166 (*systrace_probe
)(id
, *ip
, *(ip
+1), *(ip
+2), *(ip
+3), *(ip
+4));
168 (*systrace_probe
)(id
, 0, 0, 0, 0, 0);
173 * We want to explicitly allow DTrace consumers to stop a process
174 * before it actually executes the meat of the syscall.
176 p
= ttoproc(curthread
);
177 mutex_enter(&p
->p_lock
);
178 if (curthread
->t_dtrace_stop
&& !curthread
->t_lwp
->lwp_nostop
) {
179 curthread
->t_dtrace_stop
= 0;
180 stop(PR_REQUESTED
, 0);
182 mutex_exit(&p
->p_lock
);
185 rval
= (*sy
->stsy_underlying
)(pp
, uap
, rv
);
187 if ((id
= sy
->stsy_return
) != DTRACE_IDNONE
) {
189 uthread_t uthread
= (uthread_t
)get_bsdthread_info(current_thread());
192 uthread
->t_dtrace_errno
= rval
; /* Establish t_dtrace_errno now in case this enabling refers to it. */
195 * "Decode" rv for use in the call to dtrace_probe()
197 if (rval
== ERESTART
) {
198 munged_rv
= -1LL; /* System call will be reissued in user mode. Make DTrace report a -1 return. */
199 } else if (rval
!= EJUSTRETURN
) {
201 munged_rv
= -1LL; /* Mimic what libc will do. */
203 switch (sy
->stsy_return_type
) {
204 case _SYSCALL_RET_INT_T
:
207 case _SYSCALL_RET_UINT_T
:
208 munged_rv
= ((u_int
)rv
[0]);
210 case _SYSCALL_RET_OFF_T
:
211 munged_rv
= *(u_int64_t
*)rv
;
213 case _SYSCALL_RET_ADDR_T
:
214 case _SYSCALL_RET_SIZE_T
:
215 case _SYSCALL_RET_SSIZE_T
:
216 munged_rv
= *(user_addr_t
*)rv
;
218 case _SYSCALL_RET_NONE
:
229 (*systrace_probe
)(id
, munged_rv
, munged_rv
, (uint64_t)rval
, 0, 0);
236 dtrace_systrace_syscall_return(unsigned short code
, int rval
, int *rv
)
238 systrace_sysent_t
*sy
;
241 // Bounds "check" the value of code a la unix_syscall_return
242 sy
= (code
>= NUM_SYSENT
) ? &systrace_sysent
[63] : &systrace_sysent
[code
];
244 if ((id
= sy
->stsy_return
) != DTRACE_IDNONE
) {
246 uthread_t uthread
= (uthread_t
)get_bsdthread_info(current_thread());
249 uthread
->t_dtrace_errno
= rval
; /* Establish t_dtrace_errno now in case this enabling refers to it. */
252 * "Decode" rv for use in the call to dtrace_probe()
254 if (rval
== ERESTART
) {
255 munged_rv
= -1LL; /* System call will be reissued in user mode. Make DTrace report a -1 return. */
256 } else if (rval
!= EJUSTRETURN
) {
258 munged_rv
= -1LL; /* Mimic what libc will do. */
260 switch (sy
->stsy_return_type
) {
261 case _SYSCALL_RET_INT_T
:
264 case _SYSCALL_RET_UINT_T
:
265 munged_rv
= ((u_int
)rv
[0]);
267 case _SYSCALL_RET_OFF_T
:
268 munged_rv
= *(u_int64_t
*)rv
;
270 case _SYSCALL_RET_ADDR_T
:
271 case _SYSCALL_RET_SIZE_T
:
272 case _SYSCALL_RET_SSIZE_T
:
273 munged_rv
= *(user_addr_t
*)rv
;
275 case _SYSCALL_RET_NONE
:
286 (*systrace_probe
)(id
, munged_rv
, munged_rv
, (uint64_t)rval
, 0, 0);
289 #endif /* __APPLE__ */
291 #define SYSTRACE_SHIFT 16
292 #define SYSTRACE_ISENTRY(x) ((int)(x) >> SYSTRACE_SHIFT)
293 #define SYSTRACE_SYSNUM(x) ((int)(x) & ((1 << SYSTRACE_SHIFT) - 1))
294 #define SYSTRACE_ENTRY(id) ((1 << SYSTRACE_SHIFT) | (id))
295 #define SYSTRACE_RETURN(id) (id)
297 #if ((1 << SYSTRACE_SHIFT) <= NSYSCALL)
298 #error 1 << SYSTRACE_SHIFT must exceed number of system calls
301 static dev_info_t
*systrace_devi
;
302 static dtrace_provider_id_t systrace_id
;
304 #if defined(__APPLE__)
305 #define systrace_init _systrace_init /* Avoid name clash with Darwin automagic conf symbol */
308 systrace_init(struct sysent
*actual
, systrace_sysent_t
**interposed
)
310 systrace_sysent_t
*sysent
= *interposed
;
313 if (sysent
== NULL
) {
314 *interposed
= sysent
= kmem_zalloc(sizeof (systrace_sysent_t
) *
318 for (i
= 0; i
< NSYSCALL
; i
++) {
319 struct sysent
*a
= &actual
[i
];
320 systrace_sysent_t
*s
= &sysent
[i
];
322 if (LOADABLE_SYSCALL(a
) && !LOADED_SYSCALL(a
))
325 if (a
->sy_callc
== dtrace_systrace_syscall
)
328 #ifdef _SYSCALL32_IMPL
329 if (a
->sy_callc
== dtrace_systrace_syscall32
)
333 s
->stsy_underlying
= a
->sy_callc
;
334 #if defined(__APPLE__)
335 s
->stsy_return_type
= a
->sy_return_type
;
342 systrace_provide(void *arg
, const dtrace_probedesc_t
*desc
)
349 systrace_init(sysent
, &systrace_sysent
);
350 #ifdef _SYSCALL32_IMPL
351 systrace_init(sysent32
, &systrace_sysent32
);
354 for (i
= 0; i
< NSYSCALL
; i
++) {
355 if (systrace_sysent
[i
].stsy_underlying
== NULL
)
358 if (dtrace_probe_lookup(systrace_id
, NULL
,
359 syscallnames
[i
], "entry") != 0)
362 (void) dtrace_probe_create(systrace_id
, NULL
, syscallnames
[i
],
363 "entry", SYSTRACE_ARTIFICIAL_FRAMES
,
364 (void *)((uintptr_t)SYSTRACE_ENTRY(i
)));
365 (void) dtrace_probe_create(systrace_id
, NULL
, syscallnames
[i
],
366 "return", SYSTRACE_ARTIFICIAL_FRAMES
,
367 (void *)((uintptr_t)SYSTRACE_RETURN(i
)));
369 systrace_sysent
[i
].stsy_entry
= DTRACE_IDNONE
;
370 systrace_sysent
[i
].stsy_return
= DTRACE_IDNONE
;
371 #ifdef _SYSCALL32_IMPL
372 systrace_sysent32
[i
].stsy_entry
= DTRACE_IDNONE
;
373 systrace_sysent32
[i
].stsy_return
= DTRACE_IDNONE
;
377 #if defined(__APPLE__)
383 systrace_destroy(void *arg
, dtrace_id_t id
, void *parg
)
385 int sysnum
= SYSTRACE_SYSNUM((uintptr_t)parg
);
388 * There's nothing to do here but assert that we have actually been
391 if (SYSTRACE_ISENTRY((uintptr_t)parg
)) {
392 ASSERT(systrace_sysent
[sysnum
].stsy_entry
== DTRACE_IDNONE
);
393 #ifdef _SYSCALL32_IMPL
394 ASSERT(systrace_sysent32
[sysnum
].stsy_entry
== DTRACE_IDNONE
);
397 ASSERT(systrace_sysent
[sysnum
].stsy_return
== DTRACE_IDNONE
);
398 #ifdef _SYSCALL32_IMPL
399 ASSERT(systrace_sysent32
[sysnum
].stsy_return
== DTRACE_IDNONE
);
406 systrace_enable(void *arg
, dtrace_id_t id
, void *parg
)
408 int sysnum
= SYSTRACE_SYSNUM((uintptr_t)parg
);
409 int enabled
= (systrace_sysent
[sysnum
].stsy_entry
!= DTRACE_IDNONE
||
410 systrace_sysent
[sysnum
].stsy_return
!= DTRACE_IDNONE
);
412 if (SYSTRACE_ISENTRY((uintptr_t)parg
)) {
413 systrace_sysent
[sysnum
].stsy_entry
= id
;
414 #ifdef _SYSCALL32_IMPL
415 systrace_sysent32
[sysnum
].stsy_entry
= id
;
418 systrace_sysent
[sysnum
].stsy_return
= id
;
419 #ifdef _SYSCALL32_IMPL
420 systrace_sysent32
[sysnum
].stsy_return
= id
;
425 ASSERT(sysent
[sysnum
].sy_callc
== dtrace_systrace_syscall
);
429 (void) casptr(&sysent
[sysnum
].sy_callc
,
430 (void *)systrace_sysent
[sysnum
].stsy_underlying
,
431 (void *)dtrace_systrace_syscall
);
432 #ifdef _SYSCALL32_IMPL
433 (void) casptr(&sysent32
[sysnum
].sy_callc
,
434 (void *)systrace_sysent32
[sysnum
].stsy_underlying
,
435 (void *)dtrace_systrace_syscall32
);
441 systrace_disable(void *arg
, dtrace_id_t id
, void *parg
)
443 int sysnum
= SYSTRACE_SYSNUM((uintptr_t)parg
);
444 int disable
= (systrace_sysent
[sysnum
].stsy_entry
== DTRACE_IDNONE
||
445 systrace_sysent
[sysnum
].stsy_return
== DTRACE_IDNONE
);
448 (void) casptr(&sysent
[sysnum
].sy_callc
,
449 (void *)dtrace_systrace_syscall
,
450 (void *)systrace_sysent
[sysnum
].stsy_underlying
);
452 #ifdef _SYSCALL32_IMPL
453 (void) casptr(&sysent32
[sysnum
].sy_callc
,
454 (void *)dtrace_systrace_syscall32
,
455 (void *)systrace_sysent32
[sysnum
].stsy_underlying
);
459 if (SYSTRACE_ISENTRY((uintptr_t)parg
)) {
460 systrace_sysent
[sysnum
].stsy_entry
= DTRACE_IDNONE
;
461 #ifdef _SYSCALL32_IMPL
462 systrace_sysent32
[sysnum
].stsy_entry
= DTRACE_IDNONE
;
465 systrace_sysent
[sysnum
].stsy_return
= DTRACE_IDNONE
;
466 #ifdef _SYSCALL32_IMPL
467 systrace_sysent32
[sysnum
].stsy_return
= DTRACE_IDNONE
;
472 static dtrace_pattr_t systrace_attr
= {
473 { DTRACE_STABILITY_EVOLVING
, DTRACE_STABILITY_EVOLVING
, DTRACE_CLASS_COMMON
},
474 { DTRACE_STABILITY_PRIVATE
, DTRACE_STABILITY_PRIVATE
, DTRACE_CLASS_UNKNOWN
},
475 { DTRACE_STABILITY_PRIVATE
, DTRACE_STABILITY_PRIVATE
, DTRACE_CLASS_ISA
},
476 { DTRACE_STABILITY_EVOLVING
, DTRACE_STABILITY_EVOLVING
, DTRACE_CLASS_COMMON
},
477 { DTRACE_STABILITY_PRIVATE
, DTRACE_STABILITY_PRIVATE
, DTRACE_CLASS_ISA
},
480 static dtrace_pops_t systrace_pops
= {
494 systrace_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
)
500 return (DDI_SUCCESS
);
502 return (DDI_FAILURE
);
505 systrace_probe
= dtrace_probe
;
508 if (ddi_create_minor_node(devi
, "systrace", S_IFCHR
, 0,
509 DDI_PSEUDO
, NULL
) == DDI_FAILURE
||
510 dtrace_register("syscall", &systrace_attr
, DTRACE_PRIV_USER
, NULL
,
511 &systrace_pops
, NULL
, &systrace_id
) != 0) {
512 systrace_probe
= systrace_stub
;
513 ddi_remove_minor_node(devi
, NULL
);
514 return (DDI_FAILURE
);
517 ddi_report_dev(devi
);
518 systrace_devi
= devi
;
520 return (DDI_SUCCESS
);
523 #if !defined(__APPLE__)
525 systrace_detach(dev_info_t
*devi
, ddi_detach_cmd_t cmd
)
531 return (DDI_SUCCESS
);
533 return (DDI_FAILURE
);
536 if (dtrace_unregister(systrace_id
) != 0)
537 return (DDI_FAILURE
);
539 ddi_remove_minor_node(devi
, NULL
);
540 systrace_probe
= systrace_stub
;
541 return (DDI_SUCCESS
);
546 systrace_info(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
, void **result
)
551 case DDI_INFO_DEVT2DEVINFO
:
552 *result
= (void *)systrace_devi
;
555 case DDI_INFO_DEVT2INSTANCE
:
567 systrace_open(dev_t
*devp
, int flag
, int otyp
, cred_t
*cred_p
)
572 static struct cb_ops systrace_cb_ops
= {
573 systrace_open
, /* open */
575 nulldev
, /* strategy */
585 ddi_prop_op
, /* cb_prop_op */
587 D_NEW
| D_MP
/* Driver compatibility flag */
590 static struct dev_ops systrace_ops
= {
591 DEVO_REV
, /* devo_rev, */
593 systrace_info
, /* get_dev_info */
594 nulldev
, /* identify */
596 systrace_attach
, /* attach */
597 systrace_detach
, /* detach */
599 &systrace_cb_ops
, /* driver operations */
600 NULL
, /* bus operations */
601 nodev
/* dev power */
605 * Module linkage information for the kernel.
607 static struct modldrv modldrv
= {
608 &mod_driverops
, /* module type (this is a pseudo driver) */
609 "System Call Tracing", /* name of module */
610 &systrace_ops
, /* driver ops */
613 static struct modlinkage modlinkage
= {
622 return (mod_install(&modlinkage
));
626 _info(struct modinfo
*modinfop
)
628 return (mod_info(&modlinkage
, modinfop
));
634 return (mod_remove(&modlinkage
));
637 typedef kern_return_t (*mach_call_t
)(void *);
639 /* XXX From #include <kern/syscall_sw.h> which may be changed for 64 bit! */
640 typedef void mach_munge_t(const void *, void *);
643 int mach_trap_arg_count
;
644 int (*mach_trap_function
)(void);
645 #if defined(__i386__)
646 boolean_t mach_trap_stack
;
648 mach_munge_t
*mach_trap_arg_munge32
; /* system call arguments for 32-bit */
649 mach_munge_t
*mach_trap_arg_munge64
; /* system call arguments for 64-bit */
652 int mach_trap_unused
;
654 const char* mach_trap_name
;
655 #endif /* !MACH_ASSERT */
658 #define MACH_TRAP_TABLE_COUNT 128
660 extern mach_trap_t mach_trap_table
[];
661 extern int mach_trap_count
;
663 #define MACH_TRAP(name, foo, bar, baz) #name
665 /* XXX From osfmk/kern/syscall_sw.c */
666 static const char * mach_name_table
[MACH_TRAP_TABLE_COUNT
] = {
667 /* 0 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
668 /* 1 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
669 /* 2 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
670 /* 3 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
671 /* 4 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
672 /* 5 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
673 /* 6 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
674 /* 7 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
675 /* 8 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
676 /* 9 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
677 /* 10 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
678 /* 11 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
679 /* 12 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
680 /* 13 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
681 /* 14 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
682 /* 15 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
683 /* 16 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
684 /* 17 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
685 /* 18 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
686 /* 19 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
687 /* 20 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
688 /* 21 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
689 /* 22 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
690 /* 23 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
691 /* 24 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
692 /* 25 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
693 /* 26 */ MACH_TRAP(mach_reply_port
, 0, NULL
, NULL
),
694 /* 27 */ MACH_TRAP(thread_self_trap
, 0, NULL
, NULL
),
695 /* 28 */ MACH_TRAP(task_self_trap
, 0, NULL
, NULL
),
696 /* 29 */ MACH_TRAP(host_self_trap
, 0, NULL
, NULL
),
697 /* 30 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
698 /* 31 */ MACH_TRAP(mach_msg_trap
, 7, munge_wwwwwww
, munge_ddddddd
),
699 /* 32 */ MACH_TRAP(mach_msg_overwrite_trap
, 8, munge_wwwwwwww
, munge_dddddddd
),
700 /* 33 */ MACH_TRAP(semaphore_signal_trap
, 1, munge_w
, munge_d
),
701 /* 34 */ MACH_TRAP(semaphore_signal_all_trap
, 1, munge_w
, munge_d
),
702 /* 35 */ MACH_TRAP(semaphore_signal_thread_trap
, 2, munge_ww
, munge_dd
),
703 /* 36 */ MACH_TRAP(semaphore_wait_trap
, 1, munge_w
, munge_d
),
704 /* 37 */ MACH_TRAP(semaphore_wait_signal_trap
, 2, munge_ww
, munge_dd
),
705 /* 38 */ MACH_TRAP(semaphore_timedwait_trap
, 3, munge_www
, munge_ddd
),
706 /* 39 */ MACH_TRAP(semaphore_timedwait_signal_trap
, 4, munge_wwww
, munge_dddd
),
707 /* 40 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
708 /* 41 */ MACH_TRAP(init_process
, 0, NULL
, NULL
),
709 /* 42 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
710 /* 43 */ MACH_TRAP(map_fd
, 5, munge_wwwww
, munge_ddddd
),
711 /* 44 */ MACH_TRAP(task_name_for_pid
, 3, munge_www
, munge_ddd
),
712 /* 45 */ MACH_TRAP(task_for_pid
, 3, munge_www
, munge_ddd
),
713 /* 46 */ MACH_TRAP(pid_for_task
, 2, munge_ww
,munge_dd
),
714 /* 47 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
715 /* 48 */ MACH_TRAP(macx_swapon
, 4, munge_wwww
, munge_dddd
),
716 /* 49 */ MACH_TRAP(macx_swapoff
, 2, munge_ww
, munge_dd
),
717 /* 50 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
718 /* 51 */ MACH_TRAP(macx_triggers
, 4, munge_wwww
, munge_dddd
),
719 /* 52 */ MACH_TRAP(macx_backing_store_suspend
, 1, munge_w
, munge_d
),
720 /* 53 */ MACH_TRAP(macx_backing_store_recovery
, 1, munge_w
, munge_d
),
721 /* 54 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
722 /* 55 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
723 /* 56 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
724 /* 57 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
725 /* 58 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
726 /* 59 */ MACH_TRAP(swtch_pri
, 0, NULL
, NULL
),
727 /* 60 */ MACH_TRAP(swtch
, 0, NULL
, NULL
),
728 /* 61 */ MACH_TRAP(thread_switch
, 3, munge_www
, munge_ddd
),
729 /* 62 */ MACH_TRAP(clock_sleep_trap
, 5, munge_wwwww
, munge_ddddd
),
730 /* 63 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
731 /* traps 64 - 95 reserved (debo) */
732 /* 64 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
733 /* 65 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
734 /* 66 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
735 /* 67 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
736 /* 68 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
737 /* 69 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
738 /* 70 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
739 /* 71 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
740 /* 72 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
741 /* 73 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
742 /* 74 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
743 /* 75 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
744 /* 76 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
745 /* 77 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
746 /* 78 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
747 /* 79 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
748 /* 80 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
749 /* 81 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
750 /* 82 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
751 /* 83 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
752 /* 84 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
753 /* 85 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
754 /* 86 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
755 /* 87 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
756 /* 88 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
757 /* 89 */ MACH_TRAP(mach_timebase_info_trap
, 1, munge_w
, munge_d
),
758 /* 90 */ MACH_TRAP(mach_wait_until_trap
, 2, munge_l
, munge_d
),
759 /* 91 */ MACH_TRAP(mk_timer_create_trap
, 0, NULL
, NULL
),
760 /* 92 */ MACH_TRAP(mk_timer_destroy_trap
, 1, munge_w
, munge_d
),
761 /* 93 */ MACH_TRAP(mk_timer_arm_trap
, 3, munge_wl
, munge_dd
),
762 /* 94 */ MACH_TRAP(mk_timer_cancel_trap
, 2, munge_ww
, munge_dd
),
763 /* 95 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
764 /* traps 64 - 95 reserved (debo) */
765 /* 96 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
766 /* 97 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
767 /* 98 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
768 /* 99 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
769 /* traps 100-107 reserved for iokit (esb) */
770 /* 100 */ MACH_TRAP(iokit_user_client_trap
, 8, munge_wwwwwwww
, munge_dddddddd
),
771 /* 101 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
772 /* 102 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
773 /* 103 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
774 /* 104 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
775 /* 105 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
776 /* 106 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
777 /* 107 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
778 /* traps 108-127 unused */
779 /* 108 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
780 /* 109 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
781 /* 110 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
782 /* 111 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
783 /* 112 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
784 /* 113 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
785 /* 114 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
786 /* 115 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
787 /* 116 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
788 /* 117 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
789 /* 118 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
790 /* 119 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
791 /* 120 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
792 /* 121 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
793 /* 122 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
794 /* 123 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
795 /* 124 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
796 /* 125 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
797 /* 126 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
798 /* 127 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
801 /* XXX From osfmk/i386/bsd_i386.c */
802 struct mach_call_args
{
815 #define NSYSCALL mach_trap_count
817 #if ((1 << SYSTRACE_SHIFT) <= NSYSCALL)
818 #error 1 << SYSTRACE_SHIFT must exceed number of Mach traps
821 typedef systrace_sysent_t machtrace_sysent_t
;
823 static machtrace_sysent_t
*machtrace_sysent
= NULL
;
825 void (*machtrace_probe
)(dtrace_id_t
, uint64_t, uint64_t,
826 uint64_t, uint64_t, uint64_t);
828 static dev_info_t
*machtrace_devi
;
829 static dtrace_provider_id_t machtrace_id
;
832 dtrace_machtrace_syscall(struct mach_call_args
*args
)
837 machtrace_sysent_t
*sy
;
843 syscall_arg_t
*ip
= (syscall_arg_t
*)args
;
844 mach_call_t mach_call
;
846 #if defined (__ppc__) || defined (__ppc64__)
848 savearea_t
*regs
= (savearea_t
*)find_user_regs(current_thread());
850 flavor
= (((unsigned int)regs
->save_r0
) == 0)? 1: 0;
853 code
= -regs
->save_r3
;
855 code
= -regs
->save_r0
;
857 #elif defined(__i386__) || defined (__x86_64__)
858 #pragma unused(flavor)
860 x86_saved_state_t
*tagged_regs
= (x86_saved_state_t
*)find_user_regs(current_thread());
862 if (is_saved_state64(tagged_regs
)) {
863 code
= saved_state64(tagged_regs
)->rax
& SYSCALL_NUMBER_MASK
;
865 code
= -saved_state32(tagged_regs
)->eax
;
869 #error Unknown Architecture
872 sy
= &machtrace_sysent
[code
];
874 if ((id
= sy
->stsy_entry
) != DTRACE_IDNONE
)
875 (*machtrace_probe
)(id
, *ip
, *(ip
+1), *(ip
+2), *(ip
+3), *(ip
+4));
879 * We want to explicitly allow DTrace consumers to stop a process
880 * before it actually executes the meat of the syscall.
882 p
= ttoproc(curthread
);
883 mutex_enter(&p
->p_lock
);
884 if (curthread
->t_dtrace_stop
&& !curthread
->t_lwp
->lwp_nostop
) {
885 curthread
->t_dtrace_stop
= 0;
886 stop(PR_REQUESTED
, 0);
888 mutex_exit(&p
->p_lock
);
891 mach_call
= (mach_call_t
)(*sy
->stsy_underlying
);
892 rval
= mach_call(args
);
894 if ((id
= sy
->stsy_return
) != DTRACE_IDNONE
)
895 (*machtrace_probe
)(id
, (uint64_t)rval
, 0, 0, 0, 0);
901 machtrace_init(mach_trap_t
*actual
, machtrace_sysent_t
**interposed
)
903 machtrace_sysent_t
*msysent
= *interposed
;
906 if (msysent
== NULL
) {
907 *interposed
= msysent
= kmem_zalloc(sizeof (machtrace_sysent_t
) *
911 for (i
= 0; i
< NSYSCALL
; i
++) {
912 mach_trap_t
*a
= &actual
[i
];
913 machtrace_sysent_t
*s
= &msysent
[i
];
915 if (LOADABLE_SYSCALL(a
) && !LOADED_SYSCALL(a
))
918 if ((mach_call_t
)(a
->mach_trap_function
) == (mach_call_t
)(dtrace_machtrace_syscall
))
921 s
->stsy_underlying
= a
->mach_trap_function
;
927 machtrace_provide(void *arg
, const dtrace_probedesc_t
*desc
)
934 machtrace_init(mach_trap_table
, &machtrace_sysent
);
936 for (i
= 0; i
< NSYSCALL
; i
++) {
938 if (machtrace_sysent
[i
].stsy_underlying
== NULL
)
941 if (dtrace_probe_lookup(machtrace_id
, NULL
,
942 mach_name_table
[i
], "entry") != 0)
945 (void) dtrace_probe_create(machtrace_id
, NULL
, mach_name_table
[i
],
946 "entry", MACHTRACE_ARTIFICIAL_FRAMES
,
947 (void *)((uintptr_t)SYSTRACE_ENTRY(i
)));
948 (void) dtrace_probe_create(machtrace_id
, NULL
, mach_name_table
[i
],
949 "return", MACHTRACE_ARTIFICIAL_FRAMES
,
950 (void *)((uintptr_t)SYSTRACE_RETURN(i
)));
952 machtrace_sysent
[i
].stsy_entry
= DTRACE_IDNONE
;
953 machtrace_sysent
[i
].stsy_return
= DTRACE_IDNONE
;
959 machtrace_destroy(void *arg
, dtrace_id_t id
, void *parg
)
961 int sysnum
= SYSTRACE_SYSNUM((uintptr_t)parg
);
964 * There's nothing to do here but assert that we have actually been
967 if (SYSTRACE_ISENTRY((uintptr_t)parg
)) {
968 ASSERT(machtrace_sysent
[sysnum
].stsy_entry
== DTRACE_IDNONE
);
970 ASSERT(machtrace_sysent
[sysnum
].stsy_return
== DTRACE_IDNONE
);
976 machtrace_enable(void *arg
, dtrace_id_t id
, void *parg
)
978 int sysnum
= SYSTRACE_SYSNUM((uintptr_t)parg
);
979 int enabled
= (machtrace_sysent
[sysnum
].stsy_entry
!= DTRACE_IDNONE
||
980 machtrace_sysent
[sysnum
].stsy_return
!= DTRACE_IDNONE
);
982 if (SYSTRACE_ISENTRY((uintptr_t)parg
)) {
983 machtrace_sysent
[sysnum
].stsy_entry
= id
;
985 machtrace_sysent
[sysnum
].stsy_return
= id
;
989 ASSERT(sysent
[sysnum
].sy_callc
== dtrace_machtrace_syscall
);
993 (void) casptr(&mach_trap_table
[sysnum
].mach_trap_function
,
994 (void *)machtrace_sysent
[sysnum
].stsy_underlying
,
995 (void *)dtrace_machtrace_syscall
);
1000 machtrace_disable(void *arg
, dtrace_id_t id
, void *parg
)
1002 int sysnum
= SYSTRACE_SYSNUM((uintptr_t)parg
);
1003 int disable
= (machtrace_sysent
[sysnum
].stsy_entry
== DTRACE_IDNONE
||
1004 machtrace_sysent
[sysnum
].stsy_return
== DTRACE_IDNONE
);
1007 (void) casptr(&mach_trap_table
[sysnum
].mach_trap_function
,
1008 (void *)dtrace_machtrace_syscall
,
1009 (void *)machtrace_sysent
[sysnum
].stsy_underlying
);
1013 if (SYSTRACE_ISENTRY((uintptr_t)parg
)) {
1014 machtrace_sysent
[sysnum
].stsy_entry
= DTRACE_IDNONE
;
1016 machtrace_sysent
[sysnum
].stsy_return
= DTRACE_IDNONE
;
1020 static dtrace_pattr_t machtrace_attr
= {
1021 { DTRACE_STABILITY_EVOLVING
, DTRACE_STABILITY_EVOLVING
, DTRACE_CLASS_COMMON
},
1022 { DTRACE_STABILITY_PRIVATE
, DTRACE_STABILITY_PRIVATE
, DTRACE_CLASS_UNKNOWN
},
1023 { DTRACE_STABILITY_PRIVATE
, DTRACE_STABILITY_PRIVATE
, DTRACE_CLASS_ISA
},
1024 { DTRACE_STABILITY_EVOLVING
, DTRACE_STABILITY_EVOLVING
, DTRACE_CLASS_COMMON
},
1025 { DTRACE_STABILITY_PRIVATE
, DTRACE_STABILITY_PRIVATE
, DTRACE_CLASS_ISA
},
1028 static dtrace_pops_t machtrace_pops
= {
1042 machtrace_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
)
1048 return (DDI_SUCCESS
);
1050 return (DDI_FAILURE
);
1053 machtrace_probe
= dtrace_probe
;
1056 if (ddi_create_minor_node(devi
, "machtrace", S_IFCHR
, 0,
1057 DDI_PSEUDO
, NULL
) == DDI_FAILURE
||
1058 dtrace_register("mach_trap", &machtrace_attr
, DTRACE_PRIV_USER
, NULL
,
1059 &machtrace_pops
, NULL
, &machtrace_id
) != 0) {
1060 machtrace_probe
= systrace_stub
;
1061 ddi_remove_minor_node(devi
, NULL
);
1062 return (DDI_FAILURE
);
1065 ddi_report_dev(devi
);
1066 machtrace_devi
= devi
;
1068 return (DDI_SUCCESS
);
1071 d_open_t _systrace_open
;
1073 int _systrace_open(dev_t dev
, int flags
, int devtype
, struct proc
*p
)
1075 #pragma unused(dev,flags,devtype,p)
1079 #define SYSTRACE_MAJOR -24 /* let the kernel pick the device number */
1082 * A struct describing which functions will get invoked for certain
1085 static struct cdevsw systrace_cdevsw
=
1087 _systrace_open
, /* open */
1088 eno_opcl
, /* close */
1089 eno_rdwrt
, /* read */
1090 eno_rdwrt
, /* write */
1091 eno_ioctl
, /* ioctl */
1092 (stop_fcn_t
*)nulldev
, /* stop */
1093 (reset_fcn_t
*)nulldev
, /* reset */
1095 eno_select
, /* select */
1096 eno_mmap
, /* mmap */
1097 eno_strat
, /* strategy */
1098 eno_getc
, /* getc */
1099 eno_putc
, /* putc */
1103 static int gSysTraceInited
= 0;
1105 void systrace_init( void );
1107 void systrace_init( void )
1109 if (0 == gSysTraceInited
) {
1110 int majdevno
= cdevsw_add(SYSTRACE_MAJOR
, &systrace_cdevsw
);
1113 printf("systrace_init: failed to allocate a major number!\n");
1114 gSysTraceInited
= 0;
1118 systrace_attach( (dev_info_t
*)majdevno
, DDI_ATTACH
);
1119 machtrace_attach( (dev_info_t
*)majdevno
, DDI_ATTACH
);
1121 gSysTraceInited
= 1;
1123 panic("systrace_init: called twice!\n");
1125 #undef SYSTRACE_MAJOR
1126 #endif /* __APPLE__ */