]> git.saurik.com Git - apple/xnu.git/blob - bsd/dev/dtrace/systrace.c
52362b6401973c4238c438bc8ffac4f6a1900863
[apple/xnu.git] / bsd / dev / dtrace / systrace.c
1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /* #pragma ident "@(#)systrace.c 1.5 06/03/24 SMI" */
27
28 #if !defined(__APPLE__)
29 #include <sys/dtrace.h>
30 #include <sys/systrace.h>
31 #include <sys/stat.h>
32 #include <sys/systm.h>
33 #include <sys/conf.h>
34 #include <sys/ddi.h>
35 #include <sys/sunddi.h>
36 #include <sys/atomic.h>
37 #define SYSTRACE_ARTIFICIAL_FRAMES 1
38 #else
39
40 #ifdef KERNEL
41 #ifndef _KERNEL
42 #define _KERNEL /* Solaris vs. Darwin */
43 #endif
44 #endif
45
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)
55
56 typedef x86_saved_state_t savearea_t;
57 #endif
58
59 #include <sys/param.h>
60 #include <sys/systm.h>
61 #include <sys/proc.h>
62 #include <sys/errno.h>
63 #include <sys/ioctl.h>
64 #include <sys/conf.h>
65 #include <sys/fcntl.h>
66 #include <miscfs/devfs/devfs.h>
67
68 #include <sys/dtrace.h>
69 #include <sys/dtrace_impl.h>
70 #include "systrace.h"
71 #include <sys/stat.h>
72 #include <sys/systm.h>
73 #include <sys/conf.h>
74 #include <sys/user.h>
75
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
82 #else
83 #error Unknown Architecture
84 #endif
85
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 */
89
90 extern const char *syscallnames[];
91
92 #include <sys/dtrace_glue.h>
93 #define casptr dtrace_casptr
94 #define membar_enter dtrace_membar_producer
95
96 #define LOADABLE_SYSCALL(a) 0 /* Not pertinent to Darwin. */
97 #define LOADED_SYSCALL(a) 1 /* Not pertinent to Darwin. */
98
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);
102
103 void
104 systrace_stub(dtrace_id_t id, uint64_t arg0, uint64_t arg1,
105 uint64_t arg2, uint64_t arg3, uint64_t arg4)
106 {
107 #pragma unused(id,arg0,arg1,arg2,arg3,arg4)
108 }
109
110 int32_t
111 dtrace_systrace_syscall(struct proc *pp, void *uap, int *rv)
112 {
113 boolean_t flavor;
114 unsigned short code;
115
116 systrace_sysent_t *sy;
117 dtrace_id_t id;
118 int32_t rval;
119 #if 0 /* XXX */
120 proc_t *p;
121 #endif
122 syscall_arg_t *ip = (syscall_arg_t *)uap;
123
124 #if defined (__ppc__) || defined (__ppc64__)
125 {
126 savearea_t *regs = (savearea_t *)find_user_regs(current_thread());
127
128 flavor = (((unsigned int)regs->save_r0) == 0)? 1: 0;
129
130 if (flavor)
131 code = regs->save_r3;
132 else
133 code = regs->save_r0;
134 }
135 #elif defined(__i386__) || defined (__x86_64__)
136 #pragma unused(flavor)
137 {
138 x86_saved_state_t *tagged_regs = (x86_saved_state_t *)find_user_regs(current_thread());
139
140 if (is_saved_state64(tagged_regs)) {
141 x86_saved_state64_t *regs = saved_state64(tagged_regs);
142 code = regs->rax & SYSCALL_NUMBER_MASK;
143 /*
144 * Check for indirect system call... system call number
145 * passed as 'arg0'
146 */
147 if (code == 0) {
148 code = regs->rdi;
149 }
150 } else {
151 code = saved_state32(tagged_regs)->eax & I386_SYSCALL_NUMBER_MASK;
152 /*
153 * TODO: handle indirect system calls
154 */
155 }
156 }
157 #else
158 #error Unknown Architecture
159 #endif
160
161 // Bounds "check" the value of code a la unix_syscall
162 sy = (code >= NUM_SYSENT) ? &systrace_sysent[63] : &systrace_sysent[code];
163
164 if ((id = sy->stsy_entry) != DTRACE_IDNONE) {
165 if (ip)
166 (*systrace_probe)(id, *ip, *(ip+1), *(ip+2), *(ip+3), *(ip+4));
167 else
168 (*systrace_probe)(id, 0, 0, 0, 0, 0);
169 }
170
171 #if 0 /* XXX */
172 /*
173 * We want to explicitly allow DTrace consumers to stop a process
174 * before it actually executes the meat of the syscall.
175 */
176 p = ttoproc(curthread);
177 mutex_enter(&p->p_lock);
178 if (curthread->t_dtrace_stop && !curthread->t_lwp->lwp_nostop) {
179 curthread->t_dtrace_stop = 0;
180 stop(PR_REQUESTED, 0);
181 }
182 mutex_exit(&p->p_lock);
183 #endif
184
185 rval = (*sy->stsy_underlying)(pp, uap, rv);
186
187 if ((id = sy->stsy_return) != DTRACE_IDNONE) {
188 uint64_t munged_rv;
189 uthread_t uthread = (uthread_t)get_bsdthread_info(current_thread());
190
191 if (uthread)
192 uthread->t_dtrace_errno = rval; /* Establish t_dtrace_errno now in case this enabling refers to it. */
193
194 /*
195 * "Decode" rv for use in the call to dtrace_probe()
196 */
197 if (rval == ERESTART) {
198 munged_rv = -1LL; /* System call will be reissued in user mode. Make DTrace report a -1 return. */
199 } else if (rval != EJUSTRETURN) {
200 if (rval) {
201 munged_rv = -1LL; /* Mimic what libc will do. */
202 } else {
203 switch (sy->stsy_return_type) {
204 case _SYSCALL_RET_INT_T:
205 munged_rv = rv[0];
206 break;
207 case _SYSCALL_RET_UINT_T:
208 munged_rv = ((u_int)rv[0]);
209 break;
210 case _SYSCALL_RET_OFF_T:
211 munged_rv = *(u_int64_t *)rv;
212 break;
213 case _SYSCALL_RET_ADDR_T:
214 case _SYSCALL_RET_SIZE_T:
215 case _SYSCALL_RET_SSIZE_T:
216 munged_rv = *(user_addr_t *)rv;
217 break;
218 case _SYSCALL_RET_NONE:
219 munged_rv = 0LL;
220 break;
221 default:
222 munged_rv = 0LL;
223 break;
224 }
225 }
226 } else
227 munged_rv = 0LL;
228
229 (*systrace_probe)(id, munged_rv, munged_rv, (uint64_t)rval, 0, 0);
230 }
231
232 return (rval);
233 }
234
235 void
236 dtrace_systrace_syscall_return(unsigned short code, int rval, int *rv)
237 {
238 systrace_sysent_t *sy;
239 dtrace_id_t id;
240
241 // Bounds "check" the value of code a la unix_syscall_return
242 sy = (code >= NUM_SYSENT) ? &systrace_sysent[63] : &systrace_sysent[code];
243
244 if ((id = sy->stsy_return) != DTRACE_IDNONE) {
245 uint64_t munged_rv;
246 uthread_t uthread = (uthread_t)get_bsdthread_info(current_thread());
247
248 if (uthread)
249 uthread->t_dtrace_errno = rval; /* Establish t_dtrace_errno now in case this enabling refers to it. */
250
251 /*
252 * "Decode" rv for use in the call to dtrace_probe()
253 */
254 if (rval == ERESTART) {
255 munged_rv = -1LL; /* System call will be reissued in user mode. Make DTrace report a -1 return. */
256 } else if (rval != EJUSTRETURN) {
257 if (rval) {
258 munged_rv = -1LL; /* Mimic what libc will do. */
259 } else {
260 switch (sy->stsy_return_type) {
261 case _SYSCALL_RET_INT_T:
262 munged_rv = rv[0];
263 break;
264 case _SYSCALL_RET_UINT_T:
265 munged_rv = ((u_int)rv[0]);
266 break;
267 case _SYSCALL_RET_OFF_T:
268 munged_rv = *(u_int64_t *)rv;
269 break;
270 case _SYSCALL_RET_ADDR_T:
271 case _SYSCALL_RET_SIZE_T:
272 case _SYSCALL_RET_SSIZE_T:
273 munged_rv = *(user_addr_t *)rv;
274 break;
275 case _SYSCALL_RET_NONE:
276 munged_rv = 0LL;
277 break;
278 default:
279 munged_rv = 0LL;
280 break;
281 }
282 }
283 } else
284 munged_rv = 0LL;
285
286 (*systrace_probe)(id, munged_rv, munged_rv, (uint64_t)rval, 0, 0);
287 }
288 }
289 #endif /* __APPLE__ */
290
291 #define SYSTRACE_SHIFT 16
292 #define SYSTRACE_ISENTRY(x) ((int)(x) >> SYSTRACE_SHIFT)
293 #define SYSTRACE_SYSNUM(x) ((int)(x) & ((1 << SYSTRACE_SHIFT) - 1))
294 #define SYSTRACE_ENTRY(id) ((1 << SYSTRACE_SHIFT) | (id))
295 #define SYSTRACE_RETURN(id) (id)
296
297 #if ((1 << SYSTRACE_SHIFT) <= NSYSCALL)
298 #error 1 << SYSTRACE_SHIFT must exceed number of system calls
299 #endif
300
301 static dev_info_t *systrace_devi;
302 static dtrace_provider_id_t systrace_id;
303
304 #if defined(__APPLE__)
305 #define systrace_init _systrace_init /* Avoid name clash with Darwin automagic conf symbol */
306 #endif
307 static void
308 systrace_init(struct sysent *actual, systrace_sysent_t **interposed)
309 {
310 systrace_sysent_t *sysent = *interposed;
311 int i;
312
313 if (sysent == NULL) {
314 *interposed = sysent = kmem_zalloc(sizeof (systrace_sysent_t) *
315 NSYSCALL, KM_SLEEP);
316 }
317
318 for (i = 0; i < NSYSCALL; i++) {
319 struct sysent *a = &actual[i];
320 systrace_sysent_t *s = &sysent[i];
321
322 if (LOADABLE_SYSCALL(a) && !LOADED_SYSCALL(a))
323 continue;
324
325 if (a->sy_callc == dtrace_systrace_syscall)
326 continue;
327
328 #ifdef _SYSCALL32_IMPL
329 if (a->sy_callc == dtrace_systrace_syscall32)
330 continue;
331 #endif
332
333 s->stsy_underlying = a->sy_callc;
334 #if defined(__APPLE__)
335 s->stsy_return_type = a->sy_return_type;
336 #endif
337 }
338 }
339
340 /*ARGSUSED*/
341 static void
342 systrace_provide(void *arg, const dtrace_probedesc_t *desc)
343 {
344 int i;
345
346 if (desc != NULL)
347 return;
348
349 systrace_init(sysent, &systrace_sysent);
350 #ifdef _SYSCALL32_IMPL
351 systrace_init(sysent32, &systrace_sysent32);
352 #endif
353
354 for (i = 0; i < NSYSCALL; i++) {
355 if (systrace_sysent[i].stsy_underlying == NULL)
356 continue;
357
358 if (dtrace_probe_lookup(systrace_id, NULL,
359 syscallnames[i], "entry") != 0)
360 continue;
361
362 (void) dtrace_probe_create(systrace_id, NULL, syscallnames[i],
363 "entry", SYSTRACE_ARTIFICIAL_FRAMES,
364 (void *)((uintptr_t)SYSTRACE_ENTRY(i)));
365 (void) dtrace_probe_create(systrace_id, NULL, syscallnames[i],
366 "return", SYSTRACE_ARTIFICIAL_FRAMES,
367 (void *)((uintptr_t)SYSTRACE_RETURN(i)));
368
369 systrace_sysent[i].stsy_entry = DTRACE_IDNONE;
370 systrace_sysent[i].stsy_return = DTRACE_IDNONE;
371 #ifdef _SYSCALL32_IMPL
372 systrace_sysent32[i].stsy_entry = DTRACE_IDNONE;
373 systrace_sysent32[i].stsy_return = DTRACE_IDNONE;
374 #endif
375 }
376 }
377 #if defined(__APPLE__)
378 #undef systrace_init
379 #endif
380
381 /*ARGSUSED*/
382 static void
383 systrace_destroy(void *arg, dtrace_id_t id, void *parg)
384 {
385 int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg);
386
387 /*
388 * There's nothing to do here but assert that we have actually been
389 * disabled.
390 */
391 if (SYSTRACE_ISENTRY((uintptr_t)parg)) {
392 ASSERT(systrace_sysent[sysnum].stsy_entry == DTRACE_IDNONE);
393 #ifdef _SYSCALL32_IMPL
394 ASSERT(systrace_sysent32[sysnum].stsy_entry == DTRACE_IDNONE);
395 #endif
396 } else {
397 ASSERT(systrace_sysent[sysnum].stsy_return == DTRACE_IDNONE);
398 #ifdef _SYSCALL32_IMPL
399 ASSERT(systrace_sysent32[sysnum].stsy_return == DTRACE_IDNONE);
400 #endif
401 }
402 }
403
404 /*ARGSUSED*/
405 static void
406 systrace_enable(void *arg, dtrace_id_t id, void *parg)
407 {
408 int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg);
409 int enabled = (systrace_sysent[sysnum].stsy_entry != DTRACE_IDNONE ||
410 systrace_sysent[sysnum].stsy_return != DTRACE_IDNONE);
411
412 if (SYSTRACE_ISENTRY((uintptr_t)parg)) {
413 systrace_sysent[sysnum].stsy_entry = id;
414 #ifdef _SYSCALL32_IMPL
415 systrace_sysent32[sysnum].stsy_entry = id;
416 #endif
417 } else {
418 systrace_sysent[sysnum].stsy_return = id;
419 #ifdef _SYSCALL32_IMPL
420 systrace_sysent32[sysnum].stsy_return = id;
421 #endif
422 }
423
424 if (enabled) {
425 ASSERT(sysent[sysnum].sy_callc == dtrace_systrace_syscall);
426 return;
427 }
428
429 (void) casptr(&sysent[sysnum].sy_callc,
430 (void *)systrace_sysent[sysnum].stsy_underlying,
431 (void *)dtrace_systrace_syscall);
432 #ifdef _SYSCALL32_IMPL
433 (void) casptr(&sysent32[sysnum].sy_callc,
434 (void *)systrace_sysent32[sysnum].stsy_underlying,
435 (void *)dtrace_systrace_syscall32);
436 #endif
437 }
438
439 /*ARGSUSED*/
440 static void
441 systrace_disable(void *arg, dtrace_id_t id, void *parg)
442 {
443 int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg);
444 int disable = (systrace_sysent[sysnum].stsy_entry == DTRACE_IDNONE ||
445 systrace_sysent[sysnum].stsy_return == DTRACE_IDNONE);
446
447 if (disable) {
448 (void) casptr(&sysent[sysnum].sy_callc,
449 (void *)dtrace_systrace_syscall,
450 (void *)systrace_sysent[sysnum].stsy_underlying);
451
452 #ifdef _SYSCALL32_IMPL
453 (void) casptr(&sysent32[sysnum].sy_callc,
454 (void *)dtrace_systrace_syscall32,
455 (void *)systrace_sysent32[sysnum].stsy_underlying);
456 #endif
457 }
458
459 if (SYSTRACE_ISENTRY((uintptr_t)parg)) {
460 systrace_sysent[sysnum].stsy_entry = DTRACE_IDNONE;
461 #ifdef _SYSCALL32_IMPL
462 systrace_sysent32[sysnum].stsy_entry = DTRACE_IDNONE;
463 #endif
464 } else {
465 systrace_sysent[sysnum].stsy_return = DTRACE_IDNONE;
466 #ifdef _SYSCALL32_IMPL
467 systrace_sysent32[sysnum].stsy_return = DTRACE_IDNONE;
468 #endif
469 }
470 }
471
472 static dtrace_pattr_t systrace_attr = {
473 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
474 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
475 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
476 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
477 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
478 };
479
480 static dtrace_pops_t systrace_pops = {
481 systrace_provide,
482 NULL,
483 systrace_enable,
484 systrace_disable,
485 NULL,
486 NULL,
487 NULL,
488 NULL,
489 NULL,
490 systrace_destroy
491 };
492
493 static int
494 systrace_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
495 {
496 switch (cmd) {
497 case DDI_ATTACH:
498 break;
499 case DDI_RESUME:
500 return (DDI_SUCCESS);
501 default:
502 return (DDI_FAILURE);
503 }
504
505 systrace_probe = dtrace_probe;
506 membar_enter();
507
508 if (ddi_create_minor_node(devi, "systrace", S_IFCHR, 0,
509 DDI_PSEUDO, NULL) == DDI_FAILURE ||
510 dtrace_register("syscall", &systrace_attr, DTRACE_PRIV_USER, NULL,
511 &systrace_pops, NULL, &systrace_id) != 0) {
512 systrace_probe = systrace_stub;
513 ddi_remove_minor_node(devi, NULL);
514 return (DDI_FAILURE);
515 }
516
517 ddi_report_dev(devi);
518 systrace_devi = devi;
519
520 return (DDI_SUCCESS);
521 }
522
523 #if !defined(__APPLE__)
524 static int
525 systrace_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
526 {
527 switch (cmd) {
528 case DDI_DETACH:
529 break;
530 case DDI_SUSPEND:
531 return (DDI_SUCCESS);
532 default:
533 return (DDI_FAILURE);
534 }
535
536 if (dtrace_unregister(systrace_id) != 0)
537 return (DDI_FAILURE);
538
539 ddi_remove_minor_node(devi, NULL);
540 systrace_probe = systrace_stub;
541 return (DDI_SUCCESS);
542 }
543
544 /*ARGSUSED*/
545 static int
546 systrace_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
547 {
548 int error;
549
550 switch (infocmd) {
551 case DDI_INFO_DEVT2DEVINFO:
552 *result = (void *)systrace_devi;
553 error = DDI_SUCCESS;
554 break;
555 case DDI_INFO_DEVT2INSTANCE:
556 *result = (void *)0;
557 error = DDI_SUCCESS;
558 break;
559 default:
560 error = DDI_FAILURE;
561 }
562 return (error);
563 }
564
565 /*ARGSUSED*/
566 static int
567 systrace_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
568 {
569 return (0);
570 }
571
572 static struct cb_ops systrace_cb_ops = {
573 systrace_open, /* open */
574 nodev, /* close */
575 nulldev, /* strategy */
576 nulldev, /* print */
577 nodev, /* dump */
578 nodev, /* read */
579 nodev, /* write */
580 nodev, /* ioctl */
581 nodev, /* devmap */
582 nodev, /* mmap */
583 nodev, /* segmap */
584 nochpoll, /* poll */
585 ddi_prop_op, /* cb_prop_op */
586 0, /* streamtab */
587 D_NEW | D_MP /* Driver compatibility flag */
588 };
589
590 static struct dev_ops systrace_ops = {
591 DEVO_REV, /* devo_rev, */
592 0, /* refcnt */
593 systrace_info, /* get_dev_info */
594 nulldev, /* identify */
595 nulldev, /* probe */
596 systrace_attach, /* attach */
597 systrace_detach, /* detach */
598 nodev, /* reset */
599 &systrace_cb_ops, /* driver operations */
600 NULL, /* bus operations */
601 nodev /* dev power */
602 };
603
604 /*
605 * Module linkage information for the kernel.
606 */
607 static struct modldrv modldrv = {
608 &mod_driverops, /* module type (this is a pseudo driver) */
609 "System Call Tracing", /* name of module */
610 &systrace_ops, /* driver ops */
611 };
612
613 static struct modlinkage modlinkage = {
614 MODREV_1,
615 (void *)&modldrv,
616 NULL
617 };
618
619 int
620 _init(void)
621 {
622 return (mod_install(&modlinkage));
623 }
624
625 int
626 _info(struct modinfo *modinfop)
627 {
628 return (mod_info(&modlinkage, modinfop));
629 }
630
631 int
632 _fini(void)
633 {
634 return (mod_remove(&modlinkage));
635 }
636 #else
637 typedef kern_return_t (*mach_call_t)(void *);
638
639 /* XXX From #include <kern/syscall_sw.h> which may be changed for 64 bit! */
640 typedef void mach_munge_t(const void *, void *);
641
642 typedef struct {
643 int mach_trap_arg_count;
644 int (*mach_trap_function)(void);
645 #if defined(__i386__)
646 boolean_t mach_trap_stack;
647 #else
648 mach_munge_t *mach_trap_arg_munge32; /* system call arguments for 32-bit */
649 mach_munge_t *mach_trap_arg_munge64; /* system call arguments for 64-bit */
650 #endif
651 #if !MACH_ASSERT
652 int mach_trap_unused;
653 #else
654 const char* mach_trap_name;
655 #endif /* !MACH_ASSERT */
656 } mach_trap_t;
657
658 #define MACH_TRAP_TABLE_COUNT 128
659
660 extern mach_trap_t mach_trap_table[];
661 extern int mach_trap_count;
662
663 #define MACH_TRAP(name, foo, bar, baz) #name
664
665 /* XXX From osfmk/kern/syscall_sw.c */
666 static const char * mach_name_table[MACH_TRAP_TABLE_COUNT] = {
667 /* 0 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
668 /* 1 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
669 /* 2 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
670 /* 3 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
671 /* 4 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
672 /* 5 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
673 /* 6 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
674 /* 7 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
675 /* 8 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
676 /* 9 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
677 /* 10 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
678 /* 11 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
679 /* 12 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
680 /* 13 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
681 /* 14 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
682 /* 15 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
683 /* 16 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
684 /* 17 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
685 /* 18 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
686 /* 19 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
687 /* 20 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
688 /* 21 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
689 /* 22 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
690 /* 23 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
691 /* 24 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
692 /* 25 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
693 /* 26 */ MACH_TRAP(mach_reply_port, 0, NULL, NULL),
694 /* 27 */ MACH_TRAP(thread_self_trap, 0, NULL, NULL),
695 /* 28 */ MACH_TRAP(task_self_trap, 0, NULL, NULL),
696 /* 29 */ MACH_TRAP(host_self_trap, 0, NULL, NULL),
697 /* 30 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
698 /* 31 */ MACH_TRAP(mach_msg_trap, 7, munge_wwwwwww, munge_ddddddd),
699 /* 32 */ MACH_TRAP(mach_msg_overwrite_trap, 8, munge_wwwwwwww, munge_dddddddd),
700 /* 33 */ MACH_TRAP(semaphore_signal_trap, 1, munge_w, munge_d),
701 /* 34 */ MACH_TRAP(semaphore_signal_all_trap, 1, munge_w, munge_d),
702 /* 35 */ MACH_TRAP(semaphore_signal_thread_trap, 2, munge_ww, munge_dd),
703 /* 36 */ MACH_TRAP(semaphore_wait_trap, 1, munge_w, munge_d),
704 /* 37 */ MACH_TRAP(semaphore_wait_signal_trap, 2, munge_ww, munge_dd),
705 /* 38 */ MACH_TRAP(semaphore_timedwait_trap, 3, munge_www, munge_ddd),
706 /* 39 */ MACH_TRAP(semaphore_timedwait_signal_trap, 4, munge_wwww, munge_dddd),
707 /* 40 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
708 /* 41 */ MACH_TRAP(init_process, 0, NULL, NULL),
709 /* 42 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
710 /* 43 */ MACH_TRAP(map_fd, 5, munge_wwwww, munge_ddddd),
711 /* 44 */ MACH_TRAP(task_name_for_pid, 3, munge_www, munge_ddd),
712 /* 45 */ MACH_TRAP(task_for_pid, 3, munge_www, munge_ddd),
713 /* 46 */ MACH_TRAP(pid_for_task, 2, munge_ww,munge_dd),
714 /* 47 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
715 /* 48 */ MACH_TRAP(macx_swapon, 4, munge_wwww, munge_dddd),
716 /* 49 */ MACH_TRAP(macx_swapoff, 2, munge_ww, munge_dd),
717 /* 50 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
718 /* 51 */ MACH_TRAP(macx_triggers, 4, munge_wwww, munge_dddd),
719 /* 52 */ MACH_TRAP(macx_backing_store_suspend, 1, munge_w, munge_d),
720 /* 53 */ MACH_TRAP(macx_backing_store_recovery, 1, munge_w, munge_d),
721 /* 54 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
722 /* 55 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
723 /* 56 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
724 /* 57 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
725 /* 58 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
726 /* 59 */ MACH_TRAP(swtch_pri, 0, NULL, NULL),
727 /* 60 */ MACH_TRAP(swtch, 0, NULL, NULL),
728 /* 61 */ MACH_TRAP(thread_switch, 3, munge_www, munge_ddd),
729 /* 62 */ MACH_TRAP(clock_sleep_trap, 5, munge_wwwww, munge_ddddd),
730 /* 63 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
731 /* traps 64 - 95 reserved (debo) */
732 /* 64 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
733 /* 65 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
734 /* 66 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
735 /* 67 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
736 /* 68 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
737 /* 69 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
738 /* 70 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
739 /* 71 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
740 /* 72 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
741 /* 73 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
742 /* 74 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
743 /* 75 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
744 /* 76 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
745 /* 77 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
746 /* 78 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
747 /* 79 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
748 /* 80 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
749 /* 81 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
750 /* 82 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
751 /* 83 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
752 /* 84 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
753 /* 85 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
754 /* 86 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
755 /* 87 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
756 /* 88 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
757 /* 89 */ MACH_TRAP(mach_timebase_info_trap, 1, munge_w, munge_d),
758 /* 90 */ MACH_TRAP(mach_wait_until_trap, 2, munge_l, munge_d),
759 /* 91 */ MACH_TRAP(mk_timer_create_trap, 0, NULL, NULL),
760 /* 92 */ MACH_TRAP(mk_timer_destroy_trap, 1, munge_w, munge_d),
761 /* 93 */ MACH_TRAP(mk_timer_arm_trap, 3, munge_wl, munge_dd),
762 /* 94 */ MACH_TRAP(mk_timer_cancel_trap, 2, munge_ww, munge_dd),
763 /* 95 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
764 /* traps 64 - 95 reserved (debo) */
765 /* 96 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
766 /* 97 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
767 /* 98 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
768 /* 99 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
769 /* traps 100-107 reserved for iokit (esb) */
770 /* 100 */ MACH_TRAP(iokit_user_client_trap, 8, munge_wwwwwwww, munge_dddddddd),
771 /* 101 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
772 /* 102 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
773 /* 103 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
774 /* 104 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
775 /* 105 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
776 /* 106 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
777 /* 107 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
778 /* traps 108-127 unused */
779 /* 108 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
780 /* 109 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
781 /* 110 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
782 /* 111 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
783 /* 112 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
784 /* 113 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
785 /* 114 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
786 /* 115 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
787 /* 116 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
788 /* 117 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
789 /* 118 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
790 /* 119 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
791 /* 120 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
792 /* 121 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
793 /* 122 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
794 /* 123 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
795 /* 124 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
796 /* 125 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
797 /* 126 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
798 /* 127 */ MACH_TRAP(kern_invalid, 0, NULL, NULL),
799 };
800
801 /* XXX From osfmk/i386/bsd_i386.c */
802 struct mach_call_args {
803 syscall_arg_t arg1;
804 syscall_arg_t arg2;
805 syscall_arg_t arg3;
806 syscall_arg_t arg4;
807 syscall_arg_t arg5;
808 syscall_arg_t arg6;
809 syscall_arg_t arg7;
810 syscall_arg_t arg8;
811 syscall_arg_t arg9;
812 };
813
814 #undef NSYSCALL
815 #define NSYSCALL mach_trap_count
816
817 #if ((1 << SYSTRACE_SHIFT) <= NSYSCALL)
818 #error 1 << SYSTRACE_SHIFT must exceed number of Mach traps
819 #endif
820
821 typedef systrace_sysent_t machtrace_sysent_t;
822
823 static machtrace_sysent_t *machtrace_sysent = NULL;
824
825 void (*machtrace_probe)(dtrace_id_t, uint64_t, uint64_t,
826 uint64_t, uint64_t, uint64_t);
827
828 static dev_info_t *machtrace_devi;
829 static dtrace_provider_id_t machtrace_id;
830
831 static kern_return_t
832 dtrace_machtrace_syscall(struct mach_call_args *args)
833 {
834 boolean_t flavor;
835 unsigned short code;
836
837 machtrace_sysent_t *sy;
838 dtrace_id_t id;
839 kern_return_t rval;
840 #if 0 /* XXX */
841 proc_t *p;
842 #endif
843 syscall_arg_t *ip = (syscall_arg_t *)args;
844 mach_call_t mach_call;
845
846 #if defined (__ppc__) || defined (__ppc64__)
847 {
848 savearea_t *regs = (savearea_t *)find_user_regs(current_thread());
849
850 flavor = (((unsigned int)regs->save_r0) == 0)? 1: 0;
851
852 if (flavor)
853 code = -regs->save_r3;
854 else
855 code = -regs->save_r0;
856 }
857 #elif defined(__i386__) || defined (__x86_64__)
858 #pragma unused(flavor)
859 {
860 x86_saved_state_t *tagged_regs = (x86_saved_state_t *)find_user_regs(current_thread());
861
862 if (is_saved_state64(tagged_regs)) {
863 code = saved_state64(tagged_regs)->rax & SYSCALL_NUMBER_MASK;
864 } else {
865 code = -saved_state32(tagged_regs)->eax;
866 }
867 }
868 #else
869 #error Unknown Architecture
870 #endif
871
872 sy = &machtrace_sysent[code];
873
874 if ((id = sy->stsy_entry) != DTRACE_IDNONE)
875 (*machtrace_probe)(id, *ip, *(ip+1), *(ip+2), *(ip+3), *(ip+4));
876
877 #if 0 /* XXX */
878 /*
879 * We want to explicitly allow DTrace consumers to stop a process
880 * before it actually executes the meat of the syscall.
881 */
882 p = ttoproc(curthread);
883 mutex_enter(&p->p_lock);
884 if (curthread->t_dtrace_stop && !curthread->t_lwp->lwp_nostop) {
885 curthread->t_dtrace_stop = 0;
886 stop(PR_REQUESTED, 0);
887 }
888 mutex_exit(&p->p_lock);
889 #endif
890
891 mach_call = (mach_call_t)(*sy->stsy_underlying);
892 rval = mach_call(args);
893
894 if ((id = sy->stsy_return) != DTRACE_IDNONE)
895 (*machtrace_probe)(id, (uint64_t)rval, 0, 0, 0, 0);
896
897 return (rval);
898 }
899
900 static void
901 machtrace_init(mach_trap_t *actual, machtrace_sysent_t **interposed)
902 {
903 machtrace_sysent_t *msysent = *interposed;
904 int i;
905
906 if (msysent == NULL) {
907 *interposed = msysent = kmem_zalloc(sizeof (machtrace_sysent_t) *
908 NSYSCALL, KM_SLEEP);
909 }
910
911 for (i = 0; i < NSYSCALL; i++) {
912 mach_trap_t *a = &actual[i];
913 machtrace_sysent_t *s = &msysent[i];
914
915 if (LOADABLE_SYSCALL(a) && !LOADED_SYSCALL(a))
916 continue;
917
918 if ((mach_call_t)(a->mach_trap_function) == (mach_call_t)(dtrace_machtrace_syscall))
919 continue;
920
921 s->stsy_underlying = a->mach_trap_function;
922 }
923 }
924
925 /*ARGSUSED*/
926 static void
927 machtrace_provide(void *arg, const dtrace_probedesc_t *desc)
928 {
929 int i;
930
931 if (desc != NULL)
932 return;
933
934 machtrace_init(mach_trap_table, &machtrace_sysent);
935
936 for (i = 0; i < NSYSCALL; i++) {
937
938 if (machtrace_sysent[i].stsy_underlying == NULL)
939 continue;
940
941 if (dtrace_probe_lookup(machtrace_id, NULL,
942 mach_name_table[i], "entry") != 0)
943 continue;
944
945 (void) dtrace_probe_create(machtrace_id, NULL, mach_name_table[i],
946 "entry", MACHTRACE_ARTIFICIAL_FRAMES,
947 (void *)((uintptr_t)SYSTRACE_ENTRY(i)));
948 (void) dtrace_probe_create(machtrace_id, NULL, mach_name_table[i],
949 "return", MACHTRACE_ARTIFICIAL_FRAMES,
950 (void *)((uintptr_t)SYSTRACE_RETURN(i)));
951
952 machtrace_sysent[i].stsy_entry = DTRACE_IDNONE;
953 machtrace_sysent[i].stsy_return = DTRACE_IDNONE;
954 }
955 }
956
957 /*ARGSUSED*/
958 static void
959 machtrace_destroy(void *arg, dtrace_id_t id, void *parg)
960 {
961 int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg);
962
963 /*
964 * There's nothing to do here but assert that we have actually been
965 * disabled.
966 */
967 if (SYSTRACE_ISENTRY((uintptr_t)parg)) {
968 ASSERT(machtrace_sysent[sysnum].stsy_entry == DTRACE_IDNONE);
969 } else {
970 ASSERT(machtrace_sysent[sysnum].stsy_return == DTRACE_IDNONE);
971 }
972 }
973
974 /*ARGSUSED*/
975 static void
976 machtrace_enable(void *arg, dtrace_id_t id, void *parg)
977 {
978 int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg);
979 int enabled = (machtrace_sysent[sysnum].stsy_entry != DTRACE_IDNONE ||
980 machtrace_sysent[sysnum].stsy_return != DTRACE_IDNONE);
981
982 if (SYSTRACE_ISENTRY((uintptr_t)parg)) {
983 machtrace_sysent[sysnum].stsy_entry = id;
984 } else {
985 machtrace_sysent[sysnum].stsy_return = id;
986 }
987
988 if (enabled) {
989 ASSERT(sysent[sysnum].sy_callc == dtrace_machtrace_syscall);
990 return;
991 }
992
993 (void) casptr(&mach_trap_table[sysnum].mach_trap_function,
994 (void *)machtrace_sysent[sysnum].stsy_underlying,
995 (void *)dtrace_machtrace_syscall);
996 }
997
998 /*ARGSUSED*/
999 static void
1000 machtrace_disable(void *arg, dtrace_id_t id, void *parg)
1001 {
1002 int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg);
1003 int disable = (machtrace_sysent[sysnum].stsy_entry == DTRACE_IDNONE ||
1004 machtrace_sysent[sysnum].stsy_return == DTRACE_IDNONE);
1005
1006 if (disable) {
1007 (void) casptr(&mach_trap_table[sysnum].mach_trap_function,
1008 (void *)dtrace_machtrace_syscall,
1009 (void *)machtrace_sysent[sysnum].stsy_underlying);
1010
1011 }
1012
1013 if (SYSTRACE_ISENTRY((uintptr_t)parg)) {
1014 machtrace_sysent[sysnum].stsy_entry = DTRACE_IDNONE;
1015 } else {
1016 machtrace_sysent[sysnum].stsy_return = DTRACE_IDNONE;
1017 }
1018 }
1019
1020 static dtrace_pattr_t machtrace_attr = {
1021 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
1022 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
1023 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
1024 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
1025 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
1026 };
1027
1028 static dtrace_pops_t machtrace_pops = {
1029 machtrace_provide,
1030 NULL,
1031 machtrace_enable,
1032 machtrace_disable,
1033 NULL,
1034 NULL,
1035 NULL,
1036 NULL,
1037 NULL,
1038 machtrace_destroy
1039 };
1040
1041 static int
1042 machtrace_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
1043 {
1044 switch (cmd) {
1045 case DDI_ATTACH:
1046 break;
1047 case DDI_RESUME:
1048 return (DDI_SUCCESS);
1049 default:
1050 return (DDI_FAILURE);
1051 }
1052
1053 machtrace_probe = dtrace_probe;
1054 membar_enter();
1055
1056 if (ddi_create_minor_node(devi, "machtrace", S_IFCHR, 0,
1057 DDI_PSEUDO, NULL) == DDI_FAILURE ||
1058 dtrace_register("mach_trap", &machtrace_attr, DTRACE_PRIV_USER, NULL,
1059 &machtrace_pops, NULL, &machtrace_id) != 0) {
1060 machtrace_probe = systrace_stub;
1061 ddi_remove_minor_node(devi, NULL);
1062 return (DDI_FAILURE);
1063 }
1064
1065 ddi_report_dev(devi);
1066 machtrace_devi = devi;
1067
1068 return (DDI_SUCCESS);
1069 }
1070
1071 d_open_t _systrace_open;
1072
1073 int _systrace_open(dev_t dev, int flags, int devtype, struct proc *p)
1074 {
1075 #pragma unused(dev,flags,devtype,p)
1076 return 0;
1077 }
1078
1079 #define SYSTRACE_MAJOR -24 /* let the kernel pick the device number */
1080
1081 /*
1082 * A struct describing which functions will get invoked for certain
1083 * actions.
1084 */
1085 static struct cdevsw systrace_cdevsw =
1086 {
1087 _systrace_open, /* open */
1088 eno_opcl, /* close */
1089 eno_rdwrt, /* read */
1090 eno_rdwrt, /* write */
1091 eno_ioctl, /* ioctl */
1092 (stop_fcn_t *)nulldev, /* stop */
1093 (reset_fcn_t *)nulldev, /* reset */
1094 NULL, /* tty's */
1095 eno_select, /* select */
1096 eno_mmap, /* mmap */
1097 eno_strat, /* strategy */
1098 eno_getc, /* getc */
1099 eno_putc, /* putc */
1100 0 /* type */
1101 };
1102
1103 static int gSysTraceInited = 0;
1104
1105 void systrace_init( void );
1106
1107 void systrace_init( void )
1108 {
1109 if (0 == gSysTraceInited) {
1110 int majdevno = cdevsw_add(SYSTRACE_MAJOR, &systrace_cdevsw);
1111
1112 if (majdevno < 0) {
1113 printf("systrace_init: failed to allocate a major number!\n");
1114 gSysTraceInited = 0;
1115 return;
1116 }
1117
1118 systrace_attach( (dev_info_t *)majdevno, DDI_ATTACH );
1119 machtrace_attach( (dev_info_t *)majdevno, DDI_ATTACH );
1120
1121 gSysTraceInited = 1;
1122 } else
1123 panic("systrace_init: called twice!\n");
1124 }
1125 #undef SYSTRACE_MAJOR
1126 #endif /* __APPLE__ */