xref: /xnu-8020.101.4/bsd/dev/dtrace/dtrace_glue.c (revision e7776783b89a353188416a9a346c6cdb4928faad)
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 #include <kern/thread.h>
30 
31 #include <sys/time.h>
32 #include <sys/proc.h>
33 #include <sys/kauth.h>
34 #include <sys/user.h>
35 #include <sys/systm.h>
36 #include <sys/dtrace.h>
37 #include <sys/dtrace_impl.h>
38 #include <machine/atomic.h>
39 #include <libkern/OSKextLibPrivate.h>
40 #include <kern/kern_types.h>
41 #include <kern/timer_call.h>
42 #include <kern/thread_call.h>
43 #include <kern/task.h>
44 #include <kern/sched_prim.h>
45 #include <miscfs/devfs/devfs.h>
46 #include <kern/kalloc.h>
47 
48 #include <mach/vm_param.h>
49 #include <mach/mach_vm.h>
50 #include <mach/task.h>
51 #include <vm/vm_map.h> /* All the bits we care about are guarded by MACH_KERNEL_PRIVATE :-( */
52 
53 /*
54  * pid/proc
55  */
56 /* Solaris proc_t is the struct. Darwin's proc_t is a pointer to it. */
57 #define proc_t struct proc /* Steer clear of the Darwin typedef for proc_t */
58 
59 KALLOC_HEAP_DEFINE(KHEAP_DTRACE, "dtrace", KHEAP_ID_DEFAULT);
60 
61 void
dtrace_sprlock(proc_t * p)62 dtrace_sprlock(proc_t *p)
63 {
64 	lck_mtx_lock(&p->p_dtrace_sprlock);
65 }
66 
67 void
dtrace_sprunlock(proc_t * p)68 dtrace_sprunlock(proc_t *p)
69 {
70 	lck_mtx_unlock(&p->p_dtrace_sprlock);
71 }
72 
73 /* Not called from probe context */
74 proc_t *
sprlock(pid_t pid)75 sprlock(pid_t pid)
76 {
77 	proc_t* p;
78 
79 	if ((p = proc_find(pid)) == PROC_NULL) {
80 		return PROC_NULL;
81 	}
82 
83 	task_suspend_internal(p->task);
84 
85 	dtrace_sprlock(p);
86 
87 	return p;
88 }
89 
90 /* Not called from probe context */
91 void
sprunlock(proc_t * p)92 sprunlock(proc_t *p)
93 {
94 	if (p != PROC_NULL) {
95 		dtrace_sprunlock(p);
96 
97 		task_resume_internal(p->task);
98 
99 		proc_rele(p);
100 	}
101 }
102 
103 /*
104  * uread/uwrite
105  */
106 
107 // These are not exported from vm_map.h.
108 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);
109 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);
110 
111 /* Not called from probe context */
112 int
uread(proc_t * p,void * buf,user_size_t len,user_addr_t a)113 uread(proc_t *p, void *buf, user_size_t len, user_addr_t a)
114 {
115 	kern_return_t ret;
116 
117 	ASSERT(p != PROC_NULL);
118 	ASSERT(p->task != NULL);
119 
120 	task_t task = p->task;
121 
122 	/*
123 	 * Grab a reference to the task vm_map_t to make sure
124 	 * the map isn't pulled out from under us.
125 	 *
126 	 * Because the proc_lock is not held at all times on all code
127 	 * paths leading here, it is possible for the proc to have
128 	 * exited. If the map is null, fail.
129 	 */
130 	vm_map_t map = get_task_map_reference(task);
131 	if (map) {
132 		ret = vm_map_read_user( map, (vm_map_address_t)a, buf, (vm_size_t)len);
133 		vm_map_deallocate(map);
134 	} else {
135 		ret = KERN_TERMINATED;
136 	}
137 
138 	return (int)ret;
139 }
140 
141 
142 /* Not called from probe context */
143 int
uwrite(proc_t * p,void * buf,user_size_t len,user_addr_t a)144 uwrite(proc_t *p, void *buf, user_size_t len, user_addr_t a)
145 {
146 	kern_return_t ret;
147 
148 	ASSERT(p != NULL);
149 	ASSERT(p->task != NULL);
150 
151 	task_t task = p->task;
152 
153 	/*
154 	 * Grab a reference to the task vm_map_t to make sure
155 	 * the map isn't pulled out from under us.
156 	 *
157 	 * Because the proc_lock is not held at all times on all code
158 	 * paths leading here, it is possible for the proc to have
159 	 * exited. If the map is null, fail.
160 	 */
161 	vm_map_t map = get_task_map_reference(task);
162 	if (map) {
163 		/* Find the memory permissions. */
164 		uint32_t nestingDepth = 999999;
165 		vm_region_submap_short_info_data_64_t info;
166 		mach_msg_type_number_t count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
167 		mach_vm_address_t address = (mach_vm_address_t)a;
168 		mach_vm_size_t sizeOfRegion = (mach_vm_size_t)len;
169 
170 		ret = mach_vm_region_recurse(map, &address, &sizeOfRegion, &nestingDepth, (vm_region_recurse_info_t)&info, &count);
171 		if (ret != KERN_SUCCESS) {
172 			goto done;
173 		}
174 
175 		vm_prot_t reprotect;
176 
177 		if (!(info.protection & VM_PROT_WRITE)) {
178 			/* Save the original protection values for restoration later */
179 			reprotect = info.protection;
180 
181 			if (info.max_protection & VM_PROT_WRITE) {
182 				/* The memory is not currently writable, but can be made writable. */
183 				ret = mach_vm_protect(map, (mach_vm_offset_t)a, (mach_vm_size_t)len, 0, (reprotect & ~VM_PROT_EXECUTE) | VM_PROT_WRITE);
184 			} else {
185 				/*
186 				 * The memory is not currently writable, and cannot be made writable. We need to COW this memory.
187 				 *
188 				 * Strange, we can't just say "reprotect | VM_PROT_COPY", that fails.
189 				 */
190 				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);
191 			}
192 
193 			if (ret != KERN_SUCCESS) {
194 				goto done;
195 			}
196 		} else {
197 			/* The memory was already writable. */
198 			reprotect = VM_PROT_NONE;
199 		}
200 
201 		ret = vm_map_write_user( map,
202 		    buf,
203 		    (vm_map_address_t)a,
204 		    (vm_size_t)len);
205 
206 		dtrace_flush_caches();
207 
208 		if (ret != KERN_SUCCESS) {
209 			goto done;
210 		}
211 
212 		if (reprotect != VM_PROT_NONE) {
213 			ASSERT(reprotect & VM_PROT_EXECUTE);
214 			ret = mach_vm_protect(map, (mach_vm_offset_t)a, (mach_vm_size_t)len, 0, reprotect);
215 		}
216 
217 done:
218 		vm_map_deallocate(map);
219 	} else {
220 		ret = KERN_TERMINATED;
221 	}
222 
223 	return (int)ret;
224 }
225 
226 /*
227  * cpuvar
228  */
229 LCK_MTX_DECLARE_ATTR(cpu_lock, &dtrace_lck_grp, &dtrace_lck_attr);
230 LCK_MTX_DECLARE_ATTR(cyc_lock, &dtrace_lck_grp, &dtrace_lck_attr);
231 LCK_MTX_DECLARE_ATTR(mod_lock, &dtrace_lck_grp, &dtrace_lck_attr);
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 *
dtrace_CRED(void)245 dtrace_CRED(void)
246 {
247 	return current_thread_ro_unchecked()->tro_cred;
248 }
249 
250 int
PRIV_POLICY_CHOICE(void * cred,int priv,int all)251 PRIV_POLICY_CHOICE(void* cred, int priv, int all)
252 {
253 #pragma unused(priv, all)
254 	return kauth_cred_issuser(cred); /* XXX TODO: How is this different from PRIV_POLICY_ONLY? */
255 }
256 
257 int
PRIV_POLICY_ONLY(void * cr,int priv,int boolean)258 PRIV_POLICY_ONLY(void *cr, int priv, int boolean)
259 {
260 #pragma unused(priv, boolean)
261 	return kauth_cred_issuser(cr); /* XXX TODO: HAS_PRIVILEGE(cr, priv); */
262 }
263 
264 uid_t
crgetuid(const cred_t * cr)265 crgetuid(const cred_t *cr)
266 {
267 	cred_t copy_cr = *cr; return kauth_cred_getuid(&copy_cr);
268 }
269 
270 /*
271  * "cyclic"
272  */
273 
274 typedef struct wrap_timer_call {
275 	/* node attributes */
276 	cyc_handler_t           hdlr;
277 	cyc_time_t              when;
278 	uint64_t                deadline;
279 	int                     cpuid;
280 	boolean_t               suspended;
281 	struct timer_call       call;
282 
283 	/* next item in the linked list */
284 	LIST_ENTRY(wrap_timer_call) entries;
285 } wrap_timer_call_t;
286 
287 #define WAKEUP_REAPER           0x7FFFFFFFFFFFFFFFLL
288 #define NEARLY_FOREVER          0x7FFFFFFFFFFFFFFELL
289 
290 
291 typedef struct cyc_list {
292 	cyc_omni_handler_t cyl_omni;
293 	wrap_timer_call_t cyl_wrap_by_cpus[];
294 #if __arm__ && (__BIGGEST_ALIGNMENT__ > 4)
295 } __attribute__ ((aligned(8))) cyc_list_t;
296 #else
297 } cyc_list_t;
298 #endif
299 
300 /* CPU going online/offline notifications */
301 void (*dtrace_cpu_state_changed_hook)(int, boolean_t) = NULL;
302 void dtrace_cpu_state_changed(int, boolean_t);
303 
304 void
dtrace_install_cpu_hooks(void)305 dtrace_install_cpu_hooks(void)
306 {
307 	dtrace_cpu_state_changed_hook = dtrace_cpu_state_changed;
308 }
309 
310 void
dtrace_cpu_state_changed(int cpuid,boolean_t is_running)311 dtrace_cpu_state_changed(int cpuid, boolean_t is_running)
312 {
313 #pragma unused(cpuid)
314 	wrap_timer_call_t       *wrapTC = NULL;
315 	boolean_t               suspend = (is_running ? FALSE : TRUE);
316 	dtrace_icookie_t        s;
317 
318 	/* Ensure that we're not going to leave the CPU */
319 	s = dtrace_interrupt_disable();
320 	assert(cpuid == cpu_number());
321 
322 	LIST_FOREACH(wrapTC, &(cpu_list[cpu_number()].cpu_cyc_list), entries) {
323 		assert(wrapTC->cpuid == cpu_number());
324 		if (suspend) {
325 			assert(!wrapTC->suspended);
326 			/* If this fails, we'll panic anyway, so let's do this now. */
327 			if (!timer_call_cancel(&wrapTC->call)) {
328 				panic("timer_call_set_suspend() failed to cancel a timer call");
329 			}
330 			wrapTC->suspended = TRUE;
331 		} else {
332 			/* Rearm the timer, but ensure it was suspended first. */
333 			assert(wrapTC->suspended);
334 			clock_deadline_for_periodic_event(wrapTC->when.cyt_interval, mach_absolute_time(),
335 			    &wrapTC->deadline);
336 			timer_call_enter1(&wrapTC->call, (void*) wrapTC, wrapTC->deadline,
337 			    TIMER_CALL_SYS_CRITICAL | TIMER_CALL_LOCAL);
338 			wrapTC->suspended = FALSE;
339 		}
340 	}
341 
342 	/* Restore the previous interrupt state. */
343 	dtrace_interrupt_enable(s);
344 }
345 
346 static void
_timer_call_apply_cyclic(void * ignore,void * vTChdl)347 _timer_call_apply_cyclic( void *ignore, void *vTChdl )
348 {
349 #pragma unused(ignore)
350 	wrap_timer_call_t *wrapTC = (wrap_timer_call_t *)vTChdl;
351 
352 	(*(wrapTC->hdlr.cyh_func))( wrapTC->hdlr.cyh_arg );
353 
354 	clock_deadline_for_periodic_event( wrapTC->when.cyt_interval, mach_absolute_time(), &(wrapTC->deadline));
355 	timer_call_enter1( &(wrapTC->call), (void *)wrapTC, wrapTC->deadline, TIMER_CALL_SYS_CRITICAL | TIMER_CALL_LOCAL );
356 }
357 
358 static cyclic_id_t
timer_call_add_cyclic(wrap_timer_call_t * wrapTC,cyc_handler_t * handler,cyc_time_t * when)359 timer_call_add_cyclic(wrap_timer_call_t *wrapTC, cyc_handler_t *handler, cyc_time_t *when)
360 {
361 	uint64_t now;
362 	dtrace_icookie_t s;
363 
364 	timer_call_setup( &(wrapTC->call), _timer_call_apply_cyclic, NULL );
365 	wrapTC->hdlr = *handler;
366 	wrapTC->when = *when;
367 
368 	nanoseconds_to_absolutetime( wrapTC->when.cyt_interval, (uint64_t *)&wrapTC->when.cyt_interval );
369 
370 	now = mach_absolute_time();
371 	wrapTC->deadline = now;
372 
373 	clock_deadline_for_periodic_event( wrapTC->when.cyt_interval, now, &(wrapTC->deadline));
374 
375 	/* Insert the timer to the list of the running timers on this CPU, and start it. */
376 	s = dtrace_interrupt_disable();
377 	wrapTC->cpuid = cpu_number();
378 	LIST_INSERT_HEAD(&cpu_list[wrapTC->cpuid].cpu_cyc_list, wrapTC, entries);
379 	timer_call_enter1(&wrapTC->call, (void*) wrapTC, wrapTC->deadline,
380 	    TIMER_CALL_SYS_CRITICAL | TIMER_CALL_LOCAL);
381 	wrapTC->suspended = FALSE;
382 	dtrace_interrupt_enable(s);
383 
384 	return (cyclic_id_t)wrapTC;
385 }
386 
387 /*
388  * Executed on the CPU the timer is running on.
389  */
390 static void
timer_call_remove_cyclic(wrap_timer_call_t * wrapTC)391 timer_call_remove_cyclic(wrap_timer_call_t *wrapTC)
392 {
393 	assert(wrapTC);
394 	assert(cpu_number() == wrapTC->cpuid);
395 
396 	if (!timer_call_cancel(&wrapTC->call)) {
397 		panic("timer_call_remove_cyclic() failed to cancel a timer call");
398 	}
399 
400 	LIST_REMOVE(wrapTC, entries);
401 }
402 
403 static void *
timer_call_get_cyclic_arg(wrap_timer_call_t * wrapTC)404 timer_call_get_cyclic_arg(wrap_timer_call_t *wrapTC)
405 {
406 	return wrapTC ? wrapTC->hdlr.cyh_arg : NULL;
407 }
408 
409 cyclic_id_t
cyclic_timer_add(cyc_handler_t * handler,cyc_time_t * when)410 cyclic_timer_add(cyc_handler_t *handler, cyc_time_t *when)
411 {
412 	wrap_timer_call_t *wrapTC = kalloc_type(wrap_timer_call_t, Z_ZERO | Z_WAITOK);
413 	if (NULL == wrapTC) {
414 		return CYCLIC_NONE;
415 	} else {
416 		return timer_call_add_cyclic( wrapTC, handler, when );
417 	}
418 }
419 
420 void
cyclic_timer_remove(cyclic_id_t cyclic)421 cyclic_timer_remove(cyclic_id_t cyclic)
422 {
423 	ASSERT( cyclic != CYCLIC_NONE );
424 
425 	/* Removing a timer call must be done on the CPU the timer is running on. */
426 	wrap_timer_call_t *wrapTC = (wrap_timer_call_t *) cyclic;
427 	dtrace_xcall(wrapTC->cpuid, (dtrace_xcall_t) timer_call_remove_cyclic, (void*) cyclic);
428 
429 	kfree_type(wrap_timer_call_t, wrapTC);
430 }
431 
432 static void
_cyclic_add_omni(cyc_list_t * cyc_list)433 _cyclic_add_omni(cyc_list_t *cyc_list)
434 {
435 	cyc_time_t cT;
436 	cyc_handler_t cH;
437 	cyc_omni_handler_t *omni = &cyc_list->cyl_omni;
438 
439 	(omni->cyo_online)(omni->cyo_arg, CPU, &cH, &cT);
440 
441 	wrap_timer_call_t *wrapTC = &cyc_list->cyl_wrap_by_cpus[cpu_number()];
442 	timer_call_add_cyclic(wrapTC, &cH, &cT);
443 }
444 
445 cyclic_id_list_t
cyclic_add_omni(cyc_omni_handler_t * omni)446 cyclic_add_omni(cyc_omni_handler_t *omni)
447 {
448 	cyc_list_t *cyc_list = kalloc_type(cyc_list_t, wrap_timer_call_t, NCPU, Z_WAITOK | Z_ZERO);
449 
450 	if (NULL == cyc_list) {
451 		return NULL;
452 	}
453 
454 	cyc_list->cyl_omni = *omni;
455 
456 	dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)_cyclic_add_omni, (void *)cyc_list);
457 
458 	return (cyclic_id_list_t)cyc_list;
459 }
460 
461 static void
_cyclic_remove_omni(cyc_list_t * cyc_list)462 _cyclic_remove_omni(cyc_list_t *cyc_list)
463 {
464 	cyc_omni_handler_t *omni = &cyc_list->cyl_omni;
465 	void *oarg;
466 	wrap_timer_call_t *wrapTC;
467 
468 	/*
469 	 * If the processor was offline when dtrace started, we did not allocate
470 	 * a cyclic timer for this CPU.
471 	 */
472 	if ((wrapTC = &cyc_list->cyl_wrap_by_cpus[cpu_number()]) != NULL) {
473 		oarg = timer_call_get_cyclic_arg(wrapTC);
474 		timer_call_remove_cyclic(wrapTC);
475 		(omni->cyo_offline)(omni->cyo_arg, CPU, oarg);
476 	}
477 }
478 
479 void
cyclic_remove_omni(cyclic_id_list_t cyc_list)480 cyclic_remove_omni(cyclic_id_list_t cyc_list)
481 {
482 	ASSERT(cyc_list != NULL);
483 
484 	dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)_cyclic_remove_omni, (void *)cyc_list);
485 	void *cyc_list_p = (void *)cyc_list;
486 	kfree_type(cyc_list_t, wrap_timer_call_t, NCPU, cyc_list_p);
487 }
488 
489 typedef struct wrap_thread_call {
490 	thread_call_t TChdl;
491 	cyc_handler_t hdlr;
492 	cyc_time_t when;
493 	uint64_t deadline;
494 } wrap_thread_call_t;
495 
496 /*
497  * _cyclic_apply will run on some thread under kernel_task. That's OK for the
498  * cleaner and the deadman, but too distant in time and place for the profile provider.
499  */
500 static void
_cyclic_apply(void * ignore,void * vTChdl)501 _cyclic_apply( void *ignore, void *vTChdl )
502 {
503 #pragma unused(ignore)
504 	wrap_thread_call_t *wrapTC = (wrap_thread_call_t *)vTChdl;
505 
506 	(*(wrapTC->hdlr.cyh_func))( wrapTC->hdlr.cyh_arg );
507 
508 	clock_deadline_for_periodic_event( wrapTC->when.cyt_interval, mach_absolute_time(), &(wrapTC->deadline));
509 	(void)thread_call_enter1_delayed( wrapTC->TChdl, (void *)wrapTC, wrapTC->deadline );
510 
511 	/* Did cyclic_remove request a wakeup call when this thread call was re-armed? */
512 	if (wrapTC->when.cyt_interval == WAKEUP_REAPER) {
513 		thread_wakeup((event_t)wrapTC);
514 	}
515 }
516 
517 cyclic_id_t
cyclic_add(cyc_handler_t * handler,cyc_time_t * when)518 cyclic_add(cyc_handler_t *handler, cyc_time_t *when)
519 {
520 	uint64_t now;
521 
522 	wrap_thread_call_t *wrapTC = kalloc_type(wrap_thread_call_t, Z_ZERO | Z_WAITOK);
523 	if (NULL == wrapTC) {
524 		return CYCLIC_NONE;
525 	}
526 
527 	wrapTC->TChdl = thread_call_allocate( _cyclic_apply, NULL );
528 	wrapTC->hdlr = *handler;
529 	wrapTC->when = *when;
530 
531 	ASSERT(when->cyt_when == 0);
532 	ASSERT(when->cyt_interval < WAKEUP_REAPER);
533 
534 	nanoseconds_to_absolutetime(wrapTC->when.cyt_interval, (uint64_t *)&wrapTC->when.cyt_interval);
535 
536 	now = mach_absolute_time();
537 	wrapTC->deadline = now;
538 
539 	clock_deadline_for_periodic_event( wrapTC->when.cyt_interval, now, &(wrapTC->deadline));
540 	(void)thread_call_enter1_delayed( wrapTC->TChdl, (void *)wrapTC, wrapTC->deadline );
541 
542 	return (cyclic_id_t)wrapTC;
543 }
544 
545 static void
noop_cyh_func(void * ignore)546 noop_cyh_func(void * ignore)
547 {
548 #pragma unused(ignore)
549 }
550 
551 void
cyclic_remove(cyclic_id_t cyclic)552 cyclic_remove(cyclic_id_t cyclic)
553 {
554 	wrap_thread_call_t *wrapTC = (wrap_thread_call_t *)cyclic;
555 
556 	ASSERT(cyclic != CYCLIC_NONE);
557 
558 	while (!thread_call_cancel(wrapTC->TChdl)) {
559 		int ret = assert_wait(wrapTC, THREAD_UNINT);
560 		ASSERT(ret == THREAD_WAITING);
561 
562 		wrapTC->when.cyt_interval = WAKEUP_REAPER;
563 
564 		ret = thread_block(THREAD_CONTINUE_NULL);
565 		ASSERT(ret == THREAD_AWAKENED);
566 	}
567 
568 	if (thread_call_free(wrapTC->TChdl)) {
569 		kfree_type(wrap_thread_call_t, wrapTC);
570 	} else {
571 		/* Gut this cyclic and move on ... */
572 		wrapTC->hdlr.cyh_func = noop_cyh_func;
573 		wrapTC->when.cyt_interval = NEARLY_FOREVER;
574 	}
575 }
576 
577 int
ddi_driver_major(dev_info_t * devi)578 ddi_driver_major(dev_info_t     *devi)
579 {
580 	return (int)major(CAST_DOWN_EXPLICIT(int, devi));
581 }
582 
583 int
ddi_create_minor_node(dev_info_t * dip,const char * name,int spec_type,minor_t minor_num,const char * node_type,int flag)584 ddi_create_minor_node(dev_info_t *dip, const char *name, int spec_type,
585     minor_t minor_num, const char *node_type, int flag)
586 {
587 #pragma unused(spec_type,node_type,flag)
588 	dev_t dev = makedev( ddi_driver_major(dip), minor_num );
589 
590 	if (NULL == devfs_make_node( dev, DEVFS_CHAR, UID_ROOT, GID_WHEEL, 0666, "%s", name )) {
591 		return DDI_FAILURE;
592 	} else {
593 		return DDI_SUCCESS;
594 	}
595 }
596 
597 void
ddi_remove_minor_node(dev_info_t * dip,char * name)598 ddi_remove_minor_node(dev_info_t *dip, char *name)
599 {
600 #pragma unused(dip,name)
601 /* XXX called from dtrace_detach, so NOTREACHED for now. */
602 }
603 
604 major_t
getemajor(dev_t d)605 getemajor( dev_t d )
606 {
607 	return (major_t) major(d);
608 }
609 
610 minor_t
getminor(dev_t d)611 getminor( dev_t d )
612 {
613 	return (minor_t) minor(d);
614 }
615 
616 extern void Debugger(const char*);
617 
618 void
debug_enter(char * c)619 debug_enter(char *c)
620 {
621 	Debugger(c);
622 }
623 
624 /*
625  * kmem
626  */
627 
628 void *
dt_kmem_alloc_site(size_t size,int kmflag,vm_allocation_site_t * site)629 dt_kmem_alloc_site(size_t size, int kmflag, vm_allocation_site_t *site)
630 {
631 #pragma unused(kmflag)
632 
633 /*
634  * We ignore the M_NOWAIT bit in kmflag (all of kmflag, in fact).
635  * Requests larger than 8K with M_NOWAIT fail in kalloc_ext.
636  */
637 	return kalloc_ext(KHEAP_DTRACE, size, Z_WAITOK, site).addr;
638 }
639 
640 void *
dt_kmem_zalloc_site(size_t size,int kmflag,vm_allocation_site_t * site)641 dt_kmem_zalloc_site(size_t size, int kmflag, vm_allocation_site_t *site)
642 {
643 #pragma unused(kmflag)
644 
645 /*
646  * We ignore the M_NOWAIT bit in kmflag (all of kmflag, in fact).
647  * Requests larger than 8K with M_NOWAIT fail in kalloc_ext.
648  */
649 	return kalloc_ext(KHEAP_DTRACE, size, Z_WAITOK | Z_ZERO, site).addr;
650 }
651 
652 void
dt_kmem_free(void * buf,size_t size)653 dt_kmem_free(void *buf, size_t size)
654 {
655 	kheap_free(KHEAP_DTRACE, buf, size);
656 }
657 
658 
659 
660 /*
661  * aligned dt_kmem allocator
662  * align should be a power of two
663  */
664 
665 void*
dt_kmem_alloc_aligned_site(size_t size,size_t align,int kmflag,vm_allocation_site_t * site)666 dt_kmem_alloc_aligned_site(size_t size, size_t align, int kmflag, vm_allocation_site_t *site)
667 {
668 	void *mem, **addr_to_free;
669 	intptr_t mem_aligned;
670 	size_t *size_to_free, hdr_size;
671 
672 	/* Must be a power of two. */
673 	assert(align != 0);
674 	assert((align & (align - 1)) == 0);
675 
676 	/*
677 	 * We are going to add a header to the allocation. It contains
678 	 * the address to free and the total size of the buffer.
679 	 */
680 	hdr_size = sizeof(size_t) + sizeof(void*);
681 	mem = dt_kmem_alloc_site(size + align + hdr_size, kmflag, site);
682 	if (mem == NULL) {
683 		return NULL;
684 	}
685 
686 	mem_aligned = (intptr_t) (((intptr_t) mem + align + hdr_size) & ~(align - 1));
687 
688 	/* Write the address to free in the header. */
689 	addr_to_free = (void**) (mem_aligned - sizeof(void*));
690 	*addr_to_free = mem;
691 
692 	/* Write the size to free in the header. */
693 	size_to_free = (size_t*) (mem_aligned - hdr_size);
694 	*size_to_free = size + align + hdr_size;
695 
696 	return (void*) mem_aligned;
697 }
698 
699 void*
dt_kmem_zalloc_aligned_site(size_t size,size_t align,int kmflag,vm_allocation_site_t * s)700 dt_kmem_zalloc_aligned_site(size_t size, size_t align, int kmflag, vm_allocation_site_t *s)
701 {
702 	void* buf;
703 
704 	buf = dt_kmem_alloc_aligned_site(size, align, kmflag, s);
705 
706 	if (!buf) {
707 		return NULL;
708 	}
709 
710 	bzero(buf, size);
711 
712 	return buf;
713 }
714 
715 void
dt_kmem_free_aligned(void * buf,size_t size)716 dt_kmem_free_aligned(void* buf, size_t size)
717 {
718 #pragma unused(size)
719 	intptr_t ptr = (intptr_t) buf;
720 	void **addr_to_free = (void**) (ptr - sizeof(void*));
721 	size_t *size_to_free = (size_t*) (ptr - (sizeof(size_t) + sizeof(void*)));
722 
723 	if (buf == NULL) {
724 		return;
725 	}
726 
727 	dt_kmem_free(*addr_to_free, *size_to_free);
728 }
729 
730 /*
731  * vmem (Solaris "slab" allocator) used by DTrace solely to hand out resource ids
732  */
733 typedef unsigned int u_daddr_t;
734 #include "blist.h"
735 
736 /* By passing around blist *handles*, the underlying blist can be resized as needed. */
737 struct blist_hdl {
738 	blist_t blist;
739 };
740 
741 vmem_t *
vmem_create(const char * name,void * base,size_t size,size_t quantum,void * ignore5,void * ignore6,vmem_t * source,size_t qcache_max,int vmflag)742 vmem_create(const char *name, void *base, size_t size, size_t quantum, void *ignore5,
743     void *ignore6, vmem_t *source, size_t qcache_max, int vmflag)
744 {
745 #pragma unused(name,quantum,ignore5,ignore6,source,qcache_max,vmflag)
746 	blist_t bl;
747 	struct blist_hdl *p = kalloc_type(struct blist_hdl, Z_WAITOK);
748 
749 	ASSERT(quantum == 1);
750 	ASSERT(NULL == ignore5);
751 	ASSERT(NULL == ignore6);
752 	ASSERT(NULL == source);
753 	ASSERT(0 == qcache_max);
754 	ASSERT(size <= INT32_MAX);
755 	ASSERT(vmflag & VMC_IDENTIFIER);
756 
757 	size = MIN(128, size); /* Clamp to 128 initially, since the underlying data structure is pre-allocated */
758 
759 	p->blist = bl = blist_create((daddr_t)size);
760 	blist_free(bl, 0, (daddr_t)size);
761 	if (base) {
762 		blist_alloc( bl, (daddr_t)(uintptr_t)base );   /* Chomp off initial ID(s) */
763 	}
764 	return (vmem_t *)p;
765 }
766 
767 void *
vmem_alloc(vmem_t * vmp,size_t size,int vmflag)768 vmem_alloc(vmem_t *vmp, size_t size, int vmflag)
769 {
770 #pragma unused(vmflag)
771 	struct blist_hdl *q = (struct blist_hdl *)vmp;
772 	blist_t bl = q->blist;
773 	daddr_t p;
774 
775 	p = blist_alloc(bl, (daddr_t)size);
776 
777 	if (p == SWAPBLK_NONE) {
778 		blist_resize(&bl, (bl->bl_blocks) << 1, 1);
779 		q->blist = bl;
780 		p = blist_alloc(bl, (daddr_t)size);
781 		if (p == SWAPBLK_NONE) {
782 			panic("vmem_alloc: failure after blist_resize!");
783 		}
784 	}
785 
786 	return (void *)(uintptr_t)p;
787 }
788 
789 void
vmem_free(vmem_t * vmp,void * vaddr,size_t size)790 vmem_free(vmem_t *vmp, void *vaddr, size_t size)
791 {
792 	struct blist_hdl *p = (struct blist_hdl *)vmp;
793 
794 	blist_free( p->blist, (daddr_t)(uintptr_t)vaddr, (daddr_t)size );
795 }
796 
797 void
vmem_destroy(vmem_t * vmp)798 vmem_destroy(vmem_t *vmp)
799 {
800 	struct blist_hdl *p = (struct blist_hdl *)vmp;
801 
802 	blist_destroy( p->blist );
803 	kfree_type(struct blist_hdl, p);
804 }
805 
806 /*
807  * Timing
808  */
809 
810 /*
811  * dtrace_gethrestime() provides the "walltimestamp", a value that is anchored at
812  * January 1, 1970. Because it can be called from probe context, it must take no locks.
813  */
814 
815 hrtime_t
dtrace_gethrestime(void)816 dtrace_gethrestime(void)
817 {
818 	clock_sec_t             secs;
819 	clock_nsec_t    nanosecs;
820 	uint64_t                secs64, ns64;
821 
822 	clock_get_calendar_nanotime_nowait(&secs, &nanosecs);
823 	secs64 = (uint64_t)secs;
824 	ns64 = (uint64_t)nanosecs;
825 
826 	ns64 = ns64 + (secs64 * 1000000000LL);
827 	return ns64;
828 }
829 
830 /*
831  * dtrace_gethrtime() provides high-resolution timestamps with machine-dependent origin.
832  * Hence its primary use is to specify intervals.
833  */
834 
835 hrtime_t
dtrace_abs_to_nano(uint64_t elapsed)836 dtrace_abs_to_nano(uint64_t elapsed)
837 {
838 	static mach_timebase_info_data_t    sTimebaseInfo = { 0, 0 };
839 
840 	/*
841 	 * If this is the first time we've run, get the timebase.
842 	 * We can use denom == 0 to indicate that sTimebaseInfo is
843 	 * uninitialised because it makes no sense to have a zero
844 	 * denominator in a fraction.
845 	 */
846 
847 	if (sTimebaseInfo.denom == 0) {
848 		(void) clock_timebase_info(&sTimebaseInfo);
849 	}
850 
851 	/*
852 	 * Convert to nanoseconds.
853 	 * return (elapsed * (uint64_t)sTimebaseInfo.numer)/(uint64_t)sTimebaseInfo.denom;
854 	 *
855 	 * Provided the final result is representable in 64 bits the following maneuver will
856 	 * deliver that result without intermediate overflow.
857 	 */
858 	if (sTimebaseInfo.denom == sTimebaseInfo.numer) {
859 		return elapsed;
860 	} else if (sTimebaseInfo.denom == 1) {
861 		return elapsed * (uint64_t)sTimebaseInfo.numer;
862 	} else {
863 		/* Decompose elapsed = eta32 * 2^32 + eps32: */
864 		uint64_t eta32 = elapsed >> 32;
865 		uint64_t eps32 = elapsed & 0x00000000ffffffffLL;
866 
867 		uint32_t numer = sTimebaseInfo.numer, denom = sTimebaseInfo.denom;
868 
869 		/* Form product of elapsed64 (decomposed) and numer: */
870 		uint64_t mu64 = numer * eta32;
871 		uint64_t lambda64 = numer * eps32;
872 
873 		/* Divide the constituents by denom: */
874 		uint64_t q32 = mu64 / denom;
875 		uint64_t r32 = mu64 - (q32 * denom); /* mu64 % denom */
876 
877 		return (q32 << 32) + ((r32 << 32) + lambda64) / denom;
878 	}
879 }
880 
881 hrtime_t
dtrace_gethrtime(void)882 dtrace_gethrtime(void)
883 {
884 	static uint64_t        start = 0;
885 
886 	if (start == 0) {
887 		start = mach_absolute_time();
888 	}
889 
890 	return dtrace_abs_to_nano(mach_absolute_time() - start);
891 }
892 
893 /*
894  * Atomicity and synchronization
895  */
896 uint32_t
dtrace_cas32(uint32_t * target,uint32_t cmp,uint32_t new)897 dtrace_cas32(uint32_t *target, uint32_t cmp, uint32_t new)
898 {
899 	if (OSCompareAndSwap((UInt32)cmp, (UInt32)new, (volatile UInt32 *)target )) {
900 		return cmp;
901 	} else {
902 		return ~cmp; /* Must return something *other* than cmp */
903 	}
904 }
905 
906 void *
dtrace_casptr(void * target,void * cmp,void * new)907 dtrace_casptr(void *target, void *cmp, void *new)
908 {
909 	if (OSCompareAndSwapPtr( cmp, new, (void**)target )) {
910 		return cmp;
911 	} else {
912 		return (void *)(~(uintptr_t)cmp); /* Must return something *other* than cmp */
913 	}
914 }
915 
916 /*
917  * Interrupt manipulation
918  */
919 dtrace_icookie_t
dtrace_interrupt_disable(void)920 dtrace_interrupt_disable(void)
921 {
922 	return (dtrace_icookie_t)ml_set_interrupts_enabled(FALSE);
923 }
924 
925 void
dtrace_interrupt_enable(dtrace_icookie_t reenable)926 dtrace_interrupt_enable(dtrace_icookie_t reenable)
927 {
928 	(void)ml_set_interrupts_enabled((boolean_t)reenable);
929 }
930 
931 /*
932  * MP coordination
933  */
934 static void
dtrace_sync_func(void)935 dtrace_sync_func(void)
936 {
937 }
938 
939 /*
940  * dtrace_sync() is not called from probe context.
941  */
942 void
dtrace_sync(void)943 dtrace_sync(void)
944 {
945 	dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_sync_func, NULL);
946 }
947 
948 /*
949  * The dtrace_copyin/out/instr and dtrace_fuword* routines can be called from probe context.
950  */
951 
952 extern kern_return_t dtrace_copyio_preflight(addr64_t);
953 extern kern_return_t dtrace_copyio_postflight(addr64_t);
954 
955 static int
dtrace_copycheck(user_addr_t uaddr,uintptr_t kaddr,size_t size)956 dtrace_copycheck(user_addr_t uaddr, uintptr_t kaddr, size_t size)
957 {
958 #pragma unused(kaddr)
959 
960 	vm_offset_t recover = dtrace_set_thread_recover( current_thread(), 0 ); /* Snare any extant recovery point. */
961 	dtrace_set_thread_recover( current_thread(), recover ); /* Put it back. We *must not* re-enter and overwrite. */
962 
963 	ASSERT(kaddr + size >= kaddr);
964 
965 	if (uaddr + size < uaddr ||             /* Avoid address wrap. */
966 	    KERN_FAILURE == dtrace_copyio_preflight(uaddr)) {   /* Machine specific setup/constraints. */
967 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
968 		cpu_core[CPU->cpu_id].cpuc_dtrace_illval = uaddr;
969 		return 0;
970 	}
971 	return 1;
972 }
973 
974 void
dtrace_copyin(user_addr_t src,uintptr_t dst,size_t len,volatile uint16_t * flags)975 dtrace_copyin(user_addr_t src, uintptr_t dst, size_t len, volatile uint16_t *flags)
976 {
977 #pragma unused(flags)
978 
979 	if (dtrace_copycheck( src, dst, len )) {
980 		if (copyin((const user_addr_t)src, (char *)dst, (vm_size_t)len)) {
981 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
982 			cpu_core[CPU->cpu_id].cpuc_dtrace_illval = src;
983 		}
984 		dtrace_copyio_postflight(src);
985 	}
986 }
987 
988 void
dtrace_copyinstr(user_addr_t src,uintptr_t dst,size_t len,volatile uint16_t * flags)989 dtrace_copyinstr(user_addr_t src, uintptr_t dst, size_t len, volatile uint16_t *flags)
990 {
991 #pragma unused(flags)
992 
993 	size_t actual;
994 
995 	if (dtrace_copycheck( src, dst, len )) {
996 		/*  copyin as many as 'len' bytes. */
997 		int error = copyinstr((const user_addr_t)src, (char *)dst, (vm_size_t)len, &actual);
998 
999 		/*
1000 		 * ENAMETOOLONG is returned when 'len' bytes have been copied in but the NUL terminator was
1001 		 * not encountered. That does not require raising CPU_DTRACE_BADADDR, and we press on.
1002 		 * Note that we do *not* stuff a NUL terminator when returning ENAMETOOLONG, that's left
1003 		 * to the caller.
1004 		 */
1005 		if (error && error != ENAMETOOLONG) {
1006 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1007 			cpu_core[CPU->cpu_id].cpuc_dtrace_illval = src;
1008 		}
1009 		dtrace_copyio_postflight(src);
1010 	}
1011 }
1012 
1013 void
dtrace_copyout(uintptr_t src,user_addr_t dst,size_t len,volatile uint16_t * flags)1014 dtrace_copyout(uintptr_t src, user_addr_t dst, size_t len, volatile uint16_t *flags)
1015 {
1016 #pragma unused(flags)
1017 
1018 	if (dtrace_copycheck( dst, src, len )) {
1019 		if (copyout((const void *)src, dst, (vm_size_t)len)) {
1020 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1021 			cpu_core[CPU->cpu_id].cpuc_dtrace_illval = dst;
1022 		}
1023 		dtrace_copyio_postflight(dst);
1024 	}
1025 }
1026 
1027 void
dtrace_copyoutstr(uintptr_t src,user_addr_t dst,size_t len,volatile uint16_t * flags)1028 dtrace_copyoutstr(uintptr_t src, user_addr_t dst, size_t len, volatile uint16_t *flags)
1029 {
1030 #pragma unused(flags)
1031 
1032 	size_t actual;
1033 
1034 	if (dtrace_copycheck( dst, src, len )) {
1035 		/*
1036 		 * ENAMETOOLONG is returned when 'len' bytes have been copied out but the NUL terminator was
1037 		 * not encountered. We raise CPU_DTRACE_BADADDR in that case.
1038 		 * Note that we do *not* stuff a NUL terminator when returning ENAMETOOLONG, that's left
1039 		 * to the caller.
1040 		 */
1041 		if (copyoutstr((const void *)src, dst, (size_t)len, &actual)) {
1042 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1043 			cpu_core[CPU->cpu_id].cpuc_dtrace_illval = dst;
1044 		}
1045 		dtrace_copyio_postflight(dst);
1046 	}
1047 }
1048 
1049 extern const int copysize_limit_panic;
1050 
1051 int
dtrace_copy_maxsize(void)1052 dtrace_copy_maxsize(void)
1053 {
1054 	return copysize_limit_panic;
1055 }
1056 
1057 
1058 int
dtrace_buffer_copyout(const void * kaddr,user_addr_t uaddr,vm_size_t nbytes)1059 dtrace_buffer_copyout(const void *kaddr, user_addr_t uaddr, vm_size_t nbytes)
1060 {
1061 	int maxsize = dtrace_copy_maxsize();
1062 	/*
1063 	 * Partition the copyout in copysize_limit_panic-sized chunks
1064 	 */
1065 	while (nbytes >= (vm_size_t)maxsize) {
1066 		if (copyout(kaddr, uaddr, maxsize) != 0) {
1067 			return EFAULT;
1068 		}
1069 
1070 		nbytes -= maxsize;
1071 		uaddr += maxsize;
1072 		kaddr = (const void *)((uintptr_t)kaddr + maxsize);
1073 	}
1074 	if (nbytes > 0) {
1075 		if (copyout(kaddr, uaddr, nbytes) != 0) {
1076 			return EFAULT;
1077 		}
1078 	}
1079 
1080 	return 0;
1081 }
1082 
1083 uint8_t
dtrace_fuword8(user_addr_t uaddr)1084 dtrace_fuword8(user_addr_t uaddr)
1085 {
1086 	uint8_t ret = 0;
1087 
1088 	DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
1089 	if (dtrace_copycheck( uaddr, (uintptr_t)&ret, sizeof(ret))) {
1090 		if (copyin((const user_addr_t)uaddr, (char *)&ret, sizeof(ret))) {
1091 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1092 			cpu_core[CPU->cpu_id].cpuc_dtrace_illval = uaddr;
1093 		}
1094 		dtrace_copyio_postflight(uaddr);
1095 	}
1096 	DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
1097 
1098 	return ret;
1099 }
1100 
1101 uint16_t
dtrace_fuword16(user_addr_t uaddr)1102 dtrace_fuword16(user_addr_t uaddr)
1103 {
1104 	uint16_t ret = 0;
1105 
1106 	DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
1107 	if (dtrace_copycheck( uaddr, (uintptr_t)&ret, sizeof(ret))) {
1108 		if (copyin((const user_addr_t)uaddr, (char *)&ret, sizeof(ret))) {
1109 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1110 			cpu_core[CPU->cpu_id].cpuc_dtrace_illval = uaddr;
1111 		}
1112 		dtrace_copyio_postflight(uaddr);
1113 	}
1114 	DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
1115 
1116 	return ret;
1117 }
1118 
1119 uint32_t
dtrace_fuword32(user_addr_t uaddr)1120 dtrace_fuword32(user_addr_t uaddr)
1121 {
1122 	uint32_t ret = 0;
1123 
1124 	DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
1125 	if (dtrace_copycheck( uaddr, (uintptr_t)&ret, sizeof(ret))) {
1126 		if (copyin((const user_addr_t)uaddr, (char *)&ret, sizeof(ret))) {
1127 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1128 			cpu_core[CPU->cpu_id].cpuc_dtrace_illval = uaddr;
1129 		}
1130 		dtrace_copyio_postflight(uaddr);
1131 	}
1132 	DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
1133 
1134 	return ret;
1135 }
1136 
1137 uint64_t
dtrace_fuword64(user_addr_t uaddr)1138 dtrace_fuword64(user_addr_t uaddr)
1139 {
1140 	uint64_t ret = 0;
1141 
1142 	DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
1143 	if (dtrace_copycheck( uaddr, (uintptr_t)&ret, sizeof(ret))) {
1144 		if (copyin((const user_addr_t)uaddr, (char *)&ret, sizeof(ret))) {
1145 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1146 			cpu_core[CPU->cpu_id].cpuc_dtrace_illval = uaddr;
1147 		}
1148 		dtrace_copyio_postflight(uaddr);
1149 	}
1150 	DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
1151 
1152 	return ret;
1153 }
1154 
1155 /*
1156  * Emulation of Solaris fuword / suword
1157  * Called from the fasttrap provider, so the use of copyin/out requires fewer safegaurds.
1158  */
1159 
1160 int
fuword8(user_addr_t uaddr,uint8_t * value)1161 fuword8(user_addr_t uaddr, uint8_t *value)
1162 {
1163 	if (copyin((const user_addr_t)uaddr, (char *)value, sizeof(uint8_t)) != 0) {
1164 		return -1;
1165 	}
1166 
1167 	return 0;
1168 }
1169 
1170 int
fuword16(user_addr_t uaddr,uint16_t * value)1171 fuword16(user_addr_t uaddr, uint16_t *value)
1172 {
1173 	if (copyin((const user_addr_t)uaddr, (char *)value, sizeof(uint16_t)) != 0) {
1174 		return -1;
1175 	}
1176 
1177 	return 0;
1178 }
1179 
1180 int
fuword32(user_addr_t uaddr,uint32_t * value)1181 fuword32(user_addr_t uaddr, uint32_t *value)
1182 {
1183 	if (copyin((const user_addr_t)uaddr, (char *)value, sizeof(uint32_t)) != 0) {
1184 		return -1;
1185 	}
1186 
1187 	return 0;
1188 }
1189 
1190 int
fuword64(user_addr_t uaddr,uint64_t * value)1191 fuword64(user_addr_t uaddr, uint64_t *value)
1192 {
1193 	if (copyin((const user_addr_t)uaddr, (char *)value, sizeof(uint64_t)) != 0) {
1194 		return -1;
1195 	}
1196 
1197 	return 0;
1198 }
1199 
1200 void
fuword32_noerr(user_addr_t uaddr,uint32_t * value)1201 fuword32_noerr(user_addr_t uaddr, uint32_t *value)
1202 {
1203 	if (copyin((const user_addr_t)uaddr, (char *)value, sizeof(uint32_t))) {
1204 		*value = 0;
1205 	}
1206 }
1207 
1208 void
fuword64_noerr(user_addr_t uaddr,uint64_t * value)1209 fuword64_noerr(user_addr_t uaddr, uint64_t *value)
1210 {
1211 	if (copyin((const user_addr_t)uaddr, (char *)value, sizeof(uint64_t))) {
1212 		*value = 0;
1213 	}
1214 }
1215 
1216 int
suword64(user_addr_t addr,uint64_t value)1217 suword64(user_addr_t addr, uint64_t value)
1218 {
1219 	if (copyout((const void *)&value, addr, sizeof(value)) != 0) {
1220 		return -1;
1221 	}
1222 
1223 	return 0;
1224 }
1225 
1226 int
suword32(user_addr_t addr,uint32_t value)1227 suword32(user_addr_t addr, uint32_t value)
1228 {
1229 	if (copyout((const void *)&value, addr, sizeof(value)) != 0) {
1230 		return -1;
1231 	}
1232 
1233 	return 0;
1234 }
1235 
1236 /*
1237  * Miscellaneous
1238  */
1239 extern boolean_t dtrace_tally_fault(user_addr_t);
1240 
1241 boolean_t
dtrace_tally_fault(user_addr_t uaddr)1242 dtrace_tally_fault(user_addr_t uaddr)
1243 {
1244 	DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1245 	cpu_core[CPU->cpu_id].cpuc_dtrace_illval = uaddr;
1246 	return DTRACE_CPUFLAG_ISSET(CPU_DTRACE_NOFAULT) ? TRUE : FALSE;
1247 }
1248 
1249 #define TOTTY   0x02
1250 extern int prf(const char *, va_list, int, struct tty *); /* bsd/kern/subr_prf.h */
1251 
1252 int
vuprintf(const char * format,va_list ap)1253 vuprintf(const char *format, va_list ap)
1254 {
1255 	return prf(format, ap, TOTTY, NULL);
1256 }
1257 
1258 /* Not called from probe context */
1259 void
cmn_err(int level,const char * format,...)1260 cmn_err( int level, const char *format, ... )
1261 {
1262 #pragma unused(level)
1263 	va_list alist;
1264 
1265 	va_start(alist, format);
1266 	vuprintf(format, alist);
1267 	va_end(alist);
1268 	uprintf("\n");
1269 }
1270 
1271 const void*
bsearch(const void * key,const void * base0,size_t nmemb,size_t size,int (* compar)(const void *,const void *))1272 bsearch(const void *key, const void *base0, size_t nmemb, size_t size, int (*compar)(const void *, const void *))
1273 {
1274 	const char *base = base0;
1275 	size_t lim;
1276 	int cmp;
1277 	const void *p;
1278 	for (lim = nmemb; lim != 0; lim >>= 1) {
1279 		p = base + (lim >> 1) * size;
1280 		cmp = (*compar)(key, p);
1281 		if (cmp == 0) {
1282 			return p;
1283 		}
1284 		if (cmp > 0) {  /* key > p: move right */
1285 			base = (const char *)p + size;
1286 			lim--;
1287 		}               /* else move left */
1288 	}
1289 	return NULL;
1290 }
1291 
1292 /*
1293  * Runtime and ABI
1294  */
1295 uintptr_t
dtrace_caller(int ignore)1296 dtrace_caller(int ignore)
1297 {
1298 #pragma unused(ignore)
1299 	return -1; /* Just as in Solaris dtrace_asm.s */
1300 }
1301 
1302 int
dtrace_getstackdepth(int aframes)1303 dtrace_getstackdepth(int aframes)
1304 {
1305 	struct frame *fp = (struct frame *)__builtin_frame_address(0);
1306 	struct frame *nextfp, *minfp, *stacktop;
1307 	int depth = 0;
1308 	int on_intr;
1309 
1310 	if ((on_intr = CPU_ON_INTR(CPU)) != 0) {
1311 		stacktop = (struct frame *)dtrace_get_cpu_int_stack_top();
1312 	} else {
1313 		stacktop = (struct frame *)(dtrace_get_kernel_stack(current_thread()) + kernel_stack_size);
1314 	}
1315 
1316 	minfp = fp;
1317 
1318 	aframes++;
1319 
1320 	for (;;) {
1321 		depth++;
1322 
1323 		nextfp = *(struct frame **)fp;
1324 
1325 		if (nextfp <= minfp || nextfp >= stacktop) {
1326 			if (on_intr) {
1327 				/*
1328 				 * Hop from interrupt stack to thread stack.
1329 				 */
1330 				vm_offset_t kstack_base = dtrace_get_kernel_stack(current_thread());
1331 
1332 				minfp = (struct frame *)kstack_base;
1333 				stacktop = (struct frame *)(kstack_base + kernel_stack_size);
1334 
1335 				on_intr = 0;
1336 				continue;
1337 			}
1338 			break;
1339 		}
1340 
1341 		fp = nextfp;
1342 		minfp = fp;
1343 	}
1344 
1345 	if (depth <= aframes) {
1346 		return 0;
1347 	}
1348 
1349 	return depth - aframes;
1350 }
1351 
1352 int
dtrace_addr_in_module(const void * addr,const struct modctl * ctl)1353 dtrace_addr_in_module(const void* addr, const struct modctl *ctl)
1354 {
1355 	return OSKextKextForAddress(addr) == (void*)ctl->mod_address;
1356 }
1357 
1358 /*
1359  * Unconsidered
1360  */
1361 void
dtrace_vtime_enable(void)1362 dtrace_vtime_enable(void)
1363 {
1364 }
1365 
1366 void
dtrace_vtime_disable(void)1367 dtrace_vtime_disable(void)
1368 {
1369 }
1370