4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* #pragma ident "@(#)fbt.c 1.15 05/09/19 SMI" */
31 #define _KERNEL /* Solaris vs. Darwin */
35 #define MACH__POSIX_C_SOURCE_PRIVATE 1 /* pulls in suitable savearea from mach/ppc/thread_status.h */
36 #include <kern/thread.h>
37 #include <mach/thread_status.h>
38 #include <mach/vm_param.h>
39 #include <mach-o/loader.h>
40 #include <mach-o/nlist.h>
41 #include <libkern/kernel_mach_header.h>
42 #include <libkern/OSAtomic.h>
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/errno.h>
48 #include <sys/ioctl.h>
50 #include <sys/fcntl.h>
51 #include <miscfs/devfs/devfs.h>
53 #include <sys/dtrace.h>
54 #include <sys/dtrace_impl.h>
57 #include <sys/dtrace_glue.h>
59 #define DTRACE_INVOP_NOP_SKIP 1
60 #define DTRACE_INVOP_MOVL_ESP_EBP 10
61 #define DTRACE_INVOP_MOVL_ESP_EBP_SKIP 2
62 #define DTRACE_INVOP_MOV_RSP_RBP 11
63 #define DTRACE_INVOP_MOV_RSP_RBP_SKIP 3
64 #define DTRACE_INVOP_POP_RBP 12
65 #define DTRACE_INVOP_POP_RBP_SKIP 1
66 #define DTRACE_INVOP_LEAVE_SKIP 1
68 #define FBT_PUSHL_EBP 0x55
69 #define FBT_MOVL_ESP_EBP0_V0 0x8b
70 #define FBT_MOVL_ESP_EBP1_V0 0xec
71 #define FBT_MOVL_ESP_EBP0_V1 0x89
72 #define FBT_MOVL_ESP_EBP1_V1 0xe5
74 #define FBT_PUSH_RBP 0x55
75 #define FBT_REX_RSP_RBP 0x48
76 #define FBT_MOV_RSP_RBP0 0x89
77 #define FBT_MOV_RSP_RBP1 0xe5
78 #define FBT_POP_RBP 0x5d
80 #define FBT_POPL_EBP 0x5d
82 #define FBT_RET_IMM16 0xc2
83 #define FBT_LEAVE 0xc9
84 #define FBT_JMP_SHORT_REL 0xeb /* Jump short, relative, displacement relative to next instr. */
85 #define FBT_JMP_NEAR_REL 0xe9 /* Jump near, relative, displacement relative to next instr. */
86 #define FBT_JMP_FAR_ABS 0xea /* Jump far, absolute, address given in operand */
88 #define FBT_RET_IMM16_LEN 3
89 #define FBT_JMP_SHORT_REL_LEN 2
90 #define FBT_JMP_NEAR_REL_LEN 5
91 #define FBT_JMP_FAR_ABS_LEN 5
93 #define FBT_PATCHVAL 0xf0
94 #define FBT_AFRAMES_ENTRY 7
95 #define FBT_AFRAMES_RETURN 6
97 #define FBT_ENTRY "entry"
98 #define FBT_RETURN "return"
99 #define FBT_ADDR2NDX(addr) ((((uintptr_t)(addr)) >> 4) & fbt_probetab_mask)
101 extern dtrace_provider_id_t fbt_id
;
102 extern fbt_probe_t
**fbt_probetab
;
103 extern int fbt_probetab_mask
;
105 extern int gIgnoreFBTBlacklist
; /* From fbt_init */
107 kern_return_t
fbt_perfCallback(int, x86_saved_state_t
*, uintptr_t *, __unused
int);
110 * Critical routines that must not be probed. PR_5221096, PR_5379018.
111 * The blacklist must be kept in alphabetic order for purposes of bsearch().
114 static const char * critical_blacklist
[] =
135 "cpu_processor_alloc",
136 "cpu_processor_free",
137 "cpu_signal_handler",
147 "cpu_topology_start_cpu",
151 "handle_pending_TLB_flushes",
152 "hw_compare_and_store",
153 "machine_idle_cstate",
159 "pmap_cpu_high_map_vaddr",
160 "pmap_cpu_high_shared_remap",
162 "register_cpu_setup_func",
163 "unregister_cpu_setup_func",
166 #define CRITICAL_BLACKLIST_COUNT (sizeof(critical_blacklist)/sizeof(critical_blacklist[0]))
169 * The transitive closure of entry points that can be reached from probe context.
170 * (Apart from routines whose names begin with dtrace_).
172 static const char * probe_ctx_closure
[] =
177 "absolutetime_to_microtime",
180 "clock_get_calendar_nanotime_nowait",
195 "get_bsdthread_info",
200 "kernel_preempt_check",
201 "mach_absolute_time",
202 "max_valid_stack_address",
203 "ml_at_interrupt_context",
204 "ml_phys_write_byte_64",
205 "ml_phys_write_half_64",
206 "ml_phys_write_word_64",
207 "ml_set_interrupts_enabled",
212 "pmap_get_mapwindow",
215 "pmap_put_mapwindow",
225 "sync_iss_to_iks_unconditionally",
229 #define PROBE_CTX_CLOSURE_COUNT (sizeof(probe_ctx_closure)/sizeof(probe_ctx_closure[0]))
232 static int _cmp(const void *a
, const void *b
)
234 return strncmp((const char *)a
, *(const char **)b
, strlen((const char *)a
) + 1);
237 static const void * bsearch(
238 register const void *key
,
241 register size_t size
,
242 register int (*compar
)(const void *, const void *)) {
244 register const char *base
= base0
;
247 register const void *p
;
249 for (lim
= nmemb
; lim
!= 0; lim
>>= 1) {
250 p
= base
+ (lim
>> 1) * size
;
251 cmp
= (*compar
)(key
, p
);
254 if (cmp
> 0) { /* key > p: move right */
255 base
= (const char *)p
+ size
;
257 } /* else move left */
266 is_module_valid(struct modctl
* ctl
)
268 ASSERT(!MOD_FBT_PROBES_PROVIDED(ctl
));
269 ASSERT(!MOD_FBT_INVALID(ctl
));
271 if (0 == ctl
->mod_address
|| 0 == ctl
->mod_size
) {
275 if (0 == ctl
->mod_loaded
) {
279 if (strstr(ctl
->mod_modname
, "CHUD") != NULL
)
283 * If the user sets this, trust they know what they are doing.
285 if (gIgnoreFBTBlacklist
) /* per boot-arg set in fbt_init() */
289 * These drivers control low level functions that when traced
290 * cause problems often in the sleep/wake paths as well as
291 * critical debug and panic paths.
292 * If somebody really wants to drill in on one of these kexts, then
293 * they can override blacklisting using the boot-arg above.
296 if (strstr(ctl
->mod_modname
, "AppleACPIEC") != NULL
)
299 if (strstr(ctl
->mod_modname
, "AppleACPIPlatform") != NULL
)
302 if (strstr(ctl
->mod_modname
, "AppleRTC") != NULL
)
305 if (strstr(ctl
->mod_modname
, "IOACPIFamily") != NULL
)
308 if (strstr(ctl
->mod_modname
, "AppleIntelCPUPowerManagement") != NULL
)
311 if (strstr(ctl
->mod_modname
, "AppleProfile") != NULL
)
314 if (strstr(ctl
->mod_modname
, "AppleIntelProfile") != NULL
)
317 if (strstr(ctl
->mod_modname
, "AppleEFI") != NULL
)
324 * FBT probe name validation
327 is_symbol_valid(const char* name
)
330 * If the user set this, trust they know what they are doing.
332 if (gIgnoreFBTBlacklist
)
335 if (LIT_STRNSTART(name
, "dtrace_") && !LIT_STRNSTART(name
, "dtrace_safe_")) {
337 * Anything beginning with "dtrace_" may be called
338 * from probe context unless it explitly indicates
339 * that it won't be called from probe context by
340 * using the prefix "dtrace_safe_".
345 if (LIT_STRNSTART(name
, "fasttrap_") ||
346 LIT_STRNSTART(name
, "fuword") ||
347 LIT_STRNSTART(name
, "suword") ||
348 LIT_STRNEQL(name
, "sprlock") ||
349 LIT_STRNEQL(name
, "sprunlock") ||
350 LIT_STRNEQL(name
, "uread") ||
351 LIT_STRNEQL(name
, "uwrite")) {
352 return FALSE
; /* Fasttrap inner-workings. */
355 if (LIT_STRNSTART(name
, "dsmos_"))
356 return FALSE
; /* Don't Steal Mac OS X! */
358 if (LIT_STRNSTART(name
, "_dtrace"))
359 return FALSE
; /* Shims in dtrace.c */
361 if (LIT_STRNSTART(name
, "chud"))
362 return FALSE
; /* Professional courtesy. */
364 if (LIT_STRNSTART(name
, "hibernate_"))
365 return FALSE
; /* Let sleeping dogs lie. */
367 if (LIT_STRNEQL(name
, "_ZNK6OSData14getBytesNoCopyEv"))
368 return FALSE
; /* Data::getBytesNoCopy, IOHibernateSystemWake path */
370 if (LIT_STRNEQL(name
, "_ZN9IOService14newTemperatureElPS_") || /* IOService::newTemperature */
371 LIT_STRNEQL(name
, "_ZN9IOService26temperatureCriticalForZoneEPS_")) { /* IOService::temperatureCriticalForZone */
372 return FALSE
; /* Per the fire code */
376 * Place no probes (illegal instructions) in the exception handling path!
378 if (LIT_STRNEQL(name
, "t_invop") ||
379 LIT_STRNEQL(name
, "enter_lohandler") ||
380 LIT_STRNEQL(name
, "lo_alltraps") ||
381 LIT_STRNEQL(name
, "kernel_trap") ||
382 LIT_STRNEQL(name
, "interrupt") ||
383 LIT_STRNEQL(name
, "i386_astintr")) {
387 if (LIT_STRNEQL(name
, "current_thread") ||
388 LIT_STRNEQL(name
, "ast_pending") ||
389 LIT_STRNEQL(name
, "fbt_perfCallback") ||
390 LIT_STRNEQL(name
, "machine_thread_get_kern_state") ||
391 LIT_STRNEQL(name
, "get_threadtask") ||
392 LIT_STRNEQL(name
, "ml_set_interrupts_enabled") ||
393 LIT_STRNEQL(name
, "dtrace_invop") ||
394 LIT_STRNEQL(name
, "fbt_invop") ||
395 LIT_STRNEQL(name
, "sdt_invop") ||
396 LIT_STRNEQL(name
, "max_valid_stack_address")) {
403 if (LIT_STRNSTART(name
, "machine_stack_") ||
404 LIT_STRNSTART(name
, "mapping_") ||
405 LIT_STRNEQL(name
, "tmrCvt") ||
407 LIT_STRNSTART(name
, "tsc_") ||
409 LIT_STRNSTART(name
, "pmCPU") ||
410 LIT_STRNEQL(name
, "pmKextRegister") ||
411 LIT_STRNEQL(name
, "pmMarkAllCPUsOff") ||
412 LIT_STRNEQL(name
, "pmSafeMode") ||
413 LIT_STRNEQL(name
, "pmTimerSave") ||
414 LIT_STRNEQL(name
, "pmTimerRestore") ||
415 LIT_STRNEQL(name
, "pmUnRegister") ||
416 LIT_STRNSTART(name
, "pms") ||
417 LIT_STRNEQL(name
, "power_management_init") ||
418 LIT_STRNSTART(name
, "usimple_") ||
419 LIT_STRNSTART(name
, "lck_spin_lock") ||
420 LIT_STRNSTART(name
, "lck_spin_unlock") ||
422 LIT_STRNSTART(name
, "rtc_") ||
423 LIT_STRNSTART(name
, "_rtc_") ||
424 LIT_STRNSTART(name
, "rtclock_") ||
425 LIT_STRNSTART(name
, "clock_") ||
426 LIT_STRNSTART(name
, "absolutetime_to_") ||
427 LIT_STRNEQL(name
, "setPop") ||
428 LIT_STRNEQL(name
, "nanoseconds_to_absolutetime") ||
429 LIT_STRNEQL(name
, "nanotime_to_absolutetime") ||
431 LIT_STRNSTART(name
, "etimer_") ||
433 LIT_STRNSTART(name
, "commpage_") ||
434 LIT_STRNSTART(name
, "pmap_") ||
435 LIT_STRNSTART(name
, "ml_") ||
436 LIT_STRNSTART(name
, "PE_") ||
437 LIT_STRNEQL(name
, "kprintf") ||
438 LIT_STRNSTART(name
, "lapic_") ||
439 LIT_STRNSTART(name
, "act_machine") ||
440 LIT_STRNSTART(name
, "acpi_") ||
441 LIT_STRNSTART(name
, "pal_")){
446 * Avoid machine_ routines. PR_5346750.
448 if (LIT_STRNSTART(name
, "machine_"))
451 if (LIT_STRNEQL(name
, "handle_pending_TLB_flushes"))
455 * Place no probes on critical routines. PR_5221096
457 if (bsearch( name
, critical_blacklist
, CRITICAL_BLACKLIST_COUNT
, sizeof(name
), _cmp
) != NULL
)
461 * Place no probes that could be hit in probe context.
463 if (bsearch( name
, probe_ctx_closure
, PROBE_CTX_CLOSURE_COUNT
, sizeof(name
), _cmp
) != NULL
) {
468 * Place no probes that could be hit on the way to the debugger.
470 if (LIT_STRNSTART(name
, "kdp_") ||
471 LIT_STRNSTART(name
, "kdb_") ||
472 LIT_STRNSTART(name
, "kdbg_") ||
473 LIT_STRNSTART(name
, "kdebug_") ||
474 LIT_STRNSTART(name
, "kernel_debug") ||
475 LIT_STRNSTART(name
, "debug_") ||
476 LIT_STRNEQL(name
, "Debugger") ||
477 LIT_STRNEQL(name
, "Call_DebuggerC") ||
478 LIT_STRNEQL(name
, "lock_debugger") ||
479 LIT_STRNEQL(name
, "unlock_debugger") ||
480 LIT_STRNEQL(name
, "packA") ||
481 LIT_STRNEQL(name
, "unpackA") ||
482 LIT_STRNEQL(name
, "SysChoked")) {
488 * Place no probes that could be hit on the way to a panic.
490 if (NULL
!= strstr(name
, "panic_") ||
491 LIT_STRNEQL(name
, "panic") ||
492 LIT_STRNEQL(name
, "preemption_underflow_panic")) {
500 fbt_invop(uintptr_t addr
, uintptr_t *state
, uintptr_t rval
)
502 fbt_probe_t
*fbt
= fbt_probetab
[FBT_ADDR2NDX(addr
)];
504 for (; fbt
!= NULL
; fbt
= fbt
->fbtp_hashnext
) {
505 if ((uintptr_t)fbt
->fbtp_patchpoint
== addr
) {
507 if (fbt
->fbtp_roffset
== 0) {
508 x86_saved_state64_t
*regs
= (x86_saved_state64_t
*)state
;
510 CPU
->cpu_dtrace_caller
= *(uintptr_t *)(((uintptr_t)(regs
->isf
.rsp
))+sizeof(uint64_t)); // 8(%rsp)
511 /* 64-bit ABI, arguments passed in registers. */
512 dtrace_probe(fbt
->fbtp_id
, regs
->rdi
, regs
->rsi
, regs
->rdx
, regs
->rcx
, regs
->r8
);
513 CPU
->cpu_dtrace_caller
= 0;
516 dtrace_probe(fbt
->fbtp_id
, fbt
->fbtp_roffset
, rval
, 0, 0, 0);
517 CPU
->cpu_dtrace_caller
= 0;
520 return (fbt
->fbtp_rval
);
527 #define IS_USER_TRAP(regs) (regs && (((regs)->isf.cs & 3) != 0))
528 #define T_INVALID_OPCODE 6
529 #define FBT_EXCEPTION_CODE T_INVALID_OPCODE
530 #define T_PREEMPT 255
535 x86_saved_state_t
*tagged_regs
,
537 __unused
int unused2
)
539 kern_return_t retval
= KERN_FAILURE
;
540 x86_saved_state64_t
*saved_state
= saved_state64(tagged_regs
);
542 if (FBT_EXCEPTION_CODE
== trapno
&& !IS_USER_TRAP(saved_state
)) {
544 uint64_t rsp_probe
, fp
, delta
= 0;
550 oldlevel
= ml_set_interrupts_enabled(FALSE
);
552 /* Calculate where the stack pointer was when the probe instruction "fired." */
553 rsp_probe
= saved_state
->isf
.rsp
; /* Easy, x86_64 establishes this value in idt64.s */
556 "Ldtrace_invop_callsite_pre_label:\n"
558 ".private_extern _dtrace_invop_callsite_pre\n"
559 "_dtrace_invop_callsite_pre:\n"
560 " .quad Ldtrace_invop_callsite_pre_label\n"
564 emul
= dtrace_invop( saved_state
->isf
.rip
, (uintptr_t *)saved_state
, saved_state
->rax
);
567 "Ldtrace_invop_callsite_post_label:\n"
569 ".private_extern _dtrace_invop_callsite_post\n"
570 "_dtrace_invop_callsite_post:\n"
571 " .quad Ldtrace_invop_callsite_post_label\n"
576 case DTRACE_INVOP_NOP
:
577 saved_state
->isf
.rip
+= DTRACE_INVOP_NOP_SKIP
; /* Skip over the patched NOP (planted by sdt). */
578 retval
= KERN_SUCCESS
;
581 case DTRACE_INVOP_MOV_RSP_RBP
:
582 saved_state
->rbp
= rsp_probe
; /* Emulate patched mov %rsp,%rbp */
583 saved_state
->isf
.rip
+= DTRACE_INVOP_MOV_RSP_RBP_SKIP
; /* Skip over the bytes of the patched mov %rsp,%rbp */
584 retval
= KERN_SUCCESS
;
587 case DTRACE_INVOP_POP_RBP
:
588 case DTRACE_INVOP_LEAVE
:
590 * Emulate first micro-op of patched leave: mov %rbp,%rsp
591 * fp points just below the return address slot for target's ret
592 * and at the slot holding the frame pointer saved by the target's prologue.
594 fp
= saved_state
->rbp
;
595 /* Emulate second micro-op of patched leave: patched pop %rbp
596 * savearea rbp is set for the frame of the caller to target
597 * The *live* %rsp will be adjusted below for pop increment(s)
599 saved_state
->rbp
= *(uint64_t *)fp
;
600 /* Skip over the patched leave */
601 saved_state
->isf
.rip
+= DTRACE_INVOP_LEAVE_SKIP
;
603 * Lift the stack to account for the emulated leave
604 * Account for words local in this frame
605 * (in "case DTRACE_INVOP_POPL_EBP:" this is zero.)
607 delta
= ((uint32_t *)fp
) - ((uint32_t *)rsp_probe
); /* delta is a *word* increment */
608 /* Account for popping off the rbp (just accomplished by the emulation
612 saved_state
->isf
.rsp
+= (delta
<< 2);
613 /* Obtain the stack pointer recorded by the trampolines */
615 /* Shift contents of stack */
616 for (pDst
= (uint32_t *)fp
;
617 pDst
> (((uint32_t *)old_sp
));
619 *pDst
= pDst
[-delta
];
621 /* Track the stack lift in "saved_state". */
622 saved_state
= (x86_saved_state64_t
*) (((uintptr_t)saved_state
) + (delta
<< 2));
623 /* Adjust the stack pointer utilized by the trampolines */
624 *lo_spp
= old_sp
+ (delta
<< 2);
626 retval
= KERN_SUCCESS
;
630 retval
= KERN_FAILURE
;
633 saved_state
->isf
.trapno
= T_PREEMPT
; /* Avoid call to i386_astintr()! */
635 ml_set_interrupts_enabled(oldlevel
);
643 __provide_probe_64(struct modctl
*ctl
, uintptr_t instrLow
, uintptr_t instrHigh
, char *modname
, char* symbolName
, machine_inst_t
* symbolStart
)
646 unsigned int doenable
= 0;
649 fbt_probe_t
*newfbt
, *retfbt
, *entryfbt
;
650 machine_inst_t
*instr
, *limit
, theInstr
, i1
, i2
, i3
;
653 for (j
= 0, instr
= symbolStart
, theInstr
= 0;
654 (j
< 4) && ((uintptr_t)instr
>= instrLow
) && (instrHigh
> (uintptr_t)(instr
+ 2));
657 if (theInstr
== FBT_PUSH_RBP
|| theInstr
== FBT_RET
|| theInstr
== FBT_RET_IMM16
)
660 if ((size
= dtrace_instr_size(instr
)) <= 0)
666 if (theInstr
!= FBT_PUSH_RBP
)
673 limit
= (machine_inst_t
*)instrHigh
;
675 if (i1
== FBT_REX_RSP_RBP
&& i2
== FBT_MOV_RSP_RBP0
&& i3
== FBT_MOV_RSP_RBP1
) {
676 instr
+= 1; /* Advance to the mov %rsp,%rbp */
684 * Sometimes, the compiler will schedule an intervening instruction
685 * in the function prologue. Example:
688 * 000006d8 pushl %ebp
689 * 000006d9 movl $0x00000004,%edx
690 * 000006de movl %esp,%ebp
692 * Try the next instruction, to see if it is a movl %esp,%ebp
695 instr
+= 1; /* Advance past the pushl %ebp */
696 if ((size
= dtrace_instr_size(instr
)) <= 0)
701 if ((instr
+ 1) >= limit
)
707 if (!(i1
== FBT_MOVL_ESP_EBP0_V0
&& i2
== FBT_MOVL_ESP_EBP1_V0
) &&
708 !(i1
== FBT_MOVL_ESP_EBP0_V1
&& i2
== FBT_MOVL_ESP_EBP1_V1
))
711 /* instr already points at the movl %esp,%ebp */
715 thisid
= dtrace_probe_lookup(fbt_id
, modname
, symbolName
, FBT_ENTRY
);
716 newfbt
= kmem_zalloc(sizeof (fbt_probe_t
), KM_SLEEP
);
717 strlcpy( (char *)&(newfbt
->fbtp_name
), symbolName
, MAX_FBTP_NAME_CHARS
);
721 * The dtrace_probe previously existed, so we have to hook
722 * the newfbt entry onto the end of the existing fbt's chain.
723 * If we find an fbt entry that was previously patched to
724 * fire, (as indicated by the current patched value), then
725 * we want to enable this newfbt on the spot.
727 entryfbt
= dtrace_probe_arg (fbt_id
, thisid
);
728 ASSERT (entryfbt
!= NULL
);
729 for(; entryfbt
!= NULL
; entryfbt
= entryfbt
->fbtp_next
) {
730 if (entryfbt
->fbtp_currentval
== entryfbt
->fbtp_patchval
)
733 if (entryfbt
->fbtp_next
== NULL
) {
734 entryfbt
->fbtp_next
= newfbt
;
735 newfbt
->fbtp_id
= entryfbt
->fbtp_id
;
742 * The dtrace_probe did not previously exist, so we
743 * create it and hook in the newfbt. Since the probe is
744 * new, we obviously do not need to enable it on the spot.
746 newfbt
->fbtp_id
= dtrace_probe_create(fbt_id
, modname
, symbolName
, FBT_ENTRY
, FBT_AFRAMES_ENTRY
, newfbt
);
750 newfbt
->fbtp_patchpoint
= instr
;
751 newfbt
->fbtp_ctl
= ctl
;
752 newfbt
->fbtp_loadcnt
= ctl
->mod_loadcnt
;
753 newfbt
->fbtp_rval
= DTRACE_INVOP_MOV_RSP_RBP
;
754 newfbt
->fbtp_savedval
= theInstr
;
755 newfbt
->fbtp_patchval
= FBT_PATCHVAL
;
756 newfbt
->fbtp_currentval
= 0;
757 newfbt
->fbtp_hashnext
= fbt_probetab
[FBT_ADDR2NDX(instr
)];
758 fbt_probetab
[FBT_ADDR2NDX(instr
)] = newfbt
;
761 fbt_enable(NULL
, newfbt
->fbtp_id
, newfbt
);
764 * The fbt entry chain is in place, one entry point per symbol.
765 * The fbt return chain can have multiple return points per symbol.
766 * Here we find the end of the fbt return chain.
771 thisid
= dtrace_probe_lookup(fbt_id
, modname
, symbolName
, FBT_RETURN
);
773 /* The dtrace_probe previously existed, so we have to
774 * find the end of the existing fbt chain. If we find
775 * an fbt return that was previously patched to fire,
776 * (as indicated by the currrent patched value), then
777 * we want to enable any new fbts on the spot.
779 retfbt
= dtrace_probe_arg (fbt_id
, thisid
);
780 ASSERT(retfbt
!= NULL
);
781 for (; retfbt
!= NULL
; retfbt
= retfbt
->fbtp_next
) {
782 if (retfbt
->fbtp_currentval
== retfbt
->fbtp_patchval
)
784 if(retfbt
->fbtp_next
== NULL
)
798 * If this disassembly fails, then we've likely walked off into
799 * a jump table or some other unsuitable area. Bail out of the
802 if ((size
= dtrace_instr_size(instr
)) <= 0)
806 * We (desperately) want to avoid erroneously instrumenting a
807 * jump table, especially given that our markers are pretty
808 * short: two bytes on x86, and just one byte on amd64. To
809 * determine if we're looking at a true instruction sequence
810 * or an inline jump table that happens to contain the same
811 * byte sequences, we resort to some heuristic sleeze: we
812 * treat this instruction as being contained within a pointer,
813 * and see if that pointer points to within the body of the
814 * function. If it does, we refuse to instrument it.
816 for (j
= 0; j
< sizeof (uintptr_t); j
++) {
817 uintptr_t check
= (uintptr_t)instr
- j
;
820 if (check
< (uintptr_t)symbolStart
)
823 if (check
+ sizeof (uintptr_t) > (uintptr_t)limit
)
826 ptr
= *(uint8_t **)check
;
828 if (ptr
>= (uint8_t *)symbolStart
&& ptr
< limit
) {
835 * OK, it's an instruction.
839 /* Walked onto the start of the next routine? If so, bail out of this function. */
840 if (theInstr
== FBT_PUSH_RBP
)
843 if (!(size
== 1 && (theInstr
== FBT_POP_RBP
|| theInstr
== FBT_LEAVE
))) {
849 * Found the pop %rbp; or leave.
851 machine_inst_t
*patch_instr
= instr
;
854 * Scan forward for a "ret", or "jmp".
860 size
= dtrace_instr_size(instr
);
861 if (size
<= 0) /* Failed instruction decode? */
866 if (!(size
== FBT_RET_LEN
&& (theInstr
== FBT_RET
)) &&
867 !(size
== FBT_RET_IMM16_LEN
&& (theInstr
== FBT_RET_IMM16
)) &&
868 !(size
== FBT_JMP_SHORT_REL_LEN
&& (theInstr
== FBT_JMP_SHORT_REL
)) &&
869 !(size
== FBT_JMP_NEAR_REL_LEN
&& (theInstr
== FBT_JMP_NEAR_REL
)) &&
870 !(size
== FBT_JMP_FAR_ABS_LEN
&& (theInstr
== FBT_JMP_FAR_ABS
)))
874 * pop %rbp; ret; or leave; ret; or leave; jmp tailCalledFun; -- We have a winner!
876 newfbt
= kmem_zalloc(sizeof (fbt_probe_t
), KM_SLEEP
);
877 strlcpy( (char *)&(newfbt
->fbtp_name
), symbolName
, MAX_FBTP_NAME_CHARS
);
879 if (retfbt
== NULL
) {
880 newfbt
->fbtp_id
= dtrace_probe_create(fbt_id
, modname
,
881 symbolName
, FBT_RETURN
, FBT_AFRAMES_RETURN
, newfbt
);
883 retfbt
->fbtp_next
= newfbt
;
884 newfbt
->fbtp_id
= retfbt
->fbtp_id
;
888 newfbt
->fbtp_patchpoint
= patch_instr
;
889 newfbt
->fbtp_ctl
= ctl
;
890 newfbt
->fbtp_loadcnt
= ctl
->mod_loadcnt
;
892 if (*patch_instr
== FBT_POP_RBP
) {
893 newfbt
->fbtp_rval
= DTRACE_INVOP_POP_RBP
;
895 ASSERT(*patch_instr
== FBT_LEAVE
);
896 newfbt
->fbtp_rval
= DTRACE_INVOP_LEAVE
;
898 newfbt
->fbtp_roffset
=
899 (uintptr_t)(patch_instr
- (uint8_t *)symbolStart
);
901 newfbt
->fbtp_savedval
= *patch_instr
;
902 newfbt
->fbtp_patchval
= FBT_PATCHVAL
;
903 newfbt
->fbtp_hashnext
= fbt_probetab
[FBT_ADDR2NDX(patch_instr
)];
904 fbt_probetab
[FBT_ADDR2NDX(patch_instr
)] = newfbt
;
907 fbt_enable(NULL
, newfbt
->fbtp_id
, newfbt
);
914 __kernel_syms_provide_module(void *arg
, struct modctl
*ctl
)
917 kernel_mach_header_t
*mh
;
918 struct load_command
*cmd
;
919 kernel_segment_command_t
*orig_ts
= NULL
, *orig_le
= NULL
;
920 struct symtab_command
*orig_st
= NULL
;
921 kernel_nlist_t
*sym
= NULL
;
923 uintptr_t instrLow
, instrHigh
;
927 mh
= (kernel_mach_header_t
*)(ctl
->mod_address
);
928 modname
= ctl
->mod_modname
;
930 if (mh
->magic
!= MH_MAGIC_KERNEL
)
933 cmd
= (struct load_command
*) &mh
[1];
934 for (i
= 0; i
< mh
->ncmds
; i
++) {
935 if (cmd
->cmd
== LC_SEGMENT_KERNEL
) {
936 kernel_segment_command_t
*orig_sg
= (kernel_segment_command_t
*) cmd
;
938 if (LIT_STRNEQL(orig_sg
->segname
, SEG_TEXT
))
940 else if (LIT_STRNEQL(orig_sg
->segname
, SEG_LINKEDIT
))
942 else if (LIT_STRNEQL(orig_sg
->segname
, ""))
943 orig_ts
= orig_sg
; /* kexts have a single unnamed segment */
945 else if (cmd
->cmd
== LC_SYMTAB
)
946 orig_st
= (struct symtab_command
*) cmd
;
948 cmd
= (struct load_command
*) ((caddr_t
) cmd
+ cmd
->cmdsize
);
951 if ((orig_ts
== NULL
) || (orig_st
== NULL
) || (orig_le
== NULL
))
954 sym
= (kernel_nlist_t
*)(orig_le
->vmaddr
+ orig_st
->symoff
- orig_le
->fileoff
);
955 strings
= (char *)(orig_le
->vmaddr
+ orig_st
->stroff
- orig_le
->fileoff
);
957 /* Find extent of the TEXT section */
958 instrLow
= (uintptr_t)orig_ts
->vmaddr
;
959 instrHigh
= (uintptr_t)(orig_ts
->vmaddr
+ orig_ts
->vmsize
);
961 for (i
= 0; i
< orig_st
->nsyms
; i
++) {
962 uint8_t n_type
= sym
[i
].n_type
& (N_TYPE
| N_EXT
);
963 char *name
= strings
+ sym
[i
].n_un
.n_strx
;
965 /* Check that the symbol is a global and that it has a name. */
966 if (((N_SECT
| N_EXT
) != n_type
&& (N_ABS
| N_EXT
) != n_type
))
969 if (0 == sym
[i
].n_un
.n_strx
) /* iff a null, "", name. */
972 /* Lop off omnipresent leading underscore. */
977 * We're only blacklisting functions in the kernel for now.
979 if (MOD_IS_MACH_KERNEL(ctl
) && !is_symbol_valid(name
))
982 __provide_probe_64(ctl
, instrLow
, instrHigh
, modname
, name
, (machine_inst_t
*)sym
[i
].n_value
);
987 __user_syms_provide_module(void *arg
, struct modctl
*ctl
)
993 modname
= ctl
->mod_modname
;
995 dtrace_module_symbols_t
* module_symbols
= ctl
->mod_user_symbols
;
996 if (module_symbols
) {
997 for (i
=0; i
<module_symbols
->dtmodsyms_count
; i
++) {
1000 * symbol->dtsym_addr (the symbol address) passed in from
1001 * user space, is already slid for both kexts and kernel.
1003 dtrace_symbol_t
* symbol
= &module_symbols
->dtmodsyms_symbols
[i
];
1005 char* name
= symbol
->dtsym_name
;
1007 /* Lop off omnipresent leading underscore. */
1012 * We're only blacklisting functions in the kernel for now.
1014 if (MOD_IS_MACH_KERNEL(ctl
) && !is_symbol_valid(name
))
1017 __provide_probe_64(ctl
, (uintptr_t)symbol
->dtsym_addr
, (uintptr_t)(symbol
->dtsym_addr
+ symbol
->dtsym_size
), modname
, name
, (machine_inst_t
*)(uintptr_t)symbol
->dtsym_addr
);
1022 extern int dtrace_kernel_symbol_mode
;
1026 fbt_provide_module(void *arg
, struct modctl
*ctl
)
1028 ASSERT(ctl
!= NULL
);
1029 ASSERT(dtrace_kernel_symbol_mode
!= DTRACE_KERNEL_SYMBOLS_NEVER
);
1030 lck_mtx_assert(&mod_lock
, LCK_MTX_ASSERT_OWNED
);
1032 if (MOD_FBT_DONE(ctl
))
1035 if (!is_module_valid(ctl
)) {
1036 ctl
->mod_flags
|= MODCTL_FBT_INVALID
;
1040 if (MOD_HAS_KERNEL_SYMBOLS(ctl
)) {
1041 __kernel_syms_provide_module(arg
, ctl
);
1042 ctl
->mod_flags
|= MODCTL_FBT_PROBES_PROVIDED
;
1046 if (MOD_HAS_USERSPACE_SYMBOLS(ctl
)) {
1047 __user_syms_provide_module(arg
, ctl
);
1048 ctl
->mod_flags
|= MODCTL_FBT_PROBES_PROVIDED
;
1049 if (MOD_FBT_PROVIDE_PRIVATE_PROBES(ctl
))
1050 ctl
->mod_flags
|= MODCTL_FBT_PRIVATE_PROBES_PROVIDED
;