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
;
57 #elif defined(__arm__)
58 typedef struct arm_saved_state savearea_t
;
61 #include <sys/param.h>
62 #include <sys/systm.h>
64 #include <sys/errno.h>
65 #include <sys/ioctl.h>
67 #include <sys/fcntl.h>
68 #include <miscfs/devfs/devfs.h>
70 #include <sys/dtrace.h>
71 #include <sys/dtrace_impl.h>
74 #include <sys/systm.h>
78 #if defined (__ppc__) || defined (__ppc64__)
79 #define SYSTRACE_ARTIFICIAL_FRAMES 3
80 #define MACHTRACE_ARTIFICIAL_FRAMES 4
81 #elif defined(__i386__) || defined (__x86_64__)
82 #define SYSTRACE_ARTIFICIAL_FRAMES 2
83 #define MACHTRACE_ARTIFICIAL_FRAMES 3
84 #elif defined(__arm__)
85 #define SYSTRACE_ARTIFICIAL_FRAMES 2 /* XXX ARMTODO */
86 #define MACHTRACE_ARTIFICIAL_FRAMES 3 /* XXX ARMTODO */
88 #error Unknown Architecture
91 #include <sys/sysent.h>
92 #define sy_callc sy_call /* Map Solaris slot name to Darwin's */
93 #define NSYSCALL nsysent /* and is less than 500 or so */
95 extern const char *syscallnames
[];
97 #include <sys/dtrace_glue.h>
98 #define casptr dtrace_casptr
99 #define membar_enter dtrace_membar_producer
101 #define LOADABLE_SYSCALL(a) 0 /* Not pertinent to Darwin. */
102 #define LOADED_SYSCALL(a) 1 /* Not pertinent to Darwin. */
104 systrace_sysent_t
*systrace_sysent
= NULL
;
105 void (*systrace_probe
)(dtrace_id_t
, uint64_t, uint64_t,
106 uint64_t, uint64_t, uint64_t);
109 systrace_stub(dtrace_id_t id
, uint64_t arg0
, uint64_t arg1
,
110 uint64_t arg2
, uint64_t arg3
, uint64_t arg4
)
112 #pragma unused(id,arg0,arg1,arg2,arg3,arg4)
116 dtrace_systrace_syscall(struct proc
*pp
, void *uap
, int *rv
)
121 systrace_sysent_t
*sy
;
127 syscall_arg_t
*ip
= (syscall_arg_t
*)uap
;
129 #if defined (__ppc__) || defined (__ppc64__)
131 savearea_t
*regs
= (savearea_t
*)find_user_regs(current_thread());
133 flavor
= (((unsigned int)regs
->save_r0
) == 0)? 1: 0;
136 code
= regs
->save_r3
;
138 code
= regs
->save_r0
;
140 #elif defined(__i386__) || defined (__x86_64__)
141 #pragma unused(flavor)
143 x86_saved_state_t
*tagged_regs
= (x86_saved_state_t
*)find_user_regs(current_thread());
145 if (is_saved_state64(tagged_regs
)) {
146 x86_saved_state64_t
*regs
= saved_state64(tagged_regs
);
147 code
= regs
->rax
& SYSCALL_NUMBER_MASK
;
149 * Check for indirect system call... system call number
156 code
= saved_state32(tagged_regs
)->eax
& I386_SYSCALL_NUMBER_MASK
;
158 * TODO: handle indirect system calls
162 #elif defined(__arm__)
163 do {} while(0); /* XXX what is the right ABI */
165 #error Unknown Architecture
168 // Bounds "check" the value of code a la unix_syscall
169 sy
= (code
>= NUM_SYSENT
) ? &systrace_sysent
[63] : &systrace_sysent
[code
];
171 if ((id
= sy
->stsy_entry
) != DTRACE_IDNONE
)
172 (*systrace_probe
)(id
, *ip
, *(ip
+1), *(ip
+2), *(ip
+3), *(ip
+4));
176 * We want to explicitly allow DTrace consumers to stop a process
177 * before it actually executes the meat of the syscall.
179 p
= ttoproc(curthread
);
180 mutex_enter(&p
->p_lock
);
181 if (curthread
->t_dtrace_stop
&& !curthread
->t_lwp
->lwp_nostop
) {
182 curthread
->t_dtrace_stop
= 0;
183 stop(PR_REQUESTED
, 0);
185 mutex_exit(&p
->p_lock
);
188 rval
= (*sy
->stsy_underlying
)(pp
, uap
, rv
);
190 if ((id
= sy
->stsy_return
) != DTRACE_IDNONE
) {
192 uthread_t uthread
= (uthread_t
)get_bsdthread_info(current_thread());
195 uthread
->t_dtrace_errno
= rval
; /* Establish t_dtrace_errno now in case this enabling refers to it. */
198 * "Decode" rv for use in the call to dtrace_probe()
200 if (rval
== ERESTART
) {
201 munged_rv
= -1LL; /* System call will be reissued in user mode. Make DTrace report a -1 return. */
202 } else if (rval
!= EJUSTRETURN
) {
204 munged_rv
= -1LL; /* Mimic what libc will do. */
206 switch (sy
->stsy_return_type
) {
207 case _SYSCALL_RET_INT_T
:
210 case _SYSCALL_RET_UINT_T
:
211 munged_rv
= ((u_int
)rv
[0]);
213 case _SYSCALL_RET_OFF_T
:
214 munged_rv
= *(u_int64_t
*)rv
;
216 case _SYSCALL_RET_ADDR_T
:
217 case _SYSCALL_RET_SIZE_T
:
218 case _SYSCALL_RET_SSIZE_T
:
219 munged_rv
= *(user_addr_t
*)rv
;
221 case _SYSCALL_RET_NONE
:
232 (*systrace_probe
)(id
, munged_rv
, munged_rv
, (uint64_t)rval
, 0, 0);
239 dtrace_systrace_syscall_return(unsigned short code
, int rval
, int *rv
)
241 systrace_sysent_t
*sy
;
244 // Bounds "check" the value of code a la unix_syscall_return
245 sy
= (code
>= NUM_SYSENT
) ? &systrace_sysent
[63] : &systrace_sysent
[code
];
247 if ((id
= sy
->stsy_return
) != DTRACE_IDNONE
) {
249 uthread_t uthread
= (uthread_t
)get_bsdthread_info(current_thread());
252 uthread
->t_dtrace_errno
= rval
; /* Establish t_dtrace_errno now in case this enabling refers to it. */
255 * "Decode" rv for use in the call to dtrace_probe()
257 if (rval
== ERESTART
) {
258 munged_rv
= -1LL; /* System call will be reissued in user mode. Make DTrace report a -1 return. */
259 } else if (rval
!= EJUSTRETURN
) {
261 munged_rv
= -1LL; /* Mimic what libc will do. */
263 switch (sy
->stsy_return_type
) {
264 case _SYSCALL_RET_INT_T
:
267 case _SYSCALL_RET_UINT_T
:
268 munged_rv
= ((u_int
)rv
[0]);
270 case _SYSCALL_RET_OFF_T
:
271 munged_rv
= *(u_int64_t
*)rv
;
273 case _SYSCALL_RET_ADDR_T
:
274 case _SYSCALL_RET_SIZE_T
:
275 case _SYSCALL_RET_SSIZE_T
:
276 munged_rv
= *(user_addr_t
*)rv
;
278 case _SYSCALL_RET_NONE
:
289 (*systrace_probe
)(id
, munged_rv
, munged_rv
, (uint64_t)rval
, 0, 0);
292 #endif /* __APPLE__ */
294 #define SYSTRACE_SHIFT 16
295 #define SYSTRACE_ISENTRY(x) ((int)(x) >> SYSTRACE_SHIFT)
296 #define SYSTRACE_SYSNUM(x) ((int)(x) & ((1 << SYSTRACE_SHIFT) - 1))
297 #define SYSTRACE_ENTRY(id) ((1 << SYSTRACE_SHIFT) | (id))
298 #define SYSTRACE_RETURN(id) (id)
300 #if ((1 << SYSTRACE_SHIFT) <= NSYSCALL)
301 #error 1 << SYSTRACE_SHIFT must exceed number of system calls
304 static dev_info_t
*systrace_devi
;
305 static dtrace_provider_id_t systrace_id
;
307 #if defined(__APPLE__)
308 #define systrace_init _systrace_init /* Avoid name clash with Darwin automagic conf symbol */
311 systrace_init(struct sysent
*actual
, systrace_sysent_t
**interposed
)
313 systrace_sysent_t
*sysent
= *interposed
;
316 if (sysent
== NULL
) {
317 *interposed
= sysent
= kmem_zalloc(sizeof (systrace_sysent_t
) *
321 for (i
= 0; i
< NSYSCALL
; i
++) {
322 struct sysent
*a
= &actual
[i
];
323 systrace_sysent_t
*s
= &sysent
[i
];
325 if (LOADABLE_SYSCALL(a
) && !LOADED_SYSCALL(a
))
328 if (a
->sy_callc
== dtrace_systrace_syscall
)
331 #ifdef _SYSCALL32_IMPL
332 if (a
->sy_callc
== dtrace_systrace_syscall32
)
336 s
->stsy_underlying
= a
->sy_callc
;
337 #if defined(__APPLE__)
338 s
->stsy_return_type
= a
->sy_return_type
;
345 systrace_provide(void *arg
, const dtrace_probedesc_t
*desc
)
352 systrace_init(sysent
, &systrace_sysent
);
353 #ifdef _SYSCALL32_IMPL
354 systrace_init(sysent32
, &systrace_sysent32
);
357 for (i
= 0; i
< NSYSCALL
; i
++) {
358 if (systrace_sysent
[i
].stsy_underlying
== NULL
)
361 if (dtrace_probe_lookup(systrace_id
, NULL
,
362 syscallnames
[i
], "entry") != 0)
365 (void) dtrace_probe_create(systrace_id
, NULL
, syscallnames
[i
],
366 "entry", SYSTRACE_ARTIFICIAL_FRAMES
,
367 (void *)((uintptr_t)SYSTRACE_ENTRY(i
)));
368 (void) dtrace_probe_create(systrace_id
, NULL
, syscallnames
[i
],
369 "return", SYSTRACE_ARTIFICIAL_FRAMES
,
370 (void *)((uintptr_t)SYSTRACE_RETURN(i
)));
372 systrace_sysent
[i
].stsy_entry
= DTRACE_IDNONE
;
373 systrace_sysent
[i
].stsy_return
= DTRACE_IDNONE
;
374 #ifdef _SYSCALL32_IMPL
375 systrace_sysent32
[i
].stsy_entry
= DTRACE_IDNONE
;
376 systrace_sysent32
[i
].stsy_return
= DTRACE_IDNONE
;
380 #if defined(__APPLE__)
386 systrace_destroy(void *arg
, dtrace_id_t id
, void *parg
)
388 int sysnum
= SYSTRACE_SYSNUM((uintptr_t)parg
);
391 * There's nothing to do here but assert that we have actually been
394 if (SYSTRACE_ISENTRY((uintptr_t)parg
)) {
395 ASSERT(systrace_sysent
[sysnum
].stsy_entry
== DTRACE_IDNONE
);
396 #ifdef _SYSCALL32_IMPL
397 ASSERT(systrace_sysent32
[sysnum
].stsy_entry
== DTRACE_IDNONE
);
400 ASSERT(systrace_sysent
[sysnum
].stsy_return
== DTRACE_IDNONE
);
401 #ifdef _SYSCALL32_IMPL
402 ASSERT(systrace_sysent32
[sysnum
].stsy_return
== DTRACE_IDNONE
);
409 systrace_enable(void *arg
, dtrace_id_t id
, void *parg
)
411 int sysnum
= SYSTRACE_SYSNUM((uintptr_t)parg
);
412 int enabled
= (systrace_sysent
[sysnum
].stsy_entry
!= DTRACE_IDNONE
||
413 systrace_sysent
[sysnum
].stsy_return
!= DTRACE_IDNONE
);
415 if (SYSTRACE_ISENTRY((uintptr_t)parg
)) {
416 systrace_sysent
[sysnum
].stsy_entry
= id
;
417 #ifdef _SYSCALL32_IMPL
418 systrace_sysent32
[sysnum
].stsy_entry
= id
;
421 systrace_sysent
[sysnum
].stsy_return
= id
;
422 #ifdef _SYSCALL32_IMPL
423 systrace_sysent32
[sysnum
].stsy_return
= id
;
428 ASSERT(sysent
[sysnum
].sy_callc
== dtrace_systrace_syscall
);
432 (void) casptr(&sysent
[sysnum
].sy_callc
,
433 (void *)systrace_sysent
[sysnum
].stsy_underlying
,
434 (void *)dtrace_systrace_syscall
);
435 #ifdef _SYSCALL32_IMPL
436 (void) casptr(&sysent32
[sysnum
].sy_callc
,
437 (void *)systrace_sysent32
[sysnum
].stsy_underlying
,
438 (void *)dtrace_systrace_syscall32
);
444 systrace_disable(void *arg
, dtrace_id_t id
, void *parg
)
446 int sysnum
= SYSTRACE_SYSNUM((uintptr_t)parg
);
447 int disable
= (systrace_sysent
[sysnum
].stsy_entry
== DTRACE_IDNONE
||
448 systrace_sysent
[sysnum
].stsy_return
== DTRACE_IDNONE
);
451 (void) casptr(&sysent
[sysnum
].sy_callc
,
452 (void *)dtrace_systrace_syscall
,
453 (void *)systrace_sysent
[sysnum
].stsy_underlying
);
455 #ifdef _SYSCALL32_IMPL
456 (void) casptr(&sysent32
[sysnum
].sy_callc
,
457 (void *)dtrace_systrace_syscall32
,
458 (void *)systrace_sysent32
[sysnum
].stsy_underlying
);
462 if (SYSTRACE_ISENTRY((uintptr_t)parg
)) {
463 systrace_sysent
[sysnum
].stsy_entry
= DTRACE_IDNONE
;
464 #ifdef _SYSCALL32_IMPL
465 systrace_sysent32
[sysnum
].stsy_entry
= DTRACE_IDNONE
;
468 systrace_sysent
[sysnum
].stsy_return
= DTRACE_IDNONE
;
469 #ifdef _SYSCALL32_IMPL
470 systrace_sysent32
[sysnum
].stsy_return
= DTRACE_IDNONE
;
475 static dtrace_pattr_t systrace_attr
= {
476 { DTRACE_STABILITY_EVOLVING
, DTRACE_STABILITY_EVOLVING
, DTRACE_CLASS_COMMON
},
477 { DTRACE_STABILITY_PRIVATE
, DTRACE_STABILITY_PRIVATE
, DTRACE_CLASS_UNKNOWN
},
478 { DTRACE_STABILITY_PRIVATE
, DTRACE_STABILITY_PRIVATE
, DTRACE_CLASS_ISA
},
479 { DTRACE_STABILITY_EVOLVING
, DTRACE_STABILITY_EVOLVING
, DTRACE_CLASS_COMMON
},
480 { DTRACE_STABILITY_PRIVATE
, DTRACE_STABILITY_PRIVATE
, DTRACE_CLASS_ISA
},
483 static dtrace_pops_t systrace_pops
= {
497 systrace_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
)
503 return (DDI_SUCCESS
);
505 return (DDI_FAILURE
);
508 systrace_probe
= dtrace_probe
;
511 if (ddi_create_minor_node(devi
, "systrace", S_IFCHR
, 0,
512 DDI_PSEUDO
, NULL
) == DDI_FAILURE
||
513 dtrace_register("syscall", &systrace_attr
, DTRACE_PRIV_USER
, NULL
,
514 &systrace_pops
, NULL
, &systrace_id
) != 0) {
515 systrace_probe
= systrace_stub
;
516 ddi_remove_minor_node(devi
, NULL
);
517 return (DDI_FAILURE
);
520 ddi_report_dev(devi
);
521 systrace_devi
= devi
;
523 return (DDI_SUCCESS
);
526 #if !defined(__APPLE__)
528 systrace_detach(dev_info_t
*devi
, ddi_detach_cmd_t cmd
)
534 return (DDI_SUCCESS
);
536 return (DDI_FAILURE
);
539 if (dtrace_unregister(systrace_id
) != 0)
540 return (DDI_FAILURE
);
542 ddi_remove_minor_node(devi
, NULL
);
543 systrace_probe
= systrace_stub
;
544 return (DDI_SUCCESS
);
549 systrace_info(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
, void **result
)
554 case DDI_INFO_DEVT2DEVINFO
:
555 *result
= (void *)systrace_devi
;
558 case DDI_INFO_DEVT2INSTANCE
:
570 systrace_open(dev_t
*devp
, int flag
, int otyp
, cred_t
*cred_p
)
575 static struct cb_ops systrace_cb_ops
= {
576 systrace_open
, /* open */
578 nulldev
, /* strategy */
588 ddi_prop_op
, /* cb_prop_op */
590 D_NEW
| D_MP
/* Driver compatibility flag */
593 static struct dev_ops systrace_ops
= {
594 DEVO_REV
, /* devo_rev, */
596 systrace_info
, /* get_dev_info */
597 nulldev
, /* identify */
599 systrace_attach
, /* attach */
600 systrace_detach
, /* detach */
602 &systrace_cb_ops
, /* driver operations */
603 NULL
, /* bus operations */
604 nodev
/* dev power */
608 * Module linkage information for the kernel.
610 static struct modldrv modldrv
= {
611 &mod_driverops
, /* module type (this is a pseudo driver) */
612 "System Call Tracing", /* name of module */
613 &systrace_ops
, /* driver ops */
616 static struct modlinkage modlinkage
= {
625 return (mod_install(&modlinkage
));
629 _info(struct modinfo
*modinfop
)
631 return (mod_info(&modlinkage
, modinfop
));
637 return (mod_remove(&modlinkage
));
640 typedef kern_return_t (*mach_call_t
)(void *);
642 /* XXX From #include <kern/syscall_sw.h> which may be changed for 64 bit! */
643 typedef void mach_munge_t(const void *, void *);
646 int mach_trap_arg_count
;
647 int (*mach_trap_function
)(void);
648 #if defined(__i386__)
649 boolean_t mach_trap_stack
;
651 mach_munge_t
*mach_trap_arg_munge32
; /* system call arguments for 32-bit */
652 mach_munge_t
*mach_trap_arg_munge64
; /* system call arguments for 64-bit */
655 int mach_trap_unused
;
657 const char* mach_trap_name
;
658 #endif /* !MACH_ASSERT */
661 #define MACH_TRAP_TABLE_COUNT 128
663 extern mach_trap_t mach_trap_table
[];
664 extern int mach_trap_count
;
666 #define MACH_TRAP(name, foo, bar, baz) #name
668 /* XXX From osfmk/kern/syscall_sw.c */
669 static const char * mach_name_table
[MACH_TRAP_TABLE_COUNT
] = {
670 /* 0 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
671 /* 1 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
672 /* 2 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
673 /* 3 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
674 /* 4 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
675 /* 5 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
676 /* 6 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
677 /* 7 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
678 /* 8 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
679 /* 9 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
680 /* 10 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
681 /* 11 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
682 /* 12 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
683 /* 13 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
684 /* 14 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
685 /* 15 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
686 /* 16 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
687 /* 17 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
688 /* 18 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
689 /* 19 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
690 /* 20 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
691 /* 21 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
692 /* 22 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
693 /* 23 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
694 /* 24 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
695 /* 25 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
696 /* 26 */ MACH_TRAP(mach_reply_port
, 0, NULL
, NULL
),
697 /* 27 */ MACH_TRAP(thread_self_trap
, 0, NULL
, NULL
),
698 /* 28 */ MACH_TRAP(task_self_trap
, 0, NULL
, NULL
),
699 /* 29 */ MACH_TRAP(host_self_trap
, 0, NULL
, NULL
),
700 /* 30 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
701 /* 31 */ MACH_TRAP(mach_msg_trap
, 7, munge_wwwwwww
, munge_ddddddd
),
702 /* 32 */ MACH_TRAP(mach_msg_overwrite_trap
, 8, munge_wwwwwwww
, munge_dddddddd
),
703 /* 33 */ MACH_TRAP(semaphore_signal_trap
, 1, munge_w
, munge_d
),
704 /* 34 */ MACH_TRAP(semaphore_signal_all_trap
, 1, munge_w
, munge_d
),
705 /* 35 */ MACH_TRAP(semaphore_signal_thread_trap
, 2, munge_ww
, munge_dd
),
706 /* 36 */ MACH_TRAP(semaphore_wait_trap
, 1, munge_w
, munge_d
),
707 /* 37 */ MACH_TRAP(semaphore_wait_signal_trap
, 2, munge_ww
, munge_dd
),
708 /* 38 */ MACH_TRAP(semaphore_timedwait_trap
, 3, munge_www
, munge_ddd
),
709 /* 39 */ MACH_TRAP(semaphore_timedwait_signal_trap
, 4, munge_wwww
, munge_dddd
),
710 /* 40 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
711 /* 41 */ MACH_TRAP(init_process
, 0, NULL
, NULL
),
712 /* 42 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
713 /* 43 */ MACH_TRAP(map_fd
, 5, munge_wwwww
, munge_ddddd
),
714 /* 44 */ MACH_TRAP(task_name_for_pid
, 3, munge_www
, munge_ddd
),
715 /* 45 */ MACH_TRAP(task_for_pid
, 3, munge_www
, munge_ddd
),
716 /* 46 */ MACH_TRAP(pid_for_task
, 2, munge_ww
,munge_dd
),
717 /* 47 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
718 /* 48 */ MACH_TRAP(macx_swapon
, 4, munge_wwww
, munge_dddd
),
719 /* 49 */ MACH_TRAP(macx_swapoff
, 2, munge_ww
, munge_dd
),
720 /* 50 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
721 /* 51 */ MACH_TRAP(macx_triggers
, 4, munge_wwww
, munge_dddd
),
722 /* 52 */ MACH_TRAP(macx_backing_store_suspend
, 1, munge_w
, munge_d
),
723 /* 53 */ MACH_TRAP(macx_backing_store_recovery
, 1, munge_w
, munge_d
),
724 /* 54 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
725 /* 55 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
726 /* 56 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
727 /* 57 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
728 /* 58 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
729 /* 59 */ MACH_TRAP(swtch_pri
, 0, NULL
, NULL
),
730 /* 60 */ MACH_TRAP(swtch
, 0, NULL
, NULL
),
731 /* 61 */ MACH_TRAP(thread_switch
, 3, munge_www
, munge_ddd
),
732 /* 62 */ MACH_TRAP(clock_sleep_trap
, 5, munge_wwwww
, munge_ddddd
),
733 /* 63 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
734 /* traps 64 - 95 reserved (debo) */
735 /* 64 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
736 /* 65 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
737 /* 66 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
738 /* 67 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
739 /* 68 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
740 /* 69 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
741 /* 70 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
742 /* 71 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
743 /* 72 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
744 /* 73 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
745 /* 74 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
746 /* 75 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
747 /* 76 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
748 /* 77 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
749 /* 78 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
750 /* 79 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
751 /* 80 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
752 /* 81 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
753 /* 82 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
754 /* 83 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
755 /* 84 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
756 /* 85 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
757 /* 86 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
758 /* 87 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
759 /* 88 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
760 /* 89 */ MACH_TRAP(mach_timebase_info_trap
, 1, munge_w
, munge_d
),
761 /* 90 */ MACH_TRAP(mach_wait_until_trap
, 2, munge_l
, munge_d
),
762 /* 91 */ MACH_TRAP(mk_timer_create_trap
, 0, NULL
, NULL
),
763 /* 92 */ MACH_TRAP(mk_timer_destroy_trap
, 1, munge_w
, munge_d
),
764 /* 93 */ MACH_TRAP(mk_timer_arm_trap
, 3, munge_wl
, munge_dd
),
765 /* 94 */ MACH_TRAP(mk_timer_cancel_trap
, 2, munge_ww
, munge_dd
),
766 /* 95 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
767 /* traps 64 - 95 reserved (debo) */
768 /* 96 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
769 /* 97 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
770 /* 98 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
771 /* 99 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
772 /* traps 100-107 reserved for iokit (esb) */
773 /* 100 */ MACH_TRAP(iokit_user_client_trap
, 8, munge_wwwwwwww
, munge_dddddddd
),
774 /* 101 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
775 /* 102 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
776 /* 103 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
777 /* 104 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
778 /* 105 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
779 /* 106 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
780 /* 107 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
781 /* traps 108-127 unused */
782 /* 108 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
783 /* 109 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
784 /* 110 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
785 /* 111 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
786 /* 112 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
787 /* 113 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
788 /* 114 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
789 /* 115 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
790 /* 116 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
791 /* 117 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
792 /* 118 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
793 /* 119 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
794 /* 120 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
795 /* 121 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
796 /* 122 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
797 /* 123 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
798 /* 124 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
799 /* 125 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
800 /* 126 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
801 /* 127 */ MACH_TRAP(kern_invalid
, 0, NULL
, NULL
),
804 /* XXX From osfmk/i386/bsd_i386.c */
805 struct mach_call_args
{
818 #define NSYSCALL mach_trap_count
820 #if ((1 << SYSTRACE_SHIFT) <= NSYSCALL)
821 #error 1 << SYSTRACE_SHIFT must exceed number of Mach traps
824 typedef systrace_sysent_t machtrace_sysent_t
;
826 static machtrace_sysent_t
*machtrace_sysent
= NULL
;
828 void (*machtrace_probe
)(dtrace_id_t
, uint64_t, uint64_t,
829 uint64_t, uint64_t, uint64_t);
831 static dev_info_t
*machtrace_devi
;
832 static dtrace_provider_id_t machtrace_id
;
835 dtrace_machtrace_syscall(struct mach_call_args
*args
)
840 machtrace_sysent_t
*sy
;
846 syscall_arg_t
*ip
= (syscall_arg_t
*)args
;
847 mach_call_t mach_call
;
849 #if defined (__ppc__) || defined (__ppc64__)
851 savearea_t
*regs
= (savearea_t
*)find_user_regs(current_thread());
853 flavor
= (((unsigned int)regs
->save_r0
) == 0)? 1: 0;
856 code
= -regs
->save_r3
;
858 code
= -regs
->save_r0
;
860 #elif defined(__i386__) || defined (__x86_64__)
861 #pragma unused(flavor)
863 x86_saved_state_t
*tagged_regs
= (x86_saved_state_t
*)find_user_regs(current_thread());
865 if (is_saved_state64(tagged_regs
)) {
866 code
= -saved_state64(tagged_regs
)->rax
& SYSCALL_NUMBER_MASK
;
868 code
= -saved_state32(tagged_regs
)->eax
;
871 #elif defined(__arm__)
872 do {} while(0); /* XXX ARMTODO */
874 #error Unknown Architecture
877 sy
= &machtrace_sysent
[code
];
879 if ((id
= sy
->stsy_entry
) != DTRACE_IDNONE
)
880 (*machtrace_probe
)(id
, *ip
, *(ip
+1), *(ip
+2), *(ip
+3), *(ip
+4));
884 * We want to explicitly allow DTrace consumers to stop a process
885 * before it actually executes the meat of the syscall.
887 p
= ttoproc(curthread
);
888 mutex_enter(&p
->p_lock
);
889 if (curthread
->t_dtrace_stop
&& !curthread
->t_lwp
->lwp_nostop
) {
890 curthread
->t_dtrace_stop
= 0;
891 stop(PR_REQUESTED
, 0);
893 mutex_exit(&p
->p_lock
);
896 mach_call
= (mach_call_t
)(*sy
->stsy_underlying
);
897 rval
= mach_call(args
);
899 if ((id
= sy
->stsy_return
) != DTRACE_IDNONE
)
900 (*machtrace_probe
)(id
, (uint64_t)rval
, 0, 0, 0, 0);
906 machtrace_init(mach_trap_t
*actual
, machtrace_sysent_t
**interposed
)
908 machtrace_sysent_t
*msysent
= *interposed
;
911 if (msysent
== NULL
) {
912 *interposed
= msysent
= kmem_zalloc(sizeof (machtrace_sysent_t
) *
916 for (i
= 0; i
< NSYSCALL
; i
++) {
917 mach_trap_t
*a
= &actual
[i
];
918 machtrace_sysent_t
*s
= &msysent
[i
];
920 if (LOADABLE_SYSCALL(a
) && !LOADED_SYSCALL(a
))
923 if ((mach_call_t
)(a
->mach_trap_function
) == (mach_call_t
)(dtrace_machtrace_syscall
))
926 s
->stsy_underlying
= a
->mach_trap_function
;
932 machtrace_provide(void *arg
, const dtrace_probedesc_t
*desc
)
939 machtrace_init(mach_trap_table
, &machtrace_sysent
);
941 for (i
= 0; i
< NSYSCALL
; i
++) {
943 if (machtrace_sysent
[i
].stsy_underlying
== NULL
)
946 if (dtrace_probe_lookup(machtrace_id
, NULL
,
947 mach_name_table
[i
], "entry") != 0)
950 (void) dtrace_probe_create(machtrace_id
, NULL
, mach_name_table
[i
],
951 "entry", MACHTRACE_ARTIFICIAL_FRAMES
,
952 (void *)((uintptr_t)SYSTRACE_ENTRY(i
)));
953 (void) dtrace_probe_create(machtrace_id
, NULL
, mach_name_table
[i
],
954 "return", MACHTRACE_ARTIFICIAL_FRAMES
,
955 (void *)((uintptr_t)SYSTRACE_RETURN(i
)));
957 machtrace_sysent
[i
].stsy_entry
= DTRACE_IDNONE
;
958 machtrace_sysent
[i
].stsy_return
= DTRACE_IDNONE
;
964 machtrace_destroy(void *arg
, dtrace_id_t id
, void *parg
)
966 int sysnum
= SYSTRACE_SYSNUM((uintptr_t)parg
);
969 * There's nothing to do here but assert that we have actually been
972 if (SYSTRACE_ISENTRY((uintptr_t)parg
)) {
973 ASSERT(machtrace_sysent
[sysnum
].stsy_entry
== DTRACE_IDNONE
);
975 ASSERT(machtrace_sysent
[sysnum
].stsy_return
== DTRACE_IDNONE
);
981 machtrace_enable(void *arg
, dtrace_id_t id
, void *parg
)
983 int sysnum
= SYSTRACE_SYSNUM((uintptr_t)parg
);
984 int enabled
= (machtrace_sysent
[sysnum
].stsy_entry
!= DTRACE_IDNONE
||
985 machtrace_sysent
[sysnum
].stsy_return
!= DTRACE_IDNONE
);
987 if (SYSTRACE_ISENTRY((uintptr_t)parg
)) {
988 machtrace_sysent
[sysnum
].stsy_entry
= id
;
990 machtrace_sysent
[sysnum
].stsy_return
= id
;
994 ASSERT(sysent
[sysnum
].sy_callc
== dtrace_machtrace_syscall
);
998 (void) casptr(&mach_trap_table
[sysnum
].mach_trap_function
,
999 (void *)machtrace_sysent
[sysnum
].stsy_underlying
,
1000 (void *)dtrace_machtrace_syscall
);
1005 machtrace_disable(void *arg
, dtrace_id_t id
, void *parg
)
1007 int sysnum
= SYSTRACE_SYSNUM((uintptr_t)parg
);
1008 int disable
= (machtrace_sysent
[sysnum
].stsy_entry
== DTRACE_IDNONE
||
1009 machtrace_sysent
[sysnum
].stsy_return
== DTRACE_IDNONE
);
1012 (void) casptr(&mach_trap_table
[sysnum
].mach_trap_function
,
1013 (void *)dtrace_machtrace_syscall
,
1014 (void *)machtrace_sysent
[sysnum
].stsy_underlying
);
1018 if (SYSTRACE_ISENTRY((uintptr_t)parg
)) {
1019 machtrace_sysent
[sysnum
].stsy_entry
= DTRACE_IDNONE
;
1021 machtrace_sysent
[sysnum
].stsy_return
= DTRACE_IDNONE
;
1025 static dtrace_pattr_t machtrace_attr
= {
1026 { DTRACE_STABILITY_EVOLVING
, DTRACE_STABILITY_EVOLVING
, DTRACE_CLASS_COMMON
},
1027 { DTRACE_STABILITY_PRIVATE
, DTRACE_STABILITY_PRIVATE
, DTRACE_CLASS_UNKNOWN
},
1028 { DTRACE_STABILITY_PRIVATE
, DTRACE_STABILITY_PRIVATE
, DTRACE_CLASS_ISA
},
1029 { DTRACE_STABILITY_EVOLVING
, DTRACE_STABILITY_EVOLVING
, DTRACE_CLASS_COMMON
},
1030 { DTRACE_STABILITY_PRIVATE
, DTRACE_STABILITY_PRIVATE
, DTRACE_CLASS_ISA
},
1033 static dtrace_pops_t machtrace_pops
= {
1047 machtrace_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
)
1053 return (DDI_SUCCESS
);
1055 return (DDI_FAILURE
);
1058 machtrace_probe
= dtrace_probe
;
1061 if (ddi_create_minor_node(devi
, "machtrace", S_IFCHR
, 0,
1062 DDI_PSEUDO
, NULL
) == DDI_FAILURE
||
1063 dtrace_register("mach_trap", &machtrace_attr
, DTRACE_PRIV_USER
, NULL
,
1064 &machtrace_pops
, NULL
, &machtrace_id
) != 0) {
1065 machtrace_probe
= systrace_stub
;
1066 ddi_remove_minor_node(devi
, NULL
);
1067 return (DDI_FAILURE
);
1070 ddi_report_dev(devi
);
1071 machtrace_devi
= devi
;
1073 return (DDI_SUCCESS
);
1076 d_open_t _systrace_open
;
1078 int _systrace_open(dev_t dev
, int flags
, int devtype
, struct proc
*p
)
1080 #pragma unused(dev,flags,devtype,p)
1084 #define SYSTRACE_MAJOR -24 /* let the kernel pick the device number */
1087 * A struct describing which functions will get invoked for certain
1090 static struct cdevsw systrace_cdevsw
=
1092 _systrace_open
, /* open */
1093 eno_opcl
, /* close */
1094 eno_rdwrt
, /* read */
1095 eno_rdwrt
, /* write */
1096 eno_ioctl
, /* ioctl */
1097 (stop_fcn_t
*)nulldev
, /* stop */
1098 (reset_fcn_t
*)nulldev
, /* reset */
1100 eno_select
, /* select */
1101 eno_mmap
, /* mmap */
1102 eno_strat
, /* strategy */
1103 eno_getc
, /* getc */
1104 eno_putc
, /* putc */
1108 static int gSysTraceInited
= 0;
1110 void systrace_init( void );
1112 void systrace_init( void )
1114 if (0 == gSysTraceInited
) {
1115 int majdevno
= cdevsw_add(SYSTRACE_MAJOR
, &systrace_cdevsw
);
1118 printf("systrace_init: failed to allocate a major number!\n");
1119 gSysTraceInited
= 0;
1123 systrace_attach( (dev_info_t
*)majdevno
, DDI_ATTACH
);
1124 machtrace_attach( (dev_info_t
*)majdevno
, DDI_ATTACH
);
1126 gSysTraceInited
= 1;
1128 panic("systrace_init: called twice!\n");
1130 #undef SYSTRACE_MAJOR
1131 #endif /* __APPLE__ */