]> git.saurik.com Git - apple/xnu.git/blob - bsd/dev/dtrace/profile_prvd.c
xnu-1504.9.17.tar.gz
[apple/xnu.git] / bsd / dev / dtrace / profile_prvd.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 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /* #pragma ident "@(#)profile.c 1.7 07/01/10 SMI" */
27
28 #if !defined(__APPLE__)
29 #include <sys/errno.h>
30 #include <sys/stat.h>
31 #include <sys/modctl.h>
32 #include <sys/conf.h>
33 #include <sys/systm.h>
34 #include <sys/ddi.h>
35 #include <sys/sunddi.h>
36 #include <sys/cpuvar.h>
37 #include <sys/kmem.h>
38 #include <sys/strsubr.h>
39 #include <sys/dtrace.h>
40 #include <sys/cyclic.h>
41 #include <sys/atomic.h>
42 #else
43 #ifdef KERNEL
44 #ifndef _KERNEL
45 #define _KERNEL /* Solaris vs. Darwin */
46 #endif
47 #endif
48
49 #define MACH__POSIX_C_SOURCE_PRIVATE 1 /* pulls in suitable savearea from mach/ppc/thread_status.h */
50 #include <kern/cpu_data.h>
51 #include <kern/thread.h>
52 #include <mach/thread_status.h>
53
54 #include <sys/param.h>
55 #include <sys/systm.h>
56 #include <sys/errno.h>
57 #include <sys/stat.h>
58 #include <sys/ioctl.h>
59 #include <sys/conf.h>
60 #include <sys/fcntl.h>
61 #include <miscfs/devfs/devfs.h>
62
63 #include <sys/dtrace.h>
64 #include <sys/dtrace_impl.h>
65
66 #include <sys/dtrace_glue.h>
67
68 #if defined(__ppc__) || defined(__ppc64__)
69 extern struct savearea *find_kern_regs(thread_t);
70 #elif defined(__i386__) || defined(__x86_64__)
71 extern x86_saved_state_t *find_kern_regs(thread_t);
72 #else
73 #error Unknown architecture
74 #endif
75
76 #undef ASSERT
77 #define ASSERT(x) do {} while(0)
78
79 extern void profile_init(void);
80 #endif /* __APPLE__ */
81
82 static dev_info_t *profile_devi;
83 static dtrace_provider_id_t profile_id;
84
85 /*
86 * Regardless of platform, the stack frames look like this in the case of the
87 * profile provider:
88 *
89 * profile_fire
90 * cyclic_expire
91 * cyclic_fire
92 * [ cbe ]
93 * [ interrupt code ]
94 *
95 * On x86, there are five frames from the generic interrupt code; further, the
96 * interrupted instruction appears as its own stack frame, giving us a total of
97 * 10.
98 *
99 * On SPARC, the picture is further complicated because the compiler
100 * optimizes away tail-calls -- so the following frames are optimized away:
101 *
102 * profile_fire
103 * cyclic_expire
104 *
105 * This gives three frames. However, on DEBUG kernels, the cyclic_expire
106 * frame cannot be tail-call eliminated, yielding four frames in this case.
107 *
108 * All of the above constraints lead to the mess below. Yes, the profile
109 * provider should ideally figure this out on-the-fly by hitting one of its own
110 * probes and then walking its own stack trace. This is complicated, however,
111 * and the static definition doesn't seem to be overly brittle. Still, we
112 * allow for a manual override in case we get it completely wrong.
113 */
114 #if !defined(__APPLE__)
115
116 #ifdef __x86
117 #define PROF_ARTIFICIAL_FRAMES 10
118 #else
119 #ifdef __sparc
120 #if DEBUG
121 #define PROF_ARTIFICIAL_FRAMES 4
122 #else
123 #define PROF_ARTIFICIAL_FRAMES 3
124 #endif
125 #endif
126 #endif
127
128 #else /* is Mac OS X */
129
130 #if defined(__ppc__) || defined(__ppc64__)
131 #define PROF_ARTIFICIAL_FRAMES 8
132 #elif defined(__i386__) || defined(__x86_64__)
133 #define PROF_ARTIFICIAL_FRAMES 9
134 #else
135 #error Unknown architecture
136 #endif
137
138 #endif /* __APPLE__ */
139
140 #define PROF_NAMELEN 15
141
142 #define PROF_PROFILE 0
143 #define PROF_TICK 1
144 #define PROF_PREFIX_PROFILE "profile-"
145 #define PROF_PREFIX_TICK "tick-"
146
147 typedef struct profile_probe {
148 char prof_name[PROF_NAMELEN];
149 dtrace_id_t prof_id;
150 int prof_kind;
151 hrtime_t prof_interval;
152 cyclic_id_t prof_cyclic;
153 } profile_probe_t;
154
155 typedef struct profile_probe_percpu {
156 hrtime_t profc_expected;
157 hrtime_t profc_interval;
158 profile_probe_t *profc_probe;
159 } profile_probe_percpu_t;
160
161 hrtime_t profile_interval_min = NANOSEC / 5000; /* 5000 hz */
162 int profile_aframes = 0; /* override */
163
164 static int profile_rates[] = {
165 97, 199, 499, 997, 1999,
166 4001, 4999, 0, 0, 0,
167 0, 0, 0, 0, 0,
168 0, 0, 0, 0, 0
169 };
170
171 static int profile_ticks[] = {
172 1, 10, 100, 500, 1000,
173 5000, 0, 0, 0, 0,
174 0, 0, 0, 0, 0
175 };
176
177 /*
178 * profile_max defines the upper bound on the number of profile probes that
179 * can exist (this is to prevent malicious or clumsy users from exhausing
180 * system resources by creating a slew of profile probes). At mod load time,
181 * this gets its value from PROFILE_MAX_DEFAULT or profile-max-probes if it's
182 * present in the profile.conf file.
183 */
184 #define PROFILE_MAX_DEFAULT 1000 /* default max. number of probes */
185 static uint32_t profile_max; /* maximum number of profile probes */
186 static uint32_t profile_total; /* current number of profile probes */
187
188
189 static void
190 profile_fire(void *arg)
191 {
192 profile_probe_percpu_t *pcpu = arg;
193 profile_probe_t *prof = pcpu->profc_probe;
194 hrtime_t late;
195
196 late = dtrace_gethrtime() - pcpu->profc_expected;
197 pcpu->profc_expected += pcpu->profc_interval;
198
199 #if !defined(__APPLE__)
200 dtrace_probe(prof->prof_id, CPU->cpu_profile_pc,
201 CPU->cpu_profile_upc, late, 0, 0);
202 #else
203 #if defined(__ppc__) || defined(__ppc64__)
204 {
205 struct savearea *sv = find_kern_regs(current_thread());
206
207 if (sv) {
208 if (USERMODE(sv->save_srr1)) {
209 dtrace_probe(prof->prof_id, 0x0, sv->save_srr0, late, 0, 0);
210 } else {
211 dtrace_probe(prof->prof_id, sv->save_srr0, 0x0, late, 0, 0);
212 }
213 } else {
214 dtrace_probe(prof->prof_id, 0xcafebabe,
215 0x0, late, 0, 0); /* XXX_BOGUS also see profile_usermode() below. */
216 }
217 }
218 #elif defined(__i386__) || defined(__x86_64__)
219 x86_saved_state_t *kern_regs = find_kern_regs(current_thread());
220
221 if (NULL != kern_regs) {
222 /* Kernel was interrupted. */
223 #if defined(__i386__)
224 dtrace_probe(prof->prof_id, saved_state32(kern_regs)->eip, 0x0, 0, 0, 0);
225 #elif defined(__x86_64__)
226 dtrace_probe(prof->prof_id, saved_state64(kern_regs)->isf.rip, 0x0, 0, 0, 0);
227 #else
228 #error Unknown arch
229 #endif
230 } else {
231 /* Possibly a user interrupt */
232 x86_saved_state_t *tagged_regs = (x86_saved_state_t *)find_user_regs(current_thread());
233
234 if (NULL == tagged_regs) {
235 /* Too bad, so sad, no useful interrupt state. */
236 dtrace_probe(prof->prof_id, 0xcafebabe,
237 0x0, 0, 0, 0); /* XXX_BOGUS also see profile_usermode() below. */
238 } else if (is_saved_state64(tagged_regs)) {
239 x86_saved_state64_t *regs = saved_state64(tagged_regs);
240
241 dtrace_probe(prof->prof_id, 0x0, regs->isf.rip, 0, 0, 0);
242 } else {
243 x86_saved_state32_t *regs = saved_state32(tagged_regs);
244
245 dtrace_probe(prof->prof_id, 0x0, regs->eip, 0, 0, 0);
246 }
247 }
248 #else
249 #error Unknown architecture
250 #endif
251 #endif /* __APPLE__ */
252 }
253
254 static void
255 profile_tick(void *arg)
256 {
257 profile_probe_t *prof = arg;
258
259 #if !defined(__APPLE__)
260 dtrace_probe(prof->prof_id, CPU->cpu_profile_pc,
261 CPU->cpu_profile_upc, 0, 0, 0);
262 #else
263 #if defined(__ppc__) || defined(__ppc64__)
264 {
265 struct savearea *sv = find_kern_regs(current_thread());
266
267 if (sv) {
268 if (USERMODE(sv->save_srr1)) {
269 dtrace_probe(prof->prof_id, 0x0, sv->save_srr0, 0, 0, 0);
270 } else {
271 dtrace_probe(prof->prof_id, sv->save_srr0, 0x0, 0, 0, 0);
272 }
273 } else {
274 dtrace_probe(prof->prof_id, 0xcafebabe,
275 0x0, 0, 0, 0); /* XXX_BOGUS also see profile_usermode() below. */
276 }
277 }
278 #elif defined(__i386__) || defined(__x86_64__)
279 x86_saved_state_t *kern_regs = find_kern_regs(current_thread());
280
281 if (NULL != kern_regs) {
282 /* Kernel was interrupted. */
283 #if defined(__i386__)
284 dtrace_probe(prof->prof_id, saved_state32(kern_regs)->eip, 0x0, 0, 0, 0);
285 #elif defined(__x86_64__)
286 dtrace_probe(prof->prof_id, saved_state64(kern_regs)->isf.rip, 0x0, 0, 0, 0);
287 #else
288 #error Unknown arch
289 #endif
290 } else {
291 /* Possibly a user interrupt */
292 x86_saved_state_t *tagged_regs = (x86_saved_state_t *)find_user_regs(current_thread());
293
294 if (NULL == tagged_regs) {
295 /* Too bad, so sad, no useful interrupt state. */
296 dtrace_probe(prof->prof_id, 0xcafebabe,
297 0x0, 0, 0, 0); /* XXX_BOGUS also see profile_usermode() below. */
298 } else if (is_saved_state64(tagged_regs)) {
299 x86_saved_state64_t *regs = saved_state64(tagged_regs);
300
301 dtrace_probe(prof->prof_id, 0x0, regs->isf.rip, 0, 0, 0);
302 } else {
303 x86_saved_state32_t *regs = saved_state32(tagged_regs);
304
305 dtrace_probe(prof->prof_id, 0x0, regs->eip, 0, 0, 0);
306 }
307 }
308 #else
309 #error Unknown architecture
310 #endif
311 #endif /* __APPLE__ */
312 }
313
314 static void
315 profile_create(hrtime_t interval, const char *name, int kind)
316 {
317 profile_probe_t *prof;
318
319 if (interval < profile_interval_min)
320 return;
321
322 if (dtrace_probe_lookup(profile_id, NULL, NULL, name) != 0)
323 return;
324
325 atomic_add_32(&profile_total, 1);
326 if (profile_total > profile_max) {
327 atomic_add_32(&profile_total, -1);
328 return;
329 }
330
331 #if !defined(__APPLE__)
332 prof = kmem_zalloc(sizeof (profile_probe_t), KM_SLEEP);
333 #else
334 if (PROF_TICK == kind)
335 prof = kmem_zalloc(sizeof (profile_probe_t), KM_SLEEP);
336 else
337 prof = kmem_zalloc(sizeof (profile_probe_t) + NCPU*sizeof(profile_probe_percpu_t), KM_SLEEP);
338 #endif /* __APPLE__ */
339 (void) strlcpy(prof->prof_name, name, sizeof(prof->prof_name));
340 prof->prof_interval = interval;
341 prof->prof_cyclic = CYCLIC_NONE;
342 prof->prof_kind = kind;
343 prof->prof_id = dtrace_probe_create(profile_id,
344 NULL, NULL, name,
345 profile_aframes ? profile_aframes : PROF_ARTIFICIAL_FRAMES, prof);
346 }
347
348 /*ARGSUSED*/
349 static void
350 profile_provide(void *arg, const dtrace_probedesc_t *desc)
351 {
352 #pragma unused(arg) /* __APPLE__ */
353 int i, j, rate, kind;
354 hrtime_t val = 0, mult = 1, len;
355 const char *name, *suffix = NULL;
356
357 #if !defined(__APPLE__)
358 const struct {
359 char *prefix;
360 int kind;
361 } types[] = {
362 { PROF_PREFIX_PROFILE, PROF_PROFILE },
363 { PROF_PREFIX_TICK, PROF_TICK },
364 { NULL, NULL }
365 };
366
367 const struct {
368 char *name;
369 hrtime_t mult;
370 } suffixes[] = {
371 { "ns", NANOSEC / NANOSEC },
372 { "nsec", NANOSEC / NANOSEC },
373 { "us", NANOSEC / MICROSEC },
374 { "usec", NANOSEC / MICROSEC },
375 { "ms", NANOSEC / MILLISEC },
376 { "msec", NANOSEC / MILLISEC },
377 { "s", NANOSEC / SEC },
378 { "sec", NANOSEC / SEC },
379 { "m", NANOSEC * (hrtime_t)60 },
380 { "min", NANOSEC * (hrtime_t)60 },
381 { "h", NANOSEC * (hrtime_t)(60 * 60) },
382 { "hour", NANOSEC * (hrtime_t)(60 * 60) },
383 { "d", NANOSEC * (hrtime_t)(24 * 60 * 60) },
384 { "day", NANOSEC * (hrtime_t)(24 * 60 * 60) },
385 { "hz", 0 },
386 { NULL }
387 };
388 #else
389 const struct {
390 const char *prefix;
391 int kind;
392 } types[] = {
393 { PROF_PREFIX_PROFILE, PROF_PROFILE },
394 { PROF_PREFIX_TICK, PROF_TICK },
395 { NULL, 0 }
396 };
397
398 const struct {
399 const char *name;
400 hrtime_t mult;
401 } suffixes[] = {
402 { "ns", NANOSEC / NANOSEC },
403 { "nsec", NANOSEC / NANOSEC },
404 { "us", NANOSEC / MICROSEC },
405 { "usec", NANOSEC / MICROSEC },
406 { "ms", NANOSEC / MILLISEC },
407 { "msec", NANOSEC / MILLISEC },
408 { "s", NANOSEC / SEC },
409 { "sec", NANOSEC / SEC },
410 { "m", NANOSEC * (hrtime_t)60 },
411 { "min", NANOSEC * (hrtime_t)60 },
412 { "h", NANOSEC * (hrtime_t)(60 * 60) },
413 { "hour", NANOSEC * (hrtime_t)(60 * 60) },
414 { "d", NANOSEC * (hrtime_t)(24 * 60 * 60) },
415 { "day", NANOSEC * (hrtime_t)(24 * 60 * 60) },
416 { "hz", 0 },
417 { NULL, 0 }
418 };
419 #endif /* __APPLE__ */
420
421
422 if (desc == NULL) {
423 char n[PROF_NAMELEN];
424
425 /*
426 * If no description was provided, provide all of our probes.
427 */
428 #if !defined(__APPLE__)
429 for (i = 0; i < sizeof (profile_rates) / sizeof (int); i++) {
430 #else
431 for (i = 0; i < (int)(sizeof (profile_rates) / sizeof (int)); i++) {
432 #endif /* __APPLE__ */
433 if ((rate = profile_rates[i]) == 0)
434 continue;
435
436 (void) snprintf(n, PROF_NAMELEN, "%s%d",
437 PROF_PREFIX_PROFILE, rate);
438 profile_create(NANOSEC / rate, n, PROF_PROFILE);
439 }
440
441 #if !defined(__APPLE__)
442 for (i = 0; i < sizeof (profile_ticks) / sizeof (int); i++) {
443 #else
444 for (i = 0; i < (int)(sizeof (profile_ticks) / sizeof (int)); i++) {
445 #endif /* __APPLE__ */
446 if ((rate = profile_ticks[i]) == 0)
447 continue;
448
449 (void) snprintf(n, PROF_NAMELEN, "%s%d",
450 PROF_PREFIX_TICK, rate);
451 profile_create(NANOSEC / rate, n, PROF_TICK);
452 }
453
454 return;
455 }
456
457 name = desc->dtpd_name;
458
459 for (i = 0; types[i].prefix != NULL; i++) {
460 len = strlen(types[i].prefix);
461
462 if (strncmp(name, types[i].prefix, len) != 0)
463 continue;
464 break;
465 }
466
467 if (types[i].prefix == NULL)
468 return;
469
470 kind = types[i].kind;
471 j = strlen(name) - len;
472
473 /*
474 * We need to start before any time suffix.
475 */
476 for (j = strlen(name); j >= len; j--) {
477 if (name[j] >= '0' && name[j] <= '9')
478 break;
479 suffix = &name[j];
480 }
481
482 ASSERT(suffix != NULL);
483
484 /*
485 * Now determine the numerical value present in the probe name.
486 */
487 for (; j >= len; j--) {
488 if (name[j] < '0' || name[j] > '9')
489 return;
490
491 val += (name[j] - '0') * mult;
492 mult *= (hrtime_t)10;
493 }
494
495 if (val == 0)
496 return;
497
498 /*
499 * Look-up the suffix to determine the multiplier.
500 */
501 for (i = 0, mult = 0; suffixes[i].name != NULL; i++) {
502 #if !defined(__APPLE__)
503 if (strcasecmp(suffixes[i].name, suffix) == 0) {
504 mult = suffixes[i].mult;
505 break;
506 }
507 #else
508 if (strncasecmp(suffixes[i].name, suffix, strlen(suffixes[i].name) + 1) == 0) {
509 mult = suffixes[i].mult;
510 break;
511 }
512 #endif /* __APPLE__ */
513 }
514
515 if (suffixes[i].name == NULL && *suffix != '\0')
516 return;
517
518 if (mult == 0) {
519 /*
520 * The default is frequency-per-second.
521 */
522 val = NANOSEC / val;
523 } else {
524 val *= mult;
525 }
526
527 profile_create(val, name, kind);
528 }
529
530 /*ARGSUSED*/
531 static void
532 profile_destroy(void *arg, dtrace_id_t id, void *parg)
533 {
534 #pragma unused(arg,id) /* __APPLE__ */
535 profile_probe_t *prof = parg;
536
537 ASSERT(prof->prof_cyclic == CYCLIC_NONE);
538 #if !defined(__APPLE__)
539 kmem_free(prof, sizeof (profile_probe_t));
540 #else
541 if (prof->prof_kind == PROF_TICK)
542 kmem_free(prof, sizeof (profile_probe_t));
543 else
544 kmem_free(prof, sizeof (profile_probe_t) + NCPU*sizeof(profile_probe_percpu_t));
545 #endif /* __APPLE__ */
546
547 ASSERT(profile_total >= 1);
548 atomic_add_32(&profile_total, -1);
549 }
550
551 /*ARGSUSED*/
552 static void
553 profile_online(void *arg, cpu_t *cpu, cyc_handler_t *hdlr, cyc_time_t *when)
554 {
555 #pragma unused(cpu) /* __APPLE__ */
556 profile_probe_t *prof = arg;
557 profile_probe_percpu_t *pcpu;
558
559 #if !defined(__APPLE__)
560 pcpu = kmem_zalloc(sizeof (profile_probe_percpu_t), KM_SLEEP);
561 #else
562 pcpu = ((profile_probe_percpu_t *)(&(prof[1]))) + cpu_number();
563 #endif /* __APPLE__ */
564 pcpu->profc_probe = prof;
565
566 hdlr->cyh_func = profile_fire;
567 hdlr->cyh_arg = pcpu;
568 hdlr->cyh_level = CY_HIGH_LEVEL;
569
570 when->cyt_interval = prof->prof_interval;
571 #if !defined(__APPLE__)
572 when->cyt_when = dtrace_gethrtime() + when->cyt_interval;
573 #else
574 when->cyt_when = 0;
575 #endif /* __APPLE__ */
576
577 pcpu->profc_expected = when->cyt_when;
578 pcpu->profc_interval = when->cyt_interval;
579 }
580
581 /*ARGSUSED*/
582 static void
583 profile_offline(void *arg, cpu_t *cpu, void *oarg)
584 {
585 profile_probe_percpu_t *pcpu = oarg;
586
587 ASSERT(pcpu->profc_probe == arg);
588 #if !defined(__APPLE__)
589 kmem_free(pcpu, sizeof (profile_probe_percpu_t));
590 #else
591 #pragma unused(pcpu,arg,cpu) /* __APPLE__ */
592 #endif /* __APPLE__ */
593 }
594
595 /*ARGSUSED*/
596 static void
597 profile_enable(void *arg, dtrace_id_t id, void *parg)
598 {
599 #pragma unused(arg,id) /* __APPLE__ */
600 profile_probe_t *prof = parg;
601 cyc_omni_handler_t omni;
602 cyc_handler_t hdlr;
603 cyc_time_t when;
604
605 ASSERT(prof->prof_interval != 0);
606 ASSERT(MUTEX_HELD(&cpu_lock));
607
608 if (prof->prof_kind == PROF_TICK) {
609 hdlr.cyh_func = profile_tick;
610 hdlr.cyh_arg = prof;
611 hdlr.cyh_level = CY_HIGH_LEVEL;
612
613 when.cyt_interval = prof->prof_interval;
614 #if !defined(__APPLE__)
615 when.cyt_when = dtrace_gethrtime() + when.cyt_interval;
616 #else
617 when.cyt_when = 0;
618 #endif /* __APPLE__ */
619 } else {
620 ASSERT(prof->prof_kind == PROF_PROFILE);
621 omni.cyo_online = profile_online;
622 omni.cyo_offline = profile_offline;
623 omni.cyo_arg = prof;
624 }
625
626 #if !defined(__APPLE__)
627 if (prof->prof_kind == PROF_TICK) {
628 prof->prof_cyclic = cyclic_add(&hdlr, &when);
629 } else {
630 prof->prof_cyclic = cyclic_add_omni(&omni);
631 }
632 #else
633 if (prof->prof_kind == PROF_TICK) {
634 prof->prof_cyclic = cyclic_timer_add(&hdlr, &when);
635 } else {
636 prof->prof_cyclic = (cyclic_id_t)cyclic_add_omni(&omni); /* cast puns cyclic_id_list_t with cyclic_id_t */
637 }
638 #endif /* __APPLE__ */
639 }
640
641 /*ARGSUSED*/
642 static void
643 profile_disable(void *arg, dtrace_id_t id, void *parg)
644 {
645 profile_probe_t *prof = parg;
646
647 ASSERT(prof->prof_cyclic != CYCLIC_NONE);
648 ASSERT(MUTEX_HELD(&cpu_lock));
649
650 #if !defined(__APPLE__)
651 cyclic_remove(prof->prof_cyclic);
652 #else
653 #pragma unused(arg,id)
654 if (prof->prof_kind == PROF_TICK) {
655 cyclic_timer_remove(prof->prof_cyclic);
656 } else {
657 cyclic_remove_omni((cyclic_id_list_t)prof->prof_cyclic); /* cast puns cyclic_id_list_t with cyclic_id_t */
658 }
659 #endif /* __APPLE__ */
660 prof->prof_cyclic = CYCLIC_NONE;
661 }
662
663 #if !defined(__APPLE__)
664 /*ARGSUSED*/
665 static int
666 profile_usermode(void *arg, dtrace_id_t id, void *parg)
667 {
668 return (CPU->cpu_profile_pc == 0);
669 }
670 #else
671 static int
672 profile_usermode(void *arg, dtrace_id_t id, void *parg)
673 {
674 #pragma unused(arg,id,parg)
675 return 1; /* XXX_BOGUS */
676 }
677 #endif /* __APPLE__ */
678
679 static dtrace_pattr_t profile_attr = {
680 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
681 { DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_UNKNOWN },
682 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
683 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
684 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
685 };
686
687 static dtrace_pops_t profile_pops = {
688 profile_provide,
689 NULL,
690 profile_enable,
691 profile_disable,
692 NULL,
693 NULL,
694 NULL,
695 NULL,
696 profile_usermode,
697 profile_destroy
698 };
699
700 static int
701 profile_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
702 {
703 switch (cmd) {
704 case DDI_ATTACH:
705 break;
706 case DDI_RESUME:
707 return (DDI_SUCCESS);
708 default:
709 return (DDI_FAILURE);
710 }
711
712 #if !defined(__APPLE__)
713 if (ddi_create_minor_node(devi, "profile", S_IFCHR, 0,
714 DDI_PSEUDO, NULL) == DDI_FAILURE ||
715 dtrace_register("profile", &profile_attr,
716 DTRACE_PRIV_KERNEL | DTRACE_PRIV_USER, NULL,
717 &profile_pops, NULL, &profile_id) != 0) {
718 ddi_remove_minor_node(devi, NULL);
719 return (DDI_FAILURE);
720 }
721
722 profile_max = ddi_getprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
723 "profile-max-probes", PROFILE_MAX_DEFAULT);
724 #else
725 if (ddi_create_minor_node(devi, "profile", S_IFCHR, 0,
726 DDI_PSEUDO, 0) == DDI_FAILURE ||
727 dtrace_register("profile", &profile_attr,
728 DTRACE_PRIV_KERNEL | DTRACE_PRIV_USER, NULL,
729 &profile_pops, NULL, &profile_id) != 0) {
730 ddi_remove_minor_node(devi, NULL);
731 return (DDI_FAILURE);
732 }
733
734 profile_max = PROFILE_MAX_DEFAULT;
735 #endif /* __APPLE__ */
736
737 ddi_report_dev(devi);
738 profile_devi = devi;
739 return (DDI_SUCCESS);
740 }
741
742 #if !defined(__APPLE__)
743 static int
744 profile_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
745 {
746 switch (cmd) {
747 case DDI_DETACH:
748 break;
749 case DDI_SUSPEND:
750 return (DDI_SUCCESS);
751 default:
752 return (DDI_FAILURE);
753 }
754
755 if (dtrace_unregister(profile_id) != 0)
756 return (DDI_FAILURE);
757
758 ddi_remove_minor_node(devi, NULL);
759 return (DDI_SUCCESS);
760 }
761
762 /*ARGSUSED*/
763 static int
764 profile_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
765 {
766 int error;
767
768 switch (infocmd) {
769 case DDI_INFO_DEVT2DEVINFO:
770 *result = (void *)profile_devi;
771 error = DDI_SUCCESS;
772 break;
773 case DDI_INFO_DEVT2INSTANCE:
774 *result = (void *)0;
775 error = DDI_SUCCESS;
776 break;
777 default:
778 error = DDI_FAILURE;
779 }
780 return (error);
781 }
782
783 /*ARGSUSED*/
784 static int
785 profile_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
786 {
787 return (0);
788 }
789
790 static struct cb_ops profile_cb_ops = {
791 profile_open, /* open */
792 nodev, /* close */
793 nulldev, /* strategy */
794 nulldev, /* print */
795 nodev, /* dump */
796 nodev, /* read */
797 nodev, /* write */
798 nodev, /* ioctl */
799 nodev, /* devmap */
800 nodev, /* mmap */
801 nodev, /* segmap */
802 nochpoll, /* poll */
803 ddi_prop_op, /* cb_prop_op */
804 0, /* streamtab */
805 D_NEW | D_MP /* Driver compatibility flag */
806 };
807
808 static struct dev_ops profile_ops = {
809 DEVO_REV, /* devo_rev, */
810 0, /* refcnt */
811 profile_info, /* get_dev_info */
812 nulldev, /* identify */
813 nulldev, /* probe */
814 profile_attach, /* attach */
815 profile_detach, /* detach */
816 nodev, /* reset */
817 &profile_cb_ops, /* driver operations */
818 NULL, /* bus operations */
819 nodev /* dev power */
820 };
821
822 /*
823 * Module linkage information for the kernel.
824 */
825 static struct modldrv modldrv = {
826 &mod_driverops, /* module type (this is a pseudo driver) */
827 "Profile Interrupt Tracing", /* name of module */
828 &profile_ops, /* driver ops */
829 };
830
831 static struct modlinkage modlinkage = {
832 MODREV_1,
833 (void *)&modldrv,
834 NULL
835 };
836
837 int
838 _init(void)
839 {
840 return (mod_install(&modlinkage));
841 }
842
843 int
844 _info(struct modinfo *modinfop)
845 {
846 return (mod_info(&modlinkage, modinfop));
847 }
848
849 int
850 _fini(void)
851 {
852 return (mod_remove(&modlinkage));
853 }
854 #else
855 d_open_t _profile_open;
856
857 int _profile_open(dev_t dev, int flags, int devtype, struct proc *p)
858 {
859 #pragma unused(dev,flags,devtype,p)
860 return 0;
861 }
862
863 #define PROFILE_MAJOR -24 /* let the kernel pick the device number */
864
865 /*
866 * A struct describing which functions will get invoked for certain
867 * actions.
868 */
869 static struct cdevsw profile_cdevsw =
870 {
871 _profile_open, /* open */
872 eno_opcl, /* close */
873 eno_rdwrt, /* read */
874 eno_rdwrt, /* write */
875 eno_ioctl, /* ioctl */
876 (stop_fcn_t *)nulldev, /* stop */
877 (reset_fcn_t *)nulldev, /* reset */
878 NULL, /* tty's */
879 eno_select, /* select */
880 eno_mmap, /* mmap */
881 eno_strat, /* strategy */
882 eno_getc, /* getc */
883 eno_putc, /* putc */
884 0 /* type */
885 };
886
887 static int gProfileInited = 0;
888
889 void profile_init( void )
890 {
891 if (0 == gProfileInited)
892 {
893 int majdevno = cdevsw_add(PROFILE_MAJOR, &profile_cdevsw);
894
895 if (majdevno < 0) {
896 printf("profile_init: failed to allocate a major number!\n");
897 gProfileInited = 0;
898 return;
899 }
900
901 profile_attach( (dev_info_t *)(uintptr_t)majdevno, DDI_ATTACH );
902
903 gProfileInited = 1;
904 } else
905 panic("profile_init: called twice!\n");
906 }
907 #undef PROFILE_MAJOR
908 #endif /* __APPLE__ */