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.6 06/09/19 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, 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
, uint64_t arg5
, uint64_t arg6
, uint64_t arg7
)
107 #pragma unused(id,arg0,arg1,arg2,arg3,arg4,arg5,arg6,arg7)
112 dtrace_systrace_syscall(struct proc
*pp
, void *uap
, int *rv
)
117 systrace_sysent_t
*sy
;
123 syscall_arg_t
*ip
= (syscall_arg_t
*)uap
;
125 #if defined (__ppc__) || defined (__ppc64__)
127 savearea_t
*regs
= (savearea_t
*)find_user_regs(current_thread());
129 flavor
= (((unsigned int)regs
->save_r0
) == 0)? 1: 0;
132 code
= regs
->save_r3
;
134 code
= regs
->save_r0
;
137 * FIXME: unix_syscall screens for "unsafe calls" and instead calls nosys(), *not* sysent[code] !
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
;
159 vm_offset_t params
= (vm_offset_t
) (saved_state32(tagged_regs
)->uesp
+ sizeof (int));
160 code
= fuword(params
);
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
) {
173 (*systrace_probe
)(id
, *ip
, *(ip
+1), *(ip
+2), *(ip
+3), *(ip
+4), *(ip
+5), *(ip
+6), *(ip
+7));
175 (*systrace_probe
)(id
, 0, 0, 0, 0, 0, 0, 0, 0);
180 * We want to explicitly allow DTrace consumers to stop a process
181 * before it actually executes the meat of the syscall.
183 p
= ttoproc(curthread
);
184 mutex_enter(&p
->p_lock
);
185 if (curthread
->t_dtrace_stop
&& !curthread
->t_lwp
->lwp_nostop
) {
186 curthread
->t_dtrace_stop
= 0;
187 stop(PR_REQUESTED
, 0);
189 mutex_exit(&p
->p_lock
);
192 rval
= (*sy
->stsy_underlying
)(pp
, uap
, rv
);
194 if ((id
= sy
->stsy_return
) != DTRACE_IDNONE
) {
195 uint64_t munged_rv0
, munged_rv1
;
196 uthread_t uthread
= (uthread_t
)get_bsdthread_info(current_thread());
199 uthread
->t_dtrace_errno
= rval
; /* Establish t_dtrace_errno now in case this enabling refers to it. */
202 * "Decode" rv for use in the call to dtrace_probe()
204 if (rval
== ERESTART
) {
205 munged_rv0
= -1LL; /* System call will be reissued in user mode. Make DTrace report a -1 return. */
207 } else if (rval
!= EJUSTRETURN
) {
209 munged_rv0
= -1LL; /* Mimic what libc will do. */
212 switch (sy
->stsy_return_type
) {
213 case _SYSCALL_RET_INT_T
:
217 case _SYSCALL_RET_UINT_T
:
218 munged_rv0
= ((u_int
)rv
[0]);
219 munged_rv1
= ((u_int
)rv
[1]);
221 case _SYSCALL_RET_OFF_T
:
222 case _SYSCALL_RET_UINT64_T
:
223 munged_rv0
= *(u_int64_t
*)rv
;
226 case _SYSCALL_RET_ADDR_T
:
227 case _SYSCALL_RET_SIZE_T
:
228 case _SYSCALL_RET_SSIZE_T
:
229 munged_rv0
= *(user_addr_t
*)rv
;
232 case _SYSCALL_RET_NONE
:
248 * <http://mail.opensolaris.org/pipermail/dtrace-discuss/2007-January/003276.html> says:
250 * "This is a bit of an historical artifact. At first, the syscall provider just
251 * had its return value in arg0, and the fbt and pid providers had their return
252 * values in arg1 (so that we could use arg0 for the offset of the return site).
254 * We inevitably started writing scripts where we wanted to see the return
255 * values from probes in all three providers, and we made this script easier
256 * to write by replicating the syscall return values in arg1 to match fbt and
257 * pid. We debated briefly about removing the return value from arg0, but
258 * decided that it would be less confusing to have the same data in two places
259 * than to have some non-helpful, non-intuitive value in arg0.
261 * This change was made 4/23/2003 according to the DTrace project's putback log."
263 (*systrace_probe
)(id
, munged_rv0
, munged_rv0
, munged_rv1
, (uint64_t)rval
, 0, 0, 0, 0);
270 dtrace_systrace_syscall_return(unsigned short code
, int rval
, int *rv
)
272 systrace_sysent_t
*sy
;
275 // Bounds "check" the value of code a la unix_syscall_return
276 sy
= (code
>= NUM_SYSENT
) ? &systrace_sysent
[63] : &systrace_sysent
[code
];
278 if ((id
= sy
->stsy_return
) != DTRACE_IDNONE
) {
279 uint64_t munged_rv0
, munged_rv1
;
280 uthread_t uthread
= (uthread_t
)get_bsdthread_info(current_thread());
283 uthread
->t_dtrace_errno
= rval
; /* Establish t_dtrace_errno now in case this enabling refers to it. */
286 * "Decode" rv for use in the call to dtrace_probe()
288 if (rval
== ERESTART
) {
289 munged_rv0
= -1LL; /* System call will be reissued in user mode. Make DTrace report a -1 return. */
291 } else if (rval
!= EJUSTRETURN
) {
293 munged_rv0
= -1LL; /* Mimic what libc will do. */
296 switch (sy
->stsy_return_type
) {
297 case _SYSCALL_RET_INT_T
:
301 case _SYSCALL_RET_UINT_T
:
302 munged_rv0
= ((u_int
)rv
[0]);
303 munged_rv1
= ((u_int
)rv
[1]);
305 case _SYSCALL_RET_OFF_T
:
306 case _SYSCALL_RET_UINT64_T
:
307 munged_rv0
= *(u_int64_t
*)rv
;
310 case _SYSCALL_RET_ADDR_T
:
311 case _SYSCALL_RET_SIZE_T
:
312 case _SYSCALL_RET_SSIZE_T
:
313 munged_rv0
= *(user_addr_t
*)rv
;
316 case _SYSCALL_RET_NONE
:
331 (*systrace_probe
)(id
, munged_rv0
, munged_rv0
, munged_rv1
, (uint64_t)rval
, 0, 0, 0, 0);
334 #endif /* __APPLE__ */
336 #define SYSTRACE_SHIFT 16
337 #define SYSTRACE_ISENTRY(x) ((int)(x) >> SYSTRACE_SHIFT)
338 #define SYSTRACE_SYSNUM(x) ((int)(x) & ((1 << SYSTRACE_SHIFT) - 1))
339 #define SYSTRACE_ENTRY(id) ((1 << SYSTRACE_SHIFT) | (id))
340 #define SYSTRACE_RETURN(id) (id)
342 #if ((1 << SYSTRACE_SHIFT) <= NSYSCALL)
343 #error 1 << SYSTRACE_SHIFT must exceed number of system calls
346 static dev_info_t
*systrace_devi
;
347 static dtrace_provider_id_t systrace_id
;
349 #if !defined (__APPLE__)
351 systrace_init(struct sysent
*actual
, systrace_sysent_t
**interposed
)
353 systrace_sysent_t
*sysent
= *interposed
;
356 if (sysent
== NULL
) {
357 *interposed
= sysent
= kmem_zalloc(sizeof (systrace_sysent_t
) *
361 for (i
= 0; i
< NSYSCALL
; i
++) {
362 struct sysent
*a
= &actual
[i
];
363 systrace_sysent_t
*s
= &sysent
[i
];
365 if (LOADABLE_SYSCALL(a
) && !LOADED_SYSCALL(a
))
368 if (a
->sy_callc
== dtrace_systrace_syscall
)
371 #ifdef _SYSCALL32_IMPL
372 if (a
->sy_callc
== dtrace_systrace_syscall32
)
376 s
->stsy_underlying
= a
->sy_callc
;
380 #define systrace_init _systrace_init /* Avoid name clash with Darwin automagic conf symbol */
382 systrace_init(struct sysent
*actual
, systrace_sysent_t
**interposed
)
385 systrace_sysent_t
*ssysent
= *interposed
; /* Avoid sysent shadow warning
386 from bsd/sys/sysent.h */
389 if (ssysent
== NULL
) {
390 *interposed
= ssysent
= kmem_zalloc(sizeof (systrace_sysent_t
) *
394 for (i
= 0; i
< NSYSCALL
; i
++) {
395 struct sysent
*a
= &actual
[i
];
396 systrace_sysent_t
*s
= &ssysent
[i
];
398 if (LOADABLE_SYSCALL(a
) && !LOADED_SYSCALL(a
))
401 if (a
->sy_callc
== dtrace_systrace_syscall
)
404 #ifdef _SYSCALL32_IMPL
405 if (a
->sy_callc
== dtrace_systrace_syscall32
)
409 s
->stsy_underlying
= a
->sy_callc
;
410 s
->stsy_return_type
= a
->sy_return_type
;
414 #endif /* __APPLE__ */
418 systrace_provide(void *arg
, const dtrace_probedesc_t
*desc
)
420 #pragma unused(arg) /* __APPLE__ */
426 systrace_init(sysent
, &systrace_sysent
);
427 #ifdef _SYSCALL32_IMPL
428 systrace_init(sysent32
, &systrace_sysent32
);
431 for (i
= 0; i
< NSYSCALL
; i
++) {
432 if (systrace_sysent
[i
].stsy_underlying
== NULL
)
435 if (dtrace_probe_lookup(systrace_id
, NULL
,
436 syscallnames
[i
], "entry") != 0)
439 (void) dtrace_probe_create(systrace_id
, NULL
, syscallnames
[i
],
440 "entry", SYSTRACE_ARTIFICIAL_FRAMES
,
441 (void *)((uintptr_t)SYSTRACE_ENTRY(i
)));
442 (void) dtrace_probe_create(systrace_id
, NULL
, syscallnames
[i
],
443 "return", SYSTRACE_ARTIFICIAL_FRAMES
,
444 (void *)((uintptr_t)SYSTRACE_RETURN(i
)));
446 systrace_sysent
[i
].stsy_entry
= DTRACE_IDNONE
;
447 systrace_sysent
[i
].stsy_return
= DTRACE_IDNONE
;
448 #ifdef _SYSCALL32_IMPL
449 systrace_sysent32
[i
].stsy_entry
= DTRACE_IDNONE
;
450 systrace_sysent32
[i
].stsy_return
= DTRACE_IDNONE
;
454 #if defined(__APPLE__)
460 systrace_destroy(void *arg
, dtrace_id_t id
, void *parg
)
462 #pragma unused(arg,id) /* __APPLE__ */
464 int sysnum
= SYSTRACE_SYSNUM((uintptr_t)parg
);
466 #pragma unused(sysnum) /* __APPLE__ */
468 * There's nothing to do here but assert that we have actually been
471 if (SYSTRACE_ISENTRY((uintptr_t)parg
)) {
472 ASSERT(systrace_sysent
[sysnum
].stsy_entry
== DTRACE_IDNONE
);
473 #ifdef _SYSCALL32_IMPL
474 ASSERT(systrace_sysent32
[sysnum
].stsy_entry
== DTRACE_IDNONE
);
477 ASSERT(systrace_sysent
[sysnum
].stsy_return
== DTRACE_IDNONE
);
478 #ifdef _SYSCALL32_IMPL
479 ASSERT(systrace_sysent32
[sysnum
].stsy_return
== DTRACE_IDNONE
);
486 systrace_enable(void *arg
, dtrace_id_t id
, void *parg
)
488 #pragma unused(arg) /* __APPLE__ */
490 int sysnum
= SYSTRACE_SYSNUM((uintptr_t)parg
);
491 int enabled
= (systrace_sysent
[sysnum
].stsy_entry
!= DTRACE_IDNONE
||
492 systrace_sysent
[sysnum
].stsy_return
!= DTRACE_IDNONE
);
494 if (SYSTRACE_ISENTRY((uintptr_t)parg
)) {
495 systrace_sysent
[sysnum
].stsy_entry
= id
;
496 #ifdef _SYSCALL32_IMPL
497 systrace_sysent32
[sysnum
].stsy_entry
= id
;
500 systrace_sysent
[sysnum
].stsy_return
= id
;
501 #ifdef _SYSCALL32_IMPL
502 systrace_sysent32
[sysnum
].stsy_return
= id
;
507 ASSERT(sysent
[sysnum
].sy_callc
== dtrace_systrace_syscall
);
511 (void) casptr(&sysent
[sysnum
].sy_callc
,
512 (void *)systrace_sysent
[sysnum
].stsy_underlying
,
513 (void *)dtrace_systrace_syscall
);
514 #ifdef _SYSCALL32_IMPL
515 (void) casptr(&sysent32
[sysnum
].sy_callc
,
516 (void *)systrace_sysent32
[sysnum
].stsy_underlying
,
517 (void *)dtrace_systrace_syscall32
);
523 systrace_disable(void *arg
, dtrace_id_t id
, void *parg
)
525 #pragma unused(arg,id) /* __APPLE__ */
527 int sysnum
= SYSTRACE_SYSNUM((uintptr_t)parg
);
528 int disable
= (systrace_sysent
[sysnum
].stsy_entry
== DTRACE_IDNONE
||
529 systrace_sysent
[sysnum
].stsy_return
== DTRACE_IDNONE
);
532 (void) casptr(&sysent
[sysnum
].sy_callc
,
533 (void *)dtrace_systrace_syscall
,
534 (void *)systrace_sysent
[sysnum
].stsy_underlying
);
536 #ifdef _SYSCALL32_IMPL
537 (void) casptr(&sysent32
[sysnum
].sy_callc
,
538 (void *)dtrace_systrace_syscall32
,
539 (void *)systrace_sysent32
[sysnum
].stsy_underlying
);
543 if (SYSTRACE_ISENTRY((uintptr_t)parg
)) {
544 systrace_sysent
[sysnum
].stsy_entry
= DTRACE_IDNONE
;
545 #ifdef _SYSCALL32_IMPL
546 systrace_sysent32
[sysnum
].stsy_entry
= DTRACE_IDNONE
;
549 systrace_sysent
[sysnum
].stsy_return
= DTRACE_IDNONE
;
550 #ifdef _SYSCALL32_IMPL
551 systrace_sysent32
[sysnum
].stsy_return
= DTRACE_IDNONE
;
556 static dtrace_pattr_t systrace_attr
= {
557 { DTRACE_STABILITY_EVOLVING
, DTRACE_STABILITY_EVOLVING
, DTRACE_CLASS_COMMON
},
558 { DTRACE_STABILITY_PRIVATE
, DTRACE_STABILITY_PRIVATE
, DTRACE_CLASS_UNKNOWN
},
559 { DTRACE_STABILITY_PRIVATE
, DTRACE_STABILITY_PRIVATE
, DTRACE_CLASS_ISA
},
560 { DTRACE_STABILITY_EVOLVING
, DTRACE_STABILITY_EVOLVING
, DTRACE_CLASS_COMMON
},
561 { DTRACE_STABILITY_PRIVATE
, DTRACE_STABILITY_PRIVATE
, DTRACE_CLASS_ISA
},
564 static dtrace_pops_t systrace_pops
= {
578 systrace_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
)
584 return (DDI_SUCCESS
);
586 return (DDI_FAILURE
);
589 #if !defined(__APPLE__)
590 systrace_probe
= (void (*)())dtrace_probe
;
593 if (ddi_create_minor_node(devi
, "systrace", S_IFCHR
, 0,
594 DDI_PSEUDO
, NULL
) == DDI_FAILURE
||
595 dtrace_register("syscall", &systrace_attr
, DTRACE_PRIV_USER
, NULL
,
596 &systrace_pops
, NULL
, &systrace_id
) != 0) {
597 systrace_probe
= systrace_stub
;
598 ddi_remove_minor_node(devi
, NULL
);
599 return (DDI_FAILURE
);
602 systrace_probe
= (void(*))&dtrace_probe
;
605 if (ddi_create_minor_node(devi
, "systrace", S_IFCHR
, 0,
606 DDI_PSEUDO
, 0) == DDI_FAILURE
||
607 dtrace_register("syscall", &systrace_attr
, DTRACE_PRIV_USER
, NULL
,
608 &systrace_pops
, NULL
, &systrace_id
) != 0) {
609 systrace_probe
= systrace_stub
;
610 ddi_remove_minor_node(devi
, NULL
);
611 return (DDI_FAILURE
);
613 #endif /* __APPLE__ */
615 ddi_report_dev(devi
);
616 systrace_devi
= devi
;
618 return (DDI_SUCCESS
);
621 #if !defined(__APPLE__)
623 systrace_detach(dev_info_t
*devi
, ddi_detach_cmd_t cmd
)
629 return (DDI_SUCCESS
);
631 return (DDI_FAILURE
);
634 if (dtrace_unregister(systrace_id
) != 0)
635 return (DDI_FAILURE
);
637 ddi_remove_minor_node(devi
, NULL
);
638 systrace_probe
= systrace_stub
;
639 return (DDI_SUCCESS
);
644 systrace_info(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
, void **result
)
649 case DDI_INFO_DEVT2DEVINFO
:
650 *result
= (void *)systrace_devi
;
653 case DDI_INFO_DEVT2INSTANCE
:
665 systrace_open(dev_t
*devp
, int flag
, int otyp
, cred_t
*cred_p
)
670 static struct cb_ops systrace_cb_ops
= {
671 systrace_open
, /* open */
673 nulldev
, /* strategy */
683 ddi_prop_op
, /* cb_prop_op */
685 D_NEW
| D_MP
/* Driver compatibility flag */
688 static struct dev_ops systrace_ops
= {
689 DEVO_REV
, /* devo_rev, */
691 systrace_info
, /* get_dev_info */
692 nulldev
, /* identify */
694 systrace_attach
, /* attach */
695 systrace_detach
, /* detach */
697 &systrace_cb_ops
, /* driver operations */
698 NULL
, /* bus operations */
699 nodev
/* dev power */
703 * Module linkage information for the kernel.
705 static struct modldrv modldrv
= {
706 &mod_driverops
, /* module type (this is a pseudo driver) */
707 "System Call Tracing", /* name of module */
708 &systrace_ops
, /* driver ops */
711 static struct modlinkage modlinkage
= {
720 return (mod_install(&modlinkage
));
724 _info(struct modinfo
*modinfop
)
726 return (mod_info(&modlinkage
, modinfop
));
732 return (mod_remove(&modlinkage
));
735 typedef kern_return_t (*mach_call_t
)(void *);
737 /* XXX From #include <kern/syscall_sw.h> which may be changed for 64 bit! */
738 typedef void mach_munge_t(const void *, void *);
741 int mach_trap_arg_count
;
742 int (*mach_trap_function
)(void);
743 #if defined(__i386__)
744 boolean_t mach_trap_stack
;
746 mach_munge_t
*mach_trap_arg_munge32
; /* system call arguments for 32-bit */
747 mach_munge_t
*mach_trap_arg_munge64
; /* system call arguments for 64-bit */
750 int mach_trap_unused
;
752 const char* mach_trap_name
;
753 #endif /* !MACH_ASSERT */
756 extern mach_trap_t mach_trap_table
[];
757 extern int mach_trap_count
;
759 extern const char *mach_syscall_name_table
[];
761 /* XXX From osfmk/i386/bsd_i386.c */
762 struct mach_call_args
{
775 #define NSYSCALL mach_trap_count
777 #if ((1 << SYSTRACE_SHIFT) <= NSYSCALL)
778 #error 1 << SYSTRACE_SHIFT must exceed number of Mach traps
781 typedef systrace_sysent_t machtrace_sysent_t
;
783 static machtrace_sysent_t
*machtrace_sysent
= NULL
;
785 void (*machtrace_probe
)(dtrace_id_t
, uint64_t, uint64_t,
786 uint64_t, uint64_t, uint64_t);
788 static dev_info_t
*machtrace_devi
;
789 static dtrace_provider_id_t machtrace_id
;
792 dtrace_machtrace_syscall(struct mach_call_args
*args
)
797 machtrace_sysent_t
*sy
;
803 syscall_arg_t
*ip
= (syscall_arg_t
*)args
;
804 mach_call_t mach_call
;
806 #if defined (__ppc__) || defined (__ppc64__)
808 savearea_t
*regs
= (savearea_t
*)find_user_regs(current_thread());
810 flavor
= (((unsigned int)regs
->save_r0
) == 0)? 1: 0;
813 code
= -regs
->save_r3
;
815 code
= -regs
->save_r0
;
817 #elif defined(__i386__) || defined (__x86_64__)
818 #pragma unused(flavor)
820 x86_saved_state_t
*tagged_regs
= (x86_saved_state_t
*)find_user_regs(current_thread());
822 if (is_saved_state64(tagged_regs
)) {
823 code
= saved_state64(tagged_regs
)->rax
& SYSCALL_NUMBER_MASK
;
825 code
= -saved_state32(tagged_regs
)->eax
;
829 #error Unknown Architecture
832 sy
= &machtrace_sysent
[code
];
834 if ((id
= sy
->stsy_entry
) != DTRACE_IDNONE
)
835 (*machtrace_probe
)(id
, *ip
, *(ip
+1), *(ip
+2), *(ip
+3), *(ip
+4));
839 * We want to explicitly allow DTrace consumers to stop a process
840 * before it actually executes the meat of the syscall.
842 p
= ttoproc(curthread
);
843 mutex_enter(&p
->p_lock
);
844 if (curthread
->t_dtrace_stop
&& !curthread
->t_lwp
->lwp_nostop
) {
845 curthread
->t_dtrace_stop
= 0;
846 stop(PR_REQUESTED
, 0);
848 mutex_exit(&p
->p_lock
);
851 mach_call
= (mach_call_t
)(*sy
->stsy_underlying
);
852 rval
= mach_call(args
);
854 if ((id
= sy
->stsy_return
) != DTRACE_IDNONE
)
855 (*machtrace_probe
)(id
, (uint64_t)rval
, 0, 0, 0, 0);
861 machtrace_init(mach_trap_t
*actual
, machtrace_sysent_t
**interposed
)
863 machtrace_sysent_t
*msysent
= *interposed
;
866 if (msysent
== NULL
) {
867 *interposed
= msysent
= kmem_zalloc(sizeof (machtrace_sysent_t
) *
871 for (i
= 0; i
< NSYSCALL
; i
++) {
872 mach_trap_t
*a
= &actual
[i
];
873 machtrace_sysent_t
*s
= &msysent
[i
];
875 if (LOADABLE_SYSCALL(a
) && !LOADED_SYSCALL(a
))
878 if ((mach_call_t
)(a
->mach_trap_function
) == (mach_call_t
)(dtrace_machtrace_syscall
))
881 s
->stsy_underlying
= (sy_call_t
*)a
->mach_trap_function
;
887 machtrace_provide(void *arg
, const dtrace_probedesc_t
*desc
)
889 #pragma unused(arg) /* __APPLE__ */
896 machtrace_init(mach_trap_table
, &machtrace_sysent
);
898 for (i
= 0; i
< NSYSCALL
; i
++) {
900 if (machtrace_sysent
[i
].stsy_underlying
== NULL
)
903 if (dtrace_probe_lookup(machtrace_id
, NULL
,
904 mach_syscall_name_table
[i
], "entry") != 0)
907 (void) dtrace_probe_create(machtrace_id
, NULL
, mach_syscall_name_table
[i
],
908 "entry", MACHTRACE_ARTIFICIAL_FRAMES
,
909 (void *)((uintptr_t)SYSTRACE_ENTRY(i
)));
910 (void) dtrace_probe_create(machtrace_id
, NULL
, mach_syscall_name_table
[i
],
911 "return", MACHTRACE_ARTIFICIAL_FRAMES
,
912 (void *)((uintptr_t)SYSTRACE_RETURN(i
)));
914 machtrace_sysent
[i
].stsy_entry
= DTRACE_IDNONE
;
915 machtrace_sysent
[i
].stsy_return
= DTRACE_IDNONE
;
921 machtrace_destroy(void *arg
, dtrace_id_t id
, void *parg
)
923 #pragma unused(arg,id) /* __APPLE__ */
924 int sysnum
= SYSTRACE_SYSNUM((uintptr_t)parg
);
926 #pragma unused(sysnum) /* __APPLE__ */
929 * There's nothing to do here but assert that we have actually been
932 if (SYSTRACE_ISENTRY((uintptr_t)parg
)) {
933 ASSERT(machtrace_sysent
[sysnum
].stsy_entry
== DTRACE_IDNONE
);
935 ASSERT(machtrace_sysent
[sysnum
].stsy_return
== DTRACE_IDNONE
);
941 machtrace_enable(void *arg
, dtrace_id_t id
, void *parg
)
943 #pragma unused(arg) /* __APPLE__ */
945 int sysnum
= SYSTRACE_SYSNUM((uintptr_t)parg
);
946 int enabled
= (machtrace_sysent
[sysnum
].stsy_entry
!= DTRACE_IDNONE
||
947 machtrace_sysent
[sysnum
].stsy_return
!= DTRACE_IDNONE
);
949 if (SYSTRACE_ISENTRY((uintptr_t)parg
)) {
950 machtrace_sysent
[sysnum
].stsy_entry
= id
;
952 machtrace_sysent
[sysnum
].stsy_return
= id
;
956 ASSERT(sysent
[sysnum
].sy_callc
== (void *)dtrace_machtrace_syscall
);
960 (void) casptr(&mach_trap_table
[sysnum
].mach_trap_function
,
961 (void *)machtrace_sysent
[sysnum
].stsy_underlying
,
962 (void *)dtrace_machtrace_syscall
);
967 machtrace_disable(void *arg
, dtrace_id_t id
, void *parg
)
969 #pragma unused(arg,id) /* __APPLE__ */
971 int sysnum
= SYSTRACE_SYSNUM((uintptr_t)parg
);
972 int disable
= (machtrace_sysent
[sysnum
].stsy_entry
== DTRACE_IDNONE
||
973 machtrace_sysent
[sysnum
].stsy_return
== DTRACE_IDNONE
);
976 (void) casptr(&mach_trap_table
[sysnum
].mach_trap_function
,
977 (void *)dtrace_machtrace_syscall
,
978 (void *)machtrace_sysent
[sysnum
].stsy_underlying
);
982 if (SYSTRACE_ISENTRY((uintptr_t)parg
)) {
983 machtrace_sysent
[sysnum
].stsy_entry
= DTRACE_IDNONE
;
985 machtrace_sysent
[sysnum
].stsy_return
= DTRACE_IDNONE
;
989 static dtrace_pattr_t machtrace_attr
= {
990 { DTRACE_STABILITY_EVOLVING
, DTRACE_STABILITY_EVOLVING
, DTRACE_CLASS_COMMON
},
991 { DTRACE_STABILITY_PRIVATE
, DTRACE_STABILITY_PRIVATE
, DTRACE_CLASS_UNKNOWN
},
992 { DTRACE_STABILITY_PRIVATE
, DTRACE_STABILITY_PRIVATE
, DTRACE_CLASS_ISA
},
993 { DTRACE_STABILITY_EVOLVING
, DTRACE_STABILITY_EVOLVING
, DTRACE_CLASS_COMMON
},
994 { DTRACE_STABILITY_PRIVATE
, DTRACE_STABILITY_PRIVATE
, DTRACE_CLASS_ISA
},
997 static dtrace_pops_t machtrace_pops
= {
1011 machtrace_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
)
1017 return (DDI_SUCCESS
);
1019 return (DDI_FAILURE
);
1022 #if !defined(__APPLE__)
1023 machtrace_probe
= (void (*)())dtrace_probe
;
1026 if (ddi_create_minor_node(devi
, "machtrace", S_IFCHR
, 0,
1027 DDI_PSEUDO
, NULL
) == DDI_FAILURE
||
1028 dtrace_register("mach_trap", &machtrace_attr
, DTRACE_PRIV_USER
, NULL
,
1029 &machtrace_pops
, NULL
, &machtrace_id
) != 0) {
1030 machtrace_probe
= systrace_stub
;
1032 machtrace_probe
= dtrace_probe
;
1035 if (ddi_create_minor_node(devi
, "machtrace", S_IFCHR
, 0,
1036 DDI_PSEUDO
, 0) == DDI_FAILURE
||
1037 dtrace_register("mach_trap", &machtrace_attr
, DTRACE_PRIV_USER
, NULL
,
1038 &machtrace_pops
, NULL
, &machtrace_id
) != 0) {
1039 machtrace_probe
= (void (*))&systrace_stub
;
1040 #endif /* __APPLE__ */
1041 ddi_remove_minor_node(devi
, NULL
);
1042 return (DDI_FAILURE
);
1045 ddi_report_dev(devi
);
1046 machtrace_devi
= devi
;
1048 return (DDI_SUCCESS
);
1051 d_open_t _systrace_open
;
1053 int _systrace_open(dev_t dev
, int flags
, int devtype
, struct proc
*p
)
1055 #pragma unused(dev,flags,devtype,p)
1059 #define SYSTRACE_MAJOR -24 /* let the kernel pick the device number */
1062 * A struct describing which functions will get invoked for certain
1065 static struct cdevsw systrace_cdevsw
=
1067 _systrace_open
, /* open */
1068 eno_opcl
, /* close */
1069 eno_rdwrt
, /* read */
1070 eno_rdwrt
, /* write */
1071 eno_ioctl
, /* ioctl */
1072 (stop_fcn_t
*)nulldev
, /* stop */
1073 (reset_fcn_t
*)nulldev
, /* reset */
1075 eno_select
, /* select */
1076 eno_mmap
, /* mmap */
1077 eno_strat
, /* strategy */
1078 eno_getc
, /* getc */
1079 eno_putc
, /* putc */
1083 static int gSysTraceInited
= 0;
1085 void systrace_init( void );
1087 void systrace_init( void )
1089 if (0 == gSysTraceInited
) {
1090 int majdevno
= cdevsw_add(SYSTRACE_MAJOR
, &systrace_cdevsw
);
1093 printf("systrace_init: failed to allocate a major number!\n");
1094 gSysTraceInited
= 0;
1098 systrace_attach( (dev_info_t
*)(uintptr_t)majdevno
, DDI_ATTACH
);
1099 machtrace_attach( (dev_info_t
*)(uintptr_t)majdevno
, DDI_ATTACH
);
1101 gSysTraceInited
= 1;
1103 panic("systrace_init: called twice!\n");
1105 #undef SYSTRACE_MAJOR
1106 #endif /* __APPLE__ */