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(©_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 =
449 _MALLOC(sizeof(cyc_list_t) + NCPU * sizeof(wrap_timer_call_t), M_TEMP, M_ZERO | M_WAITOK);
450
451 if (NULL == cyc_list) {
452 return NULL;
453 }
454
455 cyc_list->cyl_omni = *omni;
456
457 dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)_cyclic_add_omni, (void *)cyc_list);
458
459 return (cyclic_id_list_t)cyc_list;
460 }
461
462 static void
_cyclic_remove_omni(cyc_list_t * cyc_list)463 _cyclic_remove_omni(cyc_list_t *cyc_list)
464 {
465 cyc_omni_handler_t *omni = &cyc_list->cyl_omni;
466 void *oarg;
467 wrap_timer_call_t *wrapTC;
468
469 /*
470 * If the processor was offline when dtrace started, we did not allocate
471 * a cyclic timer for this CPU.
472 */
473 if ((wrapTC = &cyc_list->cyl_wrap_by_cpus[cpu_number()]) != NULL) {
474 oarg = timer_call_get_cyclic_arg(wrapTC);
475 timer_call_remove_cyclic(wrapTC);
476 (omni->cyo_offline)(omni->cyo_arg, CPU, oarg);
477 }
478 }
479
480 void
cyclic_remove_omni(cyclic_id_list_t cyc_list)481 cyclic_remove_omni(cyclic_id_list_t cyc_list)
482 {
483 ASSERT(cyc_list != NULL);
484
485 dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)_cyclic_remove_omni, (void *)cyc_list);
486 _FREE(cyc_list, M_TEMP);
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, name, 0 )) {
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 * dtrace wants to manage just a single block: dtrace_state_percpu_t * NCPU, and
732 * doesn't specify constructor, destructor, or reclaim methods.
733 * At present, it always zeroes the block it obtains from kmem_cache_alloc().
734 * We'll manage this constricted use of kmem_cache with ordinary _MALLOC and _FREE.
735 */
736 kmem_cache_t *
kmem_cache_create(const char * name,size_t bufsize,size_t align,int (* constructor)(void *,void *,int),void (* destructor)(void *,void *),void (* reclaim)(void *),void * private,vmem_t * vmp,int cflags)737 kmem_cache_create(
738 const char *name, /* descriptive name for this cache */
739 size_t bufsize, /* size of the objects it manages */
740 size_t align, /* required object alignment */
741 int (*constructor)(void *, void *, int), /* object constructor */
742 void (*destructor)(void *, void *), /* object destructor */
743 void (*reclaim)(void *), /* memory reclaim callback */
744 void *private, /* pass-thru arg for constr/destr/reclaim */
745 vmem_t *vmp, /* vmem source for slab allocation */
746 int cflags) /* cache creation flags */
747 {
748 #pragma unused(name,align,constructor,destructor,reclaim,private,vmp,cflags)
749 return (kmem_cache_t *)bufsize; /* A cookie that tracks the single object size. */
750 }
751
752 void *
kmem_cache_alloc(kmem_cache_t * cp,int kmflag)753 kmem_cache_alloc(kmem_cache_t *cp, int kmflag)
754 {
755 #pragma unused(kmflag)
756 size_t bufsize = (size_t)cp;
757 return (void *)_MALLOC(bufsize, M_TEMP, M_WAITOK);
758 }
759
760 void
kmem_cache_free(kmem_cache_t * cp,void * buf)761 kmem_cache_free(kmem_cache_t *cp, void *buf)
762 {
763 #pragma unused(cp)
764 _FREE(buf, M_TEMP);
765 }
766
767 void
kmem_cache_destroy(kmem_cache_t * cp)768 kmem_cache_destroy(kmem_cache_t *cp)
769 {
770 #pragma unused(cp)
771 }
772
773 /*
774 * vmem (Solaris "slab" allocator) used by DTrace solely to hand out resource ids
775 */
776 typedef unsigned int u_daddr_t;
777 #include "blist.h"
778
779 /* By passing around blist *handles*, the underlying blist can be resized as needed. */
780 struct blist_hdl {
781 blist_t blist;
782 };
783
784 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)785 vmem_create(const char *name, void *base, size_t size, size_t quantum, void *ignore5,
786 void *ignore6, vmem_t *source, size_t qcache_max, int vmflag)
787 {
788 #pragma unused(name,quantum,ignore5,ignore6,source,qcache_max,vmflag)
789 blist_t bl;
790 struct blist_hdl *p = kalloc_type(struct blist_hdl, Z_WAITOK);
791
792 ASSERT(quantum == 1);
793 ASSERT(NULL == ignore5);
794 ASSERT(NULL == ignore6);
795 ASSERT(NULL == source);
796 ASSERT(0 == qcache_max);
797 ASSERT(size <= INT32_MAX);
798 ASSERT(vmflag & VMC_IDENTIFIER);
799
800 size = MIN(128, size); /* Clamp to 128 initially, since the underlying data structure is pre-allocated */
801
802 p->blist = bl = blist_create((daddr_t)size);
803 blist_free(bl, 0, (daddr_t)size);
804 if (base) {
805 blist_alloc( bl, (daddr_t)(uintptr_t)base ); /* Chomp off initial ID(s) */
806 }
807 return (vmem_t *)p;
808 }
809
810 void *
vmem_alloc(vmem_t * vmp,size_t size,int vmflag)811 vmem_alloc(vmem_t *vmp, size_t size, int vmflag)
812 {
813 #pragma unused(vmflag)
814 struct blist_hdl *q = (struct blist_hdl *)vmp;
815 blist_t bl = q->blist;
816 daddr_t p;
817
818 p = blist_alloc(bl, (daddr_t)size);
819
820 if (p == SWAPBLK_NONE) {
821 blist_resize(&bl, (bl->bl_blocks) << 1, 1);
822 q->blist = bl;
823 p = blist_alloc(bl, (daddr_t)size);
824 if (p == SWAPBLK_NONE) {
825 panic("vmem_alloc: failure after blist_resize!");
826 }
827 }
828
829 return (void *)(uintptr_t)p;
830 }
831
832 void
vmem_free(vmem_t * vmp,void * vaddr,size_t size)833 vmem_free(vmem_t *vmp, void *vaddr, size_t size)
834 {
835 struct blist_hdl *p = (struct blist_hdl *)vmp;
836
837 blist_free( p->blist, (daddr_t)(uintptr_t)vaddr, (daddr_t)size );
838 }
839
840 void
vmem_destroy(vmem_t * vmp)841 vmem_destroy(vmem_t *vmp)
842 {
843 struct blist_hdl *p = (struct blist_hdl *)vmp;
844
845 blist_destroy( p->blist );
846 kfree_type(struct blist_hdl, p);
847 }
848
849 /*
850 * Timing
851 */
852
853 /*
854 * dtrace_gethrestime() provides the "walltimestamp", a value that is anchored at
855 * January 1, 1970. Because it can be called from probe context, it must take no locks.
856 */
857
858 hrtime_t
dtrace_gethrestime(void)859 dtrace_gethrestime(void)
860 {
861 clock_sec_t secs;
862 clock_nsec_t nanosecs;
863 uint64_t secs64, ns64;
864
865 clock_get_calendar_nanotime_nowait(&secs, &nanosecs);
866 secs64 = (uint64_t)secs;
867 ns64 = (uint64_t)nanosecs;
868
869 ns64 = ns64 + (secs64 * 1000000000LL);
870 return ns64;
871 }
872
873 /*
874 * dtrace_gethrtime() provides high-resolution timestamps with machine-dependent origin.
875 * Hence its primary use is to specify intervals.
876 */
877
878 hrtime_t
dtrace_abs_to_nano(uint64_t elapsed)879 dtrace_abs_to_nano(uint64_t elapsed)
880 {
881 static mach_timebase_info_data_t sTimebaseInfo = { 0, 0 };
882
883 /*
884 * If this is the first time we've run, get the timebase.
885 * We can use denom == 0 to indicate that sTimebaseInfo is
886 * uninitialised because it makes no sense to have a zero
887 * denominator in a fraction.
888 */
889
890 if (sTimebaseInfo.denom == 0) {
891 (void) clock_timebase_info(&sTimebaseInfo);
892 }
893
894 /*
895 * Convert to nanoseconds.
896 * return (elapsed * (uint64_t)sTimebaseInfo.numer)/(uint64_t)sTimebaseInfo.denom;
897 *
898 * Provided the final result is representable in 64 bits the following maneuver will
899 * deliver that result without intermediate overflow.
900 */
901 if (sTimebaseInfo.denom == sTimebaseInfo.numer) {
902 return elapsed;
903 } else if (sTimebaseInfo.denom == 1) {
904 return elapsed * (uint64_t)sTimebaseInfo.numer;
905 } else {
906 /* Decompose elapsed = eta32 * 2^32 + eps32: */
907 uint64_t eta32 = elapsed >> 32;
908 uint64_t eps32 = elapsed & 0x00000000ffffffffLL;
909
910 uint32_t numer = sTimebaseInfo.numer, denom = sTimebaseInfo.denom;
911
912 /* Form product of elapsed64 (decomposed) and numer: */
913 uint64_t mu64 = numer * eta32;
914 uint64_t lambda64 = numer * eps32;
915
916 /* Divide the constituents by denom: */
917 uint64_t q32 = mu64 / denom;
918 uint64_t r32 = mu64 - (q32 * denom); /* mu64 % denom */
919
920 return (q32 << 32) + ((r32 << 32) + lambda64) / denom;
921 }
922 }
923
924 hrtime_t
dtrace_gethrtime(void)925 dtrace_gethrtime(void)
926 {
927 static uint64_t start = 0;
928
929 if (start == 0) {
930 start = mach_absolute_time();
931 }
932
933 return dtrace_abs_to_nano(mach_absolute_time() - start);
934 }
935
936 /*
937 * Atomicity and synchronization
938 */
939 uint32_t
dtrace_cas32(uint32_t * target,uint32_t cmp,uint32_t new)940 dtrace_cas32(uint32_t *target, uint32_t cmp, uint32_t new)
941 {
942 if (OSCompareAndSwap((UInt32)cmp, (UInt32)new, (volatile UInt32 *)target )) {
943 return cmp;
944 } else {
945 return ~cmp; /* Must return something *other* than cmp */
946 }
947 }
948
949 void *
dtrace_casptr(void * target,void * cmp,void * new)950 dtrace_casptr(void *target, void *cmp, void *new)
951 {
952 if (OSCompareAndSwapPtr( cmp, new, (void**)target )) {
953 return cmp;
954 } else {
955 return (void *)(~(uintptr_t)cmp); /* Must return something *other* than cmp */
956 }
957 }
958
959 /*
960 * Interrupt manipulation
961 */
962 dtrace_icookie_t
dtrace_interrupt_disable(void)963 dtrace_interrupt_disable(void)
964 {
965 return (dtrace_icookie_t)ml_set_interrupts_enabled(FALSE);
966 }
967
968 void
dtrace_interrupt_enable(dtrace_icookie_t reenable)969 dtrace_interrupt_enable(dtrace_icookie_t reenable)
970 {
971 (void)ml_set_interrupts_enabled((boolean_t)reenable);
972 }
973
974 /*
975 * MP coordination
976 */
977 static void
dtrace_sync_func(void)978 dtrace_sync_func(void)
979 {
980 }
981
982 /*
983 * dtrace_sync() is not called from probe context.
984 */
985 void
dtrace_sync(void)986 dtrace_sync(void)
987 {
988 dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_sync_func, NULL);
989 }
990
991 /*
992 * The dtrace_copyin/out/instr and dtrace_fuword* routines can be called from probe context.
993 */
994
995 extern kern_return_t dtrace_copyio_preflight(addr64_t);
996 extern kern_return_t dtrace_copyio_postflight(addr64_t);
997
998 static int
dtrace_copycheck(user_addr_t uaddr,uintptr_t kaddr,size_t size)999 dtrace_copycheck(user_addr_t uaddr, uintptr_t kaddr, size_t size)
1000 {
1001 #pragma unused(kaddr)
1002
1003 vm_offset_t recover = dtrace_set_thread_recover( current_thread(), 0 ); /* Snare any extant recovery point. */
1004 dtrace_set_thread_recover( current_thread(), recover ); /* Put it back. We *must not* re-enter and overwrite. */
1005
1006 ASSERT(kaddr + size >= kaddr);
1007
1008 if (uaddr + size < uaddr || /* Avoid address wrap. */
1009 KERN_FAILURE == dtrace_copyio_preflight(uaddr)) { /* Machine specific setup/constraints. */
1010 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1011 cpu_core[CPU->cpu_id].cpuc_dtrace_illval = uaddr;
1012 return 0;
1013 }
1014 return 1;
1015 }
1016
1017 void
dtrace_copyin(user_addr_t src,uintptr_t dst,size_t len,volatile uint16_t * flags)1018 dtrace_copyin(user_addr_t src, uintptr_t dst, size_t len, volatile uint16_t *flags)
1019 {
1020 #pragma unused(flags)
1021
1022 if (dtrace_copycheck( src, dst, len )) {
1023 if (copyin((const user_addr_t)src, (char *)dst, (vm_size_t)len)) {
1024 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1025 cpu_core[CPU->cpu_id].cpuc_dtrace_illval = src;
1026 }
1027 dtrace_copyio_postflight(src);
1028 }
1029 }
1030
1031 void
dtrace_copyinstr(user_addr_t src,uintptr_t dst,size_t len,volatile uint16_t * flags)1032 dtrace_copyinstr(user_addr_t src, uintptr_t dst, size_t len, volatile uint16_t *flags)
1033 {
1034 #pragma unused(flags)
1035
1036 size_t actual;
1037
1038 if (dtrace_copycheck( src, dst, len )) {
1039 /* copyin as many as 'len' bytes. */
1040 int error = copyinstr((const user_addr_t)src, (char *)dst, (vm_size_t)len, &actual);
1041
1042 /*
1043 * ENAMETOOLONG is returned when 'len' bytes have been copied in but the NUL terminator was
1044 * not encountered. That does not require raising CPU_DTRACE_BADADDR, and we press on.
1045 * Note that we do *not* stuff a NUL terminator when returning ENAMETOOLONG, that's left
1046 * to the caller.
1047 */
1048 if (error && error != ENAMETOOLONG) {
1049 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1050 cpu_core[CPU->cpu_id].cpuc_dtrace_illval = src;
1051 }
1052 dtrace_copyio_postflight(src);
1053 }
1054 }
1055
1056 void
dtrace_copyout(uintptr_t src,user_addr_t dst,size_t len,volatile uint16_t * flags)1057 dtrace_copyout(uintptr_t src, user_addr_t dst, size_t len, volatile uint16_t *flags)
1058 {
1059 #pragma unused(flags)
1060
1061 if (dtrace_copycheck( dst, src, len )) {
1062 if (copyout((const void *)src, dst, (vm_size_t)len)) {
1063 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1064 cpu_core[CPU->cpu_id].cpuc_dtrace_illval = dst;
1065 }
1066 dtrace_copyio_postflight(dst);
1067 }
1068 }
1069
1070 void
dtrace_copyoutstr(uintptr_t src,user_addr_t dst,size_t len,volatile uint16_t * flags)1071 dtrace_copyoutstr(uintptr_t src, user_addr_t dst, size_t len, volatile uint16_t *flags)
1072 {
1073 #pragma unused(flags)
1074
1075 size_t actual;
1076
1077 if (dtrace_copycheck( dst, src, len )) {
1078 /*
1079 * ENAMETOOLONG is returned when 'len' bytes have been copied out but the NUL terminator was
1080 * not encountered. We raise CPU_DTRACE_BADADDR in that case.
1081 * Note that we do *not* stuff a NUL terminator when returning ENAMETOOLONG, that's left
1082 * to the caller.
1083 */
1084 if (copyoutstr((const void *)src, dst, (size_t)len, &actual)) {
1085 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1086 cpu_core[CPU->cpu_id].cpuc_dtrace_illval = dst;
1087 }
1088 dtrace_copyio_postflight(dst);
1089 }
1090 }
1091
1092 extern const int copysize_limit_panic;
1093
1094 int
dtrace_copy_maxsize(void)1095 dtrace_copy_maxsize(void)
1096 {
1097 return copysize_limit_panic;
1098 }
1099
1100
1101 int
dtrace_buffer_copyout(const void * kaddr,user_addr_t uaddr,vm_size_t nbytes)1102 dtrace_buffer_copyout(const void *kaddr, user_addr_t uaddr, vm_size_t nbytes)
1103 {
1104 int maxsize = dtrace_copy_maxsize();
1105 /*
1106 * Partition the copyout in copysize_limit_panic-sized chunks
1107 */
1108 while (nbytes >= (vm_size_t)maxsize) {
1109 if (copyout(kaddr, uaddr, maxsize) != 0) {
1110 return EFAULT;
1111 }
1112
1113 nbytes -= maxsize;
1114 uaddr += maxsize;
1115 kaddr = (const void *)((uintptr_t)kaddr + maxsize);
1116 }
1117 if (nbytes > 0) {
1118 if (copyout(kaddr, uaddr, nbytes) != 0) {
1119 return EFAULT;
1120 }
1121 }
1122
1123 return 0;
1124 }
1125
1126 uint8_t
dtrace_fuword8(user_addr_t uaddr)1127 dtrace_fuword8(user_addr_t uaddr)
1128 {
1129 uint8_t ret = 0;
1130
1131 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
1132 if (dtrace_copycheck( uaddr, (uintptr_t)&ret, sizeof(ret))) {
1133 if (copyin((const user_addr_t)uaddr, (char *)&ret, sizeof(ret))) {
1134 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1135 cpu_core[CPU->cpu_id].cpuc_dtrace_illval = uaddr;
1136 }
1137 dtrace_copyio_postflight(uaddr);
1138 }
1139 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
1140
1141 return ret;
1142 }
1143
1144 uint16_t
dtrace_fuword16(user_addr_t uaddr)1145 dtrace_fuword16(user_addr_t uaddr)
1146 {
1147 uint16_t ret = 0;
1148
1149 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
1150 if (dtrace_copycheck( uaddr, (uintptr_t)&ret, sizeof(ret))) {
1151 if (copyin((const user_addr_t)uaddr, (char *)&ret, sizeof(ret))) {
1152 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1153 cpu_core[CPU->cpu_id].cpuc_dtrace_illval = uaddr;
1154 }
1155 dtrace_copyio_postflight(uaddr);
1156 }
1157 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
1158
1159 return ret;
1160 }
1161
1162 uint32_t
dtrace_fuword32(user_addr_t uaddr)1163 dtrace_fuword32(user_addr_t uaddr)
1164 {
1165 uint32_t ret = 0;
1166
1167 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
1168 if (dtrace_copycheck( uaddr, (uintptr_t)&ret, sizeof(ret))) {
1169 if (copyin((const user_addr_t)uaddr, (char *)&ret, sizeof(ret))) {
1170 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1171 cpu_core[CPU->cpu_id].cpuc_dtrace_illval = uaddr;
1172 }
1173 dtrace_copyio_postflight(uaddr);
1174 }
1175 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
1176
1177 return ret;
1178 }
1179
1180 uint64_t
dtrace_fuword64(user_addr_t uaddr)1181 dtrace_fuword64(user_addr_t uaddr)
1182 {
1183 uint64_t ret = 0;
1184
1185 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
1186 if (dtrace_copycheck( uaddr, (uintptr_t)&ret, sizeof(ret))) {
1187 if (copyin((const user_addr_t)uaddr, (char *)&ret, sizeof(ret))) {
1188 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1189 cpu_core[CPU->cpu_id].cpuc_dtrace_illval = uaddr;
1190 }
1191 dtrace_copyio_postflight(uaddr);
1192 }
1193 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
1194
1195 return ret;
1196 }
1197
1198 /*
1199 * Emulation of Solaris fuword / suword
1200 * Called from the fasttrap provider, so the use of copyin/out requires fewer safegaurds.
1201 */
1202
1203 int
fuword8(user_addr_t uaddr,uint8_t * value)1204 fuword8(user_addr_t uaddr, uint8_t *value)
1205 {
1206 if (copyin((const user_addr_t)uaddr, (char *)value, sizeof(uint8_t)) != 0) {
1207 return -1;
1208 }
1209
1210 return 0;
1211 }
1212
1213 int
fuword16(user_addr_t uaddr,uint16_t * value)1214 fuword16(user_addr_t uaddr, uint16_t *value)
1215 {
1216 if (copyin((const user_addr_t)uaddr, (char *)value, sizeof(uint16_t)) != 0) {
1217 return -1;
1218 }
1219
1220 return 0;
1221 }
1222
1223 int
fuword32(user_addr_t uaddr,uint32_t * value)1224 fuword32(user_addr_t uaddr, uint32_t *value)
1225 {
1226 if (copyin((const user_addr_t)uaddr, (char *)value, sizeof(uint32_t)) != 0) {
1227 return -1;
1228 }
1229
1230 return 0;
1231 }
1232
1233 int
fuword64(user_addr_t uaddr,uint64_t * value)1234 fuword64(user_addr_t uaddr, uint64_t *value)
1235 {
1236 if (copyin((const user_addr_t)uaddr, (char *)value, sizeof(uint64_t)) != 0) {
1237 return -1;
1238 }
1239
1240 return 0;
1241 }
1242
1243 void
fuword32_noerr(user_addr_t uaddr,uint32_t * value)1244 fuword32_noerr(user_addr_t uaddr, uint32_t *value)
1245 {
1246 if (copyin((const user_addr_t)uaddr, (char *)value, sizeof(uint32_t))) {
1247 *value = 0;
1248 }
1249 }
1250
1251 void
fuword64_noerr(user_addr_t uaddr,uint64_t * value)1252 fuword64_noerr(user_addr_t uaddr, uint64_t *value)
1253 {
1254 if (copyin((const user_addr_t)uaddr, (char *)value, sizeof(uint64_t))) {
1255 *value = 0;
1256 }
1257 }
1258
1259 int
suword64(user_addr_t addr,uint64_t value)1260 suword64(user_addr_t addr, uint64_t value)
1261 {
1262 if (copyout((const void *)&value, addr, sizeof(value)) != 0) {
1263 return -1;
1264 }
1265
1266 return 0;
1267 }
1268
1269 int
suword32(user_addr_t addr,uint32_t value)1270 suword32(user_addr_t addr, uint32_t value)
1271 {
1272 if (copyout((const void *)&value, addr, sizeof(value)) != 0) {
1273 return -1;
1274 }
1275
1276 return 0;
1277 }
1278
1279 /*
1280 * Miscellaneous
1281 */
1282 extern boolean_t dtrace_tally_fault(user_addr_t);
1283
1284 boolean_t
dtrace_tally_fault(user_addr_t uaddr)1285 dtrace_tally_fault(user_addr_t uaddr)
1286 {
1287 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1288 cpu_core[CPU->cpu_id].cpuc_dtrace_illval = uaddr;
1289 return DTRACE_CPUFLAG_ISSET(CPU_DTRACE_NOFAULT) ? TRUE : FALSE;
1290 }
1291
1292 #define TOTTY 0x02
1293 extern int prf(const char *, va_list, int, struct tty *); /* bsd/kern/subr_prf.h */
1294
1295 int
vuprintf(const char * format,va_list ap)1296 vuprintf(const char *format, va_list ap)
1297 {
1298 return prf(format, ap, TOTTY, NULL);
1299 }
1300
1301 /* Not called from probe context */
1302 void
cmn_err(int level,const char * format,...)1303 cmn_err( int level, const char *format, ... )
1304 {
1305 #pragma unused(level)
1306 va_list alist;
1307
1308 va_start(alist, format);
1309 vuprintf(format, alist);
1310 va_end(alist);
1311 uprintf("\n");
1312 }
1313
1314 const void*
bsearch(const void * key,const void * base0,size_t nmemb,size_t size,int (* compar)(const void *,const void *))1315 bsearch(const void *key, const void *base0, size_t nmemb, size_t size, int (*compar)(const void *, const void *))
1316 {
1317 const char *base = base0;
1318 size_t lim;
1319 int cmp;
1320 const void *p;
1321 for (lim = nmemb; lim != 0; lim >>= 1) {
1322 p = base + (lim >> 1) * size;
1323 cmp = (*compar)(key, p);
1324 if (cmp == 0) {
1325 return p;
1326 }
1327 if (cmp > 0) { /* key > p: move right */
1328 base = (const char *)p + size;
1329 lim--;
1330 } /* else move left */
1331 }
1332 return NULL;
1333 }
1334
1335 /*
1336 * Runtime and ABI
1337 */
1338 uintptr_t
dtrace_caller(int ignore)1339 dtrace_caller(int ignore)
1340 {
1341 #pragma unused(ignore)
1342 return -1; /* Just as in Solaris dtrace_asm.s */
1343 }
1344
1345 int
dtrace_getstackdepth(int aframes)1346 dtrace_getstackdepth(int aframes)
1347 {
1348 struct frame *fp = (struct frame *)__builtin_frame_address(0);
1349 struct frame *nextfp, *minfp, *stacktop;
1350 int depth = 0;
1351 int on_intr;
1352
1353 if ((on_intr = CPU_ON_INTR(CPU)) != 0) {
1354 stacktop = (struct frame *)dtrace_get_cpu_int_stack_top();
1355 } else {
1356 stacktop = (struct frame *)(dtrace_get_kernel_stack(current_thread()) + kernel_stack_size);
1357 }
1358
1359 minfp = fp;
1360
1361 aframes++;
1362
1363 for (;;) {
1364 depth++;
1365
1366 nextfp = *(struct frame **)fp;
1367
1368 if (nextfp <= minfp || nextfp >= stacktop) {
1369 if (on_intr) {
1370 /*
1371 * Hop from interrupt stack to thread stack.
1372 */
1373 vm_offset_t kstack_base = dtrace_get_kernel_stack(current_thread());
1374
1375 minfp = (struct frame *)kstack_base;
1376 stacktop = (struct frame *)(kstack_base + kernel_stack_size);
1377
1378 on_intr = 0;
1379 continue;
1380 }
1381 break;
1382 }
1383
1384 fp = nextfp;
1385 minfp = fp;
1386 }
1387
1388 if (depth <= aframes) {
1389 return 0;
1390 }
1391
1392 return depth - aframes;
1393 }
1394
1395 int
dtrace_addr_in_module(void * addr,struct modctl * ctl)1396 dtrace_addr_in_module(void* addr, struct modctl *ctl)
1397 {
1398 return OSKextKextForAddress(addr) == (void*)ctl->mod_address;
1399 }
1400
1401 /*
1402 * Unconsidered
1403 */
1404 void
dtrace_vtime_enable(void)1405 dtrace_vtime_enable(void)
1406 {
1407 }
1408
1409 void
dtrace_vtime_disable(void)1410 dtrace_vtime_disable(void)
1411 {
1412 }
1413