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
)
165 (*systrace_probe
)(id
, *ip
, *(ip
+1), *(ip
+2), *(ip
+3), *(ip
+4));
169 * We want to explicitly allow DTrace consumers to stop a process
170 * before it actually executes the meat of the syscall.
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);
178 mutex_exit(&p
->p_lock
);
181 rval
= (*sy
->stsy_underlying
)(pp
, uap
, rv
);
183 if ((id
= sy
->stsy_return
) != DTRACE_IDNONE
) {
185 uthread_t uthread
= (uthread_t
)get_bsdthread_info(current_thread());
188 uthread
->t_dtrace_errno
= rval
; /* Establish t_dtrace_errno now in case this enabling refers to it. */
191 * "Decode" rv for use in the call to dtrace_probe()
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
) {
197 munged_rv
= -1LL; /* Mimic what libc will do. */
199 switch (sy
->stsy_return_type
) {
200 case _SYSCALL_RET_INT_T
:
203 case _SYSCALL_RET_UINT_T
:
204 munged_rv
= ((u_int
)rv
[0]);
206 case _SYSCALL_RET_OFF_T
:
207 munged_rv
= *(u_int64_t
*)rv
;
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
;
214 case _SYSCALL_RET_NONE
:
225 (*systrace_probe
)(id
, munged_rv
, munged_rv
, (uint64_t)rval
, 0, 0);
232 dtrace_systrace_syscall_return(unsigned short code
, int rval
, int *rv
)
234 systrace_sysent_t
*sy
;
237 // Bounds "check" the value of code a la unix_syscall_return
238 sy
= (code
>= NUM_SYSENT
) ? &systrace_sysent
[63] : &systrace_sysent
[code
];
240 if ((id
= sy
->stsy_return
) != DTRACE_IDNONE
) {
242 uthread_t uthread
= (uthread_t
)get_bsdthread_info(current_thread());
245 uthread
->t_dtrace_errno
= rval
; /* Establish t_dtrace_errno now in case this enabling refers to it. */
248 * "Decode" rv for use in the call to dtrace_probe()
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
) {
254 munged_rv
= -1LL; /* Mimic what libc will do. */
256 switch (sy
->stsy_return_type
) {
257 case _SYSCALL_RET_INT_T
:
260 case _SYSCALL_RET_UINT_T
:
261 munged_rv
= ((u_int
)rv
[0]);
263 case _SYSCALL_RET_OFF_T
:
264 munged_rv
= *(u_int64_t
*)rv
;
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
;
271 case _SYSCALL_RET_NONE
:
282 (*systrace_probe
)(id
, munged_rv
, munged_rv
, (uint64_t)rval
, 0, 0);
285 #endif /* __APPLE__ */
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)
293 #if ((1 << SYSTRACE_SHIFT) <= NSYSCALL)
294 #error 1 << SYSTRACE_SHIFT must exceed number of system calls
297 static dev_info_t
*systrace_devi
;
298 static dtrace_provider_id_t systrace_id
;
300 #if defined(__APPLE__)
301 #define systrace_init _systrace_init /* Avoid name clash with Darwin automagic conf symbol */
304 systrace_init(struct sysent
*actual
, systrace_sysent_t
**interposed
)
306 systrace_sysent_t
*sysent
= *interposed
;
309 if (sysent
== NULL
) {
310 *interposed
= sysent
= kmem_zalloc(sizeof (systrace_sysent_t
) *
314 for (i
= 0; i
< NSYSCALL
; i
++) {
315 struct sysent
*a
= &actual
[i
];
316 systrace_sysent_t
*s
= &sysent
[i
];
318 if (LOADABLE_SYSCALL(a
) && !LOADED_SYSCALL(a
))
321 if (a
->sy_callc
== dtrace_systrace_syscall
)
324 #ifdef _SYSCALL32_IMPL
325 if (a
->sy_callc
== dtrace_systrace_syscall32
)
329 s
->stsy_underlying
= a
->sy_callc
;
330 #if defined(__APPLE__)
331 s
->stsy_return_type
= a
->sy_return_type
;
338 systrace_provide(void *arg
, const dtrace_probedesc_t
*desc
)
345 systrace_init(sysent
, &systrace_sysent
);
346 #ifdef _SYSCALL32_IMPL
347 systrace_init(sysent32
, &systrace_sysent32
);
350 for (i
= 0; i
< NSYSCALL
; i
++) {
351 if (systrace_sysent
[i
].stsy_underlying
== NULL
)
354 if (dtrace_probe_lookup(systrace_id
, NULL
,
355 syscallnames
[i
], "entry") != 0)
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
)));
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
;
373 #if defined(__APPLE__)
379 systrace_destroy(void *arg
, dtrace_id_t id
, void *parg
)
381 int sysnum
= SYSTRACE_SYSNUM((uintptr_t)parg
);
384 * There's nothing to do here but assert that we have actually been
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
);
393 ASSERT(systrace_sysent
[sysnum
].stsy_return
== DTRACE_IDNONE
);
394 #ifdef _SYSCALL32_IMPL
395 ASSERT(systrace_sysent32
[sysnum
].stsy_return
== DTRACE_IDNONE
);
402 systrace_enable(void *arg
, dtrace_id_t id
, void *parg
)
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
);
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
;
414 systrace_sysent
[sysnum
].stsy_return
= id
;
415 #ifdef _SYSCALL32_IMPL
416 systrace_sysent32
[sysnum
].stsy_return
= id
;
421 ASSERT(sysent
[sysnum
].sy_callc
== dtrace_systrace_syscall
);
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
);
437 systrace_disable(void *arg
, dtrace_id_t id
, void *parg
)
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
);
444 (void) casptr(&sysent
[sysnum
].sy_callc
,
445 (void *)dtrace_systrace_syscall
,
446 (void *)systrace_sysent
[sysnum
].stsy_underlying
);
448 #ifdef _SYSCALL32_IMPL
449 (void) casptr(&sysent32
[sysnum
].sy_callc
,
450 (void *)dtrace_systrace_syscall32
,
451 (void *)systrace_sysent32
[sysnum
].stsy_underlying
);
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
;
461 systrace_sysent
[sysnum
].stsy_return
= DTRACE_IDNONE
;
462 #ifdef _SYSCALL32_IMPL
463 systrace_sysent32
[sysnum
].stsy_return
= DTRACE_IDNONE
;
468 static 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
},
476 static dtrace_pops_t systrace_pops
= {
490 systrace_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
)
496 return (DDI_SUCCESS
);
498 return (DDI_FAILURE
);
501 systrace_probe
= dtrace_probe
;
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
);
513 ddi_report_dev(devi
);
514 systrace_devi
= devi
;
516 return (DDI_SUCCESS
);
519 #if !defined(__APPLE__)
521 systrace_detach(dev_info_t
*devi
, ddi_detach_cmd_t cmd
)
527 return (DDI_SUCCESS
);
529 return (DDI_FAILURE
);
532 if (dtrace_unregister(systrace_id
) != 0)
533 return (DDI_FAILURE
);
535 ddi_remove_minor_node(devi
, NULL
);
536 systrace_probe
= systrace_stub
;
537 return (DDI_SUCCESS
);
542 systrace_info(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
, void **result
)
547 case DDI_INFO_DEVT2DEVINFO
:
548 *result
= (void *)systrace_devi
;
551 case DDI_INFO_DEVT2INSTANCE
:
563 systrace_open(dev_t
*devp
, int flag
, int otyp
, cred_t
*cred_p
)
568 static struct cb_ops systrace_cb_ops
= {
569 systrace_open
, /* open */
571 nulldev
, /* strategy */
581 ddi_prop_op
, /* cb_prop_op */
583 D_NEW
| D_MP
/* Driver compatibility flag */
586 static struct dev_ops systrace_ops
= {
587 DEVO_REV
, /* devo_rev, */
589 systrace_info
, /* get_dev_info */
590 nulldev
, /* identify */
592 systrace_attach
, /* attach */
593 systrace_detach
, /* detach */
595 &systrace_cb_ops
, /* driver operations */
596 NULL
, /* bus operations */
597 nodev
/* dev power */
601 * Module linkage information for the kernel.
603 static 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 */
609 static struct modlinkage modlinkage
= {
618 return (mod_install(&modlinkage
));
622 _info(struct modinfo
*modinfop
)
624 return (mod_info(&modlinkage
, modinfop
));
630 return (mod_remove(&modlinkage
));
633 typedef kern_return_t (*mach_call_t
)(void *);
635 /* XXX From #include <kern/syscall_sw.h> which may be changed for 64 bit! */
636 typedef void mach_munge_t(const void *, void *);
639 int mach_trap_arg_count
;
640 int (*mach_trap_function
)(void);
641 #if defined(__i386__)
642 boolean_t mach_trap_stack
;
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 */
648 int mach_trap_unused
;
650 const char* mach_trap_name
;
651 #endif /* !MACH_ASSERT */
654 #define MACH_TRAP_TABLE_COUNT 128
656 extern mach_trap_t mach_trap_table
[];
657 extern int mach_trap_count
;
659 #define MACH_TRAP(name, foo, bar, baz) #name
661 /* XXX From osfmk/kern/syscall_sw.c */
662 static 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
),
797 /* XXX From osfmk/i386/bsd_i386.c */
798 struct mach_call_args
{
811 #define NSYSCALL mach_trap_count
813 #if ((1 << SYSTRACE_SHIFT) <= NSYSCALL)
814 #error 1 << SYSTRACE_SHIFT must exceed number of Mach traps
817 typedef systrace_sysent_t machtrace_sysent_t
;
819 static machtrace_sysent_t
*machtrace_sysent
= NULL
;
821 void (*machtrace_probe
)(dtrace_id_t
, uint64_t, uint64_t,
822 uint64_t, uint64_t, uint64_t);
824 static dev_info_t
*machtrace_devi
;
825 static dtrace_provider_id_t machtrace_id
;
828 dtrace_machtrace_syscall(struct mach_call_args
*args
)
833 machtrace_sysent_t
*sy
;
839 syscall_arg_t
*ip
= (syscall_arg_t
*)args
;
840 mach_call_t mach_call
;
842 #if defined (__ppc__) || defined (__ppc64__)
844 savearea_t
*regs
= (savearea_t
*)find_user_regs(current_thread());
846 flavor
= (((unsigned int)regs
->save_r0
) == 0)? 1: 0;
849 code
= -regs
->save_r3
;
851 code
= -regs
->save_r0
;
853 #elif defined(__i386__) || defined (__x86_64__)
854 #pragma unused(flavor)
856 x86_saved_state_t
*tagged_regs
= (x86_saved_state_t
*)find_user_regs(current_thread());
858 if (is_saved_state64(tagged_regs
)) {
859 code
= saved_state64(tagged_regs
)->rax
& SYSCALL_NUMBER_MASK
;
861 code
= -saved_state32(tagged_regs
)->eax
;
865 #error Unknown Architecture
868 sy
= &machtrace_sysent
[code
];
870 if ((id
= sy
->stsy_entry
) != DTRACE_IDNONE
)
871 (*machtrace_probe
)(id
, *ip
, *(ip
+1), *(ip
+2), *(ip
+3), *(ip
+4));
875 * We want to explicitly allow DTrace consumers to stop a process
876 * before it actually executes the meat of the syscall.
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);
884 mutex_exit(&p
->p_lock
);
887 mach_call
= (mach_call_t
)(*sy
->stsy_underlying
);
888 rval
= mach_call(args
);
890 if ((id
= sy
->stsy_return
) != DTRACE_IDNONE
)
891 (*machtrace_probe
)(id
, (uint64_t)rval
, 0, 0, 0, 0);
897 machtrace_init(mach_trap_t
*actual
, machtrace_sysent_t
**interposed
)
899 machtrace_sysent_t
*msysent
= *interposed
;
902 if (msysent
== NULL
) {
903 *interposed
= msysent
= kmem_zalloc(sizeof (machtrace_sysent_t
) *
907 for (i
= 0; i
< NSYSCALL
; i
++) {
908 mach_trap_t
*a
= &actual
[i
];
909 machtrace_sysent_t
*s
= &msysent
[i
];
911 if (LOADABLE_SYSCALL(a
) && !LOADED_SYSCALL(a
))
914 if ((mach_call_t
)(a
->mach_trap_function
) == (mach_call_t
)(dtrace_machtrace_syscall
))
917 s
->stsy_underlying
= a
->mach_trap_function
;
923 machtrace_provide(void *arg
, const dtrace_probedesc_t
*desc
)
930 machtrace_init(mach_trap_table
, &machtrace_sysent
);
932 for (i
= 0; i
< NSYSCALL
; i
++) {
934 if (machtrace_sysent
[i
].stsy_underlying
== NULL
)
937 if (dtrace_probe_lookup(machtrace_id
, NULL
,
938 mach_name_table
[i
], "entry") != 0)
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
)));
948 machtrace_sysent
[i
].stsy_entry
= DTRACE_IDNONE
;
949 machtrace_sysent
[i
].stsy_return
= DTRACE_IDNONE
;
955 machtrace_destroy(void *arg
, dtrace_id_t id
, void *parg
)
957 int sysnum
= SYSTRACE_SYSNUM((uintptr_t)parg
);
960 * There's nothing to do here but assert that we have actually been
963 if (SYSTRACE_ISENTRY((uintptr_t)parg
)) {
964 ASSERT(machtrace_sysent
[sysnum
].stsy_entry
== DTRACE_IDNONE
);
966 ASSERT(machtrace_sysent
[sysnum
].stsy_return
== DTRACE_IDNONE
);
972 machtrace_enable(void *arg
, dtrace_id_t id
, void *parg
)
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
);
978 if (SYSTRACE_ISENTRY((uintptr_t)parg
)) {
979 machtrace_sysent
[sysnum
].stsy_entry
= id
;
981 machtrace_sysent
[sysnum
].stsy_return
= id
;
985 ASSERT(sysent
[sysnum
].sy_callc
== dtrace_machtrace_syscall
);
989 (void) casptr(&mach_trap_table
[sysnum
].mach_trap_function
,
990 (void *)machtrace_sysent
[sysnum
].stsy_underlying
,
991 (void *)dtrace_machtrace_syscall
);
996 machtrace_disable(void *arg
, dtrace_id_t id
, void *parg
)
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
);
1003 (void) casptr(&mach_trap_table
[sysnum
].mach_trap_function
,
1004 (void *)dtrace_machtrace_syscall
,
1005 (void *)machtrace_sysent
[sysnum
].stsy_underlying
);
1009 if (SYSTRACE_ISENTRY((uintptr_t)parg
)) {
1010 machtrace_sysent
[sysnum
].stsy_entry
= DTRACE_IDNONE
;
1012 machtrace_sysent
[sysnum
].stsy_return
= DTRACE_IDNONE
;
1016 static 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
},
1024 static dtrace_pops_t machtrace_pops
= {
1038 machtrace_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
)
1044 return (DDI_SUCCESS
);
1046 return (DDI_FAILURE
);
1049 machtrace_probe
= dtrace_probe
;
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
);
1061 ddi_report_dev(devi
);
1062 machtrace_devi
= devi
;
1064 return (DDI_SUCCESS
);
1067 d_open_t _systrace_open
;
1069 int _systrace_open(dev_t dev
, int flags
, int devtype
, struct proc
*p
)
1071 #pragma unused(dev,flags,devtype,p)
1075 #define SYSTRACE_MAJOR -24 /* let the kernel pick the device number */
1078 * A struct describing which functions will get invoked for certain
1081 static struct cdevsw systrace_cdevsw
=
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 */
1091 eno_select
, /* select */
1092 eno_mmap
, /* mmap */
1093 eno_strat
, /* strategy */
1094 eno_getc
, /* getc */
1095 eno_putc
, /* putc */
1099 static int gSysTraceInited
= 0;
1101 void systrace_init( void );
1103 void systrace_init( void )
1105 if (0 == gSysTraceInited
) {
1106 int majdevno
= cdevsw_add(SYSTRACE_MAJOR
, &systrace_cdevsw
);
1109 printf("systrace_init: failed to allocate a major number!\n");
1110 gSysTraceInited
= 0;
1114 systrace_attach( (dev_info_t
*)majdevno
, DDI_ATTACH
);
1115 machtrace_attach( (dev_info_t
*)majdevno
, DDI_ATTACH
);
1117 gSysTraceInited
= 1;
1119 panic("systrace_init: called twice!\n");
1121 #undef SYSTRACE_MAJOR
1122 #endif /* __APPLE__ */