* Use is subject to license terms.
*/
-/* #pragma ident "@(#)fbt.c 1.18 07/01/10 SMI" */
-
-#ifdef KERNEL
-#ifndef _KERNEL
-#define _KERNEL /* Solaris vs. Darwin */
-#endif
-#endif
-
#include <mach-o/loader.h>
#include <libkern/kernel_mach_header.h>
#include <sys/dtrace_glue.h>
#include <san/kasan.h>
+#include <ptrauth.h>
+
/* #include <machine/trap.h> */
struct savearea_t; /* Used anonymously */
void
qsort(void *a, size_t n, size_t es, int (*cmp)(const void *, const void *));
-#define FBT_ADDR2NDX(addr) ((((uintptr_t)(addr)) >> 4) & fbt_probetab_mask)
-#define FBT_PROBETAB_SIZE 0x8000 /* 32k entries -- 128K total */
+#define FBT_ADDR2NDX(addr) ((((uintptr_t)(addr)) >> 4) & fbt_probetab_mask)
+#define FBT_PROBETAB_SIZE 0x8000 /* 32k entries -- 128K total */
-static int fbt_probetab_size;
-dtrace_provider_id_t fbt_id;
-fbt_probe_t **fbt_probetab;
-int fbt_probetab_mask;
-static int fbt_verbose = 0;
+static int fbt_probetab_size;
+dtrace_provider_id_t fbt_id;
+fbt_probe_t **fbt_probetab;
+int fbt_probetab_mask;
+static int fbt_verbose = 0;
-int ignore_fbt_blacklist = 0;
+extern int ignore_fbt_blacklist;
extern int dtrace_kernel_symbol_mode;
void fbt_init( void );
-/*
- * Critical routines that must not be probed. PR_5221096, PR_5379018.
- * The blacklist must be kept in alphabetic order for purposes of bsearch().
- */
-static const char * critical_blacklist[] =
-{
- "Call_DebuggerC",
- "DebuggerCall",
- "DebuggerTrapWithState",
- "DebuggerXCallEnter",
- "IOCPURunPlatformPanicActions",
- "PEARMDebugPanicHook",
- "PEHaltRestart",
- "SavePanicInfo",
- "SysChoked",
- "_ZN9IOService14newTemperatureElPS_", /* IOService::newTemperature */
- "_ZN9IOService26temperatureCriticalForZoneEPS_", /* IOService::temperatureCriticalForZone */
- "_ZNK6OSData14getBytesNoCopyEv", /* Data::getBytesNoCopy, IOHibernateSystemWake path */
- "__ZN16IOPlatformExpert11haltRestartEj",
- "__ZN18IODTPlatformExpert11haltRestartEj",
- "__ZN9IODTNVRAM13savePanicInfoEPhy"
- "_disable_preemption",
- "_enable_preemption",
- "alternate_debugger_enter",
- "bcopy_phys",
- "console_cpu_alloc",
- "console_cpu_free",
- "cpu_IA32e_disable",
- "cpu_IA32e_enable",
- "cpu_NMI_interrupt",
- "cpu_control",
- "cpu_data_alloc",
- "cpu_desc_init",
- "cpu_desc_init64",
- "cpu_desc_load",
- "cpu_desc_load64",
- "cpu_exit_wait",
- "cpu_info",
- "cpu_info_count",
- "cpu_init",
- "cpu_interrupt",
- "cpu_machine_init",
- "cpu_mode_init",
- "cpu_processor_alloc",
- "cpu_processor_free",
- "cpu_signal_handler",
- "cpu_sleep",
- "cpu_start",
- "cpu_subtype",
- "cpu_thread_alloc",
- "cpu_thread_halt",
- "cpu_thread_init",
- "cpu_threadtype",
- "cpu_to_processor",
- "cpu_topology_sort",
- "cpu_topology_start_cpu",
- "cpu_type",
- "cpuid_cpu_display",
- "cpuid_extfeatures",
- "dtrace_invop",
- "enter_lohandler",
- "fbt_invop",
- "fbt_perfCallback",
- "get_preemption_level"
- "get_threadtask",
- "handle_pending_TLB_flushes",
- "hw_compare_and_store",
- "interrupt",
- "is_saved_state32",
- "kernel_preempt_check",
- "kernel_trap",
- "kprintf",
- "ks_dispatch_kernel",
- "ks_dispatch_user",
- "ks_kernel_trap",
- "lo_alltraps",
- "lock_debugger",
- "machine_idle_cstate",
- "machine_thread_get_kern_state",
- "mca_cpu_alloc",
- "mca_cpu_init",
- "ml_nofault_copy",
- "nanoseconds_to_absolutetime",
- "nanotime_to_absolutetime",
- "packA",
- "panic",
- "phystokv",
- "phystokv_range",
- "pltrace",
- "pmKextRegister",
- "pmMarkAllCPUsOff",
- "pmSafeMode",
- "pmTimerRestore",
- "pmTimerSave",
- "pmUnRegister",
- "pmap_cpu_alloc",
- "pmap_cpu_free",
- "pmap_cpu_high_map_vaddr",
- "pmap_cpu_high_shared_remap",
- "pmap_cpu_init",
- "power_management_init",
- "preemption_underflow_panic",
- "register_cpu_setup_func",
- "ret64_iret"
- "ret_to_user"
- "return_to_kernel",
- "return_to_user",
- "saved_state64",
- "sdt_invop",
- "sprlock",
- "sprunlock",
- "strlen",
- "strncmp",
- "t_invop",
- "tmrCvt",
- "trap_from_kernel",
- "uart_putc",
- "unlock_debugger",
- "unpackA",
- "unregister_cpu_setup_func",
- "uread",
- "uwrite",
- "vstart"
-};
-
-#define CRITICAL_BLACKLIST_COUNT (sizeof(critical_blacklist)/sizeof(critical_blacklist[0]))
-
-/*
- * The transitive closure of entry points that can be reached from probe context.
- * (Apart from routines whose names begin with dtrace_).
- */
-static const char * probe_ctx_closure[] =
-{
- "ClearIdlePop",
- "Debugger",
- "IS_64BIT_PROCESS",
- "OSCompareAndSwap",
- "SetIdlePop",
- "__dtrace_probe",
- "absolutetime_to_microtime",
- "act_set_astbsd",
- "arm_init_idle_cpu",
- "ast_dtrace_on",
- "ast_pending",
- "clean_dcache",
- "clean_mmu_dcache",
- "clock_get_calendar_nanotime_nowait",
- "copyin",
- "copyin_kern",
- "copyin_user",
- "copyinstr",
- "copyout",
- "copyoutstr",
- "cpu_number",
- "current_proc",
- "current_processor",
- "current_task",
- "current_thread",
- "debug_enter",
- "drain_write_buffer",
- "find_user_regs",
- "flush_dcache",
- "flush_tlb64",
- "get_bsdtask_info",
- "get_bsdthread_info",
- "hertz_tick",
- "hw_atomic_and",
- "invalidate_mmu_icache",
- "kauth_cred_get",
- "kauth_getgid",
- "kauth_getuid",
- "kernel_preempt_check",
- "kvtophys",
- "mach_absolute_time",
- "max_valid_stack_address",
- "memcpy",
- "memmove",
- "ml_at_interrupt_context",
- "ml_phys_write_byte_64",
- "ml_phys_write_half_64",
- "ml_phys_write_word_64",
- "ml_set_interrupts_enabled",
- "mt_core_snap",
- "mt_cur_cpu_cycles",
- "mt_cur_cpu_instrs",
- "mt_cur_thread_cycles",
- "mt_cur_thread_instrs",
- "mt_fixed_counts",
- "mt_fixed_counts_internal",
- "mt_mtc_update_count",
- "mt_update_thread",
- "ovbcopy",
- "panic",
- "pmap64_pde",
- "pmap64_pdpt",
- "pmap_find_phys",
- "pmap_get_mapwindow",
- "pmap_pde",
- "pmap_pte",
- "pmap_put_mapwindow",
- "pmap_valid_page",
- "prf",
- "proc_is64bit",
- "proc_selfname",
- "psignal_lock",
- "rtc_nanotime_load",
- "rtc_nanotime_read",
- "sdt_getargdesc",
- "setPop",
- "strlcpy",
- "sync_iss_to_iks_unconditionally",
- "systrace_stub",
- "timer_grab"
-};
-#define PROBE_CTX_CLOSURE_COUNT (sizeof(probe_ctx_closure)/sizeof(probe_ctx_closure[0]))
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wcast-qual"
-static int _cmp(const void *a, const void *b)
-{
- return strncmp((const char *)a, *(const char **)b, strlen((const char *)a) + 1);
-}
-#pragma clang diagnostic pop
-/*
- * Module validation
- */
-int
-fbt_module_excluded(struct modctl* ctl)
-{
- ASSERT(!MOD_FBT_DONE(ctl));
-
- if (ctl->mod_address == 0 || ctl->mod_size == 0) {
- return TRUE;
- }
-
- if (ctl->mod_loaded == 0) {
- return TRUE;
- }
-
- /*
- * If the user sets this, trust they know what they are doing.
- */
- if (ignore_fbt_blacklist)
- return FALSE;
-
- /*
- * These drivers control low level functions that when traced
- * cause problems often in the sleep/wake paths as well as
- * critical debug and panic paths.
- * If somebody really wants to drill in on one of these kexts, then
- * they can override blacklisting using the boot-arg above.
- */
-
-#ifdef __x86_64__
- if (strstr(ctl->mod_modname, "AppleACPIEC") != NULL)
- return TRUE;
-
- if (strstr(ctl->mod_modname, "AppleACPIPlatform") != NULL)
- return TRUE;
-
- if (strstr(ctl->mod_modname, "AppleRTC") != NULL)
- return TRUE;
-
- if (strstr(ctl->mod_modname, "IOACPIFamily") != NULL)
- return TRUE;
-
- if (strstr(ctl->mod_modname, "AppleIntelCPUPowerManagement") != NULL)
- return TRUE;
-
- if (strstr(ctl->mod_modname, "AppleProfile") != NULL)
- return TRUE;
-
- if (strstr(ctl->mod_modname, "AppleIntelProfile") != NULL)
- return TRUE;
-
- if (strstr(ctl->mod_modname, "AppleEFI") != NULL)
- return TRUE;
-
-#elif __arm__ || __arm64__
- if (LIT_STRNEQL(ctl->mod_modname, "com.apple.driver.AppleARMPlatform") ||
- LIT_STRNEQL(ctl->mod_modname, "com.apple.driver.AppleARMPL192VIC") ||
- LIT_STRNEQL(ctl->mod_modname, "com.apple.driver.AppleInterruptController"))
- return TRUE;
-#endif
-
- return FALSE;
-}
-
-/*
- * FBT probe name validation
- */
-int
-fbt_excluded(const char* name)
-{
- /*
- * If the user set this, trust they know what they are doing.
- */
- if (ignore_fbt_blacklist)
- return FALSE;
-
- if (LIT_STRNSTART(name, "dtrace_") && !LIT_STRNSTART(name, "dtrace_safe_")) {
- /*
- * Anything beginning with "dtrace_" may be called
- * from probe context unless it explitly indicates
- * that it won't be called from probe context by
- * using the prefix "dtrace_safe_".
- */
- return TRUE;
- }
-
- /*
- * Place no probes on critical routines (5221096)
- */
- if (bsearch( name, critical_blacklist, CRITICAL_BLACKLIST_COUNT, sizeof(name), _cmp ) != NULL)
- return TRUE;
-
- /*
- * Place no probes that could be hit in probe context.
- */
- if (bsearch( name, probe_ctx_closure, PROBE_CTX_CLOSURE_COUNT, sizeof(name), _cmp ) != NULL) {
- return TRUE;
- }
-
- /*
- * Place no probes that could be hit in probe context.
- * In the interests of safety, some of these may be overly cautious.
- * Also exclude very low-level "firmware" class calls.
- */
- if (LIT_STRNSTART(name, "cpu_") || /* Coarse */
- LIT_STRNSTART(name, "platform_") || /* Coarse */
- LIT_STRNSTART(name, "machine_") || /* Coarse */
- LIT_STRNSTART(name, "ml_") || /* Coarse */
- LIT_STRNSTART(name, "PE_") || /* Coarse */
- LIT_STRNSTART(name, "rtc_") || /* Coarse */
- LIT_STRNSTART(name, "_rtc_") ||
- LIT_STRNSTART(name, "rtclock_") ||
- LIT_STRNSTART(name, "clock_") ||
- LIT_STRNSTART(name, "bcopy") ||
- LIT_STRNSTART(name, "pmap_") ||
- LIT_STRNSTART(name, "hw_") || /* Coarse */
- LIT_STRNSTART(name, "lapic_") || /* Coarse */
- LIT_STRNSTART(name, "OSAdd") ||
- LIT_STRNSTART(name, "OSBit") ||
- LIT_STRNSTART(name, "OSDecrement") ||
- LIT_STRNSTART(name, "OSIncrement") ||
- LIT_STRNSTART(name, "OSCompareAndSwap") ||
- LIT_STRNSTART(name, "etimer_") ||
- LIT_STRNSTART(name, "dtxnu_kern_") ||
- LIT_STRNSTART(name, "flush_mmu_tlb_"))
- return TRUE;
- /*
- * Fasttrap inner-workings we can't instrument
- * on Intel (6230149)
- */
- if (LIT_STRNSTART(name, "fasttrap_") ||
- LIT_STRNSTART(name, "fuword") ||
- LIT_STRNSTART(name, "suword"))
- return TRUE;
-
- if (LIT_STRNSTART(name, "_dtrace"))
- return TRUE; /* Shims in dtrace.c */
-
- if (LIT_STRNSTART(name, "hibernate_"))
- return TRUE;
-
- /*
- * Place no probes in the exception handling path
- */
-#if __arm__ || __arm64__
- if (LIT_STRNSTART(name, "fleh_") ||
- LIT_STRNSTART(name, "sleh_") ||
- LIT_STRNSTART(name, "timer_state_event") ||
- LIT_STRNEQL(name, "get_vfp_enabled"))
- return TRUE;
-
- if (LIT_STRNSTART(name, "_ZNK15OSMetaClassBase8metaCastEPK11OSMetaClass") ||
- LIT_STRNSTART(name, "_ZN15OSMetaClassBase12safeMetaCastEPKS_PK11OSMetaClass") ||
- LIT_STRNSTART(name, "_ZNK11OSMetaClass13checkMetaCastEPK15OSMetaClassBase"))
- return TRUE;
-#endif
-
-#ifdef __x86_64__
- if (LIT_STRNSTART(name, "machine_") ||
- LIT_STRNSTART(name, "idt64") ||
- LIT_STRNSTART(name, "ks_") ||
- LIT_STRNSTART(name, "hndl_") ||
- LIT_STRNSTART(name, "_intr_") ||
- LIT_STRNSTART(name, "mapping_") ||
- LIT_STRNSTART(name, "tsc_") ||
- LIT_STRNSTART(name, "pmCPU") ||
- LIT_STRNSTART(name, "pms") ||
- LIT_STRNSTART(name, "usimple_") ||
- LIT_STRNSTART(name, "lck_spin_lock") ||
- LIT_STRNSTART(name, "lck_spin_unlock") ||
- LIT_STRNSTART(name, "absolutetime_to_") ||
- LIT_STRNSTART(name, "commpage_") ||
- LIT_STRNSTART(name, "ml_") ||
- LIT_STRNSTART(name, "PE_") ||
- LIT_STRNSTART(name, "act_machine") ||
- LIT_STRNSTART(name, "acpi_") ||
- LIT_STRNSTART(name, "pal_")) {
- return TRUE;
- }
- // Don't Steal Mac OS X
- if (LIT_STRNSTART(name, "dsmos_"))
- return TRUE;
-
-#endif
-
- /*
- * Place no probes that could be hit on the way to the debugger.
- */
- if (LIT_STRNSTART(name, "kdp_") ||
- LIT_STRNSTART(name, "kdb_") ||
- LIT_STRNSTART(name, "debug_")) {
- return TRUE;
- }
-
-#if KASAN
- if (LIT_STRNSTART(name, "kasan") ||
- LIT_STRNSTART(name, "__kasan") ||
- LIT_STRNSTART(name, "__asan")) {
- return TRUE;
- }
-#endif
-
- /*
- * Place no probes that could be hit on the way to a panic.
- */
- if (NULL != strstr(name, "panic_"))
- return TRUE;
-
- return FALSE;
-}
-
-
/*ARGSUSED*/
static void
fbt_destroy(void *arg, dtrace_id_t id, void *parg)
}
next = fbt->fbtp_next;
- kmem_free(fbt, sizeof (fbt_probe_t));
+ kmem_free(fbt, sizeof(fbt_probe_t));
fbt = next;
} while (fbt != NULL);
fbt_probe_t *fbt = parg;
struct modctl *ctl = NULL;
- for (; fbt != NULL; fbt = fbt->fbtp_next) {
+ for (; fbt != NULL; fbt = fbt->fbtp_next) {
+ ctl = fbt->fbtp_ctl;
- ctl = fbt->fbtp_ctl;
+ if (!ctl->mod_loaded) {
+ if (fbt_verbose) {
+ cmn_err(CE_NOTE, "fbt is failing for probe %s "
+ "(module %s unloaded)",
+ fbt->fbtp_name, ctl->mod_modname);
+ }
- if (!ctl->mod_loaded) {
- if (fbt_verbose) {
- cmn_err(CE_NOTE, "fbt is failing for probe %s "
- "(module %s unloaded)",
- fbt->fbtp_name, ctl->mod_modname);
+ continue;
}
- continue;
- }
+ /*
+ * Now check that our modctl has the expected load count. If it
+ * doesn't, this module must have been unloaded and reloaded -- and
+ * we're not going to touch it.
+ */
+ if (ctl->mod_loadcnt != fbt->fbtp_loadcnt) {
+ if (fbt_verbose) {
+ cmn_err(CE_NOTE, "fbt is failing for probe %s "
+ "(module %s reloaded)",
+ fbt->fbtp_name, ctl->mod_modname);
+ }
- /*
- * Now check that our modctl has the expected load count. If it
- * doesn't, this module must have been unloaded and reloaded -- and
- * we're not going to touch it.
- */
- if (ctl->mod_loadcnt != fbt->fbtp_loadcnt) {
- if (fbt_verbose) {
- cmn_err(CE_NOTE, "fbt is failing for probe %s "
- "(module %s reloaded)",
- fbt->fbtp_name, ctl->mod_modname);
+ continue;
}
- continue;
- }
-
- dtrace_casptr(&tempDTraceTrapHook, NULL, fbt_perfCallback);
- if (tempDTraceTrapHook != (perfCallback)fbt_perfCallback) {
- if (fbt_verbose) {
- cmn_err(CE_NOTE, "fbt_enable is failing for probe %s "
- "in module %s: tempDTraceTrapHook already occupied.",
- fbt->fbtp_name, ctl->mod_modname);
+ dtrace_casptr(&tempDTraceTrapHook, NULL, ptrauth_nop_cast(void *, &fbt_perfCallback));
+ if (tempDTraceTrapHook != (perfCallback)fbt_perfCallback) {
+ if (fbt_verbose) {
+ cmn_err(CE_NOTE, "fbt_enable is failing for probe %s "
+ "in module %s: tempDTraceTrapHook already occupied.",
+ fbt->fbtp_name, ctl->mod_modname);
+ }
+ continue;
}
- continue;
- }
- if (fbt->fbtp_currentval != fbt->fbtp_patchval) {
+ if (fbt->fbtp_currentval != fbt->fbtp_patchval) {
#if KASAN
- /* Since dtrace probes can call into KASan and vice versa, things can get
- * very slow if we have a lot of probes. This call will disable the KASan
- * fakestack after a threshold of probes is reached. */
- kasan_fakestack_suspend();
+ /* Since dtrace probes can call into KASan and vice versa, things can get
+ * very slow if we have a lot of probes. This call will disable the KASan
+ * fakestack after a threshold of probes is reached. */
+ kasan_fakestack_suspend();
#endif
- (void)ml_nofault_copy( (vm_offset_t)&fbt->fbtp_patchval, (vm_offset_t)fbt->fbtp_patchpoint,
- sizeof(fbt->fbtp_patchval));
- /*
- * Make the patched instruction visible via a data + instruction
- * cache flush for the platforms that need it
- */
- flush_dcache((vm_offset_t)fbt->fbtp_patchpoint,(vm_size_t)sizeof(fbt->fbtp_patchval), 0);
- invalidate_icache((vm_offset_t)fbt->fbtp_patchpoint,(vm_size_t)sizeof(fbt->fbtp_patchval), 0);
- fbt->fbtp_currentval = fbt->fbtp_patchval;
+ (void)ml_nofault_copy((vm_offset_t)&fbt->fbtp_patchval, (vm_offset_t)fbt->fbtp_patchpoint,
+ sizeof(fbt->fbtp_patchval));
+ /*
+ * Make the patched instruction visible via a data + instruction
+ * cache flush for the platforms that need it
+ */
+ flush_dcache((vm_offset_t)fbt->fbtp_patchpoint, (vm_size_t)sizeof(fbt->fbtp_patchval), 0);
+ invalidate_icache((vm_offset_t)fbt->fbtp_patchpoint, (vm_size_t)sizeof(fbt->fbtp_patchval), 0);
+ fbt->fbtp_currentval = fbt->fbtp_patchval;
- ctl->mod_nenabled++;
+ ctl->mod_nenabled++;
+ }
}
- }
-
- dtrace_membar_consumer();
+ dtrace_membar_consumer();
- return (0);
+ return 0;
}
/*ARGSUSED*/
struct modctl *ctl = NULL;
for (; fbt != NULL; fbt = fbt->fbtp_next) {
- ctl = fbt->fbtp_ctl;
+ ctl = fbt->fbtp_ctl;
- if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt))
- continue;
+ if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt)) {
+ continue;
+ }
- if (fbt->fbtp_currentval != fbt->fbtp_savedval) {
- (void)ml_nofault_copy( (vm_offset_t)&fbt->fbtp_savedval, (vm_offset_t)fbt->fbtp_patchpoint,
- sizeof(fbt->fbtp_savedval));
- /*
- * Make the patched instruction visible via a data + instruction
- * cache flush for the platforms that need it
- */
- flush_dcache((vm_offset_t)fbt->fbtp_patchpoint,(vm_size_t)sizeof(fbt->fbtp_patchval), 0);
- invalidate_icache((vm_offset_t)fbt->fbtp_patchpoint,(vm_size_t)sizeof(fbt->fbtp_patchval), 0);
+ if (fbt->fbtp_currentval != fbt->fbtp_savedval) {
+ (void)ml_nofault_copy((vm_offset_t)&fbt->fbtp_savedval, (vm_offset_t)fbt->fbtp_patchpoint,
+ sizeof(fbt->fbtp_savedval));
+ /*
+ * Make the patched instruction visible via a data + instruction
+ * cache flush for the platforms that need it
+ */
+ flush_dcache((vm_offset_t)fbt->fbtp_patchpoint, (vm_size_t)sizeof(fbt->fbtp_patchval), 0);
+ invalidate_icache((vm_offset_t)fbt->fbtp_patchpoint, (vm_size_t)sizeof(fbt->fbtp_patchval), 0);
- fbt->fbtp_currentval = fbt->fbtp_savedval;
- ASSERT(ctl->mod_nenabled > 0);
- ctl->mod_nenabled--;
+ fbt->fbtp_currentval = fbt->fbtp_savedval;
+ ASSERT(ctl->mod_nenabled > 0);
+ ctl->mod_nenabled--;
#if KASAN
- kasan_fakestack_resume();
+ kasan_fakestack_resume();
#endif
- }
+ }
}
dtrace_membar_consumer();
}
struct modctl *ctl = NULL;
for (; fbt != NULL; fbt = fbt->fbtp_next) {
- ctl = fbt->fbtp_ctl;
+ ctl = fbt->fbtp_ctl;
- ASSERT(ctl->mod_nenabled > 0);
- if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt))
- continue;
+ ASSERT(ctl->mod_nenabled > 0);
+ if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt)) {
+ continue;
+ }
- (void)ml_nofault_copy( (vm_offset_t)&fbt->fbtp_savedval, (vm_offset_t)fbt->fbtp_patchpoint,
- sizeof(fbt->fbtp_savedval));
+ (void)ml_nofault_copy((vm_offset_t)&fbt->fbtp_savedval, (vm_offset_t)fbt->fbtp_patchpoint,
+ sizeof(fbt->fbtp_savedval));
/*
* Make the patched instruction visible via a data + instruction
* cache flush for the platforms that need it
*/
- flush_dcache((vm_offset_t)fbt->fbtp_patchpoint,(vm_size_t)sizeof(fbt->fbtp_savedval), 0);
- invalidate_icache((vm_offset_t)fbt->fbtp_patchpoint,(vm_size_t)sizeof(fbt->fbtp_savedval), 0);
+ flush_dcache((vm_offset_t)fbt->fbtp_patchpoint, (vm_size_t)sizeof(fbt->fbtp_savedval), 0);
+ invalidate_icache((vm_offset_t)fbt->fbtp_patchpoint, (vm_size_t)sizeof(fbt->fbtp_savedval), 0);
fbt->fbtp_currentval = fbt->fbtp_savedval;
}
struct modctl *ctl = NULL;
for (; fbt != NULL; fbt = fbt->fbtp_next) {
- ctl = fbt->fbtp_ctl;
-
- ASSERT(ctl->mod_nenabled > 0);
- if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt))
- continue;
-
- dtrace_casptr(&tempDTraceTrapHook, NULL, fbt_perfCallback);
- if (tempDTraceTrapHook != (perfCallback)fbt_perfCallback) {
- if (fbt_verbose) {
- cmn_err(CE_NOTE, "fbt_resume is failing for probe %s "
- "in module %s: tempDTraceTrapHook already occupied.",
- fbt->fbtp_name, ctl->mod_modname);
+ ctl = fbt->fbtp_ctl;
+
+ ASSERT(ctl->mod_nenabled > 0);
+ if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt)) {
+ continue;
}
- return;
- }
- (void)ml_nofault_copy( (vm_offset_t)&fbt->fbtp_patchval, (vm_offset_t)fbt->fbtp_patchpoint,
- sizeof(fbt->fbtp_patchval));
+ dtrace_casptr(&tempDTraceTrapHook, NULL, ptrauth_nop_cast(void *, &fbt_perfCallback));
+ if (tempDTraceTrapHook != (perfCallback)fbt_perfCallback) {
+ if (fbt_verbose) {
+ cmn_err(CE_NOTE, "fbt_resume is failing for probe %s "
+ "in module %s: tempDTraceTrapHook already occupied.",
+ fbt->fbtp_name, ctl->mod_modname);
+ }
+ return;
+ }
+
+ (void)ml_nofault_copy((vm_offset_t)&fbt->fbtp_patchval, (vm_offset_t)fbt->fbtp_patchpoint,
+ sizeof(fbt->fbtp_patchval));
/*
* Make the patched instruction visible via a data + instruction cache flush.
*/
- flush_dcache((vm_offset_t)fbt->fbtp_patchpoint,(vm_size_t)sizeof(fbt->fbtp_patchval), 0);
- invalidate_icache((vm_offset_t)fbt->fbtp_patchpoint,(vm_size_t)sizeof(fbt->fbtp_patchval), 0);
+ flush_dcache((vm_offset_t)fbt->fbtp_patchpoint, (vm_size_t)sizeof(fbt->fbtp_patchval), 0);
+ invalidate_icache((vm_offset_t)fbt->fbtp_patchpoint, (vm_size_t)sizeof(fbt->fbtp_patchval), 0);
- fbt->fbtp_currentval = fbt->fbtp_patchval;
+ fbt->fbtp_currentval = fbt->fbtp_patchval;
}
dtrace_membar_consumer();
dtrace_module_symbols_t* module_symbols = ctl->mod_user_symbols;
if (module_symbols) {
- for (i=0; i<module_symbols->dtmodsyms_count; i++) {
-
- /*
+ for (i = 0; i < module_symbols->dtmodsyms_count; i++) {
+ /*
* symbol->dtsym_addr (the symbol address) passed in from
* user space, is already slid for both kexts and kernel.
*/
char* name = symbol->dtsym_name;
/* Lop off omnipresent leading underscore. */
- if (*name == '_')
+ if (*name == '_') {
name += 1;
+ }
- if (MOD_IS_MACH_KERNEL(ctl) && fbt_excluded(name))
+ if (fbt_excluded(name)) {
continue;
+ }
/*
* Ignore symbols with a null address
*/
- if (!symbol->dtsym_addr)
+ if (!symbol->dtsym_addr) {
continue;
+ }
/*
* Ignore symbols not part of this module
*/
- if (!dtrace_addr_in_module((void*)symbol->dtsym_addr, ctl))
+ if (!dtrace_addr_in_module((void*)symbol->dtsym_addr, ctl)) {
continue;
+ }
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));
}
const char *name = strings + sym[i].n_un.n_strx;
uint64_t limit;
- if (sym[i].n_value < sect_start || sym[i].n_value > sect_end)
+ if (sym[i].n_value < sect_start || sym[i].n_value > sect_end) {
continue;
+ }
/* Check that the symbol is a global and that it has a name. */
- if (((N_SECT | N_EXT) != n_type && (N_ABS | N_EXT) != n_type))
+ if (((N_SECT | N_EXT) != n_type && (N_ABS | N_EXT) != n_type)) {
continue;
+ }
- if (0 == sym[i].n_un.n_strx) /* iff a null, "", name. */
+ if (0 == sym[i].n_un.n_strx) { /* iff a null, "", name. */
continue;
+ }
/* Lop off omnipresent leading underscore. */
- if (*name == '_')
+ if (*name == '_') {
name += 1;
+ }
#if defined(__arm__)
// Skip non-thumb functions on arm32
}
#endif /* defined(__arm__) */
- if (MOD_IS_MACH_KERNEL(ctl) && fbt_excluded(name))
+ if (fbt_excluded(name)) {
continue;
+ }
/*
* Find the function boundary by looking at either the
*/
if (i == nsyms - 1) {
limit = sect_end;
- }
- else {
+ } else {
limit = sym[i + 1].n_value;
}
fbt_provide_probe(ctl, ctl->mod_modname, name, (machine_inst_t*)sym[i].n_value, (machine_inst_t*)limit);
}
-
}
static int
unsigned int i;
size_t symlen;
- if (mh->magic != MH_MAGIC_KERNEL)
+ if (mh->magic != MH_MAGIC_KERNEL) {
return;
+ }
cmd = (struct load_command *) &mh[1];
for (i = 0; i < mh->ncmds; i++) {
if (cmd->cmd == LC_SEGMENT_KERNEL) {
kernel_segment_command_t *orig_sg = (kernel_segment_command_t *) cmd;
- if (LIT_STRNEQL(orig_sg->segname, SEG_LINKEDIT))
+ if (LIT_STRNEQL(orig_sg->segname, SEG_LINKEDIT)) {
linkedit = orig_sg;
+ }
} else if (cmd->cmd == LC_SYMTAB) {
symtab = (struct symtab_command *) cmd;
}
for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
kernel_section_t *sect = firstsect(seg);
- if (strcmp(seg->segname, "__KLD") == 0) {
+ if (strcmp(seg->segname, "__KLD") == 0 || strcmp(seg->segname, "__KLDDATA") == 0) {
continue;
}
ASSERT(dtrace_kernel_symbol_mode != DTRACE_KERNEL_SYMBOLS_NEVER);
LCK_MTX_ASSERT(&mod_lock, LCK_MTX_ASSERT_OWNED);
+ if (dtrace_fbt_probes_restricted()) {
+ return;
+ }
+
// Update the "ignore blacklist" bit
- if (ignore_fbt_blacklist)
+ if (ignore_fbt_blacklist) {
ctl->mod_flags |= MODCTL_FBT_PROVIDE_BLACKLISTED_PROBES;
+ }
- if (MOD_FBT_DONE(ctl))
+ if (MOD_FBT_DONE(ctl)) {
return;
+ }
if (fbt_module_excluded(ctl)) {
ctl->mod_flags |= MODCTL_FBT_INVALID;
if (MOD_HAS_KERNEL_SYMBOLS(ctl)) {
fbt_provide_module_kernel_syms(ctl);
ctl->mod_flags |= MODCTL_FBT_PROBES_PROVIDED;
- if (MOD_FBT_PROVIDE_BLACKLISTED_PROBES(ctl))
+ if (MOD_FBT_PROVIDE_BLACKLISTED_PROBES(ctl)) {
ctl->mod_flags |= MODCTL_FBT_BLACKLISTED_PROBES_PROVIDED;
+ }
return;
}
if (MOD_HAS_USERSPACE_SYMBOLS(ctl)) {
fbt_provide_module_user_syms(ctl);
ctl->mod_flags |= MODCTL_FBT_PROBES_PROVIDED;
- if (MOD_FBT_PROVIDE_PRIVATE_PROBES(ctl))
- ctl->mod_flags |= MODCTL_FBT_PRIVATE_PROBES_PROVIDED;
- if (MOD_FBT_PROVIDE_BLACKLISTED_PROBES(ctl))
+ if (MOD_FBT_PROVIDE_BLACKLISTED_PROBES(ctl)) {
ctl->mod_flags |= MODCTL_FBT_BLACKLISTED_PROBES_PROVIDED;
+ }
return;
}
}
static dtrace_pattr_t fbt_attr = {
-{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
-{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
-{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
-{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
-{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
+ { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
+ { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
+ { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
+ { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
+ { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
};
static dtrace_pops_t fbt_pops = {
- .dtps_provide = NULL,
- .dtps_provide_module = fbt_provide_module,
- .dtps_enable = fbt_enable,
- .dtps_disable = fbt_disable,
- .dtps_suspend = fbt_suspend,
- .dtps_resume = fbt_resume,
- .dtps_getargdesc = NULL, /* APPLE NOTE: fbt_getargdesc implemented in userspace */
- .dtps_getargval = NULL,
- .dtps_usermode = NULL,
- .dtps_destroy = fbt_destroy
+ .dtps_provide = NULL,
+ .dtps_provide_module = fbt_provide_module,
+ .dtps_enable = fbt_enable,
+ .dtps_disable = fbt_disable,
+ .dtps_suspend = fbt_suspend,
+ .dtps_resume = fbt_resume,
+ .dtps_getargdesc = NULL, /* APPLE NOTE: fbt_getargdesc implemented in userspace */
+ .dtps_getargval = NULL,
+ .dtps_usermode = NULL,
+ .dtps_destroy = fbt_destroy
};
static void
{
dtrace_invop_remove(fbt_invop);
ddi_remove_minor_node(devi, NULL);
- kmem_free(fbt_probetab, fbt_probetab_size * sizeof (fbt_probe_t *));
+ kmem_free(fbt_probetab, fbt_probetab_size * sizeof(fbt_probe_t *));
fbt_probetab = NULL;
fbt_probetab_mask = 0;
}
static int
fbt_attach(dev_info_t *devi)
{
- if (fbt_probetab_size == 0)
+ if (fbt_probetab_size == 0) {
fbt_probetab_size = FBT_PROBETAB_SIZE;
+ }
fbt_probetab_mask = fbt_probetab_size - 1;
fbt_probetab =
- kmem_zalloc(fbt_probetab_size * sizeof (fbt_probe_t *), KM_SLEEP);
+ kmem_zalloc(fbt_probetab_size * sizeof(fbt_probe_t *), KM_SLEEP);
dtrace_invop_add(fbt_invop);
dtrace_register("fbt", &fbt_attr, DTRACE_PRIV_KERNEL, NULL,
&fbt_pops, NULL, &fbt_id) != 0) {
fbt_cleanup(devi);
- return (DDI_FAILURE);
+ return DDI_FAILURE;
}
- return (DDI_SUCCESS);
+ return DDI_SUCCESS;
}
static d_open_t _fbt_open;
#define FBT_MAJOR -24 /* let the kernel pick the device number */
-SYSCTL_DECL(_kern_dtrace);
-
-static int
-sysctl_dtrace_ignore_fbt_blacklist SYSCTL_HANDLER_ARGS
-{
-#pragma unused(oidp, arg2)
- int err;
- int value = *(int*)arg1;
-
- err = sysctl_io_number(req, value, sizeof(value), &value, NULL);
- if (err)
- return (err);
- if (req->newptr) {
- if (!(value == 0 || value == 1))
- return (ERANGE);
-
- /*
- * We do not allow setting the blacklist back to on, as we have no way
- * of knowing if those unsafe probes are still used.
- *
- * If we are using kernel symbols, we also do not allow any change,
- * since the symbols are jettison'd after the first pass.
- *
- * We do not need to take any locks here because those symbol modes
- * are permanent and do not change after boot.
- */
- if (value != 1 || dtrace_kernel_symbol_mode == DTRACE_KERNEL_SYMBOLS_NEVER ||
- dtrace_kernel_symbol_mode == DTRACE_KERNEL_SYMBOLS_ALWAYS_FROM_KERNEL)
- return (EPERM);
-
- ignore_fbt_blacklist = 1;
- }
-
- return (0);
-}
-
-SYSCTL_PROC(_kern_dtrace, OID_AUTO, ignore_fbt_blacklist,
- CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
- &ignore_fbt_blacklist, 0,
- sysctl_dtrace_ignore_fbt_blacklist, "I", "fbt provider ignore blacklist");
-
-/*
- * A struct describing which functions will get invoked for certain
- * actions.
- */
-static struct cdevsw fbt_cdevsw =
+static const struct cdevsw fbt_cdevsw =
{
- _fbt_open, /* open */
- eno_opcl, /* close */
- eno_rdwrt, /* read */
- eno_rdwrt, /* write */
- eno_ioctl, /* ioctl */
- (stop_fcn_t *)nulldev, /* stop */
- (reset_fcn_t *)nulldev, /* reset */
- NULL, /* tty's */
- eno_select, /* select */
- eno_mmap, /* mmap */
- eno_strat, /* strategy */
- eno_getc, /* getc */
- eno_putc, /* putc */
- 0 /* type */
+ .d_open = _fbt_open,
+ .d_close = eno_opcl,
+ .d_read = eno_rdwrt,
+ .d_write = eno_rdwrt,
+ .d_ioctl = eno_ioctl,
+ .d_stop = (stop_fcn_t *)nulldev,
+ .d_reset = (reset_fcn_t *)nulldev,
+ .d_select = eno_select,
+ .d_mmap = eno_mmap,
+ .d_strategy = eno_strat,
+ .d_reserved_1 = eno_getc,
+ .d_reserved_2 = eno_putc,
};
#undef kmem_alloc /* from its binding to dt_kmem_alloc glue */
#undef kmem_free /* from its binding to dt_kmem_free glue */
#include <vm/vm_kern.h>
+
void
fbt_init( void )
{
return;
}
- PE_parse_boot_argn("IgnoreFBTBlacklist", &ignore_fbt_blacklist, sizeof (ignore_fbt_blacklist));
-
+ fbt_blacklist_init();
fbt_attach((dev_info_t*)(uintptr_t)majdevno);
}
#undef FBT_MAJOR