]> git.saurik.com Git - apple/xnu.git/blob - bsd/dev/dtrace/dtrace_glue.c
xnu-2422.90.20.tar.gz
[apple/xnu.git] / bsd / dev / dtrace / dtrace_glue.c
1 /*
2 * Copyright (c) 2005-2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29
30 /*
31 * APPLE NOTE: This file is compiled even if dtrace is unconfig'd. A symbol
32 * from this file (_dtrace_register_anon_DOF) always needs to be exported for
33 * an external kext to link against.
34 */
35
36 #if CONFIG_DTRACE
37
38 #define MACH__POSIX_C_SOURCE_PRIVATE 1 /* pulls in suitable savearea from mach/ppc/thread_status.h */
39 #include <kern/thread.h>
40 #include <mach/thread_status.h>
41
42 #include <stdarg.h>
43 #include <string.h>
44 #include <sys/malloc.h>
45 #include <sys/time.h>
46 #include <sys/proc.h>
47 #include <sys/proc_internal.h>
48 #include <sys/kauth.h>
49 #include <sys/user.h>
50 #include <sys/systm.h>
51 #include <sys/dtrace.h>
52 #include <sys/dtrace_impl.h>
53 #include <libkern/OSAtomic.h>
54 #include <kern/kern_types.h>
55 #include <kern/timer_call.h>
56 #include <kern/thread_call.h>
57 #include <kern/task.h>
58 #include <kern/sched_prim.h>
59 #include <kern/queue.h>
60 #include <miscfs/devfs/devfs.h>
61 #include <kern/kalloc.h>
62
63 #include <mach/vm_param.h>
64 #include <mach/mach_vm.h>
65 #include <mach/task.h>
66 #include <vm/pmap.h>
67 #include <vm/vm_map.h> /* All the bits we care about are guarded by MACH_KERNEL_PRIVATE :-( */
68
69
70 /*
71 * pid/proc
72 */
73 /* Solaris proc_t is the struct. Darwin's proc_t is a pointer to it. */
74 #define proc_t struct proc /* Steer clear of the Darwin typedef for proc_t */
75
76 /* Not called from probe context */
77 proc_t *
78 sprlock(pid_t pid)
79 {
80 proc_t* p;
81
82 if ((p = proc_find(pid)) == PROC_NULL) {
83 return PROC_NULL;
84 }
85
86 task_suspend(p->task);
87
88 proc_lock(p);
89
90 lck_mtx_lock(&p->p_dtrace_sprlock);
91
92 return p;
93 }
94
95 /* Not called from probe context */
96 void
97 sprunlock(proc_t *p)
98 {
99 if (p != PROC_NULL) {
100 lck_mtx_unlock(&p->p_dtrace_sprlock);
101
102 proc_unlock(p);
103
104 task_resume(p->task);
105
106 proc_rele(p);
107 }
108 }
109
110 /*
111 * uread/uwrite
112 */
113
114 // These are not exported from vm_map.h.
115 extern kern_return_t vm_map_read_user(vm_map_t map, vm_map_address_t src_addr, void *dst_p, vm_size_t size);
116 extern kern_return_t vm_map_write_user(vm_map_t map, void *src_p, vm_map_address_t dst_addr, vm_size_t size);
117
118 /* Not called from probe context */
119 int
120 uread(proc_t *p, void *buf, user_size_t len, user_addr_t a)
121 {
122 kern_return_t ret;
123
124 ASSERT(p != PROC_NULL);
125 ASSERT(p->task != NULL);
126
127 task_t task = p->task;
128
129 /*
130 * Grab a reference to the task vm_map_t to make sure
131 * the map isn't pulled out from under us.
132 *
133 * Because the proc_lock is not held at all times on all code
134 * paths leading here, it is possible for the proc to have
135 * exited. If the map is null, fail.
136 */
137 vm_map_t map = get_task_map_reference(task);
138 if (map) {
139 ret = vm_map_read_user( map, (vm_map_address_t)a, buf, (vm_size_t)len);
140 vm_map_deallocate(map);
141 } else
142 ret = KERN_TERMINATED;
143
144 return (int)ret;
145 }
146
147
148 /* Not called from probe context */
149 int
150 uwrite(proc_t *p, void *buf, user_size_t len, user_addr_t a)
151 {
152 kern_return_t ret;
153
154 ASSERT(p != NULL);
155 ASSERT(p->task != NULL);
156
157 task_t task = p->task;
158
159 /*
160 * Grab a reference to the task vm_map_t to make sure
161 * the map isn't pulled out from under us.
162 *
163 * Because the proc_lock is not held at all times on all code
164 * paths leading here, it is possible for the proc to have
165 * exited. If the map is null, fail.
166 */
167 vm_map_t map = get_task_map_reference(task);
168 if (map) {
169 /* Find the memory permissions. */
170 uint32_t nestingDepth=999999;
171 vm_region_submap_short_info_data_64_t info;
172 mach_msg_type_number_t count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
173 mach_vm_address_t address = (mach_vm_address_t)a;
174 mach_vm_size_t sizeOfRegion = (mach_vm_size_t)len;
175
176 ret = mach_vm_region_recurse(map, &address, &sizeOfRegion, &nestingDepth, (vm_region_recurse_info_t)&info, &count);
177 if (ret != KERN_SUCCESS)
178 goto done;
179
180 vm_prot_t reprotect;
181
182 if (!(info.protection & VM_PROT_WRITE)) {
183 /* Save the original protection values for restoration later */
184 reprotect = info.protection;
185
186 if (info.max_protection & VM_PROT_WRITE) {
187 /* The memory is not currently writable, but can be made writable. */
188 ret = mach_vm_protect (map, (mach_vm_offset_t)a, (mach_vm_size_t)len, 0, reprotect | VM_PROT_WRITE);
189 } else {
190 /*
191 * The memory is not currently writable, and cannot be made writable. We need to COW this memory.
192 *
193 * Strange, we can't just say "reprotect | VM_PROT_COPY", that fails.
194 */
195 ret = mach_vm_protect (map, (mach_vm_offset_t)a, (mach_vm_size_t)len, 0, VM_PROT_COPY | VM_PROT_READ | VM_PROT_WRITE);
196 }
197
198 if (ret != KERN_SUCCESS)
199 goto done;
200
201 } else {
202 /* The memory was already writable. */
203 reprotect = VM_PROT_NONE;
204 }
205
206 ret = vm_map_write_user( map,
207 buf,
208 (vm_map_address_t)a,
209 (vm_size_t)len);
210
211 if (ret != KERN_SUCCESS)
212 goto done;
213
214 if (reprotect != VM_PROT_NONE) {
215 ASSERT(reprotect & VM_PROT_EXECUTE);
216 ret = mach_vm_protect (map, (mach_vm_offset_t)a, (mach_vm_size_t)len, 0, reprotect);
217 }
218
219 done:
220 vm_map_deallocate(map);
221 } else
222 ret = KERN_TERMINATED;
223
224 return (int)ret;
225 }
226
227 /*
228 * cpuvar
229 */
230 lck_mtx_t cpu_lock;
231 lck_mtx_t mod_lock;
232
233 dtrace_cpu_t *cpu_list;
234 cpu_core_t *cpu_core; /* XXX TLB lockdown? */
235
236 /*
237 * cred_t
238 */
239
240 /*
241 * dtrace_CRED() can be called from probe context. We cannot simply call kauth_cred_get() since
242 * that function may try to resolve a lazy credential binding, which entails taking the proc_lock.
243 */
244 cred_t *
245 dtrace_CRED(void)
246 {
247 struct uthread *uthread = get_bsdthread_info(current_thread());
248
249 if (uthread == NULL)
250 return NULL;
251 else
252 return uthread->uu_ucred; /* May return NOCRED which is defined to be 0 */
253 }
254
255 #define HAS_ALLPRIVS(cr) priv_isfullset(&CR_OEPRIV(cr))
256 #define HAS_PRIVILEGE(cr, pr) ((pr) == PRIV_ALL ? \
257 HAS_ALLPRIVS(cr) : \
258 PRIV_ISASSERT(&CR_OEPRIV(cr), pr))
259
260 int PRIV_POLICY_CHOICE(void* cred, int priv, int all)
261 {
262 #pragma unused(priv, all)
263 return kauth_cred_issuser(cred); /* XXX TODO: How is this different from PRIV_POLICY_ONLY? */
264 }
265
266 int
267 PRIV_POLICY_ONLY(void *cr, int priv, int boolean)
268 {
269 #pragma unused(priv, boolean)
270 return kauth_cred_issuser(cr); /* XXX TODO: HAS_PRIVILEGE(cr, priv); */
271 }
272
273 /* XXX Get around const poisoning using structure assigns */
274 gid_t
275 crgetgid(const cred_t *cr) { cred_t copy_cr = *cr; return kauth_cred_getgid(&copy_cr); }
276
277 uid_t
278 crgetuid(const cred_t *cr) { cred_t copy_cr = *cr; return kauth_cred_getuid(&copy_cr); }
279
280 /*
281 * "cyclic"
282 */
283
284 typedef struct wrap_timer_call {
285 cyc_handler_t hdlr;
286 cyc_time_t when;
287 uint64_t deadline;
288 struct timer_call call;
289 } wrap_timer_call_t;
290
291 #define WAKEUP_REAPER 0x7FFFFFFFFFFFFFFFLL
292 #define NEARLY_FOREVER 0x7FFFFFFFFFFFFFFELL
293
294 static void
295 _timer_call_apply_cyclic( void *ignore, void *vTChdl )
296 {
297 #pragma unused(ignore)
298 wrap_timer_call_t *wrapTC = (wrap_timer_call_t *)vTChdl;
299
300 (*(wrapTC->hdlr.cyh_func))( wrapTC->hdlr.cyh_arg );
301
302 clock_deadline_for_periodic_event( wrapTC->when.cyt_interval, mach_absolute_time(), &(wrapTC->deadline) );
303 timer_call_enter1( &(wrapTC->call), (void *)wrapTC, wrapTC->deadline, TIMER_CALL_SYS_CRITICAL | TIMER_CALL_LOCAL );
304
305 /* Did timer_call_remove_cyclic request a wakeup call when this timer call was re-armed? */
306 if (wrapTC->when.cyt_interval == WAKEUP_REAPER)
307 thread_wakeup((event_t)wrapTC);
308 }
309
310 static cyclic_id_t
311 timer_call_add_cyclic(wrap_timer_call_t *wrapTC, cyc_handler_t *handler, cyc_time_t *when)
312 {
313 uint64_t now;
314
315 timer_call_setup( &(wrapTC->call), _timer_call_apply_cyclic, NULL );
316 wrapTC->hdlr = *handler;
317 wrapTC->when = *when;
318
319 nanoseconds_to_absolutetime( wrapTC->when.cyt_interval, (uint64_t *)&wrapTC->when.cyt_interval );
320
321 now = mach_absolute_time();
322 wrapTC->deadline = now;
323
324 clock_deadline_for_periodic_event( wrapTC->when.cyt_interval, now, &(wrapTC->deadline) );
325 timer_call_enter1( &(wrapTC->call), (void *)wrapTC, wrapTC->deadline, TIMER_CALL_SYS_CRITICAL | TIMER_CALL_LOCAL );
326
327 return (cyclic_id_t)wrapTC;
328 }
329
330 static void
331 timer_call_remove_cyclic(cyclic_id_t cyclic)
332 {
333 wrap_timer_call_t *wrapTC = (wrap_timer_call_t *)cyclic;
334
335 while (!timer_call_cancel(&(wrapTC->call))) {
336 int ret = assert_wait(wrapTC, THREAD_UNINT);
337 ASSERT(ret == THREAD_WAITING);
338
339 wrapTC->when.cyt_interval = WAKEUP_REAPER;
340
341 ret = thread_block(THREAD_CONTINUE_NULL);
342 ASSERT(ret == THREAD_AWAKENED);
343 }
344 }
345
346 static void *
347 timer_call_get_cyclic_arg(cyclic_id_t cyclic)
348 {
349 wrap_timer_call_t *wrapTC = (wrap_timer_call_t *)cyclic;
350
351 return (wrapTC ? wrapTC->hdlr.cyh_arg : NULL);
352 }
353
354 cyclic_id_t
355 cyclic_timer_add(cyc_handler_t *handler, cyc_time_t *when)
356 {
357 wrap_timer_call_t *wrapTC = _MALLOC(sizeof(wrap_timer_call_t), M_TEMP, M_ZERO | M_WAITOK);
358 if (NULL == wrapTC)
359 return CYCLIC_NONE;
360 else
361 return timer_call_add_cyclic( wrapTC, handler, when );
362 }
363
364 void
365 cyclic_timer_remove(cyclic_id_t cyclic)
366 {
367 ASSERT( cyclic != CYCLIC_NONE );
368
369 timer_call_remove_cyclic( cyclic );
370 _FREE((void *)cyclic, M_TEMP);
371 }
372
373 static void
374 _cyclic_add_omni(cyclic_id_list_t cyc_list)
375 {
376 cyc_time_t cT;
377 cyc_handler_t cH;
378 wrap_timer_call_t *wrapTC;
379 cyc_omni_handler_t *omni = (cyc_omni_handler_t *)cyc_list;
380 char *t;
381
382 (omni->cyo_online)(omni->cyo_arg, CPU, &cH, &cT);
383
384 t = (char *)cyc_list;
385 t += sizeof(cyc_omni_handler_t);
386 cyc_list = (cyclic_id_list_t)(uintptr_t)t;
387
388 t += sizeof(cyclic_id_t)*NCPU;
389 t += (sizeof(wrap_timer_call_t))*cpu_number();
390 wrapTC = (wrap_timer_call_t *)(uintptr_t)t;
391
392 cyc_list[cpu_number()] = timer_call_add_cyclic(wrapTC, &cH, &cT);
393 }
394
395 cyclic_id_list_t
396 cyclic_add_omni(cyc_omni_handler_t *omni)
397 {
398 cyclic_id_list_t cyc_list =
399 _MALLOC( (sizeof(wrap_timer_call_t))*NCPU +
400 sizeof(cyclic_id_t)*NCPU +
401 sizeof(cyc_omni_handler_t), M_TEMP, M_ZERO | M_WAITOK);
402 if (NULL == cyc_list)
403 return (cyclic_id_list_t)CYCLIC_NONE;
404
405 *(cyc_omni_handler_t *)cyc_list = *omni;
406 dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)_cyclic_add_omni, (void *)cyc_list);
407
408 return cyc_list;
409 }
410
411 static void
412 _cyclic_remove_omni(cyclic_id_list_t cyc_list)
413 {
414 cyc_omni_handler_t *omni = (cyc_omni_handler_t *)cyc_list;
415 void *oarg;
416 cyclic_id_t cid;
417 char *t;
418
419 t = (char *)cyc_list;
420 t += sizeof(cyc_omni_handler_t);
421 cyc_list = (cyclic_id_list_t)(uintptr_t)t;
422
423 cid = cyc_list[cpu_number()];
424 oarg = timer_call_get_cyclic_arg(cid);
425
426 timer_call_remove_cyclic( cid );
427 (omni->cyo_offline)(omni->cyo_arg, CPU, oarg);
428 }
429
430 void
431 cyclic_remove_omni(cyclic_id_list_t cyc_list)
432 {
433 ASSERT( cyc_list != (cyclic_id_list_t)CYCLIC_NONE );
434
435 dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)_cyclic_remove_omni, (void *)cyc_list);
436 _FREE(cyc_list, M_TEMP);
437 }
438
439 typedef struct wrap_thread_call {
440 thread_call_t TChdl;
441 cyc_handler_t hdlr;
442 cyc_time_t when;
443 uint64_t deadline;
444 } wrap_thread_call_t;
445
446 /*
447 * _cyclic_apply will run on some thread under kernel_task. That's OK for the
448 * cleaner and the deadman, but too distant in time and place for the profile provider.
449 */
450 static void
451 _cyclic_apply( void *ignore, void *vTChdl )
452 {
453 #pragma unused(ignore)
454 wrap_thread_call_t *wrapTC = (wrap_thread_call_t *)vTChdl;
455
456 (*(wrapTC->hdlr.cyh_func))( wrapTC->hdlr.cyh_arg );
457
458 clock_deadline_for_periodic_event( wrapTC->when.cyt_interval, mach_absolute_time(), &(wrapTC->deadline) );
459 (void)thread_call_enter1_delayed( wrapTC->TChdl, (void *)wrapTC, wrapTC->deadline );
460
461 /* Did cyclic_remove request a wakeup call when this thread call was re-armed? */
462 if (wrapTC->when.cyt_interval == WAKEUP_REAPER)
463 thread_wakeup((event_t)wrapTC);
464 }
465
466 cyclic_id_t
467 cyclic_add(cyc_handler_t *handler, cyc_time_t *when)
468 {
469 uint64_t now;
470
471 wrap_thread_call_t *wrapTC = _MALLOC(sizeof(wrap_thread_call_t), M_TEMP, M_ZERO | M_WAITOK);
472 if (NULL == wrapTC)
473 return CYCLIC_NONE;
474
475 wrapTC->TChdl = thread_call_allocate( _cyclic_apply, NULL );
476 wrapTC->hdlr = *handler;
477 wrapTC->when = *when;
478
479 ASSERT(when->cyt_when == 0);
480 ASSERT(when->cyt_interval < WAKEUP_REAPER);
481
482 nanoseconds_to_absolutetime(wrapTC->when.cyt_interval, (uint64_t *)&wrapTC->when.cyt_interval);
483
484 now = mach_absolute_time();
485 wrapTC->deadline = now;
486
487 clock_deadline_for_periodic_event( wrapTC->when.cyt_interval, now, &(wrapTC->deadline) );
488 (void)thread_call_enter1_delayed( wrapTC->TChdl, (void *)wrapTC, wrapTC->deadline );
489
490 return (cyclic_id_t)wrapTC;
491 }
492
493 static void
494 noop_cyh_func(void * ignore)
495 {
496 #pragma unused(ignore)
497 }
498
499 void
500 cyclic_remove(cyclic_id_t cyclic)
501 {
502 wrap_thread_call_t *wrapTC = (wrap_thread_call_t *)cyclic;
503
504 ASSERT(cyclic != CYCLIC_NONE);
505
506 while (!thread_call_cancel(wrapTC->TChdl)) {
507 int ret = assert_wait(wrapTC, THREAD_UNINT);
508 ASSERT(ret == THREAD_WAITING);
509
510 wrapTC->when.cyt_interval = WAKEUP_REAPER;
511
512 ret = thread_block(THREAD_CONTINUE_NULL);
513 ASSERT(ret == THREAD_AWAKENED);
514 }
515
516 if (thread_call_free(wrapTC->TChdl))
517 _FREE(wrapTC, M_TEMP);
518 else {
519 /* Gut this cyclic and move on ... */
520 wrapTC->hdlr.cyh_func = noop_cyh_func;
521 wrapTC->when.cyt_interval = NEARLY_FOREVER;
522 }
523 }
524
525 /*
526 * timeout / untimeout (converted to dtrace_timeout / dtrace_untimeout due to name collision)
527 */
528
529 thread_call_t
530 dtrace_timeout(void (*func)(void *, void *), void* arg, uint64_t nanos)
531 {
532 #pragma unused(arg)
533 thread_call_t call = thread_call_allocate(func, NULL);
534
535 nanoseconds_to_absolutetime(nanos, &nanos);
536
537 /*
538 * This method does not use clock_deadline_for_periodic_event() because it is a one-shot,
539 * and clock drift on later invocations is not a worry.
540 */
541 uint64_t deadline = mach_absolute_time() + nanos;
542 /* DRK: consider using a lower priority callout here */
543 thread_call_enter_delayed(call, deadline);
544
545 return call;
546 }
547
548 /*
549 * ddi
550 */
551 void
552 ddi_report_dev(dev_info_t *devi)
553 {
554 #pragma unused(devi)
555 }
556
557 #define NSOFT_STATES 32 /* XXX No more than 32 clients at a time, please. */
558 static void *soft[NSOFT_STATES];
559
560 int
561 ddi_soft_state_init(void **state_p, size_t size, size_t n_items)
562 {
563 #pragma unused(n_items)
564 int i;
565
566 for (i = 0; i < NSOFT_STATES; ++i) soft[i] = _MALLOC(size, M_TEMP, M_ZERO | M_WAITOK);
567 *(size_t *)state_p = size;
568 return 0;
569 }
570
571 int
572 ddi_soft_state_zalloc(void *state, int item)
573 {
574 #pragma unused(state)
575 if (item < NSOFT_STATES)
576 return DDI_SUCCESS;
577 else
578 return DDI_FAILURE;
579 }
580
581 void *
582 ddi_get_soft_state(void *state, int item)
583 {
584 #pragma unused(state)
585 ASSERT(item < NSOFT_STATES);
586 return soft[item];
587 }
588
589 int
590 ddi_soft_state_free(void *state, int item)
591 {
592 ASSERT(item < NSOFT_STATES);
593 bzero( soft[item], (size_t)state );
594 return DDI_SUCCESS;
595 }
596
597 void
598 ddi_soft_state_fini(void **state_p)
599 {
600 #pragma unused(state_p)
601 int i;
602
603 for (i = 0; i < NSOFT_STATES; ++i) _FREE( soft[i], M_TEMP );
604 }
605
606 static unsigned int gRegisteredProps = 0;
607 static struct {
608 char name[32]; /* enough for "dof-data-" + digits */
609 int *data;
610 uint_t nelements;
611 } gPropTable[16];
612
613 kern_return_t _dtrace_register_anon_DOF(char *, uchar_t *, uint_t);
614
615 kern_return_t
616 _dtrace_register_anon_DOF(char *name, uchar_t *data, uint_t nelements)
617 {
618 if (gRegisteredProps < sizeof(gPropTable)/sizeof(gPropTable[0])) {
619 int *p = (int *)_MALLOC(nelements*sizeof(int), M_TEMP, M_WAITOK);
620
621 if (NULL == p)
622 return KERN_FAILURE;
623
624 strlcpy(gPropTable[gRegisteredProps].name, name, sizeof(gPropTable[0].name));
625 gPropTable[gRegisteredProps].nelements = nelements;
626 gPropTable[gRegisteredProps].data = p;
627
628 while (nelements-- > 0) {
629 *p++ = (int)(*data++);
630 }
631
632 gRegisteredProps++;
633 return KERN_SUCCESS;
634 }
635 else
636 return KERN_FAILURE;
637 }
638
639 int
640 ddi_prop_lookup_int_array(dev_t match_dev, dev_info_t *dip, uint_t flags,
641 const char *name, int **data, uint_t *nelements)
642 {
643 #pragma unused(match_dev,dip,flags)
644 unsigned int i;
645 for (i = 0; i < gRegisteredProps; ++i)
646 {
647 if (0 == strncmp(name, gPropTable[i].name,
648 sizeof(gPropTable[i].name))) {
649 *data = gPropTable[i].data;
650 *nelements = gPropTable[i].nelements;
651 return DDI_SUCCESS;
652 }
653 }
654 return DDI_FAILURE;
655 }
656
657 int
658 ddi_prop_free(void *buf)
659 {
660 _FREE(buf, M_TEMP);
661 return DDI_SUCCESS;
662 }
663
664 int
665 ddi_driver_major(dev_info_t *devi) { return (int)major(CAST_DOWN_EXPLICIT(int,devi)); }
666
667 int
668 ddi_create_minor_node(dev_info_t *dip, const char *name, int spec_type,
669 minor_t minor_num, const char *node_type, int flag)
670 {
671 #pragma unused(spec_type,node_type,flag)
672 dev_t dev = makedev( ddi_driver_major(dip), minor_num );
673
674 if (NULL == devfs_make_node( dev, DEVFS_CHAR, UID_ROOT, GID_WHEEL, 0666, name, 0 ))
675 return DDI_FAILURE;
676 else
677 return DDI_SUCCESS;
678 }
679
680 void
681 ddi_remove_minor_node(dev_info_t *dip, char *name)
682 {
683 #pragma unused(dip,name)
684 /* XXX called from dtrace_detach, so NOTREACHED for now. */
685 }
686
687 major_t
688 getemajor( dev_t d )
689 {
690 return (major_t) major(d);
691 }
692
693 minor_t
694 getminor ( dev_t d )
695 {
696 return (minor_t) minor(d);
697 }
698
699 dev_t
700 makedevice(major_t major, minor_t minor)
701 {
702 return makedev( major, minor );
703 }
704
705 int ddi_getprop(dev_t dev, dev_info_t *dip, int flags, const char *name, int defvalue)
706 {
707 #pragma unused(dev, dip, flags, name)
708
709 return defvalue;
710 }
711
712 /*
713 * Kernel Debug Interface
714 */
715 int
716 kdi_dtrace_set(kdi_dtrace_set_t ignore)
717 {
718 #pragma unused(ignore)
719 return 0; /* Success */
720 }
721
722 extern void Debugger(const char*);
723
724 void
725 debug_enter(char *c) { Debugger(c); }
726
727 /*
728 * kmem
729 */
730
731 void *
732 dt_kmem_alloc(size_t size, int kmflag)
733 {
734 #pragma unused(kmflag)
735
736 /*
737 * We ignore the M_NOWAIT bit in kmflag (all of kmflag, in fact).
738 * Requests larger than 8K with M_NOWAIT fail in kalloc_canblock.
739 */
740 #if defined(DTRACE_MEMORY_ZONES)
741 return dtrace_alloc(size);
742 #else
743 return kalloc(size);
744 #endif
745 }
746
747 void *
748 dt_kmem_zalloc(size_t size, int kmflag)
749 {
750 #pragma unused(kmflag)
751
752 /*
753 * We ignore the M_NOWAIT bit in kmflag (all of kmflag, in fact).
754 * Requests larger than 8K with M_NOWAIT fail in kalloc_canblock.
755 */
756 #if defined(DTRACE_MEMORY_ZONES)
757 void* buf = dtrace_alloc(size);
758 #else
759 void* buf = kalloc(size);
760 #endif
761
762 if(!buf)
763 return NULL;
764
765 bzero(buf, size);
766
767 return buf;
768 }
769
770 void
771 dt_kmem_free(void *buf, size_t size)
772 {
773 #pragma unused(size)
774 /*
775 * DTrace relies on this, its doing a lot of NULL frees.
776 * A null free causes the debug builds to panic.
777 */
778 if (buf == NULL) return;
779
780 ASSERT(size > 0);
781
782 #if defined(DTRACE_MEMORY_ZONES)
783 dtrace_free(buf, size);
784 #else
785 kfree(buf, size);
786 #endif
787 }
788
789
790
791 /*
792 * aligned kmem allocator
793 * align should be a power of two
794 */
795
796 void* dt_kmem_alloc_aligned(size_t size, size_t align, int kmflag)
797 {
798 void* buf;
799 intptr_t p;
800 void** buf_backup;
801
802 buf = dt_kmem_alloc(align + sizeof(void*) + size, kmflag);
803
804 if(!buf)
805 return NULL;
806
807 p = (intptr_t)buf;
808 p += sizeof(void*); /* now we have enough room to store the backup */
809 p = P2ROUNDUP(p, align); /* and now we're aligned */
810
811 buf_backup = (void**)(p - sizeof(void*));
812 *buf_backup = buf; /* back up the address we need to free */
813
814 return (void*)p;
815 }
816
817 void* dt_kmem_zalloc_aligned(size_t size, size_t align, int kmflag)
818 {
819 void* buf;
820
821 buf = dt_kmem_alloc_aligned(size, align, kmflag);
822
823 if(!buf)
824 return NULL;
825
826 bzero(buf, size);
827
828 return buf;
829 }
830
831 void dt_kmem_free_aligned(void* buf, size_t size)
832 {
833 #pragma unused(size)
834 intptr_t p;
835 void** buf_backup;
836
837 p = (intptr_t)buf;
838 p -= sizeof(void*);
839 buf_backup = (void**)(p);
840
841 dt_kmem_free(*buf_backup, size + ((char*)buf - (char*)*buf_backup));
842 }
843
844 /*
845 * dtrace wants to manage just a single block: dtrace_state_percpu_t * NCPU, and
846 * doesn't specify constructor, destructor, or reclaim methods.
847 * At present, it always zeroes the block it obtains from kmem_cache_alloc().
848 * We'll manage this constricted use of kmem_cache with ordinary _MALLOC and _FREE.
849 */
850 kmem_cache_t *
851 kmem_cache_create(
852 const char *name, /* descriptive name for this cache */
853 size_t bufsize, /* size of the objects it manages */
854 size_t align, /* required object alignment */
855 int (*constructor)(void *, void *, int), /* object constructor */
856 void (*destructor)(void *, void *), /* object destructor */
857 void (*reclaim)(void *), /* memory reclaim callback */
858 void *private, /* pass-thru arg for constr/destr/reclaim */
859 vmem_t *vmp, /* vmem source for slab allocation */
860 int cflags) /* cache creation flags */
861 {
862 #pragma unused(name,align,constructor,destructor,reclaim,private,vmp,cflags)
863 return (kmem_cache_t *)bufsize; /* A cookie that tracks the single object size. */
864 }
865
866 void *
867 kmem_cache_alloc(kmem_cache_t *cp, int kmflag)
868 {
869 #pragma unused(kmflag)
870 size_t bufsize = (size_t)cp;
871 return (void *)_MALLOC(bufsize, M_TEMP, M_WAITOK);
872 }
873
874 void
875 kmem_cache_free(kmem_cache_t *cp, void *buf)
876 {
877 #pragma unused(cp)
878 _FREE(buf, M_TEMP);
879 }
880
881 void
882 kmem_cache_destroy(kmem_cache_t *cp)
883 {
884 #pragma unused(cp)
885 }
886
887 /*
888 * taskq
889 */
890 extern void thread_call_setup(thread_call_t, thread_call_func_t, thread_call_param_t); /* XXX MACH_KERNEL_PRIVATE */
891
892 static void
893 _taskq_apply( task_func_t func, thread_call_param_t arg )
894 {
895 func( (void *)arg );
896 }
897
898 taskq_t *
899 taskq_create(const char *name, int nthreads, pri_t pri, int minalloc,
900 int maxalloc, uint_t flags)
901 {
902 #pragma unused(name,nthreads,pri,minalloc,maxalloc,flags)
903
904 return (taskq_t *)thread_call_allocate( (thread_call_func_t)_taskq_apply, NULL );
905 }
906
907 taskqid_t
908 taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t flags)
909 {
910 #pragma unused(flags)
911 thread_call_setup( (thread_call_t) tq, (thread_call_func_t)_taskq_apply, (thread_call_param_t)func );
912 thread_call_enter1( (thread_call_t) tq, (thread_call_param_t)arg );
913 return (taskqid_t) tq /* for lack of anything better */;
914 }
915
916 void
917 taskq_destroy(taskq_t *tq)
918 {
919 thread_call_cancel( (thread_call_t) tq );
920 thread_call_free( (thread_call_t) tq );
921 }
922
923 pri_t maxclsyspri;
924
925 /*
926 * vmem (Solaris "slab" allocator) used by DTrace solely to hand out resource ids
927 */
928 typedef unsigned int u_daddr_t;
929 #include "blist.h"
930
931 /* By passing around blist *handles*, the underlying blist can be resized as needed. */
932 struct blist_hdl {
933 blist_t blist;
934 };
935
936 vmem_t *
937 vmem_create(const char *name, void *base, size_t size, size_t quantum, void *ignore5,
938 void *ignore6, vmem_t *source, size_t qcache_max, int vmflag)
939 {
940 #pragma unused(name,quantum,ignore5,ignore6,source,qcache_max,vmflag)
941 blist_t bl;
942 struct blist_hdl *p = _MALLOC(sizeof(struct blist_hdl), M_TEMP, M_WAITOK);
943
944 ASSERT(quantum == 1);
945 ASSERT(NULL == ignore5);
946 ASSERT(NULL == ignore6);
947 ASSERT(NULL == source);
948 ASSERT(0 == qcache_max);
949 ASSERT(vmflag & VMC_IDENTIFIER);
950
951 size = MIN(128, size); /* Clamp to 128 initially, since the underlying data structure is pre-allocated */
952
953 p->blist = bl = blist_create( size );
954 blist_free(bl, 0, size);
955 if (base) blist_alloc( bl, (daddr_t)(uintptr_t)base ); /* Chomp off initial ID(s) */
956
957 return (vmem_t *)p;
958 }
959
960 void *
961 vmem_alloc(vmem_t *vmp, size_t size, int vmflag)
962 {
963 #pragma unused(vmflag)
964 struct blist_hdl *q = (struct blist_hdl *)vmp;
965 blist_t bl = q->blist;
966 daddr_t p;
967
968 p = blist_alloc(bl, (daddr_t)size);
969
970 if ((daddr_t)-1 == p) {
971 blist_resize(&bl, (bl->bl_blocks) << 1, 1);
972 q->blist = bl;
973 p = blist_alloc(bl, (daddr_t)size);
974 if ((daddr_t)-1 == p)
975 panic("vmem_alloc: failure after blist_resize!");
976 }
977
978 return (void *)(uintptr_t)p;
979 }
980
981 void
982 vmem_free(vmem_t *vmp, void *vaddr, size_t size)
983 {
984 struct blist_hdl *p = (struct blist_hdl *)vmp;
985
986 blist_free( p->blist, (daddr_t)(uintptr_t)vaddr, (daddr_t)size );
987 }
988
989 void
990 vmem_destroy(vmem_t *vmp)
991 {
992 struct blist_hdl *p = (struct blist_hdl *)vmp;
993
994 blist_destroy( p->blist );
995 _FREE( p, sizeof(struct blist_hdl) );
996 }
997
998 /*
999 * Timing
1000 */
1001
1002 /*
1003 * dtrace_gethrestime() provides the "walltimestamp", a value that is anchored at
1004 * January 1, 1970. Because it can be called from probe context, it must take no locks.
1005 */
1006
1007 hrtime_t
1008 dtrace_gethrestime(void)
1009 {
1010 clock_sec_t secs;
1011 clock_nsec_t nanosecs;
1012 uint64_t secs64, ns64;
1013
1014 clock_get_calendar_nanotime_nowait(&secs, &nanosecs);
1015 secs64 = (uint64_t)secs;
1016 ns64 = (uint64_t)nanosecs;
1017
1018 ns64 = ns64 + (secs64 * 1000000000LL);
1019 return ns64;
1020 }
1021
1022 /*
1023 * dtrace_gethrtime() provides high-resolution timestamps with machine-dependent origin.
1024 * Hence its primary use is to specify intervals.
1025 */
1026
1027 hrtime_t
1028 dtrace_abs_to_nano(uint64_t elapsed)
1029 {
1030 static mach_timebase_info_data_t sTimebaseInfo = { 0, 0 };
1031
1032 /*
1033 * If this is the first time we've run, get the timebase.
1034 * We can use denom == 0 to indicate that sTimebaseInfo is
1035 * uninitialised because it makes no sense to have a zero
1036 * denominator in a fraction.
1037 */
1038
1039 if ( sTimebaseInfo.denom == 0 ) {
1040 (void) clock_timebase_info(&sTimebaseInfo);
1041 }
1042
1043 /*
1044 * Convert to nanoseconds.
1045 * return (elapsed * (uint64_t)sTimebaseInfo.numer)/(uint64_t)sTimebaseInfo.denom;
1046 *
1047 * Provided the final result is representable in 64 bits the following maneuver will
1048 * deliver that result without intermediate overflow.
1049 */
1050 if (sTimebaseInfo.denom == sTimebaseInfo.numer)
1051 return elapsed;
1052 else if (sTimebaseInfo.denom == 1)
1053 return elapsed * (uint64_t)sTimebaseInfo.numer;
1054 else {
1055 /* Decompose elapsed = eta32 * 2^32 + eps32: */
1056 uint64_t eta32 = elapsed >> 32;
1057 uint64_t eps32 = elapsed & 0x00000000ffffffffLL;
1058
1059 uint32_t numer = sTimebaseInfo.numer, denom = sTimebaseInfo.denom;
1060
1061 /* Form product of elapsed64 (decomposed) and numer: */
1062 uint64_t mu64 = numer * eta32;
1063 uint64_t lambda64 = numer * eps32;
1064
1065 /* Divide the constituents by denom: */
1066 uint64_t q32 = mu64/denom;
1067 uint64_t r32 = mu64 - (q32 * denom); /* mu64 % denom */
1068
1069 return (q32 << 32) + ((r32 << 32) + lambda64)/denom;
1070 }
1071 }
1072
1073 hrtime_t
1074 dtrace_gethrtime(void)
1075 {
1076 static uint64_t start = 0;
1077
1078 if (start == 0)
1079 start = mach_absolute_time();
1080
1081 return dtrace_abs_to_nano(mach_absolute_time() - start);
1082 }
1083
1084 /*
1085 * Atomicity and synchronization
1086 */
1087 uint32_t
1088 dtrace_cas32(uint32_t *target, uint32_t cmp, uint32_t new)
1089 {
1090 if (OSCompareAndSwap( (UInt32)cmp, (UInt32)new, (volatile UInt32 *)target ))
1091 return cmp;
1092 else
1093 return ~cmp; /* Must return something *other* than cmp */
1094 }
1095
1096 void *
1097 dtrace_casptr(void *target, void *cmp, void *new)
1098 {
1099 if (OSCompareAndSwapPtr( cmp, new, (void**)target ))
1100 return cmp;
1101 else
1102 return (void *)(~(uintptr_t)cmp); /* Must return something *other* than cmp */
1103 }
1104
1105 /*
1106 * Interrupt manipulation
1107 */
1108 dtrace_icookie_t
1109 dtrace_interrupt_disable(void)
1110 {
1111 return (dtrace_icookie_t)ml_set_interrupts_enabled(FALSE);
1112 }
1113
1114 void
1115 dtrace_interrupt_enable(dtrace_icookie_t reenable)
1116 {
1117 (void)ml_set_interrupts_enabled((boolean_t)reenable);
1118 }
1119
1120 /*
1121 * MP coordination
1122 */
1123 static void
1124 dtrace_sync_func(void) {}
1125
1126 /*
1127 * dtrace_sync() is not called from probe context.
1128 */
1129 void
1130 dtrace_sync(void)
1131 {
1132 dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_sync_func, NULL);
1133 }
1134
1135 /*
1136 * The dtrace_copyin/out/instr and dtrace_fuword* routines can be called from probe context.
1137 */
1138
1139 extern kern_return_t dtrace_copyio_preflight(addr64_t);
1140 extern kern_return_t dtrace_copyio_postflight(addr64_t);
1141
1142 static int
1143 dtrace_copycheck(user_addr_t uaddr, uintptr_t kaddr, size_t size)
1144 {
1145 #pragma unused(kaddr)
1146
1147 vm_offset_t recover = dtrace_set_thread_recover( current_thread(), 0 ); /* Snare any extant recovery point. */
1148 dtrace_set_thread_recover( current_thread(), recover ); /* Put it back. We *must not* re-enter and overwrite. */
1149
1150 ASSERT(kaddr + size >= kaddr);
1151
1152 if ( uaddr + size < uaddr || /* Avoid address wrap. */
1153 KERN_FAILURE == dtrace_copyio_preflight(uaddr)) /* Machine specific setup/constraints. */
1154 {
1155 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1156 cpu_core[CPU->cpu_id].cpuc_dtrace_illval = uaddr;
1157 return (0);
1158 }
1159 return (1);
1160 }
1161
1162 void
1163 dtrace_copyin(user_addr_t src, uintptr_t dst, size_t len, volatile uint16_t *flags)
1164 {
1165 #pragma unused(flags)
1166
1167 if (dtrace_copycheck( src, dst, len )) {
1168 if (copyin((const user_addr_t)src, (char *)dst, (vm_size_t)len)) {
1169 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1170 cpu_core[CPU->cpu_id].cpuc_dtrace_illval = src;
1171 }
1172 dtrace_copyio_postflight(src);
1173 }
1174 }
1175
1176 void
1177 dtrace_copyinstr(user_addr_t src, uintptr_t dst, size_t len, volatile uint16_t *flags)
1178 {
1179 #pragma unused(flags)
1180
1181 size_t actual;
1182
1183 if (dtrace_copycheck( src, dst, len )) {
1184 /* copyin as many as 'len' bytes. */
1185 int error = copyinstr((const user_addr_t)src, (char *)dst, (vm_size_t)len, &actual);
1186
1187 /*
1188 * ENAMETOOLONG is returned when 'len' bytes have been copied in but the NUL terminator was
1189 * not encountered. That does not require raising CPU_DTRACE_BADADDR, and we press on.
1190 * Note that we do *not* stuff a NUL terminator when returning ENAMETOOLONG, that's left
1191 * to the caller.
1192 */
1193 if (error && error != ENAMETOOLONG) {
1194 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1195 cpu_core[CPU->cpu_id].cpuc_dtrace_illval = src;
1196 }
1197 dtrace_copyio_postflight(src);
1198 }
1199 }
1200
1201 void
1202 dtrace_copyout(uintptr_t src, user_addr_t dst, size_t len, volatile uint16_t *flags)
1203 {
1204 #pragma unused(flags)
1205
1206 if (dtrace_copycheck( dst, src, len )) {
1207 if (copyout((const void *)src, dst, (vm_size_t)len)) {
1208 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1209 cpu_core[CPU->cpu_id].cpuc_dtrace_illval = dst;
1210 }
1211 dtrace_copyio_postflight(dst);
1212 }
1213 }
1214
1215 void
1216 dtrace_copyoutstr(uintptr_t src, user_addr_t dst, size_t len, volatile uint16_t *flags)
1217 {
1218 #pragma unused(flags)
1219
1220 size_t actual;
1221
1222 if (dtrace_copycheck( dst, src, len )) {
1223
1224 /*
1225 * ENAMETOOLONG is returned when 'len' bytes have been copied out but the NUL terminator was
1226 * not encountered. We raise CPU_DTRACE_BADADDR in that case.
1227 * Note that we do *not* stuff a NUL terminator when returning ENAMETOOLONG, that's left
1228 * to the caller.
1229 */
1230 if (copyoutstr((const void *)src, dst, (size_t)len, &actual)) {
1231 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1232 cpu_core[CPU->cpu_id].cpuc_dtrace_illval = dst;
1233 }
1234 dtrace_copyio_postflight(dst);
1235 }
1236 }
1237
1238 uint8_t
1239 dtrace_fuword8(user_addr_t uaddr)
1240 {
1241 uint8_t ret = 0;
1242
1243 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
1244 if (dtrace_copycheck( uaddr, (uintptr_t)&ret, sizeof(ret))) {
1245 if (copyin((const user_addr_t)uaddr, (char *)&ret, sizeof(ret))) {
1246 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1247 cpu_core[CPU->cpu_id].cpuc_dtrace_illval = uaddr;
1248 }
1249 dtrace_copyio_postflight(uaddr);
1250 }
1251 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
1252
1253 return(ret);
1254 }
1255
1256 uint16_t
1257 dtrace_fuword16(user_addr_t uaddr)
1258 {
1259 uint16_t ret = 0;
1260
1261 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
1262 if (dtrace_copycheck( uaddr, (uintptr_t)&ret, sizeof(ret))) {
1263 if (copyin((const user_addr_t)uaddr, (char *)&ret, sizeof(ret))) {
1264 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1265 cpu_core[CPU->cpu_id].cpuc_dtrace_illval = uaddr;
1266 }
1267 dtrace_copyio_postflight(uaddr);
1268 }
1269 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
1270
1271 return(ret);
1272 }
1273
1274 uint32_t
1275 dtrace_fuword32(user_addr_t uaddr)
1276 {
1277 uint32_t ret = 0;
1278
1279 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
1280 if (dtrace_copycheck( uaddr, (uintptr_t)&ret, sizeof(ret))) {
1281 if (copyin((const user_addr_t)uaddr, (char *)&ret, sizeof(ret))) {
1282 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1283 cpu_core[CPU->cpu_id].cpuc_dtrace_illval = uaddr;
1284 }
1285 dtrace_copyio_postflight(uaddr);
1286 }
1287 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
1288
1289 return(ret);
1290 }
1291
1292 uint64_t
1293 dtrace_fuword64(user_addr_t uaddr)
1294 {
1295 uint64_t ret = 0;
1296
1297 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
1298 if (dtrace_copycheck( uaddr, (uintptr_t)&ret, sizeof(ret))) {
1299 if (copyin((const user_addr_t)uaddr, (char *)&ret, sizeof(ret))) {
1300 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1301 cpu_core[CPU->cpu_id].cpuc_dtrace_illval = uaddr;
1302 }
1303 dtrace_copyio_postflight(uaddr);
1304 }
1305 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
1306
1307 return(ret);
1308 }
1309
1310 /*
1311 * Emulation of Solaris fuword / suword
1312 * Called from the fasttrap provider, so the use of copyin/out requires fewer safegaurds.
1313 */
1314
1315 int
1316 fuword8(user_addr_t uaddr, uint8_t *value)
1317 {
1318 if (copyin((const user_addr_t)uaddr, (char *)value, sizeof(uint8_t)) != 0) {
1319 return -1;
1320 }
1321
1322 return 0;
1323 }
1324
1325 int
1326 fuword16(user_addr_t uaddr, uint16_t *value)
1327 {
1328 if (copyin((const user_addr_t)uaddr, (char *)value, sizeof(uint16_t)) != 0) {
1329 return -1;
1330 }
1331
1332 return 0;
1333 }
1334
1335 int
1336 fuword32(user_addr_t uaddr, uint32_t *value)
1337 {
1338 if (copyin((const user_addr_t)uaddr, (char *)value, sizeof(uint32_t)) != 0) {
1339 return -1;
1340 }
1341
1342 return 0;
1343 }
1344
1345 int
1346 fuword64(user_addr_t uaddr, uint64_t *value)
1347 {
1348 if (copyin((const user_addr_t)uaddr, (char *)value, sizeof(uint64_t)) != 0) {
1349 return -1;
1350 }
1351
1352 return 0;
1353 }
1354
1355 void
1356 fuword8_noerr(user_addr_t uaddr, uint8_t *value)
1357 {
1358 if (copyin((const user_addr_t)uaddr, (char *)value, sizeof(uint8_t))) {
1359 *value = 0;
1360 }
1361 }
1362
1363 void
1364 fuword16_noerr(user_addr_t uaddr, uint16_t *value)
1365 {
1366 if (copyin((const user_addr_t)uaddr, (char *)value, sizeof(uint16_t))) {
1367 *value = 0;
1368 }
1369 }
1370
1371 void
1372 fuword32_noerr(user_addr_t uaddr, uint32_t *value)
1373 {
1374 if (copyin((const user_addr_t)uaddr, (char *)value, sizeof(uint32_t))) {
1375 *value = 0;
1376 }
1377 }
1378
1379 void
1380 fuword64_noerr(user_addr_t uaddr, uint64_t *value)
1381 {
1382 if (copyin((const user_addr_t)uaddr, (char *)value, sizeof(uint64_t))) {
1383 *value = 0;
1384 }
1385 }
1386
1387 int
1388 suword64(user_addr_t addr, uint64_t value)
1389 {
1390 if (copyout((const void *)&value, addr, sizeof(value)) != 0) {
1391 return -1;
1392 }
1393
1394 return 0;
1395 }
1396
1397 int
1398 suword32(user_addr_t addr, uint32_t value)
1399 {
1400 if (copyout((const void *)&value, addr, sizeof(value)) != 0) {
1401 return -1;
1402 }
1403
1404 return 0;
1405 }
1406
1407 int
1408 suword16(user_addr_t addr, uint16_t value)
1409 {
1410 if (copyout((const void *)&value, addr, sizeof(value)) != 0) {
1411 return -1;
1412 }
1413
1414 return 0;
1415 }
1416
1417 int
1418 suword8(user_addr_t addr, uint8_t value)
1419 {
1420 if (copyout((const void *)&value, addr, sizeof(value)) != 0) {
1421 return -1;
1422 }
1423
1424 return 0;
1425 }
1426
1427
1428 /*
1429 * Miscellaneous
1430 */
1431 extern boolean_t dtrace_tally_fault(user_addr_t);
1432
1433 boolean_t
1434 dtrace_tally_fault(user_addr_t uaddr)
1435 {
1436 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1437 cpu_core[CPU->cpu_id].cpuc_dtrace_illval = uaddr;
1438 return( DTRACE_CPUFLAG_ISSET(CPU_DTRACE_NOFAULT) ? TRUE : FALSE );
1439 }
1440
1441 #define TOTTY 0x02
1442 extern int prf(const char *, va_list, int, struct tty *); /* bsd/kern/subr_prf.h */
1443
1444 int
1445 vuprintf(const char *format, va_list ap)
1446 {
1447 return prf(format, ap, TOTTY, NULL);
1448 }
1449
1450 /* Not called from probe context */
1451 void cmn_err( int level, const char *format, ... )
1452 {
1453 #pragma unused(level)
1454 va_list alist;
1455
1456 va_start(alist, format);
1457 vuprintf(format, alist);
1458 va_end(alist);
1459 uprintf("\n");
1460 }
1461
1462 /*
1463 * History:
1464 * 2002-01-24 gvdl Initial implementation of strstr
1465 */
1466
1467 __private_extern__ const char *
1468 strstr(const char *in, const char *str)
1469 {
1470 char c;
1471 size_t len;
1472
1473 c = *str++;
1474 if (!c)
1475 return (const char *) in; // Trivial empty string case
1476
1477 len = strlen(str);
1478 do {
1479 char sc;
1480
1481 do {
1482 sc = *in++;
1483 if (!sc)
1484 return (char *) 0;
1485 } while (sc != c);
1486 } while (strncmp(in, str, len) != 0);
1487
1488 return (const char *) (in - 1);
1489 }
1490
1491 /*
1492 * Runtime and ABI
1493 */
1494 uintptr_t
1495 dtrace_caller(int ignore)
1496 {
1497 #pragma unused(ignore)
1498 return -1; /* Just as in Solaris dtrace_asm.s */
1499 }
1500
1501 int
1502 dtrace_getstackdepth(int aframes)
1503 {
1504 struct frame *fp = (struct frame *)__builtin_frame_address(0);
1505 struct frame *nextfp, *minfp, *stacktop;
1506 int depth = 0;
1507 int on_intr;
1508
1509 if ((on_intr = CPU_ON_INTR(CPU)) != 0)
1510 stacktop = (struct frame *)dtrace_get_cpu_int_stack_top();
1511 else
1512 stacktop = (struct frame *)(dtrace_get_kernel_stack(current_thread()) + kernel_stack_size);
1513
1514 minfp = fp;
1515
1516 aframes++;
1517
1518 for (;;) {
1519 depth++;
1520
1521 nextfp = *(struct frame **)fp;
1522
1523 if (nextfp <= minfp || nextfp >= stacktop) {
1524 if (on_intr) {
1525 /*
1526 * Hop from interrupt stack to thread stack.
1527 */
1528 vm_offset_t kstack_base = dtrace_get_kernel_stack(current_thread());
1529
1530 minfp = (struct frame *)kstack_base;
1531 stacktop = (struct frame *)(kstack_base + kernel_stack_size);
1532
1533 on_intr = 0;
1534 continue;
1535 }
1536 break;
1537 }
1538
1539 fp = nextfp;
1540 minfp = fp;
1541 }
1542
1543 if (depth <= aframes)
1544 return (0);
1545
1546 return (depth - aframes);
1547 }
1548
1549 /*
1550 * Unconsidered
1551 */
1552 void
1553 dtrace_vtime_enable(void) {}
1554
1555 void
1556 dtrace_vtime_disable(void) {}
1557
1558 #else /* else ! CONFIG_DTRACE */
1559
1560 #include <sys/types.h>
1561 #include <mach/vm_types.h>
1562 #include <mach/kmod.h>
1563
1564 /*
1565 * This exists to prevent build errors when dtrace is unconfigured.
1566 */
1567
1568 kern_return_t _dtrace_register_anon_DOF(char *, unsigned char *, uint32_t);
1569
1570 kern_return_t _dtrace_register_anon_DOF(char *arg1, unsigned char *arg2, uint32_t arg3) {
1571 #pragma unused(arg1, arg2, arg3)
1572
1573 return KERN_FAILURE;
1574 }
1575
1576 #endif /* CONFIG_DTRACE */