]> git.saurik.com Git - apple/xnu.git/blame - bsd/dev/dtrace/fbt.c
xnu-4903.270.47.tar.gz
[apple/xnu.git] / bsd / dev / dtrace / fbt.c
CommitLineData
2d21ac55
A
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
b0d623f7
A
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
2d21ac55
A
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
6d2010ae 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
2d21ac55
A
23 * Use is subject to license terms.
24 */
25
b0d623f7 26/* #pragma ident "@(#)fbt.c 1.18 07/01/10 SMI" */
2d21ac55
A
27
28#ifdef KERNEL
29#ifndef _KERNEL
30#define _KERNEL /* Solaris vs. Darwin */
31#endif
32#endif
33
5ba3f43e 34#include <mach-o/loader.h>
b0d623f7 35#include <libkern/kernel_mach_header.h>
2d21ac55
A
36
37#include <sys/param.h>
38#include <sys/systm.h>
5ba3f43e 39#include <sys/sysctl.h>
2d21ac55
A
40#include <sys/errno.h>
41#include <sys/stat.h>
42#include <sys/ioctl.h>
43#include <sys/conf.h>
44#include <sys/fcntl.h>
45#include <miscfs/devfs/devfs.h>
46#include <pexpert/pexpert.h>
47
48#include <sys/dtrace.h>
49#include <sys/dtrace_impl.h>
50#include <sys/fbt.h>
51
52#include <sys/dtrace_glue.h>
a39ff7e2 53#include <san/kasan.h>
2d21ac55
A
54
55/* #include <machine/trap.h> */
56struct savearea_t; /* Used anonymously */
2d21ac55 57
5ba3f43e
A
58#if defined(__arm__) || defined(__arm64__)
59typedef kern_return_t (*perfCallback)(int, struct savearea_t *, __unused int, __unused int);
60extern perfCallback tempDTraceTrapHook;
61extern kern_return_t fbt_perfCallback(int, struct savearea_t *, __unused int, __unused int);
62#elif defined(__x86_64__)
39236c6e 63typedef kern_return_t (*perfCallback)(int, struct savearea_t *, uintptr_t *, __unused int);
2d21ac55 64extern perfCallback tempDTraceTrapHook;
39236c6e 65extern kern_return_t fbt_perfCallback(int, struct savearea_t *, uintptr_t *, __unused int);
fe8ab488
A
66#else
67#error Unknown architecture
68#endif
2d21ac55 69
d9a64523
A
70__private_extern__
71void
72qsort(void *a, size_t n, size_t es, int (*cmp)(const void *, const void *));
73
0a7de745
A
74#define FBT_ADDR2NDX(addr) ((((uintptr_t)(addr)) >> 4) & fbt_probetab_mask)
75#define FBT_PROBETAB_SIZE 0x8000 /* 32k entries -- 128K total */
2d21ac55 76
0a7de745
A
77static int fbt_probetab_size;
78dtrace_provider_id_t fbt_id;
79fbt_probe_t **fbt_probetab;
80int fbt_probetab_mask;
81static int fbt_verbose = 0;
2d21ac55 82
5ba3f43e
A
83int ignore_fbt_blacklist = 0;
84
85extern int dtrace_kernel_symbol_mode;
86
87
2d21ac55
A
88void fbt_init( void );
89
5ba3f43e
A
90/*
91 * Critical routines that must not be probed. PR_5221096, PR_5379018.
92 * The blacklist must be kept in alphabetic order for purposes of bsearch().
93 */
94static const char * critical_blacklist[] =
95{
96 "Call_DebuggerC",
d9a64523
A
97 "DebuggerCall",
98 "DebuggerTrapWithState",
99 "DebuggerXCallEnter",
100 "IOCPURunPlatformPanicActions",
101 "PEARMDebugPanicHook",
102 "PEHaltRestart",
103 "SavePanicInfo",
5ba3f43e
A
104 "SysChoked",
105 "_ZN9IOService14newTemperatureElPS_", /* IOService::newTemperature */
106 "_ZN9IOService26temperatureCriticalForZoneEPS_", /* IOService::temperatureCriticalForZone */
107 "_ZNK6OSData14getBytesNoCopyEv", /* Data::getBytesNoCopy, IOHibernateSystemWake path */
d9a64523
A
108 "__ZN16IOPlatformExpert11haltRestartEj",
109 "__ZN18IODTPlatformExpert11haltRestartEj",
0a7de745 110 "__ZN9IODTNVRAM13savePanicInfoEPhy",
5ba3f43e
A
111 "_disable_preemption",
112 "_enable_preemption",
d9a64523 113 "alternate_debugger_enter",
5ba3f43e
A
114 "bcopy_phys",
115 "console_cpu_alloc",
116 "console_cpu_free",
117 "cpu_IA32e_disable",
118 "cpu_IA32e_enable",
119 "cpu_NMI_interrupt",
120 "cpu_control",
121 "cpu_data_alloc",
122 "cpu_desc_init",
123 "cpu_desc_init64",
124 "cpu_desc_load",
125 "cpu_desc_load64",
126 "cpu_exit_wait",
127 "cpu_info",
128 "cpu_info_count",
129 "cpu_init",
130 "cpu_interrupt",
131 "cpu_machine_init",
132 "cpu_mode_init",
133 "cpu_processor_alloc",
134 "cpu_processor_free",
135 "cpu_signal_handler",
136 "cpu_sleep",
137 "cpu_start",
138 "cpu_subtype",
139 "cpu_thread_alloc",
140 "cpu_thread_halt",
141 "cpu_thread_init",
142 "cpu_threadtype",
143 "cpu_to_processor",
144 "cpu_topology_sort",
145 "cpu_topology_start_cpu",
146 "cpu_type",
147 "cpuid_cpu_display",
148 "cpuid_extfeatures",
149 "dtrace_invop",
150 "enter_lohandler",
151 "fbt_invop",
152 "fbt_perfCallback",
d9a64523 153 "get_preemption_level"
5ba3f43e
A
154 "get_threadtask",
155 "handle_pending_TLB_flushes",
156 "hw_compare_and_store",
157 "interrupt",
d9a64523
A
158 "is_saved_state32",
159 "kernel_preempt_check",
5ba3f43e
A
160 "kernel_trap",
161 "kprintf",
d9a64523
A
162 "ks_dispatch_kernel",
163 "ks_dispatch_user",
164 "ks_kernel_trap",
5ba3f43e
A
165 "lo_alltraps",
166 "lock_debugger",
167 "machine_idle_cstate",
168 "machine_thread_get_kern_state",
169 "mca_cpu_alloc",
170 "mca_cpu_init",
171 "ml_nofault_copy",
172 "nanoseconds_to_absolutetime",
173 "nanotime_to_absolutetime",
174 "packA",
175 "panic",
d9a64523
A
176 "phystokv",
177 "phystokv_range",
178 "pltrace",
5ba3f43e
A
179 "pmKextRegister",
180 "pmMarkAllCPUsOff",
181 "pmSafeMode",
182 "pmTimerRestore",
183 "pmTimerSave",
184 "pmUnRegister",
185 "pmap_cpu_alloc",
186 "pmap_cpu_free",
187 "pmap_cpu_high_map_vaddr",
188 "pmap_cpu_high_shared_remap",
189 "pmap_cpu_init",
190 "power_management_init",
191 "preemption_underflow_panic",
192 "register_cpu_setup_func",
d9a64523
A
193 "ret64_iret"
194 "ret_to_user"
195 "return_to_kernel",
196 "return_to_user",
197 "saved_state64",
5ba3f43e
A
198 "sdt_invop",
199 "sprlock",
200 "sprunlock",
d9a64523
A
201 "strlen",
202 "strncmp",
5ba3f43e
A
203 "t_invop",
204 "tmrCvt",
d9a64523
A
205 "trap_from_kernel",
206 "uart_putc",
5ba3f43e
A
207 "unlock_debugger",
208 "unpackA",
209 "unregister_cpu_setup_func",
d9a64523
A
210 "uread",
211 "uwrite",
5ba3f43e
A
212 "vstart"
213};
d9a64523 214
5ba3f43e
A
215#define CRITICAL_BLACKLIST_COUNT (sizeof(critical_blacklist)/sizeof(critical_blacklist[0]))
216
217/*
218 * The transitive closure of entry points that can be reached from probe context.
219 * (Apart from routines whose names begin with dtrace_).
220 */
221static const char * probe_ctx_closure[] =
222{
223 "ClearIdlePop",
224 "Debugger",
225 "IS_64BIT_PROCESS",
226 "OSCompareAndSwap",
227 "SetIdlePop",
d9a64523 228 "__dtrace_probe",
5ba3f43e
A
229 "absolutetime_to_microtime",
230 "act_set_astbsd",
231 "arm_init_idle_cpu",
232 "ast_dtrace_on",
233 "ast_pending",
234 "clean_dcache",
235 "clean_mmu_dcache",
236 "clock_get_calendar_nanotime_nowait",
237 "copyin",
238 "copyin_kern",
239 "copyin_user",
240 "copyinstr",
241 "copyout",
242 "copyoutstr",
243 "cpu_number",
244 "current_proc",
245 "current_processor",
246 "current_task",
247 "current_thread",
248 "debug_enter",
249 "drain_write_buffer",
250 "find_user_regs",
251 "flush_dcache",
252 "flush_tlb64",
253 "get_bsdtask_info",
254 "get_bsdthread_info",
255 "hertz_tick",
256 "hw_atomic_and",
257 "invalidate_mmu_icache",
258 "kauth_cred_get",
259 "kauth_getgid",
260 "kauth_getuid",
261 "kernel_preempt_check",
262 "kvtophys",
263 "mach_absolute_time",
264 "max_valid_stack_address",
265 "memcpy",
266 "memmove",
267 "ml_at_interrupt_context",
268 "ml_phys_write_byte_64",
269 "ml_phys_write_half_64",
270 "ml_phys_write_word_64",
271 "ml_set_interrupts_enabled",
272 "mt_core_snap",
273 "mt_cur_cpu_cycles",
274 "mt_cur_cpu_instrs",
275 "mt_cur_thread_cycles",
276 "mt_cur_thread_instrs",
277 "mt_fixed_counts",
278 "mt_fixed_counts_internal",
279 "mt_mtc_update_count",
280 "mt_update_thread",
281 "ovbcopy",
282 "panic",
5ba3f43e
A
283 "pmap64_pdpt",
284 "pmap_find_phys",
285 "pmap_get_mapwindow",
286 "pmap_pde",
0a7de745
A
287 "pmap_pde_internal0",
288 "pmap_pde_internal1",
5ba3f43e 289 "pmap_pte",
0a7de745 290 "pmap_pte_internal",
5ba3f43e
A
291 "pmap_put_mapwindow",
292 "pmap_valid_page",
293 "prf",
294 "proc_is64bit",
295 "proc_selfname",
296 "psignal_lock",
297 "rtc_nanotime_load",
298 "rtc_nanotime_read",
299 "sdt_getargdesc",
300 "setPop",
301 "strlcpy",
302 "sync_iss_to_iks_unconditionally",
303 "systrace_stub",
304 "timer_grab"
305};
306#define PROBE_CTX_CLOSURE_COUNT (sizeof(probe_ctx_closure)/sizeof(probe_ctx_closure[0]))
307
308#pragma clang diagnostic push
309#pragma clang diagnostic ignored "-Wcast-qual"
0a7de745
A
310static int
311_cmp(const void *a, const void *b)
5ba3f43e 312{
0a7de745 313 return strncmp((const char *)a, *(const char **)b, strlen((const char *)a) + 1);
5ba3f43e
A
314}
315#pragma clang diagnostic pop
316/*
317 * Module validation
318 */
319int
320fbt_module_excluded(struct modctl* ctl)
321{
322 ASSERT(!MOD_FBT_DONE(ctl));
323
324 if (ctl->mod_address == 0 || ctl->mod_size == 0) {
325 return TRUE;
326 }
d9a64523 327
5ba3f43e 328 if (ctl->mod_loaded == 0) {
0a7de745 329 return TRUE;
5ba3f43e
A
330 }
331
0a7de745 332 /*
5ba3f43e
A
333 * If the user sets this, trust they know what they are doing.
334 */
0a7de745 335 if (ignore_fbt_blacklist) {
5ba3f43e 336 return FALSE;
0a7de745 337 }
5ba3f43e
A
338
339 /*
340 * These drivers control low level functions that when traced
341 * cause problems often in the sleep/wake paths as well as
342 * critical debug and panic paths.
343 * If somebody really wants to drill in on one of these kexts, then
344 * they can override blacklisting using the boot-arg above.
345 */
346
347#ifdef __x86_64__
0a7de745 348 if (strstr(ctl->mod_modname, "AppleACPIEC") != NULL) {
5ba3f43e 349 return TRUE;
0a7de745 350 }
5ba3f43e 351
0a7de745 352 if (strstr(ctl->mod_modname, "AppleACPIPlatform") != NULL) {
5ba3f43e 353 return TRUE;
0a7de745 354 }
5ba3f43e 355
0a7de745 356 if (strstr(ctl->mod_modname, "AppleRTC") != NULL) {
5ba3f43e 357 return TRUE;
0a7de745 358 }
5ba3f43e 359
0a7de745 360 if (strstr(ctl->mod_modname, "IOACPIFamily") != NULL) {
5ba3f43e 361 return TRUE;
0a7de745 362 }
5ba3f43e 363
0a7de745 364 if (strstr(ctl->mod_modname, "AppleIntelCPUPowerManagement") != NULL) {
5ba3f43e 365 return TRUE;
0a7de745 366 }
5ba3f43e 367
0a7de745 368 if (strstr(ctl->mod_modname, "AppleProfile") != NULL) {
5ba3f43e 369 return TRUE;
0a7de745 370 }
5ba3f43e 371
0a7de745 372 if (strstr(ctl->mod_modname, "AppleIntelProfile") != NULL) {
5ba3f43e 373 return TRUE;
0a7de745 374 }
5ba3f43e 375
0a7de745 376 if (strstr(ctl->mod_modname, "AppleEFI") != NULL) {
5ba3f43e 377 return TRUE;
0a7de745 378 }
5ba3f43e
A
379
380#elif __arm__ || __arm64__
381 if (LIT_STRNEQL(ctl->mod_modname, "com.apple.driver.AppleARMPlatform") ||
0a7de745
A
382 LIT_STRNEQL(ctl->mod_modname, "com.apple.driver.AppleARMPL192VIC") ||
383 LIT_STRNEQL(ctl->mod_modname, "com.apple.driver.AppleInterruptController")) {
5ba3f43e 384 return TRUE;
0a7de745 385 }
5ba3f43e
A
386#endif
387
388 return FALSE;
389}
390
391/*
392 * FBT probe name validation
393 */
394int
395fbt_excluded(const char* name)
396{
397 /*
398 * If the user set this, trust they know what they are doing.
399 */
0a7de745 400 if (ignore_fbt_blacklist) {
5ba3f43e 401 return FALSE;
0a7de745 402 }
5ba3f43e
A
403
404 if (LIT_STRNSTART(name, "dtrace_") && !LIT_STRNSTART(name, "dtrace_safe_")) {
405 /*
406 * Anything beginning with "dtrace_" may be called
407 * from probe context unless it explitly indicates
408 * that it won't be called from probe context by
409 * using the prefix "dtrace_safe_".
410 */
411 return TRUE;
412 }
413
414 /*
0a7de745
A
415 * Place no probes on critical routines (5221096)
416 */
417 if (bsearch( name, critical_blacklist, CRITICAL_BLACKLIST_COUNT, sizeof(name), _cmp ) != NULL) {
5ba3f43e 418 return TRUE;
0a7de745 419 }
5ba3f43e
A
420
421 /*
0a7de745
A
422 * Place no probes that could be hit in probe context.
423 */
5ba3f43e
A
424 if (bsearch( name, probe_ctx_closure, PROBE_CTX_CLOSURE_COUNT, sizeof(name), _cmp ) != NULL) {
425 return TRUE;
426 }
427
428 /*
0a7de745
A
429 * Place no probes that could be hit in probe context.
430 * In the interests of safety, some of these may be overly cautious.
431 * Also exclude very low-level "firmware" class calls.
432 */
433 if (LIT_STRNSTART(name, "cpu_") || /* Coarse */
434 LIT_STRNSTART(name, "platform_") || /* Coarse */
435 LIT_STRNSTART(name, "machine_") || /* Coarse */
436 LIT_STRNSTART(name, "ml_") || /* Coarse */
437 LIT_STRNSTART(name, "PE_") || /* Coarse */
438 LIT_STRNSTART(name, "rtc_") || /* Coarse */
439 LIT_STRNSTART(name, "_rtc_") ||
440 LIT_STRNSTART(name, "rtclock_") ||
441 LIT_STRNSTART(name, "clock_") ||
442 LIT_STRNSTART(name, "bcopy") ||
443 LIT_STRNSTART(name, "pmap_") ||
444 LIT_STRNSTART(name, "hw_") || /* Coarse */
445 LIT_STRNSTART(name, "lapic_") || /* Coarse */
446 LIT_STRNSTART(name, "OSAdd") ||
447 LIT_STRNSTART(name, "OSBit") ||
448 LIT_STRNSTART(name, "OSDecrement") ||
449 LIT_STRNSTART(name, "OSIncrement") ||
450 LIT_STRNSTART(name, "OSCompareAndSwap") ||
451 LIT_STRNSTART(name, "etimer_") ||
452 LIT_STRNSTART(name, "dtxnu_kern_") ||
453 LIT_STRNSTART(name, "flush_mmu_tlb_")) {
5ba3f43e 454 return TRUE;
0a7de745 455 }
5ba3f43e
A
456 /*
457 * Fasttrap inner-workings we can't instrument
458 * on Intel (6230149)
0a7de745 459 */
5ba3f43e 460 if (LIT_STRNSTART(name, "fasttrap_") ||
0a7de745
A
461 LIT_STRNSTART(name, "fuword") ||
462 LIT_STRNSTART(name, "suword")) {
5ba3f43e 463 return TRUE;
0a7de745 464 }
5ba3f43e 465
0a7de745 466 if (LIT_STRNSTART(name, "_dtrace")) {
5ba3f43e 467 return TRUE; /* Shims in dtrace.c */
0a7de745
A
468 }
469 if (LIT_STRNSTART(name, "hibernate_")) {
5ba3f43e 470 return TRUE;
0a7de745 471 }
5ba3f43e
A
472
473 /*
474 * Place no probes in the exception handling path
475 */
476#if __arm__ || __arm64__
477 if (LIT_STRNSTART(name, "fleh_") ||
0a7de745
A
478 LIT_STRNSTART(name, "sleh_") ||
479 LIT_STRNSTART(name, "timer_state_event") ||
480 LIT_STRNEQL(name, "get_vfp_enabled")) {
5ba3f43e 481 return TRUE;
0a7de745 482 }
5ba3f43e
A
483
484 if (LIT_STRNSTART(name, "_ZNK15OSMetaClassBase8metaCastEPK11OSMetaClass") ||
0a7de745
A
485 LIT_STRNSTART(name, "_ZN15OSMetaClassBase12safeMetaCastEPKS_PK11OSMetaClass") ||
486 LIT_STRNSTART(name, "_ZNK11OSMetaClass13checkMetaCastEPK15OSMetaClassBase")) {
5ba3f43e 487 return TRUE;
0a7de745 488 }
5ba3f43e
A
489#endif
490
5ba3f43e
A
491#ifdef __x86_64__
492 if (LIT_STRNSTART(name, "machine_") ||
0a7de745
A
493 LIT_STRNSTART(name, "idt64") ||
494 LIT_STRNSTART(name, "ks_") ||
495 LIT_STRNSTART(name, "hndl_") ||
496 LIT_STRNSTART(name, "_intr_") ||
497 LIT_STRNSTART(name, "mapping_") ||
498 LIT_STRNSTART(name, "tsc_") ||
499 LIT_STRNSTART(name, "pmCPU") ||
500 LIT_STRNSTART(name, "pms") ||
501 LIT_STRNSTART(name, "usimple_") ||
502 LIT_STRNSTART(name, "lck_spin_lock") ||
503 LIT_STRNSTART(name, "lck_spin_unlock") ||
504 LIT_STRNSTART(name, "absolutetime_to_") ||
505 LIT_STRNSTART(name, "commpage_") ||
506 LIT_STRNSTART(name, "ml_") ||
507 LIT_STRNSTART(name, "PE_") ||
508 LIT_STRNSTART(name, "act_machine") ||
509 LIT_STRNSTART(name, "acpi_") ||
510 LIT_STRNSTART(name, "pal_")) {
5ba3f43e
A
511 return TRUE;
512 }
513 // Don't Steal Mac OS X
0a7de745 514 if (LIT_STRNSTART(name, "dsmos_")) {
5ba3f43e 515 return TRUE;
0a7de745 516 }
5ba3f43e
A
517
518#endif
519
520 /*
0a7de745
A
521 * Place no probes that could be hit on the way to the debugger.
522 */
5ba3f43e 523 if (LIT_STRNSTART(name, "kdp_") ||
0a7de745
A
524 LIT_STRNSTART(name, "kdb_") ||
525 LIT_STRNSTART(name, "debug_")) {
5ba3f43e
A
526 return TRUE;
527 }
528
a39ff7e2
A
529#if KASAN
530 if (LIT_STRNSTART(name, "kasan") ||
0a7de745
A
531 LIT_STRNSTART(name, "__kasan") ||
532 LIT_STRNSTART(name, "__asan")) {
a39ff7e2
A
533 return TRUE;
534 }
535#endif
536
5ba3f43e
A
537 /*
538 * Place no probes that could be hit on the way to a panic.
539 */
0a7de745 540 if (NULL != strstr(name, "panic_")) {
5ba3f43e 541 return TRUE;
0a7de745 542 }
5ba3f43e
A
543
544 return FALSE;
545}
546
547
2d21ac55
A
548/*ARGSUSED*/
549static void
550fbt_destroy(void *arg, dtrace_id_t id, void *parg)
551{
552#pragma unused(arg,id)
553 fbt_probe_t *fbt = parg, *next, *hash, *last;
554 int ndx;
555
556 do {
557 /*
558 * Now we need to remove this probe from the fbt_probetab.
559 */
560 ndx = FBT_ADDR2NDX(fbt->fbtp_patchpoint);
561 last = NULL;
562 hash = fbt_probetab[ndx];
563
564 while (hash != fbt) {
565 ASSERT(hash != NULL);
566 last = hash;
567 hash = hash->fbtp_hashnext;
568 }
569
570 if (last != NULL) {
571 last->fbtp_hashnext = fbt->fbtp_hashnext;
572 } else {
573 fbt_probetab[ndx] = fbt->fbtp_hashnext;
574 }
575
576 next = fbt->fbtp_next;
0a7de745 577 kmem_free(fbt, sizeof(fbt_probe_t));
2d21ac55
A
578
579 fbt = next;
580 } while (fbt != NULL);
581}
582
583/*ARGSUSED*/
6d2010ae 584int
2d21ac55
A
585fbt_enable(void *arg, dtrace_id_t id, void *parg)
586{
587#pragma unused(arg,id)
588 fbt_probe_t *fbt = parg;
6d2010ae
A
589 struct modctl *ctl = NULL;
590
0a7de745
A
591 for (; fbt != NULL; fbt = fbt->fbtp_next) {
592 ctl = fbt->fbtp_ctl;
2d21ac55 593
0a7de745
A
594 if (!ctl->mod_loaded) {
595 if (fbt_verbose) {
596 cmn_err(CE_NOTE, "fbt is failing for probe %s "
597 "(module %s unloaded)",
598 fbt->fbtp_name, ctl->mod_modname);
599 }
d9a64523 600
0a7de745 601 continue;
2d21ac55 602 }
6d2010ae 603
0a7de745
A
604 /*
605 * Now check that our modctl has the expected load count. If it
606 * doesn't, this module must have been unloaded and reloaded -- and
607 * we're not going to touch it.
608 */
609 if (ctl->mod_loadcnt != fbt->fbtp_loadcnt) {
610 if (fbt_verbose) {
611 cmn_err(CE_NOTE, "fbt is failing for probe %s "
612 "(module %s reloaded)",
613 fbt->fbtp_name, ctl->mod_modname);
614 }
6d2010ae 615
0a7de745 616 continue;
6d2010ae
A
617 }
618
0a7de745
A
619 dtrace_casptr(&tempDTraceTrapHook, NULL, fbt_perfCallback);
620 if (tempDTraceTrapHook != (perfCallback)fbt_perfCallback) {
621 if (fbt_verbose) {
622 cmn_err(CE_NOTE, "fbt_enable is failing for probe %s "
623 "in module %s: tempDTraceTrapHook already occupied.",
624 fbt->fbtp_name, ctl->mod_modname);
625 }
626 continue;
2d21ac55 627 }
2d21ac55 628
0a7de745 629 if (fbt->fbtp_currentval != fbt->fbtp_patchval) {
a39ff7e2 630#if KASAN
0a7de745
A
631 /* Since dtrace probes can call into KASan and vice versa, things can get
632 * very slow if we have a lot of probes. This call will disable the KASan
633 * fakestack after a threshold of probes is reached. */
634 kasan_fakestack_suspend();
a39ff7e2
A
635#endif
636
0a7de745
A
637 (void)ml_nofault_copy((vm_offset_t)&fbt->fbtp_patchval, (vm_offset_t)fbt->fbtp_patchpoint,
638 sizeof(fbt->fbtp_patchval));
639 /*
640 * Make the patched instruction visible via a data + instruction
641 * cache flush for the platforms that need it
642 */
643 flush_dcache((vm_offset_t)fbt->fbtp_patchpoint, (vm_size_t)sizeof(fbt->fbtp_patchval), 0);
644 invalidate_icache((vm_offset_t)fbt->fbtp_patchpoint, (vm_size_t)sizeof(fbt->fbtp_patchval), 0);
645 fbt->fbtp_currentval = fbt->fbtp_patchval;
39037602 646
0a7de745
A
647 ctl->mod_nenabled++;
648 }
6d2010ae
A
649 }
650
0a7de745 651 dtrace_membar_consumer();
d9a64523 652
0a7de745 653 return 0;
2d21ac55
A
654}
655
656/*ARGSUSED*/
657static void
658fbt_disable(void *arg, dtrace_id_t id, void *parg)
659{
660#pragma unused(arg,id)
661 fbt_probe_t *fbt = parg;
6d2010ae
A
662 struct modctl *ctl = NULL;
663
664 for (; fbt != NULL; fbt = fbt->fbtp_next) {
0a7de745 665 ctl = fbt->fbtp_ctl;
d9a64523 666
0a7de745
A
667 if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt)) {
668 continue;
669 }
2d21ac55 670
0a7de745
A
671 if (fbt->fbtp_currentval != fbt->fbtp_savedval) {
672 (void)ml_nofault_copy((vm_offset_t)&fbt->fbtp_savedval, (vm_offset_t)fbt->fbtp_patchpoint,
673 sizeof(fbt->fbtp_savedval));
674 /*
675 * Make the patched instruction visible via a data + instruction
676 * cache flush for the platforms that need it
677 */
678 flush_dcache((vm_offset_t)fbt->fbtp_patchpoint, (vm_size_t)sizeof(fbt->fbtp_patchval), 0);
679 invalidate_icache((vm_offset_t)fbt->fbtp_patchpoint, (vm_size_t)sizeof(fbt->fbtp_patchval), 0);
39037602 680
0a7de745
A
681 fbt->fbtp_currentval = fbt->fbtp_savedval;
682 ASSERT(ctl->mod_nenabled > 0);
683 ctl->mod_nenabled--;
a39ff7e2
A
684
685#if KASAN
0a7de745 686 kasan_fakestack_resume();
a39ff7e2 687#endif
0a7de745 688 }
6d2010ae 689 }
2d21ac55
A
690 dtrace_membar_consumer();
691}
692
693/*ARGSUSED*/
694static void
695fbt_suspend(void *arg, dtrace_id_t id, void *parg)
696{
697#pragma unused(arg,id)
698 fbt_probe_t *fbt = parg;
6d2010ae 699 struct modctl *ctl = NULL;
2d21ac55 700
6d2010ae 701 for (; fbt != NULL; fbt = fbt->fbtp_next) {
0a7de745 702 ctl = fbt->fbtp_ctl;
6d2010ae 703
0a7de745
A
704 ASSERT(ctl->mod_nenabled > 0);
705 if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt)) {
706 continue;
707 }
6d2010ae 708
0a7de745
A
709 (void)ml_nofault_copy((vm_offset_t)&fbt->fbtp_savedval, (vm_offset_t)fbt->fbtp_patchpoint,
710 sizeof(fbt->fbtp_savedval));
d9a64523 711
39037602
A
712 /*
713 * Make the patched instruction visible via a data + instruction
714 * cache flush for the platforms that need it
715 */
0a7de745
A
716 flush_dcache((vm_offset_t)fbt->fbtp_patchpoint, (vm_size_t)sizeof(fbt->fbtp_savedval), 0);
717 invalidate_icache((vm_offset_t)fbt->fbtp_patchpoint, (vm_size_t)sizeof(fbt->fbtp_savedval), 0);
d9a64523 718
39037602 719 fbt->fbtp_currentval = fbt->fbtp_savedval;
6d2010ae 720 }
d9a64523 721
2d21ac55
A
722 dtrace_membar_consumer();
723}
724
725/*ARGSUSED*/
726static void
727fbt_resume(void *arg, dtrace_id_t id, void *parg)
728{
729#pragma unused(arg,id)
730 fbt_probe_t *fbt = parg;
6d2010ae 731 struct modctl *ctl = NULL;
2d21ac55 732
6d2010ae 733 for (; fbt != NULL; fbt = fbt->fbtp_next) {
0a7de745
A
734 ctl = fbt->fbtp_ctl;
735
736 ASSERT(ctl->mod_nenabled > 0);
737 if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt)) {
738 continue;
2d21ac55 739 }
d9a64523 740
0a7de745
A
741 dtrace_casptr(&tempDTraceTrapHook, NULL, fbt_perfCallback);
742 if (tempDTraceTrapHook != (perfCallback)fbt_perfCallback) {
743 if (fbt_verbose) {
744 cmn_err(CE_NOTE, "fbt_resume is failing for probe %s "
745 "in module %s: tempDTraceTrapHook already occupied.",
746 fbt->fbtp_name, ctl->mod_modname);
747 }
748 return;
749 }
750
751 (void)ml_nofault_copy((vm_offset_t)&fbt->fbtp_patchval, (vm_offset_t)fbt->fbtp_patchpoint,
752 sizeof(fbt->fbtp_patchval));
39236c6e 753
5ba3f43e
A
754 /*
755 * Make the patched instruction visible via a data + instruction cache flush.
756 */
0a7de745
A
757 flush_dcache((vm_offset_t)fbt->fbtp_patchpoint, (vm_size_t)sizeof(fbt->fbtp_patchval), 0);
758 invalidate_icache((vm_offset_t)fbt->fbtp_patchpoint, (vm_size_t)sizeof(fbt->fbtp_patchval), 0);
2d21ac55 759
0a7de745 760 fbt->fbtp_currentval = fbt->fbtp_patchval;
2d21ac55 761 }
2d21ac55 762
d9a64523 763 dtrace_membar_consumer();
2d21ac55 764}
2d21ac55 765
5ba3f43e
A
766static void
767fbt_provide_module_user_syms(struct modctl *ctl)
768{
769 unsigned int i;
770 char *modname = ctl->mod_modname;
771
772 dtrace_module_symbols_t* module_symbols = ctl->mod_user_symbols;
773 if (module_symbols) {
0a7de745
A
774 for (i = 0; i < module_symbols->dtmodsyms_count; i++) {
775 /*
5ba3f43e
A
776 * symbol->dtsym_addr (the symbol address) passed in from
777 * user space, is already slid for both kexts and kernel.
778 */
779 dtrace_symbol_t* symbol = &module_symbols->dtmodsyms_symbols[i];
780
781 char* name = symbol->dtsym_name;
782
783 /* Lop off omnipresent leading underscore. */
0a7de745 784 if (*name == '_') {
5ba3f43e 785 name += 1;
0a7de745 786 }
5ba3f43e 787
0a7de745 788 if (MOD_IS_MACH_KERNEL(ctl) && fbt_excluded(name)) {
d9a64523 789 continue;
0a7de745 790 }
5ba3f43e
A
791
792 /*
793 * Ignore symbols with a null address
794 */
0a7de745 795 if (!symbol->dtsym_addr) {
5ba3f43e 796 continue;
0a7de745 797 }
5ba3f43e 798
d9a64523
A
799 /*
800 * Ignore symbols not part of this module
801 */
0a7de745 802 if (!dtrace_addr_in_module((void*)symbol->dtsym_addr, ctl)) {
d9a64523 803 continue;
0a7de745 804 }
d9a64523
A
805
806 fbt_provide_probe(ctl, modname, name, (machine_inst_t*)(uintptr_t)symbol->dtsym_addr, (machine_inst_t*)(uintptr_t)(symbol->dtsym_addr + symbol->dtsym_size));
5ba3f43e
A
807 }
808 }
809}
d9a64523
A
810static void
811fbt_provide_kernel_section(struct modctl *ctl, kernel_section_t *sect, kernel_nlist_t *sym, uint32_t nsyms, const char *strings)
812{
813 uintptr_t sect_start = (uintptr_t)sect->addr;
814 uintptr_t sect_end = (uintptr_t)sect->size + sect->addr;
815 unsigned int i;
816
817 if ((sect->flags & S_ATTR_PURE_INSTRUCTIONS) != S_ATTR_PURE_INSTRUCTIONS) {
818 return;
819 }
820
821 for (i = 0; i < nsyms; i++) {
822 uint8_t n_type = sym[i].n_type & (N_TYPE | N_EXT);
823 const char *name = strings + sym[i].n_un.n_strx;
824 uint64_t limit;
825
0a7de745 826 if (sym[i].n_value < sect_start || sym[i].n_value > sect_end) {
d9a64523 827 continue;
0a7de745 828 }
d9a64523
A
829
830 /* Check that the symbol is a global and that it has a name. */
0a7de745 831 if (((N_SECT | N_EXT) != n_type && (N_ABS | N_EXT) != n_type)) {
d9a64523 832 continue;
0a7de745 833 }
d9a64523 834
0a7de745 835 if (0 == sym[i].n_un.n_strx) { /* iff a null, "", name. */
d9a64523 836 continue;
0a7de745 837 }
d9a64523
A
838
839 /* Lop off omnipresent leading underscore. */
0a7de745 840 if (*name == '_') {
d9a64523 841 name += 1;
0a7de745 842 }
d9a64523
A
843
844#if defined(__arm__)
845 // Skip non-thumb functions on arm32
846 if (sym[i].n_sect == 1 && !(sym[i].n_desc & N_ARM_THUMB_DEF)) {
847 continue;
848 }
849#endif /* defined(__arm__) */
850
0a7de745 851 if (MOD_IS_MACH_KERNEL(ctl) && fbt_excluded(name)) {
d9a64523 852 continue;
0a7de745 853 }
d9a64523
A
854
855 /*
856 * Find the function boundary by looking at either the
857 * end of the section or the beginning of the next symbol
858 */
859 if (i == nsyms - 1) {
860 limit = sect_end;
0a7de745 861 } else {
d9a64523
A
862 limit = sym[i + 1].n_value;
863 }
864
865 fbt_provide_probe(ctl, ctl->mod_modname, name, (machine_inst_t*)sym[i].n_value, (machine_inst_t*)limit);
866 }
d9a64523
A
867}
868
869static int
870fbt_sym_cmp(const void *ap, const void *bp)
871{
872 return (int)(((const kernel_nlist_t*)ap)->n_value - ((const kernel_nlist_t*)bp)->n_value);
873}
874
875static void
876fbt_provide_module_kernel_syms(struct modctl *ctl)
877{
878 kernel_mach_header_t *mh = (kernel_mach_header_t *)(ctl->mod_address);
879 kernel_segment_command_t *seg;
880 struct load_command *cmd;
881 kernel_segment_command_t *linkedit = NULL;
882 struct symtab_command *symtab = NULL;
883 kernel_nlist_t *syms = NULL, *sorted_syms = NULL;
884 const char *strings;
885 unsigned int i;
886 size_t symlen;
887
0a7de745 888 if (mh->magic != MH_MAGIC_KERNEL) {
d9a64523 889 return;
0a7de745 890 }
d9a64523
A
891
892 cmd = (struct load_command *) &mh[1];
893 for (i = 0; i < mh->ncmds; i++) {
894 if (cmd->cmd == LC_SEGMENT_KERNEL) {
895 kernel_segment_command_t *orig_sg = (kernel_segment_command_t *) cmd;
0a7de745 896 if (LIT_STRNEQL(orig_sg->segname, SEG_LINKEDIT)) {
d9a64523 897 linkedit = orig_sg;
0a7de745 898 }
d9a64523
A
899 } else if (cmd->cmd == LC_SYMTAB) {
900 symtab = (struct symtab_command *) cmd;
901 }
902 if (symtab && linkedit) {
903 break;
904 }
905 cmd = (struct load_command *) ((caddr_t) cmd + cmd->cmdsize);
906 }
5ba3f43e 907
d9a64523
A
908 if ((symtab == NULL) || (linkedit == NULL)) {
909 return;
910 }
911
912 syms = (kernel_nlist_t *)(linkedit->vmaddr + symtab->symoff - linkedit->fileoff);
913 strings = (const char *)(linkedit->vmaddr + symtab->stroff - linkedit->fileoff);
914
915 /*
916 * Make a copy of the symbol table and sort it to not cross into the next function
917 * when disassembling the function
918 */
919 symlen = sizeof(kernel_nlist_t) * symtab->nsyms;
920 sorted_syms = kmem_alloc(symlen, KM_SLEEP);
921 bcopy(syms, sorted_syms, symlen);
922 qsort(sorted_syms, symtab->nsyms, sizeof(kernel_nlist_t), fbt_sym_cmp);
923
924 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
925 kernel_section_t *sect = firstsect(seg);
926
927 if (strcmp(seg->segname, "__KLD") == 0) {
928 continue;
929 }
930
931 for (sect = firstsect(seg); sect != NULL; sect = nextsect(seg, sect)) {
932 fbt_provide_kernel_section(ctl, sect, sorted_syms, symtab->nsyms, strings);
933 }
934 }
935
936 kmem_free(sorted_syms, symlen);
937}
5ba3f43e
A
938
939void
940fbt_provide_module(void *arg, struct modctl *ctl)
941{
942#pragma unused(arg)
943 ASSERT(ctl != NULL);
944 ASSERT(dtrace_kernel_symbol_mode != DTRACE_KERNEL_SYMBOLS_NEVER);
945 LCK_MTX_ASSERT(&mod_lock, LCK_MTX_ASSERT_OWNED);
946
947 // Update the "ignore blacklist" bit
0a7de745 948 if (ignore_fbt_blacklist) {
5ba3f43e 949 ctl->mod_flags |= MODCTL_FBT_PROVIDE_BLACKLISTED_PROBES;
0a7de745 950 }
5ba3f43e 951
0a7de745 952 if (MOD_FBT_DONE(ctl)) {
5ba3f43e 953 return;
0a7de745 954 }
5ba3f43e
A
955
956 if (fbt_module_excluded(ctl)) {
957 ctl->mod_flags |= MODCTL_FBT_INVALID;
958 return;
959 }
960
961 if (MOD_HAS_KERNEL_SYMBOLS(ctl)) {
962 fbt_provide_module_kernel_syms(ctl);
963 ctl->mod_flags |= MODCTL_FBT_PROBES_PROVIDED;
0a7de745 964 if (MOD_FBT_PROVIDE_BLACKLISTED_PROBES(ctl)) {
5ba3f43e 965 ctl->mod_flags |= MODCTL_FBT_BLACKLISTED_PROBES_PROVIDED;
0a7de745 966 }
5ba3f43e
A
967 return;
968 }
969
970 if (MOD_HAS_USERSPACE_SYMBOLS(ctl)) {
971 fbt_provide_module_user_syms(ctl);
972 ctl->mod_flags |= MODCTL_FBT_PROBES_PROVIDED;
0a7de745 973 if (MOD_FBT_PROVIDE_PRIVATE_PROBES(ctl)) {
5ba3f43e 974 ctl->mod_flags |= MODCTL_FBT_PRIVATE_PROBES_PROVIDED;
0a7de745
A
975 }
976 if (MOD_FBT_PROVIDE_BLACKLISTED_PROBES(ctl)) {
5ba3f43e 977 ctl->mod_flags |= MODCTL_FBT_BLACKLISTED_PROBES_PROVIDED;
0a7de745 978 }
5ba3f43e
A
979 return;
980 }
981}
982
2d21ac55 983static dtrace_pattr_t fbt_attr = {
0a7de745
A
984 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
985 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
986 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
987 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
988 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
2d21ac55
A
989};
990
991static dtrace_pops_t fbt_pops = {
0a7de745
A
992 .dtps_provide = NULL,
993 .dtps_provide_module = fbt_provide_module,
994 .dtps_enable = fbt_enable,
995 .dtps_disable = fbt_disable,
996 .dtps_suspend = fbt_suspend,
997 .dtps_resume = fbt_resume,
998 .dtps_getargdesc = NULL, /* APPLE NOTE: fbt_getargdesc implemented in userspace */
999 .dtps_getargval = NULL,
1000 .dtps_usermode = NULL,
1001 .dtps_destroy = fbt_destroy
2d21ac55
A
1002};
1003
1004static void
1005fbt_cleanup(dev_info_t *devi)
1006{
1007 dtrace_invop_remove(fbt_invop);
1008 ddi_remove_minor_node(devi, NULL);
0a7de745 1009 kmem_free(fbt_probetab, fbt_probetab_size * sizeof(fbt_probe_t *));
2d21ac55
A
1010 fbt_probetab = NULL;
1011 fbt_probetab_mask = 0;
1012}
1013
1014static int
d9a64523 1015fbt_attach(dev_info_t *devi)
2d21ac55 1016{
0a7de745 1017 if (fbt_probetab_size == 0) {
2d21ac55 1018 fbt_probetab_size = FBT_PROBETAB_SIZE;
0a7de745 1019 }
2d21ac55
A
1020
1021 fbt_probetab_mask = fbt_probetab_size - 1;
1022 fbt_probetab =
0a7de745 1023 kmem_zalloc(fbt_probetab_size * sizeof(fbt_probe_t *), KM_SLEEP);
2d21ac55
A
1024
1025 dtrace_invop_add(fbt_invop);
1026
b0d623f7
A
1027 if (ddi_create_minor_node(devi, "fbt", S_IFCHR, 0,
1028 DDI_PSEUDO, 0) == DDI_FAILURE ||
1029 dtrace_register("fbt", &fbt_attr, DTRACE_PRIV_KERNEL, NULL,
1030 &fbt_pops, NULL, &fbt_id) != 0) {
1031 fbt_cleanup(devi);
0a7de745 1032 return DDI_FAILURE;
b0d623f7 1033 }
2d21ac55 1034
0a7de745 1035 return DDI_SUCCESS;
2d21ac55
A
1036}
1037
1038static d_open_t _fbt_open;
1039
1040static int
1041_fbt_open(dev_t dev, int flags, int devtype, struct proc *p)
1042{
1043#pragma unused(dev,flags,devtype,p)
1044 return 0;
1045}
1046
1047#define FBT_MAJOR -24 /* let the kernel pick the device number */
1048
5ba3f43e
A
1049SYSCTL_DECL(_kern_dtrace);
1050
1051static int
1052sysctl_dtrace_ignore_fbt_blacklist SYSCTL_HANDLER_ARGS
1053{
1054#pragma unused(oidp, arg2)
1055 int err;
1056 int value = *(int*)arg1;
1057
1058 err = sysctl_io_number(req, value, sizeof(value), &value, NULL);
0a7de745
A
1059 if (err) {
1060 return err;
1061 }
5ba3f43e 1062 if (req->newptr) {
0a7de745
A
1063 if (!(value == 0 || value == 1)) {
1064 return ERANGE;
1065 }
5ba3f43e
A
1066
1067 /*
1068 * We do not allow setting the blacklist back to on, as we have no way
1069 * of knowing if those unsafe probes are still used.
1070 *
1071 * If we are using kernel symbols, we also do not allow any change,
1072 * since the symbols are jettison'd after the first pass.
1073 *
1074 * We do not need to take any locks here because those symbol modes
1075 * are permanent and do not change after boot.
1076 */
1077 if (value != 1 || dtrace_kernel_symbol_mode == DTRACE_KERNEL_SYMBOLS_NEVER ||
0a7de745
A
1078 dtrace_kernel_symbol_mode == DTRACE_KERNEL_SYMBOLS_ALWAYS_FROM_KERNEL) {
1079 return EPERM;
1080 }
5ba3f43e
A
1081
1082 ignore_fbt_blacklist = 1;
1083 }
1084
0a7de745 1085 return 0;
5ba3f43e
A
1086}
1087
1088SYSCTL_PROC(_kern_dtrace, OID_AUTO, ignore_fbt_blacklist,
0a7de745
A
1089 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
1090 &ignore_fbt_blacklist, 0,
1091 sysctl_dtrace_ignore_fbt_blacklist, "I", "fbt provider ignore blacklist");
5ba3f43e 1092
2d21ac55
A
1093/*
1094 * A struct describing which functions will get invoked for certain
1095 * actions.
1096 */
1097static struct cdevsw fbt_cdevsw =
1098{
0a7de745
A
1099 _fbt_open, /* open */
1100 eno_opcl, /* close */
1101 eno_rdwrt, /* read */
1102 eno_rdwrt, /* write */
1103 eno_ioctl, /* ioctl */
2d21ac55
A
1104 (stop_fcn_t *)nulldev, /* stop */
1105 (reset_fcn_t *)nulldev, /* reset */
0a7de745
A
1106 NULL, /* tty's */
1107 eno_select, /* select */
1108 eno_mmap, /* mmap */
1109 eno_strat, /* strategy */
1110 eno_getc, /* getc */
1111 eno_putc, /* putc */
1112 0 /* type */
2d21ac55
A
1113};
1114
2d21ac55
A
1115#undef kmem_alloc /* from its binding to dt_kmem_alloc glue */
1116#undef kmem_free /* from its binding to dt_kmem_free glue */
1117#include <vm/vm_kern.h>
1118
1119void
1120fbt_init( void )
1121{
d9a64523 1122 int majdevno = cdevsw_add(FBT_MAJOR, &fbt_cdevsw);
2d21ac55 1123
d9a64523
A
1124 if (majdevno < 0) {
1125 printf("fbt_init: failed to allocate a major number!\n");
1126 return;
2d21ac55 1127 }
d9a64523 1128
0a7de745 1129 PE_parse_boot_argn("IgnoreFBTBlacklist", &ignore_fbt_blacklist, sizeof(ignore_fbt_blacklist));
d9a64523
A
1130
1131 fbt_attach((dev_info_t*)(uintptr_t)majdevno);
2d21ac55
A
1132}
1133#undef FBT_MAJOR