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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* #pragma ident "@(#)systrace.c 1.6 06/09/19 SMI" */
30 #define _KERNEL /* Solaris vs. Darwin */
34 #include <kern/thread.h>
35 #include <mach/thread_status.h>
37 /* XXX All of these should really be derived from syscall_sw.h */
38 #if defined (__x86_64__)
39 #define SYSCALL_CLASS_SHIFT 24
40 #define SYSCALL_CLASS_MASK (0xFF << SYSCALL_CLASS_SHIFT)
41 #define SYSCALL_NUMBER_MASK (~SYSCALL_CLASS_MASK)
42 #define I386_SYSCALL_NUMBER_MASK (0xFFFF)
45 #include <sys/param.h>
46 #include <sys/systm.h>
48 #include <sys/errno.h>
49 #include <sys/ioctl.h>
51 #include <sys/fcntl.h>
52 #include <sys/syscall.h>
53 #include <miscfs/devfs/devfs.h>
55 #include <sys/dtrace.h>
56 #include <sys/dtrace_impl.h>
57 #include <sys/systrace_args.h>
60 #include <sys/systm.h>
64 #include <machine/pal_routines.h>
66 #if defined (__x86_64__)
67 #define SYSTRACE_ARTIFICIAL_FRAMES 2
68 #define MACHTRACE_ARTIFICIAL_FRAMES 3
69 #elif defined(__arm__) || defined(__arm64__)
70 #define SYSTRACE_ARTIFICIAL_FRAMES 2
71 #define MACHTRACE_ARTIFICIAL_FRAMES 3
73 #error Unknown Architecture
76 #define SYSTRACE_NARGS (int)(sizeof(((uthread_t)NULL)->uu_arg) / sizeof(((uthread_t)NULL)->uu_arg[0]))
78 #include <sys/sysent.h>
79 #define sy_callc sy_call /* Map Solaris slot name to Darwin's */
80 #define NSYSCALL nsysent /* and is less than 500 or so */
82 extern const char *syscallnames
[];
84 #include <sys/dtrace_glue.h>
85 #define casptr dtrace_casptr
86 #define membar_enter dtrace_membar_producer
88 #define LOADABLE_SYSCALL(a) 0 /* Not pertinent to Darwin. */
89 #define LOADED_SYSCALL(a) 1 /* Not pertinent to Darwin. */
91 extern lck_attr_t
* dtrace_lck_attr
;
92 extern lck_grp_t
* dtrace_lck_grp
;
93 static lck_mtx_t dtrace_systrace_lock
; /* probe state lock */
95 systrace_sysent_t
*systrace_sysent
= NULL
;
96 void (*systrace_probe
)(dtrace_id_t
, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
98 static uint64_t systrace_getargval(void *, dtrace_id_t
, void *, int, int);
99 static void systrace_getargdesc(void *, dtrace_id_t
, void *, dtrace_argdesc_t
*);
102 systrace_stub(dtrace_id_t id
, uint64_t arg0
, uint64_t arg1
,
103 uint64_t arg2
, uint64_t arg3
, uint64_t arg4
)
105 #pragma unused(id,arg0,arg1,arg2,arg3,arg4)
109 dtrace_systrace_syscall(struct proc
*pp
, void *uap
, int *rv
)
111 unsigned short code
; /* The system call number */
113 systrace_sysent_t
*sy
;
116 syscall_arg_t
*ip
= (syscall_arg_t
*)uap
;
117 uint64_t uargs
[SYSTRACE_NARGS
] = {0};
119 #if defined (__x86_64__)
121 pal_register_cache_state(current_thread(), VALID
);
122 x86_saved_state_t
*tagged_regs
= (x86_saved_state_t
*)find_user_regs(current_thread());
124 if (is_saved_state64(tagged_regs
)) {
125 x86_saved_state64_t
*regs
= saved_state64(tagged_regs
);
126 code
= regs
->rax
& SYSCALL_NUMBER_MASK
;
128 * Check for indirect system call... system call number
135 code
= saved_state32(tagged_regs
)->eax
& I386_SYSCALL_NUMBER_MASK
;
138 vm_offset_t params
= (vm_offset_t
) (saved_state32(tagged_regs
)->uesp
+ sizeof (int));
139 code
= fuword(params
);
143 #elif defined(__arm__)
146 * On arm, syscall numbers depend on a flavor (indirect or not)
147 * and can be in either r0 or r12 (always u32)
150 /* See bsd/dev/arm/systemcalls.c:arm_get_syscall_number */
151 arm_saved_state_t
*arm_regs
= (arm_saved_state_t
*) find_user_regs(current_thread());
153 /* Check for indirect system call */
154 if (arm_regs
->r
[12] != 0)
155 code
= arm_regs
->r
[12];
157 code
= arm_regs
->r
[0];
159 #elif defined(__arm64__)
162 * On arm64, syscall numbers depend on a flavor (indirect or not)
163 * ... and for u32 can be in either r0 or r12
164 * ... and for u64 can be in either x0 or x16
167 /* see bsd/dev/arm/systemcalls.c:arm_get_syscall_number */
168 arm_saved_state_t
*arm_regs
= (arm_saved_state_t
*) find_user_regs(current_thread());
170 if (is_saved_state32(arm_regs
)) {
171 /* Check for indirect system call */
172 if (saved_state32(arm_regs
)->r
[12] != 0) {
173 code
= saved_state32(arm_regs
)->r
[12];
176 code
= saved_state32(arm_regs
)->r
[0];
179 /* Check for indirect system call */
180 if (saved_state64(arm_regs
)->x
[ARM64_SYSCALL_CODE_REG_NUM
] != 0 ) {
181 code
= saved_state64(arm_regs
)->x
[ARM64_SYSCALL_CODE_REG_NUM
];
184 code
= saved_state64(arm_regs
)->x
[0];
189 #error Unknown Architecture
192 // Bounds "check" the value of code a la unix_syscall
193 sy
= (code
>= nsysent
) ? &systrace_sysent
[SYS_invalid
] : &systrace_sysent
[code
];
195 systrace_args(code
, ip
, uargs
);
197 if ((id
= sy
->stsy_entry
) != DTRACE_IDNONE
) {
198 uthread_t uthread
= (uthread_t
)get_bsdthread_info(current_thread());
200 uthread
->t_dtrace_syscall_args
= uargs
;
202 static_assert(SYSTRACE_NARGS
>= 5, "not enough system call arguments");
203 (*systrace_probe
)(id
, uargs
[0], uargs
[1], uargs
[2], uargs
[3], uargs
[4]);
206 uthread
->t_dtrace_syscall_args
= NULL
;
213 * APPLE NOTE: Not implemented.
214 * We want to explicitly allow DTrace consumers to stop a process
215 * before it actually executes the meat of the syscall.
217 p
= ttoproc(curthread
);
218 mutex_enter(&p
->p_lock
);
219 if (curthread
->t_dtrace_stop
&& !curthread
->t_lwp
->lwp_nostop
) {
220 curthread
->t_dtrace_stop
= 0;
221 stop(PR_REQUESTED
, 0);
223 mutex_exit(&p
->p_lock
);
226 rval
= (*sy
->stsy_underlying
)(pp
, uap
, rv
);
228 if ((id
= sy
->stsy_return
) != DTRACE_IDNONE
) {
229 uint64_t munged_rv0
, munged_rv1
;
230 uthread_t uthread
= (uthread_t
)get_bsdthread_info(current_thread());
233 uthread
->t_dtrace_errno
= rval
; /* Establish t_dtrace_errno now in case this enabling refers to it. */
236 * "Decode" rv for use in the call to dtrace_probe()
238 if (rval
== ERESTART
) {
239 munged_rv0
= -1LL; /* System call will be reissued in user mode. Make DTrace report a -1 return. */
241 } else if (rval
!= EJUSTRETURN
) {
243 munged_rv0
= -1LL; /* Mimic what libc will do. */
246 switch (sy
->stsy_return_type
) {
247 case _SYSCALL_RET_INT_T
:
251 case _SYSCALL_RET_UINT_T
:
252 munged_rv0
= ((u_int
)rv
[0]);
253 munged_rv1
= ((u_int
)rv
[1]);
255 case _SYSCALL_RET_OFF_T
:
256 case _SYSCALL_RET_UINT64_T
:
257 munged_rv0
= *(u_int64_t
*)rv
;
260 case _SYSCALL_RET_ADDR_T
:
261 case _SYSCALL_RET_SIZE_T
:
262 case _SYSCALL_RET_SSIZE_T
:
263 munged_rv0
= *(user_addr_t
*)rv
;
266 case _SYSCALL_RET_NONE
:
282 * <http://mail.opensolaris.org/pipermail/dtrace-discuss/2007-January/003276.html> says:
284 * "This is a bit of an historical artifact. At first, the syscall provider just
285 * had its return value in arg0, and the fbt and pid providers had their return
286 * values in arg1 (so that we could use arg0 for the offset of the return site).
288 * We inevitably started writing scripts where we wanted to see the return
289 * values from probes in all three providers, and we made this script easier
290 * to write by replicating the syscall return values in arg1 to match fbt and
291 * pid. We debated briefly about removing the return value from arg0, but
292 * decided that it would be less confusing to have the same data in two places
293 * than to have some non-helpful, non-intuitive value in arg0.
295 * This change was made 4/23/2003 according to the DTrace project's putback log."
297 (*systrace_probe
)(id
, munged_rv0
, munged_rv0
, munged_rv1
, (uint64_t)rval
, 0);
304 dtrace_systrace_syscall_return(unsigned short code
, int rval
, int *rv
)
306 systrace_sysent_t
*sy
;
309 // Bounds "check" the value of code a la unix_syscall_return
310 sy
= (code
>= nsysent
) ? &systrace_sysent
[SYS_invalid
] : &systrace_sysent
[code
];
312 if ((id
= sy
->stsy_return
) != DTRACE_IDNONE
) {
313 uint64_t munged_rv0
, munged_rv1
;
314 uthread_t uthread
= (uthread_t
)get_bsdthread_info(current_thread());
317 uthread
->t_dtrace_errno
= rval
; /* Establish t_dtrace_errno now in case this enabling refers to it. */
320 * "Decode" rv for use in the call to dtrace_probe()
322 if (rval
== ERESTART
) {
323 munged_rv0
= -1LL; /* System call will be reissued in user mode. Make DTrace report a -1 return. */
325 } else if (rval
!= EJUSTRETURN
) {
327 munged_rv0
= -1LL; /* Mimic what libc will do. */
330 switch (sy
->stsy_return_type
) {
331 case _SYSCALL_RET_INT_T
:
335 case _SYSCALL_RET_UINT_T
:
336 munged_rv0
= ((u_int
)rv
[0]);
337 munged_rv1
= ((u_int
)rv
[1]);
339 case _SYSCALL_RET_OFF_T
:
340 case _SYSCALL_RET_UINT64_T
:
341 munged_rv0
= *(u_int64_t
*)rv
;
344 case _SYSCALL_RET_ADDR_T
:
345 case _SYSCALL_RET_SIZE_T
:
346 case _SYSCALL_RET_SSIZE_T
:
347 munged_rv0
= *(user_addr_t
*)rv
;
350 case _SYSCALL_RET_NONE
:
365 (*systrace_probe
)(id
, munged_rv0
, munged_rv0
, munged_rv1
, (uint64_t)rval
, 0);
369 #define SYSTRACE_SHIFT 16
370 #define SYSTRACE_ISENTRY(x) ((int)(x) >> SYSTRACE_SHIFT)
371 #define SYSTRACE_SYSNUM(x) ((int)(x) & ((1 << SYSTRACE_SHIFT) - 1))
372 #define SYSTRACE_ENTRY(id) ((1 << SYSTRACE_SHIFT) | (id))
373 #define SYSTRACE_RETURN(id) (id)
375 #if ((1 << SYSTRACE_SHIFT) <= NSYSCALL)
376 #error 1 << SYSTRACE_SHIFT must exceed number of system calls
379 static dev_info_t
*systrace_devi
;
380 static dtrace_provider_id_t systrace_id
;
383 * APPLE NOTE: Avoid name clash with Darwin automagic conf symbol.
384 * See balanced undef below.
386 #define systrace_init _systrace_init
389 systrace_init(struct sysent
*actual
, systrace_sysent_t
**interposed
)
392 systrace_sysent_t
*ssysent
= *interposed
; /* Avoid sysent shadow warning
393 from bsd/sys/sysent.h */
396 if (ssysent
== NULL
) {
397 *interposed
= ssysent
= kmem_zalloc(sizeof (systrace_sysent_t
) *
401 for (i
= 0; i
< NSYSCALL
; i
++) {
402 struct sysent
*a
= &actual
[i
];
403 systrace_sysent_t
*s
= &ssysent
[i
];
405 if (LOADABLE_SYSCALL(a
) && !LOADED_SYSCALL(a
))
408 if (a
->sy_callc
== dtrace_systrace_syscall
)
411 s
->stsy_underlying
= a
->sy_callc
;
412 s
->stsy_return_type
= a
->sy_return_type
;
414 lck_mtx_init(&dtrace_systrace_lock
, dtrace_lck_grp
, dtrace_lck_attr
);
420 systrace_provide(void *arg
, const dtrace_probedesc_t
*desc
)
422 #pragma unused(arg) /* __APPLE__ */
428 systrace_init(sysent
, &systrace_sysent
);
430 for (i
= 0; i
< NSYSCALL
; i
++) {
431 if (systrace_sysent
[i
].stsy_underlying
== NULL
)
434 if (dtrace_probe_lookup(systrace_id
, NULL
,
435 syscallnames
[i
], "entry") != 0)
438 (void) dtrace_probe_create(systrace_id
, NULL
, syscallnames
[i
],
439 "entry", SYSTRACE_ARTIFICIAL_FRAMES
,
440 (void *)((uintptr_t)SYSTRACE_ENTRY(i
)));
441 (void) dtrace_probe_create(systrace_id
, NULL
, syscallnames
[i
],
442 "return", SYSTRACE_ARTIFICIAL_FRAMES
,
443 (void *)((uintptr_t)SYSTRACE_RETURN(i
)));
445 systrace_sysent
[i
].stsy_entry
= DTRACE_IDNONE
;
446 systrace_sysent
[i
].stsy_return
= DTRACE_IDNONE
;
453 systrace_destroy(void *arg
, dtrace_id_t id
, void *parg
)
455 #pragma unused(arg,id) /* __APPLE__ */
457 int sysnum
= SYSTRACE_SYSNUM((uintptr_t)parg
);
459 #pragma unused(sysnum) /* __APPLE__ */
461 * There's nothing to do here but assert that we have actually been
464 if (SYSTRACE_ISENTRY((uintptr_t)parg
)) {
465 ASSERT(systrace_sysent
[sysnum
].stsy_entry
== DTRACE_IDNONE
);
467 ASSERT(systrace_sysent
[sysnum
].stsy_return
== DTRACE_IDNONE
);
473 systrace_enable(void *arg
, dtrace_id_t id
, void *parg
)
475 #pragma unused(arg) /* __APPLE__ */
477 int sysnum
= SYSTRACE_SYSNUM((uintptr_t)parg
);
478 int enabled
= (systrace_sysent
[sysnum
].stsy_entry
!= DTRACE_IDNONE
||
479 systrace_sysent
[sysnum
].stsy_return
!= DTRACE_IDNONE
);
481 if (SYSTRACE_ISENTRY((uintptr_t)parg
)) {
482 systrace_sysent
[sysnum
].stsy_entry
= id
;
484 systrace_sysent
[sysnum
].stsy_return
= id
;
488 ASSERT(sysent
[sysnum
].sy_callc
== dtrace_systrace_syscall
);
492 lck_mtx_lock(&dtrace_systrace_lock
);
493 if (sysent
[sysnum
].sy_callc
== systrace_sysent
[sysnum
].stsy_underlying
) {
494 vm_offset_t dss
= (vm_offset_t
)&dtrace_systrace_syscall
;
495 ml_nofault_copy((vm_offset_t
)&dss
, (vm_offset_t
)&sysent
[sysnum
].sy_callc
, sizeof(vm_offset_t
));
497 lck_mtx_unlock(&dtrace_systrace_lock
);
503 systrace_disable(void *arg
, dtrace_id_t id
, void *parg
)
505 #pragma unused(arg,id) /* __APPLE__ */
507 int sysnum
= SYSTRACE_SYSNUM((uintptr_t)parg
);
508 int disable
= (systrace_sysent
[sysnum
].stsy_entry
== DTRACE_IDNONE
||
509 systrace_sysent
[sysnum
].stsy_return
== DTRACE_IDNONE
);
512 lck_mtx_lock(&dtrace_systrace_lock
);
513 if (sysent
[sysnum
].sy_callc
== dtrace_systrace_syscall
)
514 ml_nofault_copy((vm_offset_t
)&systrace_sysent
[sysnum
].stsy_underlying
, (vm_offset_t
)&sysent
[sysnum
].sy_callc
, sizeof(systrace_sysent
[sysnum
].stsy_underlying
));
515 lck_mtx_unlock(&dtrace_systrace_lock
);
519 if (SYSTRACE_ISENTRY((uintptr_t)parg
)) {
520 systrace_sysent
[sysnum
].stsy_entry
= DTRACE_IDNONE
;
522 systrace_sysent
[sysnum
].stsy_return
= DTRACE_IDNONE
;
526 static dtrace_pattr_t systrace_attr
= {
527 { DTRACE_STABILITY_EVOLVING
, DTRACE_STABILITY_EVOLVING
, DTRACE_CLASS_COMMON
},
528 { DTRACE_STABILITY_PRIVATE
, DTRACE_STABILITY_PRIVATE
, DTRACE_CLASS_UNKNOWN
},
529 { DTRACE_STABILITY_PRIVATE
, DTRACE_STABILITY_PRIVATE
, DTRACE_CLASS_ISA
},
530 { DTRACE_STABILITY_EVOLVING
, DTRACE_STABILITY_EVOLVING
, DTRACE_CLASS_COMMON
},
531 { DTRACE_STABILITY_PRIVATE
, DTRACE_STABILITY_PRIVATE
, DTRACE_CLASS_ISA
},
534 static dtrace_pops_t systrace_pops
= {
548 systrace_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
)
554 return (DDI_SUCCESS
);
556 return (DDI_FAILURE
);
559 systrace_probe
= (void(*))&dtrace_probe
;
562 if (ddi_create_minor_node(devi
, "systrace", S_IFCHR
, 0,
563 DDI_PSEUDO
, 0) == DDI_FAILURE
||
564 dtrace_register("syscall", &systrace_attr
, DTRACE_PRIV_USER
, NULL
,
565 &systrace_pops
, NULL
, &systrace_id
) != 0) {
566 systrace_probe
= systrace_stub
;
567 ddi_remove_minor_node(devi
, NULL
);
568 return (DDI_FAILURE
);
571 ddi_report_dev(devi
);
572 systrace_devi
= devi
;
574 return (DDI_SUCCESS
);
579 * APPLE NOTE: systrace_detach not implemented
581 #if !defined(__APPLE__)
583 systrace_detach(dev_info_t
*devi
, ddi_detach_cmd_t cmd
)
589 return (DDI_SUCCESS
);
591 return (DDI_FAILURE
);
594 if (dtrace_unregister(systrace_id
) != 0)
595 return (DDI_FAILURE
);
597 ddi_remove_minor_node(devi
, NULL
);
598 systrace_probe
= systrace_stub
;
599 return (DDI_SUCCESS
);
601 #endif /* __APPLE__ */
604 typedef kern_return_t (*mach_call_t
)(void *);
606 /* APPLE NOTE: From #include <kern/syscall_sw.h> which may be changed for 64 bit! */
607 typedef void mach_munge_t(void *);
610 int mach_trap_arg_count
;
611 kern_return_t (*mach_trap_function
)(void *);
612 #if defined(__arm64__) || defined(__x86_64__)
613 mach_munge_t
*mach_trap_arg_munge32
; /* system call arguments for 32-bit */
615 int mach_trap_u32_words
;
617 const char* mach_trap_name
;
618 #endif /* MACH_ASSERT */
621 extern const mach_trap_t mach_trap_table
[]; /* syscall_sw.h now declares this as const */
622 extern int mach_trap_count
;
624 extern const char *mach_syscall_name_table
[];
626 /* XXX From osfmk/i386/bsd_i386.c */
627 struct mach_call_args
{
640 #define NSYSCALL mach_trap_count
642 #if ((1 << SYSTRACE_SHIFT) <= NSYSCALL)
643 #error 1 << SYSTRACE_SHIFT must exceed number of Mach traps
646 typedef struct machtrace_sysent
{
647 dtrace_id_t stsy_entry
;
648 dtrace_id_t stsy_return
;
649 kern_return_t (*stsy_underlying
)(void *);
650 int32_t stsy_return_type
;
651 } machtrace_sysent_t
;
653 static machtrace_sysent_t
*machtrace_sysent
= NULL
;
655 void (*machtrace_probe
)(dtrace_id_t
, uint64_t, uint64_t,
656 uint64_t, uint64_t, uint64_t);
658 static uint64_t machtrace_getarg(void *, dtrace_id_t
, void *, int, int);
660 static dev_info_t
*machtrace_devi
;
661 static dtrace_provider_id_t machtrace_id
;
664 dtrace_machtrace_syscall(struct mach_call_args
*args
)
666 int code
; /* The mach call number */
668 machtrace_sysent_t
*sy
;
674 syscall_arg_t
*ip
= (syscall_arg_t
*)args
;
675 mach_call_t mach_call
;
677 #if defined (__x86_64__)
679 pal_register_cache_state(current_thread(), VALID
);
680 x86_saved_state_t
*tagged_regs
= (x86_saved_state_t
*)find_user_regs(current_thread());
682 if (is_saved_state64(tagged_regs
)) {
683 code
= saved_state64(tagged_regs
)->rax
& SYSCALL_NUMBER_MASK
;
685 code
= -saved_state32(tagged_regs
)->eax
;
688 #elif defined(__arm__)
690 /* r12 has the machcall number, but it is -ve */
691 arm_saved_state_t
*arm_regs
= (arm_saved_state_t
*) find_user_regs(current_thread());
692 code
= (int)arm_regs
->r
[12];
693 ASSERT(code
< 0); /* Otherwise it would be a Unix syscall */
696 #elif defined(__arm64__)
698 /* From arm/thread_status.h:get_saved_state_svc_number */
699 arm_saved_state_t
*arm_regs
= (arm_saved_state_t
*) find_user_regs(current_thread());
700 if (is_saved_state32(arm_regs
)) {
701 code
= (int)saved_state32(arm_regs
)->r
[12];
703 code
= (int)saved_state64(arm_regs
)->x
[ARM64_SYSCALL_CODE_REG_NUM
];
706 /* From bsd/arm64.c:mach_syscall */
707 ASSERT(code
< 0); /* Otherwise it would be a Unix syscall */
711 #error Unknown Architecture
714 sy
= &machtrace_sysent
[code
];
716 if ((id
= sy
->stsy_entry
) != DTRACE_IDNONE
) {
717 uthread_t uthread
= (uthread_t
)get_bsdthread_info(current_thread());
720 uthread
->t_dtrace_syscall_args
= (void *)ip
;
722 (*machtrace_probe
)(id
, *ip
, *(ip
+1), *(ip
+2), *(ip
+3), *(ip
+4));
725 uthread
->t_dtrace_syscall_args
= (void *)0;
730 * APPLE NOTE: Not implemented.
731 * We want to explicitly allow DTrace consumers to stop a process
732 * before it actually executes the meat of the syscall.
734 p
= ttoproc(curthread
);
735 mutex_enter(&p
->p_lock
);
736 if (curthread
->t_dtrace_stop
&& !curthread
->t_lwp
->lwp_nostop
) {
737 curthread
->t_dtrace_stop
= 0;
738 stop(PR_REQUESTED
, 0);
740 mutex_exit(&p
->p_lock
);
743 mach_call
= (mach_call_t
)(*sy
->stsy_underlying
);
744 rval
= mach_call(args
);
746 if ((id
= sy
->stsy_return
) != DTRACE_IDNONE
)
747 (*machtrace_probe
)(id
, (uint64_t)rval
, 0, 0, 0, 0);
753 machtrace_init(const mach_trap_t
*actual
, machtrace_sysent_t
**interposed
)
755 machtrace_sysent_t
*msysent
= *interposed
;
758 if (msysent
== NULL
) {
759 *interposed
= msysent
= kmem_zalloc(sizeof (machtrace_sysent_t
) *
763 for (i
= 0; i
< NSYSCALL
; i
++) {
764 const mach_trap_t
*a
= &actual
[i
];
765 machtrace_sysent_t
*s
= &msysent
[i
];
767 if (LOADABLE_SYSCALL(a
) && !LOADED_SYSCALL(a
))
770 if (a
->mach_trap_function
== (mach_call_t
)(dtrace_machtrace_syscall
))
773 s
->stsy_underlying
= a
->mach_trap_function
;
779 machtrace_provide(void *arg
, const dtrace_probedesc_t
*desc
)
781 #pragma unused(arg) /* __APPLE__ */
788 machtrace_init(mach_trap_table
, &machtrace_sysent
);
790 for (i
= 0; i
< NSYSCALL
; i
++) {
792 if (machtrace_sysent
[i
].stsy_underlying
== NULL
)
795 if (dtrace_probe_lookup(machtrace_id
, NULL
,
796 mach_syscall_name_table
[i
], "entry") != 0)
799 (void) dtrace_probe_create(machtrace_id
, NULL
, mach_syscall_name_table
[i
],
800 "entry", MACHTRACE_ARTIFICIAL_FRAMES
,
801 (void *)((uintptr_t)SYSTRACE_ENTRY(i
)));
802 (void) dtrace_probe_create(machtrace_id
, NULL
, mach_syscall_name_table
[i
],
803 "return", MACHTRACE_ARTIFICIAL_FRAMES
,
804 (void *)((uintptr_t)SYSTRACE_RETURN(i
)));
806 machtrace_sysent
[i
].stsy_entry
= DTRACE_IDNONE
;
807 machtrace_sysent
[i
].stsy_return
= DTRACE_IDNONE
;
813 machtrace_destroy(void *arg
, dtrace_id_t id
, void *parg
)
815 #pragma unused(arg,id) /* __APPLE__ */
816 int sysnum
= SYSTRACE_SYSNUM((uintptr_t)parg
);
818 #pragma unused(sysnum) /* __APPLE__ */
821 * There's nothing to do here but assert that we have actually been
824 if (SYSTRACE_ISENTRY((uintptr_t)parg
)) {
825 ASSERT(machtrace_sysent
[sysnum
].stsy_entry
== DTRACE_IDNONE
);
827 ASSERT(machtrace_sysent
[sysnum
].stsy_return
== DTRACE_IDNONE
);
833 machtrace_enable(void *arg
, dtrace_id_t id
, void *parg
)
835 #pragma unused(arg) /* __APPLE__ */
837 int sysnum
= SYSTRACE_SYSNUM((uintptr_t)parg
);
838 int enabled
= (machtrace_sysent
[sysnum
].stsy_entry
!= DTRACE_IDNONE
||
839 machtrace_sysent
[sysnum
].stsy_return
!= DTRACE_IDNONE
);
841 if (SYSTRACE_ISENTRY((uintptr_t)parg
)) {
842 machtrace_sysent
[sysnum
].stsy_entry
= id
;
844 machtrace_sysent
[sysnum
].stsy_return
= id
;
848 ASSERT(mach_trap_table
[sysnum
].mach_trap_function
== (void *)dtrace_machtrace_syscall
);
852 lck_mtx_lock(&dtrace_systrace_lock
);
854 if (mach_trap_table
[sysnum
].mach_trap_function
== machtrace_sysent
[sysnum
].stsy_underlying
) {
855 vm_offset_t dss
= (vm_offset_t
)&dtrace_machtrace_syscall
;
856 ml_nofault_copy((vm_offset_t
)&dss
, (vm_offset_t
)&mach_trap_table
[sysnum
].mach_trap_function
, sizeof(vm_offset_t
));
859 lck_mtx_unlock(&dtrace_systrace_lock
);
866 machtrace_disable(void *arg
, dtrace_id_t id
, void *parg
)
868 #pragma unused(arg,id) /* __APPLE__ */
870 int sysnum
= SYSTRACE_SYSNUM((uintptr_t)parg
);
871 int disable
= (machtrace_sysent
[sysnum
].stsy_entry
== DTRACE_IDNONE
||
872 machtrace_sysent
[sysnum
].stsy_return
== DTRACE_IDNONE
);
876 lck_mtx_lock(&dtrace_systrace_lock
);
878 if (mach_trap_table
[sysnum
].mach_trap_function
== (mach_call_t
)dtrace_machtrace_syscall
) {
879 ml_nofault_copy((vm_offset_t
)&machtrace_sysent
[sysnum
].stsy_underlying
, (vm_offset_t
)&mach_trap_table
[sysnum
].mach_trap_function
, sizeof(vm_offset_t
));
881 lck_mtx_unlock(&dtrace_systrace_lock
);
884 if (SYSTRACE_ISENTRY((uintptr_t)parg
)) {
885 machtrace_sysent
[sysnum
].stsy_entry
= DTRACE_IDNONE
;
887 machtrace_sysent
[sysnum
].stsy_return
= DTRACE_IDNONE
;
891 static dtrace_pattr_t machtrace_attr
= {
892 { DTRACE_STABILITY_EVOLVING
, DTRACE_STABILITY_EVOLVING
, DTRACE_CLASS_COMMON
},
893 { DTRACE_STABILITY_PRIVATE
, DTRACE_STABILITY_PRIVATE
, DTRACE_CLASS_UNKNOWN
},
894 { DTRACE_STABILITY_PRIVATE
, DTRACE_STABILITY_PRIVATE
, DTRACE_CLASS_ISA
},
895 { DTRACE_STABILITY_EVOLVING
, DTRACE_STABILITY_EVOLVING
, DTRACE_CLASS_COMMON
},
896 { DTRACE_STABILITY_PRIVATE
, DTRACE_STABILITY_PRIVATE
, DTRACE_CLASS_ISA
},
899 static dtrace_pops_t machtrace_pops
= {
913 machtrace_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
)
919 return (DDI_SUCCESS
);
921 return (DDI_FAILURE
);
924 machtrace_probe
= dtrace_probe
;
927 if (ddi_create_minor_node(devi
, "machtrace", S_IFCHR
, 0,
928 DDI_PSEUDO
, 0) == DDI_FAILURE
||
929 dtrace_register("mach_trap", &machtrace_attr
, DTRACE_PRIV_USER
, NULL
,
930 &machtrace_pops
, NULL
, &machtrace_id
) != 0) {
931 machtrace_probe
= (void (*))&systrace_stub
;
932 ddi_remove_minor_node(devi
, NULL
);
933 return (DDI_FAILURE
);
936 ddi_report_dev(devi
);
937 machtrace_devi
= devi
;
939 return (DDI_SUCCESS
);
942 d_open_t _systrace_open
;
944 int _systrace_open(dev_t dev
, int flags
, int devtype
, struct proc
*p
)
946 #pragma unused(dev,flags,devtype,p)
950 #define SYSTRACE_MAJOR -24 /* let the kernel pick the device number */
953 * A struct describing which functions will get invoked for certain
956 static struct cdevsw systrace_cdevsw
=
958 _systrace_open
, /* open */
959 eno_opcl
, /* close */
960 eno_rdwrt
, /* read */
961 eno_rdwrt
, /* write */
962 eno_ioctl
, /* ioctl */
963 (stop_fcn_t
*)nulldev
, /* stop */
964 (reset_fcn_t
*)nulldev
, /* reset */
966 eno_select
, /* select */
968 eno_strat
, /* strategy */
974 static int gSysTraceInited
= 0;
976 void systrace_init( void );
978 void systrace_init( void )
980 if (0 == gSysTraceInited
) {
981 if (dtrace_sdt_probes_restricted()) {
985 int majdevno
= cdevsw_add(SYSTRACE_MAJOR
, &systrace_cdevsw
);
988 printf("systrace_init: failed to allocate a major number!\n");
993 systrace_attach( (dev_info_t
*)(uintptr_t)majdevno
, DDI_ATTACH
);
994 machtrace_attach( (dev_info_t
*)(uintptr_t)majdevno
, DDI_ATTACH
);
998 panic("systrace_init: called twice!\n");
1000 #undef SYSTRACE_MAJOR
1003 systrace_getargval(void *arg
, dtrace_id_t id
, void *parg
, int argno
, int aframes
)
1005 #pragma unused(arg,id,parg,aframes) /* __APPLE__ */
1007 uint64_t *uargs
= NULL
;
1009 uthread_t uthread
= (uthread_t
)get_bsdthread_info(current_thread());
1012 uargs
= uthread
->t_dtrace_syscall_args
;
1015 if (argno
< 0 || argno
> SYSTRACE_NARGS
)
1018 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT
);
1020 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT
);
1025 systrace_getargdesc(void *arg
, dtrace_id_t id
, void *parg
,
1026 dtrace_argdesc_t
*desc
)
1028 #pragma unused(arg, id)
1029 int sysnum
= SYSTRACE_SYSNUM(parg
);
1030 uthread_t uthread
= (uthread_t
)get_bsdthread_info(current_thread());
1031 uint64_t *uargs
= NULL
;
1034 desc
->dtargd_ndx
= DTRACE_ARGNONE
;
1038 uargs
= uthread
->t_dtrace_syscall_args
;
1040 if (SYSTRACE_ISENTRY((uintptr_t)parg
)) {
1041 systrace_entry_setargdesc(sysnum
, desc
->dtargd_ndx
,
1042 desc
->dtargd_native
, sizeof(desc
->dtargd_native
));
1045 systrace_return_setargdesc(sysnum
, desc
->dtargd_ndx
,
1046 desc
->dtargd_native
, sizeof(desc
->dtargd_native
));
1049 if (desc
->dtargd_native
[0] == '\0')
1050 desc
->dtargd_ndx
= DTRACE_ARGNONE
;
1054 machtrace_getarg(void *arg
, dtrace_id_t id
, void *parg
, int argno
, int aframes
)
1056 #pragma unused(arg,id,parg,aframes) /* __APPLE__ */
1058 syscall_arg_t
*stack
= (syscall_arg_t
*)NULL
;
1060 uthread_t uthread
= (uthread_t
)get_bsdthread_info(current_thread());
1063 stack
= (syscall_arg_t
*)uthread
->t_dtrace_syscall_args
;
1068 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT
);
1069 /* dtrace_probe arguments arg0 .. arg4 are 64bits wide */
1070 val
= (uint64_t)*(stack
+argno
);
1071 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT
);