]> git.saurik.com Git - apple/xnu.git/blob - bsd/dev/dtrace/systrace.c
xnu-1228.tar.gz
[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 #elif defined(__arm__)
58 typedef struct arm_saved_state savearea_t;
59 #endif
60
61 #include <sys/param.h>
62 #include <sys/systm.h>
63 #include <sys/proc.h>
64 #include <sys/errno.h>
65 #include <sys/ioctl.h>
66 #include <sys/conf.h>
67 #include <sys/fcntl.h>
68 #include <miscfs/devfs/devfs.h>
69
70 #include <sys/dtrace.h>
71 #include <sys/dtrace_impl.h>
72 #include "systrace.h"
73 #include <sys/stat.h>
74 #include <sys/systm.h>
75 #include <sys/conf.h>
76 #include <sys/user.h>
77
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 */
87 #else
88 #error Unknown Architecture
89 #endif
90
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 */
94
95 extern const char *syscallnames[];
96
97 #include <sys/dtrace_glue.h>
98 #define casptr dtrace_casptr
99 #define membar_enter dtrace_membar_producer
100
101 #define LOADABLE_SYSCALL(a) 0 /* Not pertinent to Darwin. */
102 #define LOADED_SYSCALL(a) 1 /* Not pertinent to Darwin. */
103
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);
107
108 void
109 systrace_stub(dtrace_id_t id, uint64_t arg0, uint64_t arg1,
110 uint64_t arg2, uint64_t arg3, uint64_t arg4)
111 {
112 #pragma unused(id,arg0,arg1,arg2,arg3,arg4)
113 }
114
115 int32_t
116 dtrace_systrace_syscall(struct proc *pp, void *uap, int *rv)
117 {
118 boolean_t flavor;
119 unsigned short code;
120
121 systrace_sysent_t *sy;
122 dtrace_id_t id;
123 int32_t rval;
124 #if 0 /* XXX */
125 proc_t *p;
126 #endif
127 syscall_arg_t *ip = (syscall_arg_t *)uap;
128
129 #if defined (__ppc__) || defined (__ppc64__)
130 {
131 savearea_t *regs = (savearea_t *)find_user_regs(current_thread());
132
133 flavor = (((unsigned int)regs->save_r0) == 0)? 1: 0;
134
135 if (flavor)
136 code = regs->save_r3;
137 else
138 code = regs->save_r0;
139 }
140 #elif defined(__i386__) || defined (__x86_64__)
141 #pragma unused(flavor)
142 {
143 x86_saved_state_t *tagged_regs = (x86_saved_state_t *)find_user_regs(current_thread());
144
145 if (is_saved_state64(tagged_regs)) {
146 x86_saved_state64_t *regs = saved_state64(tagged_regs);
147 code = regs->rax & SYSCALL_NUMBER_MASK;
148 /*
149 * Check for indirect system call... system call number
150 * passed as 'arg0'
151 */
152 if (code == 0) {
153 code = regs->rdi;
154 }
155 } else {
156 code = saved_state32(tagged_regs)->eax & I386_SYSCALL_NUMBER_MASK;
157 /*
158 * TODO: handle indirect system calls
159 */
160 }
161 }
162 #elif defined(__arm__)
163 do {} while(0); /* XXX what is the right ABI */
164 #else
165 #error Unknown Architecture
166 #endif
167
168 // Bounds "check" the value of code a la unix_syscall
169 sy = (code >= NUM_SYSENT) ? &systrace_sysent[63] : &systrace_sysent[code];
170
171 if ((id = sy->stsy_entry) != DTRACE_IDNONE)
172 (*systrace_probe)(id, *ip, *(ip+1), *(ip+2), *(ip+3), *(ip+4));
173
174 #if 0 /* XXX */
175 /*
176 * We want to explicitly allow DTrace consumers to stop a process
177 * before it actually executes the meat of the syscall.
178 */
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);
184 }
185 mutex_exit(&p->p_lock);
186 #endif
187
188 rval = (*sy->stsy_underlying)(pp, uap, rv);
189
190 if ((id = sy->stsy_return) != DTRACE_IDNONE) {
191 uint64_t munged_rv;
192 uthread_t uthread = (uthread_t)get_bsdthread_info(current_thread());
193
194 if (uthread)
195 uthread->t_dtrace_errno = rval; /* Establish t_dtrace_errno now in case this enabling refers to it. */
196
197 /*
198 * "Decode" rv for use in the call to dtrace_probe()
199 */
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) {
203 if (rval) {
204 munged_rv = -1LL; /* Mimic what libc will do. */
205 } else {
206 switch (sy->stsy_return_type) {
207 case _SYSCALL_RET_INT_T:
208 munged_rv = rv[0];
209 break;
210 case _SYSCALL_RET_UINT_T:
211 munged_rv = ((u_int)rv[0]);
212 break;
213 case _SYSCALL_RET_OFF_T:
214 munged_rv = *(u_int64_t *)rv;
215 break;
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;
220 break;
221 case _SYSCALL_RET_NONE:
222 munged_rv = 0LL;
223 break;
224 default:
225 munged_rv = 0LL;
226 break;
227 }
228 }
229 } else
230 munged_rv = 0LL;
231
232 (*systrace_probe)(id, munged_rv, munged_rv, (uint64_t)rval, 0, 0);
233 }
234
235 return (rval);
236 }
237
238 void
239 dtrace_systrace_syscall_return(unsigned short code, int rval, int *rv)
240 {
241 systrace_sysent_t *sy;
242 dtrace_id_t id;
243
244 // Bounds "check" the value of code a la unix_syscall_return
245 sy = (code >= NUM_SYSENT) ? &systrace_sysent[63] : &systrace_sysent[code];
246
247 if ((id = sy->stsy_return) != DTRACE_IDNONE) {
248 uint64_t munged_rv;
249 uthread_t uthread = (uthread_t)get_bsdthread_info(current_thread());
250
251 if (uthread)
252 uthread->t_dtrace_errno = rval; /* Establish t_dtrace_errno now in case this enabling refers to it. */
253
254 /*
255 * "Decode" rv for use in the call to dtrace_probe()
256 */
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) {
260 if (rval) {
261 munged_rv = -1LL; /* Mimic what libc will do. */
262 } else {
263 switch (sy->stsy_return_type) {
264 case _SYSCALL_RET_INT_T:
265 munged_rv = rv[0];
266 break;
267 case _SYSCALL_RET_UINT_T:
268 munged_rv = ((u_int)rv[0]);
269 break;
270 case _SYSCALL_RET_OFF_T:
271 munged_rv = *(u_int64_t *)rv;
272 break;
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;
277 break;
278 case _SYSCALL_RET_NONE:
279 munged_rv = 0LL;
280 break;
281 default:
282 munged_rv = 0LL;
283 break;
284 }
285 }
286 } else
287 munged_rv = 0LL;
288
289 (*systrace_probe)(id, munged_rv, munged_rv, (uint64_t)rval, 0, 0);
290 }
291 }
292 #endif /* __APPLE__ */
293
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)
299
300 #if ((1 << SYSTRACE_SHIFT) <= NSYSCALL)
301 #error 1 << SYSTRACE_SHIFT must exceed number of system calls
302 #endif
303
304 static dev_info_t *systrace_devi;
305 static dtrace_provider_id_t systrace_id;
306
307 #if defined(__APPLE__)
308 #define systrace_init _systrace_init /* Avoid name clash with Darwin automagic conf symbol */
309 #endif
310 static void
311 systrace_init(struct sysent *actual, systrace_sysent_t **interposed)
312 {
313 systrace_sysent_t *sysent = *interposed;
314 int i;
315
316 if (sysent == NULL) {
317 *interposed = sysent = kmem_zalloc(sizeof (systrace_sysent_t) *
318 NSYSCALL, KM_SLEEP);
319 }
320
321 for (i = 0; i < NSYSCALL; i++) {
322 struct sysent *a = &actual[i];
323 systrace_sysent_t *s = &sysent[i];
324
325 if (LOADABLE_SYSCALL(a) && !LOADED_SYSCALL(a))
326 continue;
327
328 if (a->sy_callc == dtrace_systrace_syscall)
329 continue;
330
331 #ifdef _SYSCALL32_IMPL
332 if (a->sy_callc == dtrace_systrace_syscall32)
333 continue;
334 #endif
335
336 s->stsy_underlying = a->sy_callc;
337 #if defined(__APPLE__)
338 s->stsy_return_type = a->sy_return_type;
339 #endif
340 }
341 }
342
343 /*ARGSUSED*/
344 static void
345 systrace_provide(void *arg, const dtrace_probedesc_t *desc)
346 {
347 int i;
348
349 if (desc != NULL)
350 return;
351
352 systrace_init(sysent, &systrace_sysent);
353 #ifdef _SYSCALL32_IMPL
354 systrace_init(sysent32, &systrace_sysent32);
355 #endif
356
357 for (i = 0; i < NSYSCALL; i++) {
358 if (systrace_sysent[i].stsy_underlying == NULL)
359 continue;
360
361 if (dtrace_probe_lookup(systrace_id, NULL,
362 syscallnames[i], "entry") != 0)
363 continue;
364
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)));
371
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;
377 #endif
378 }
379 }
380 #if defined(__APPLE__)
381 #undef systrace_init
382 #endif
383
384 /*ARGSUSED*/
385 static void
386 systrace_destroy(void *arg, dtrace_id_t id, void *parg)
387 {
388 int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg);
389
390 /*
391 * There's nothing to do here but assert that we have actually been
392 * disabled.
393 */
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);
398 #endif
399 } else {
400 ASSERT(systrace_sysent[sysnum].stsy_return == DTRACE_IDNONE);
401 #ifdef _SYSCALL32_IMPL
402 ASSERT(systrace_sysent32[sysnum].stsy_return == DTRACE_IDNONE);
403 #endif
404 }
405 }
406
407 /*ARGSUSED*/
408 static void
409 systrace_enable(void *arg, dtrace_id_t id, void *parg)
410 {
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);
414
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;
419 #endif
420 } else {
421 systrace_sysent[sysnum].stsy_return = id;
422 #ifdef _SYSCALL32_IMPL
423 systrace_sysent32[sysnum].stsy_return = id;
424 #endif
425 }
426
427 if (enabled) {
428 ASSERT(sysent[sysnum].sy_callc == dtrace_systrace_syscall);
429 return;
430 }
431
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);
439 #endif
440 }
441
442 /*ARGSUSED*/
443 static void
444 systrace_disable(void *arg, dtrace_id_t id, void *parg)
445 {
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);
449
450 if (disable) {
451 (void) casptr(&sysent[sysnum].sy_callc,
452 (void *)dtrace_systrace_syscall,
453 (void *)systrace_sysent[sysnum].stsy_underlying);
454
455 #ifdef _SYSCALL32_IMPL
456 (void) casptr(&sysent32[sysnum].sy_callc,
457 (void *)dtrace_systrace_syscall32,
458 (void *)systrace_sysent32[sysnum].stsy_underlying);
459 #endif
460 }
461
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;
466 #endif
467 } else {
468 systrace_sysent[sysnum].stsy_return = DTRACE_IDNONE;
469 #ifdef _SYSCALL32_IMPL
470 systrace_sysent32[sysnum].stsy_return = DTRACE_IDNONE;
471 #endif
472 }
473 }
474
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 },
481 };
482
483 static dtrace_pops_t systrace_pops = {
484 systrace_provide,
485 NULL,
486 systrace_enable,
487 systrace_disable,
488 NULL,
489 NULL,
490 NULL,
491 NULL,
492 NULL,
493 systrace_destroy
494 };
495
496 static int
497 systrace_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
498 {
499 switch (cmd) {
500 case DDI_ATTACH:
501 break;
502 case DDI_RESUME:
503 return (DDI_SUCCESS);
504 default:
505 return (DDI_FAILURE);
506 }
507
508 systrace_probe = dtrace_probe;
509 membar_enter();
510
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);
518 }
519
520 ddi_report_dev(devi);
521 systrace_devi = devi;
522
523 return (DDI_SUCCESS);
524 }
525
526 #if !defined(__APPLE__)
527 static int
528 systrace_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
529 {
530 switch (cmd) {
531 case DDI_DETACH:
532 break;
533 case DDI_SUSPEND:
534 return (DDI_SUCCESS);
535 default:
536 return (DDI_FAILURE);
537 }
538
539 if (dtrace_unregister(systrace_id) != 0)
540 return (DDI_FAILURE);
541
542 ddi_remove_minor_node(devi, NULL);
543 systrace_probe = systrace_stub;
544 return (DDI_SUCCESS);
545 }
546
547 /*ARGSUSED*/
548 static int
549 systrace_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
550 {
551 int error;
552
553 switch (infocmd) {
554 case DDI_INFO_DEVT2DEVINFO:
555 *result = (void *)systrace_devi;
556 error = DDI_SUCCESS;
557 break;
558 case DDI_INFO_DEVT2INSTANCE:
559 *result = (void *)0;
560 error = DDI_SUCCESS;
561 break;
562 default:
563 error = DDI_FAILURE;
564 }
565 return (error);
566 }
567
568 /*ARGSUSED*/
569 static int
570 systrace_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
571 {
572 return (0);
573 }
574
575 static struct cb_ops systrace_cb_ops = {
576 systrace_open, /* open */
577 nodev, /* close */
578 nulldev, /* strategy */
579 nulldev, /* print */
580 nodev, /* dump */
581 nodev, /* read */
582 nodev, /* write */
583 nodev, /* ioctl */
584 nodev, /* devmap */
585 nodev, /* mmap */
586 nodev, /* segmap */
587 nochpoll, /* poll */
588 ddi_prop_op, /* cb_prop_op */
589 0, /* streamtab */
590 D_NEW | D_MP /* Driver compatibility flag */
591 };
592
593 static struct dev_ops systrace_ops = {
594 DEVO_REV, /* devo_rev, */
595 0, /* refcnt */
596 systrace_info, /* get_dev_info */
597 nulldev, /* identify */
598 nulldev, /* probe */
599 systrace_attach, /* attach */
600 systrace_detach, /* detach */
601 nodev, /* reset */
602 &systrace_cb_ops, /* driver operations */
603 NULL, /* bus operations */
604 nodev /* dev power */
605 };
606
607 /*
608 * Module linkage information for the kernel.
609 */
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 */
614 };
615
616 static struct modlinkage modlinkage = {
617 MODREV_1,
618 (void *)&modldrv,
619 NULL
620 };
621
622 int
623 _init(void)
624 {
625 return (mod_install(&modlinkage));
626 }
627
628 int
629 _info(struct modinfo *modinfop)
630 {
631 return (mod_info(&modlinkage, modinfop));
632 }
633
634 int
635 _fini(void)
636 {
637 return (mod_remove(&modlinkage));
638 }
639 #else
640 typedef kern_return_t (*mach_call_t)(void *);
641
642 /* XXX From #include <kern/syscall_sw.h> which may be changed for 64 bit! */
643 typedef void mach_munge_t(const void *, void *);
644
645 typedef struct {
646 int mach_trap_arg_count;
647 int (*mach_trap_function)(void);
648 #if defined(__i386__)
649 boolean_t mach_trap_stack;
650 #else
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 */
653 #endif
654 #if !MACH_ASSERT
655 int mach_trap_unused;
656 #else
657 const char* mach_trap_name;
658 #endif /* !MACH_ASSERT */
659 } mach_trap_t;
660
661 #define MACH_TRAP_TABLE_COUNT 128
662
663 extern mach_trap_t mach_trap_table[];
664 extern int mach_trap_count;
665
666 #define MACH_TRAP(name, foo, bar, baz) #name
667
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),
802 };
803
804 /* XXX From osfmk/i386/bsd_i386.c */
805 struct mach_call_args {
806 syscall_arg_t arg1;
807 syscall_arg_t arg2;
808 syscall_arg_t arg3;
809 syscall_arg_t arg4;
810 syscall_arg_t arg5;
811 syscall_arg_t arg6;
812 syscall_arg_t arg7;
813 syscall_arg_t arg8;
814 syscall_arg_t arg9;
815 };
816
817 #undef NSYSCALL
818 #define NSYSCALL mach_trap_count
819
820 #if ((1 << SYSTRACE_SHIFT) <= NSYSCALL)
821 #error 1 << SYSTRACE_SHIFT must exceed number of Mach traps
822 #endif
823
824 typedef systrace_sysent_t machtrace_sysent_t;
825
826 static machtrace_sysent_t *machtrace_sysent = NULL;
827
828 void (*machtrace_probe)(dtrace_id_t, uint64_t, uint64_t,
829 uint64_t, uint64_t, uint64_t);
830
831 static dev_info_t *machtrace_devi;
832 static dtrace_provider_id_t machtrace_id;
833
834 static kern_return_t
835 dtrace_machtrace_syscall(struct mach_call_args *args)
836 {
837 boolean_t flavor;
838 unsigned short code;
839
840 machtrace_sysent_t *sy;
841 dtrace_id_t id;
842 kern_return_t rval;
843 #if 0 /* XXX */
844 proc_t *p;
845 #endif
846 syscall_arg_t *ip = (syscall_arg_t *)args;
847 mach_call_t mach_call;
848
849 #if defined (__ppc__) || defined (__ppc64__)
850 {
851 savearea_t *regs = (savearea_t *)find_user_regs(current_thread());
852
853 flavor = (((unsigned int)regs->save_r0) == 0)? 1: 0;
854
855 if (flavor)
856 code = -regs->save_r3;
857 else
858 code = -regs->save_r0;
859 }
860 #elif defined(__i386__) || defined (__x86_64__)
861 #pragma unused(flavor)
862 {
863 x86_saved_state_t *tagged_regs = (x86_saved_state_t *)find_user_regs(current_thread());
864
865 if (is_saved_state64(tagged_regs)) {
866 code = -saved_state64(tagged_regs)->rax & SYSCALL_NUMBER_MASK;
867 } else {
868 code = -saved_state32(tagged_regs)->eax;
869 }
870 }
871 #elif defined(__arm__)
872 do {} while(0); /* XXX ARMTODO */
873 #else
874 #error Unknown Architecture
875 #endif
876
877 sy = &machtrace_sysent[code];
878
879 if ((id = sy->stsy_entry) != DTRACE_IDNONE)
880 (*machtrace_probe)(id, *ip, *(ip+1), *(ip+2), *(ip+3), *(ip+4));
881
882 #if 0 /* XXX */
883 /*
884 * We want to explicitly allow DTrace consumers to stop a process
885 * before it actually executes the meat of the syscall.
886 */
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);
892 }
893 mutex_exit(&p->p_lock);
894 #endif
895
896 mach_call = (mach_call_t)(*sy->stsy_underlying);
897 rval = mach_call(args);
898
899 if ((id = sy->stsy_return) != DTRACE_IDNONE)
900 (*machtrace_probe)(id, (uint64_t)rval, 0, 0, 0, 0);
901
902 return (rval);
903 }
904
905 static void
906 machtrace_init(mach_trap_t *actual, machtrace_sysent_t **interposed)
907 {
908 machtrace_sysent_t *msysent = *interposed;
909 int i;
910
911 if (msysent == NULL) {
912 *interposed = msysent = kmem_zalloc(sizeof (machtrace_sysent_t) *
913 NSYSCALL, KM_SLEEP);
914 }
915
916 for (i = 0; i < NSYSCALL; i++) {
917 mach_trap_t *a = &actual[i];
918 machtrace_sysent_t *s = &msysent[i];
919
920 if (LOADABLE_SYSCALL(a) && !LOADED_SYSCALL(a))
921 continue;
922
923 if ((mach_call_t)(a->mach_trap_function) == (mach_call_t)(dtrace_machtrace_syscall))
924 continue;
925
926 s->stsy_underlying = a->mach_trap_function;
927 }
928 }
929
930 /*ARGSUSED*/
931 static void
932 machtrace_provide(void *arg, const dtrace_probedesc_t *desc)
933 {
934 int i;
935
936 if (desc != NULL)
937 return;
938
939 machtrace_init(mach_trap_table, &machtrace_sysent);
940
941 for (i = 0; i < NSYSCALL; i++) {
942
943 if (machtrace_sysent[i].stsy_underlying == NULL)
944 continue;
945
946 if (dtrace_probe_lookup(machtrace_id, NULL,
947 mach_name_table[i], "entry") != 0)
948 continue;
949
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)));
956
957 machtrace_sysent[i].stsy_entry = DTRACE_IDNONE;
958 machtrace_sysent[i].stsy_return = DTRACE_IDNONE;
959 }
960 }
961
962 /*ARGSUSED*/
963 static void
964 machtrace_destroy(void *arg, dtrace_id_t id, void *parg)
965 {
966 int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg);
967
968 /*
969 * There's nothing to do here but assert that we have actually been
970 * disabled.
971 */
972 if (SYSTRACE_ISENTRY((uintptr_t)parg)) {
973 ASSERT(machtrace_sysent[sysnum].stsy_entry == DTRACE_IDNONE);
974 } else {
975 ASSERT(machtrace_sysent[sysnum].stsy_return == DTRACE_IDNONE);
976 }
977 }
978
979 /*ARGSUSED*/
980 static void
981 machtrace_enable(void *arg, dtrace_id_t id, void *parg)
982 {
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);
986
987 if (SYSTRACE_ISENTRY((uintptr_t)parg)) {
988 machtrace_sysent[sysnum].stsy_entry = id;
989 } else {
990 machtrace_sysent[sysnum].stsy_return = id;
991 }
992
993 if (enabled) {
994 ASSERT(sysent[sysnum].sy_callc == dtrace_machtrace_syscall);
995 return;
996 }
997
998 (void) casptr(&mach_trap_table[sysnum].mach_trap_function,
999 (void *)machtrace_sysent[sysnum].stsy_underlying,
1000 (void *)dtrace_machtrace_syscall);
1001 }
1002
1003 /*ARGSUSED*/
1004 static void
1005 machtrace_disable(void *arg, dtrace_id_t id, void *parg)
1006 {
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);
1010
1011 if (disable) {
1012 (void) casptr(&mach_trap_table[sysnum].mach_trap_function,
1013 (void *)dtrace_machtrace_syscall,
1014 (void *)machtrace_sysent[sysnum].stsy_underlying);
1015
1016 }
1017
1018 if (SYSTRACE_ISENTRY((uintptr_t)parg)) {
1019 machtrace_sysent[sysnum].stsy_entry = DTRACE_IDNONE;
1020 } else {
1021 machtrace_sysent[sysnum].stsy_return = DTRACE_IDNONE;
1022 }
1023 }
1024
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 },
1031 };
1032
1033 static dtrace_pops_t machtrace_pops = {
1034 machtrace_provide,
1035 NULL,
1036 machtrace_enable,
1037 machtrace_disable,
1038 NULL,
1039 NULL,
1040 NULL,
1041 NULL,
1042 NULL,
1043 machtrace_destroy
1044 };
1045
1046 static int
1047 machtrace_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
1048 {
1049 switch (cmd) {
1050 case DDI_ATTACH:
1051 break;
1052 case DDI_RESUME:
1053 return (DDI_SUCCESS);
1054 default:
1055 return (DDI_FAILURE);
1056 }
1057
1058 machtrace_probe = dtrace_probe;
1059 membar_enter();
1060
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);
1068 }
1069
1070 ddi_report_dev(devi);
1071 machtrace_devi = devi;
1072
1073 return (DDI_SUCCESS);
1074 }
1075
1076 d_open_t _systrace_open;
1077
1078 int _systrace_open(dev_t dev, int flags, int devtype, struct proc *p)
1079 {
1080 #pragma unused(dev,flags,devtype,p)
1081 return 0;
1082 }
1083
1084 #define SYSTRACE_MAJOR -24 /* let the kernel pick the device number */
1085
1086 /*
1087 * A struct describing which functions will get invoked for certain
1088 * actions.
1089 */
1090 static struct cdevsw systrace_cdevsw =
1091 {
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 */
1099 NULL, /* tty's */
1100 eno_select, /* select */
1101 eno_mmap, /* mmap */
1102 eno_strat, /* strategy */
1103 eno_getc, /* getc */
1104 eno_putc, /* putc */
1105 0 /* type */
1106 };
1107
1108 static int gSysTraceInited = 0;
1109
1110 void systrace_init( void );
1111
1112 void systrace_init( void )
1113 {
1114 if (0 == gSysTraceInited) {
1115 int majdevno = cdevsw_add(SYSTRACE_MAJOR, &systrace_cdevsw);
1116
1117 if (majdevno < 0) {
1118 printf("systrace_init: failed to allocate a major number!\n");
1119 gSysTraceInited = 0;
1120 return;
1121 }
1122
1123 systrace_attach( (dev_info_t *)majdevno, DDI_ATTACH );
1124 machtrace_attach( (dev_info_t *)majdevno, DDI_ATTACH );
1125
1126 gSysTraceInited = 1;
1127 } else
1128 panic("systrace_init: called twice!\n");
1129 }
1130 #undef SYSTRACE_MAJOR
1131 #endif /* __APPLE__ */