4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/param.h>
27 #include <sys/systm.h>
28 #include <sys/errno.h>
30 #include <sys/ioctl.h>
32 #include <sys/fcntl.h>
33 #include <miscfs/devfs/devfs.h>
35 #if defined(__arm__) || defined(__arm64__)
36 #include <arm/caches_internal.h>
37 #endif /* defined(__arm__) || defined(__arm64__) */
39 #include <sys/dtrace.h>
40 #include <sys/dtrace_impl.h>
42 #include <sys/dtrace_glue.h>
44 #include <sys/sdt_impl.h>
45 extern int dtrace_kernel_symbol_mode
;
49 /* #include <machine/trap.h */
50 struct savearea_t
; /* Used anonymously */
53 typedef kern_return_t (*perfCallback
)(int, struct savearea_t
*, __unused
int, __unused
int);
54 extern perfCallback tempDTraceTrapHook
;
55 extern kern_return_t
fbt_perfCallback(int, struct savearea_t
*, __unused
int, __unused
int);
56 #define SDT_PATCHVAL 0xdefc
58 #elif defined(__arm64__)
59 typedef kern_return_t (*perfCallback
)(int, struct savearea_t
*, __unused
int, __unused
int);
60 extern perfCallback tempDTraceTrapHook
;
61 extern kern_return_t
fbt_perfCallback(int, struct savearea_t
*, __unused
int, __unused
int);
62 #define SDT_PATCHVAL 0xe7eeee7e
64 #elif defined(__x86_64__)
65 typedef kern_return_t (*perfCallback
)(int, struct savearea_t
*, uintptr_t *, int);
66 extern perfCallback tempDTraceTrapHook
;
67 extern kern_return_t
fbt_perfCallback(int, struct savearea_t
*, uintptr_t *, int);
68 #define SDT_PATCHVAL 0xf0
71 #error Unknown architecture
74 #define SDT_PROBETAB_SIZE 0x1000 /* 4k entries -- 16K total */
76 #define DTRACE_PROBE_PREFIX "_dtrace_probe$"
78 static int sdt_verbose
= 0;
79 sdt_probe_t
**sdt_probetab
;
80 int sdt_probetab_size
;
81 int sdt_probetab_mask
;
85 __sdt_provide_module(void *arg
, struct modctl
*ctl
)
88 struct module *mp
= (struct module *)ctl
->mod_address
;
89 char *modname
= ctl
->mod_modname
;
90 sdt_probedesc_t
*sdpd
;
91 sdt_probe_t
*sdp
, *old
;
95 * One for all, and all for one: if we haven't yet registered all of
96 * our providers, we'll refuse to provide anything.
98 for (prov
= sdt_providers
; prov
->sdtp_name
!= NULL
; prov
++) {
99 if (prov
->sdtp_id
== DTRACE_PROVNONE
) {
104 if (!mp
|| mp
->sdt_nprobes
!= 0 || (sdpd
= mp
->sdt_probes
) == NULL
) {
108 for (sdpd
= mp
->sdt_probes
; sdpd
!= NULL
; sdpd
= sdpd
->sdpd_next
) {
112 /* Validate probe's provider name. Do not provide probes for unknown providers. */
113 for (prov
= sdt_providers
; prov
->sdtp_name
!= NULL
; prov
++) {
114 if (strcmp(prov
->sdtp_prefix
, sdpd
->sdpd_prov
) == 0) {
119 if (prov
->sdtp_name
== NULL
) {
120 printf("Ignoring probes from unsupported provider %s\n", sdpd
->sdpd_prov
);
124 sdp
= kmem_zalloc(sizeof(sdt_probe_t
), KM_SLEEP
);
125 sdp
->sdp_loadcnt
= ctl
->mod_loadcnt
;
127 sdp
->sdp_name
= kmem_alloc(strlen(sdpd
->sdpd_name
) + 1, KM_SLEEP
);
128 strncpy(sdp
->sdp_name
, sdpd
->sdpd_name
, strlen(sdpd
->sdpd_name
) + 1);
129 sdp
->sdp_namelen
= strlen(sdpd
->sdpd_name
) + 1;
130 sdp
->sdp_provider
= prov
;
132 func
= (sdpd
->sdpd_func
!= NULL
) ? sdpd
->sdpd_func
: "<unknown>";
135 * We have our provider. Now create the probe.
137 if ((id
= dtrace_probe_lookup(prov
->sdtp_id
, modname
,
138 func
, sdp
->sdp_name
)) != DTRACE_IDNONE
) {
139 old
= dtrace_probe_arg(prov
->sdtp_id
, id
);
142 sdp
->sdp_next
= old
->sdp_next
;
146 sdp
->sdp_id
= dtrace_probe_create(prov
->sdtp_id
,
147 modname
, func
, sdp
->sdp_name
, SDT_AFRAMES
, sdp
);
153 printf("__sdt_provide_module: sdpd=0x%p sdp=0x%p name=%s, id=%d\n", sdpd
, sdp
,
154 sdp
->sdp_name
, sdp
->sdp_id
);
158 sdt_probetab
[SDT_ADDR2NDX(sdpd
->sdpd_offset
)];
159 sdt_probetab
[SDT_ADDR2NDX(sdpd
->sdpd_offset
)] = sdp
;
161 sdp
->sdp_patchval
= SDT_PATCHVAL
;
162 sdp
->sdp_patchpoint
= (sdt_instr_t
*)sdpd
->sdpd_offset
;
163 sdp
->sdp_savedval
= *sdp
->sdp_patchpoint
;
169 sdt_destroy(void *arg
, dtrace_id_t id
, void *parg
)
171 #pragma unused(arg,id)
172 sdt_probe_t
*sdp
= parg
, *old
, *last
, *hash
;
175 #if !defined(__APPLE__)
177 * APPLE NOTE: sdt probes for kexts not yet implemented
179 struct modctl
*ctl
= sdp
->sdp_ctl
;
181 if (ctl
!= NULL
&& ctl
->mod_loadcnt
== sdp
->sdp_loadcnt
) {
182 if ((ctl
->mod_loadcnt
== sdp
->sdp_loadcnt
&&
184 ((struct module *)(ctl
->mod_mp
))->sdt_nprobes
--;
187 #endif /* __APPLE__ */
189 while (sdp
!= NULL
) {
193 * Now we need to remove this probe from the sdt_probetab.
195 ndx
= SDT_ADDR2NDX(sdp
->sdp_patchpoint
);
197 hash
= sdt_probetab
[ndx
];
199 while (hash
!= sdp
) {
200 ASSERT(hash
!= NULL
);
202 hash
= hash
->sdp_hashnext
;
206 last
->sdp_hashnext
= sdp
->sdp_hashnext
;
208 sdt_probetab
[ndx
] = sdp
->sdp_hashnext
;
211 kmem_free(sdp
->sdp_name
, sdp
->sdp_namelen
);
213 kmem_free(old
, sizeof(sdt_probe_t
));
219 sdt_enable(void *arg
, dtrace_id_t id
, void *parg
)
221 #pragma unused(arg,id)
222 sdt_probe_t
*sdp
= parg
;
223 struct modctl
*ctl
= sdp
->sdp_ctl
;
228 * If this module has disappeared since we discovered its probes,
229 * refuse to enable it.
231 if (!ctl
->mod_loaded
) {
233 cmn_err(CE_NOTE
, "sdt is failing for probe %s "
234 "(module %s unloaded)",
235 sdp
->sdp_name
, ctl
->mod_modname
);
241 * Now check that our modctl has the expected load count. If it
242 * doesn't, this module must have been unloaded and reloaded -- and
243 * we're not going to touch it.
245 if (ctl
->mod_loadcnt
!= sdp
->sdp_loadcnt
) {
247 cmn_err(CE_NOTE
, "sdt is failing for probe %s "
248 "(module %s reloaded)",
249 sdp
->sdp_name
, ctl
->mod_modname
);
254 dtrace_casptr(&tempDTraceTrapHook
, NULL
, ptrauth_nop_cast(void *, &fbt_perfCallback
));
255 if (tempDTraceTrapHook
!= (perfCallback
)fbt_perfCallback
) {
257 cmn_err(CE_NOTE
, "sdt_enable is failing for probe %s "
258 "in module %s: tempDTraceTrapHook already occupied.",
259 sdp
->sdp_name
, ctl
->mod_modname
);
264 while (sdp
!= NULL
) {
265 (void)ml_nofault_copy((vm_offset_t
)&sdp
->sdp_patchval
, (vm_offset_t
)sdp
->sdp_patchpoint
,
266 (vm_size_t
)sizeof(sdp
->sdp_patchval
));
269 * Make the patched instruction visible via a data + instruction
270 * cache fush on platforms that need it
272 flush_dcache((vm_offset_t
)sdp
->sdp_patchpoint
, (vm_size_t
)sizeof(sdp
->sdp_patchval
), 0);
273 invalidate_icache((vm_offset_t
)sdp
->sdp_patchpoint
, (vm_size_t
)sizeof(sdp
->sdp_patchval
), 0);
284 sdt_disable(void *arg
, dtrace_id_t id
, void *parg
)
286 #pragma unused(arg,id)
287 sdt_probe_t
*sdp
= parg
;
288 struct modctl
*ctl
= sdp
->sdp_ctl
;
292 if (!ctl
->mod_loaded
|| ctl
->mod_loadcnt
!= sdp
->sdp_loadcnt
) {
296 while (sdp
!= NULL
) {
297 (void)ml_nofault_copy((vm_offset_t
)&sdp
->sdp_savedval
, (vm_offset_t
)sdp
->sdp_patchpoint
,
298 (vm_size_t
)sizeof(sdp
->sdp_savedval
));
300 * Make the patched instruction visible via a data + instruction
301 * cache flush on platforms that need it
303 flush_dcache((vm_offset_t
)sdp
->sdp_patchpoint
, (vm_size_t
)sizeof(sdp
->sdp_savedval
), 0);
304 invalidate_icache((vm_offset_t
)sdp
->sdp_patchpoint
, (vm_size_t
)sizeof(sdp
->sdp_savedval
), 0);
312 static dtrace_pops_t sdt_pops
= {
313 .dtps_provide
= NULL
,
314 .dtps_provide_module
= sdt_provide_module
,
315 .dtps_enable
= sdt_enable
,
316 .dtps_disable
= sdt_disable
,
317 .dtps_suspend
= NULL
,
319 .dtps_getargdesc
= sdt_getargdesc
,
320 .dtps_getargval
= sdt_getarg
,
321 .dtps_usermode
= NULL
,
322 .dtps_destroy
= sdt_destroy
,
327 sdt_attach(dev_info_t
*devi
)
329 sdt_provider_t
*prov
;
331 if (ddi_create_minor_node(devi
, "sdt", S_IFCHR
,
332 0, DDI_PSEUDO
, 0) == DDI_FAILURE
) {
333 cmn_err(CE_NOTE
, "/dev/sdt couldn't create minor node");
334 ddi_remove_minor_node(devi
, NULL
);
338 if (sdt_probetab_size
== 0) {
339 sdt_probetab_size
= SDT_PROBETAB_SIZE
;
342 sdt_probetab_mask
= sdt_probetab_size
- 1;
344 kmem_zalloc(sdt_probetab_size
* sizeof(sdt_probe_t
*), KM_SLEEP
);
345 dtrace_invop_add(sdt_invop
);
347 for (prov
= sdt_providers
; prov
->sdtp_name
!= NULL
; prov
++) {
348 if (dtrace_register(prov
->sdtp_name
, prov
->sdtp_attr
,
349 DTRACE_PRIV_KERNEL
, NULL
,
350 &sdt_pops
, prov
, &prov
->sdtp_id
) != 0) {
351 cmn_err(CE_WARN
, "failed to register sdt provider %s",
360 * APPLE NOTE: sdt_detach not implemented
362 #if !defined(__APPLE__)
365 sdt_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
367 sdt_provider_t
*prov
;
380 for (prov
= sdt_providers
; prov
->sdtp_name
!= NULL
; prov
++) {
381 if (prov
->sdtp_id
!= DTRACE_PROVNONE
) {
382 if (dtrace_unregister(prov
->sdtp_id
) != 0) {
386 prov
->sdtp_id
= DTRACE_PROVNONE
;
390 dtrace_invop_remove(sdt_invop
);
391 kmem_free(sdt_probetab
, sdt_probetab_size
* sizeof(sdt_probe_t
*));
395 #endif /* __APPLE__ */
400 _sdt_open(dev_t dev
, int flags
, int devtype
, struct proc
*p
)
402 #pragma unused(dev,flags,devtype,p)
406 #define SDT_MAJOR -24 /* let the kernel pick the device number */
408 static const struct cdevsw sdt_cdevsw
=
413 .d_write
= eno_rdwrt
,
414 .d_ioctl
= eno_ioctl
,
415 .d_stop
= (stop_fcn_t
*)nulldev
,
416 .d_reset
= (reset_fcn_t
*)nulldev
,
417 .d_select
= eno_select
,
419 .d_strategy
= eno_strat
,
420 .d_reserved_1
= eno_getc
,
421 .d_reserved_2
= eno_putc
,
424 static struct modctl g_sdt_kernctl
;
425 static struct module g_sdt_mach_module
;
427 #include <mach-o/nlist.h>
428 #include <libkern/kernel_mach_header.h>
431 * Represents single record in __DATA,__sdt section.
433 typedef struct dtrace_sdt_def
{
434 uintptr_t dsd_addr
; /* probe site location */
435 const char *dsd_prov
; /* provider's name */
436 const char *dsd_name
; /* probe's name */
437 } __attribute__((__packed__
)) dtrace_sdt_def_t
;
440 * Creates a copy of name and unescapes '-' characters.
443 sdt_strdup_name(const char *name
)
445 size_t len
= strlen(name
) + 1;
447 char *nname
= kmem_alloc(len
, KM_SLEEP
);
449 for (i
= 0, j
= 0; name
[j
] != '\0'; i
++) {
450 if (name
[j
] == '_' && name
[j
+ 1] == '_') {
454 nname
[i
] = name
[j
++];
463 sdt_early_init( void )
465 if (dtrace_sdt_probes_restricted()) {
468 if (MH_MAGIC_KERNEL
!= _mh_execute_header
.magic
) {
469 g_sdt_kernctl
.mod_address
= (vm_address_t
)NULL
;
470 g_sdt_kernctl
.mod_size
= 0;
472 kernel_mach_header_t
*mh
;
473 struct load_command
*cmd
;
474 kernel_segment_command_t
*orig_ts
= NULL
, *orig_le
= NULL
;
475 kernel_section_t
*orig_dt
= NULL
;
476 struct symtab_command
*orig_st
= NULL
;
477 kernel_nlist_t
*sym
= NULL
;
482 g_sdt_mach_module
.sdt_nprobes
= 0;
483 g_sdt_mach_module
.sdt_probes
= NULL
;
485 g_sdt_kernctl
.mod_address
= (vm_address_t
)&g_sdt_mach_module
;
486 g_sdt_kernctl
.mod_size
= 0;
487 strncpy((char *)&(g_sdt_kernctl
.mod_modname
), "mach_kernel", KMOD_MAX_NAME
);
489 g_sdt_kernctl
.mod_next
= NULL
;
490 g_sdt_kernctl
.mod_stale
= NULL
;
491 g_sdt_kernctl
.mod_id
= 0;
492 g_sdt_kernctl
.mod_loadcnt
= 1;
493 g_sdt_kernctl
.mod_loaded
= 1;
494 g_sdt_kernctl
.mod_flags
= 0;
495 g_sdt_kernctl
.mod_nenabled
= 0;
497 mh
= &_mh_execute_header
;
498 cmd
= (struct load_command
*) &mh
[1];
499 for (i
= 0; i
< mh
->ncmds
; i
++) {
500 if (cmd
->cmd
== LC_SEGMENT_KERNEL
) {
501 kernel_segment_command_t
*orig_sg
= (kernel_segment_command_t
*) cmd
;
503 if (LIT_STRNEQL(orig_sg
->segname
, SEG_TEXT
)) {
505 } else if (LIT_STRNEQL(orig_sg
->segname
, SEG_LINKEDIT
)) {
507 } else if (LIT_STRNEQL(orig_sg
->segname
, "")) {
508 orig_ts
= orig_sg
; /* kexts have a single unnamed segment */
510 } else if (cmd
->cmd
== LC_SYMTAB
) {
511 orig_st
= (struct symtab_command
*) cmd
;
514 cmd
= (struct load_command
*) ((uintptr_t) cmd
+ cmd
->cmdsize
);
517 /* Locate DTrace SDT section in the object. */
518 if ((orig_dt
= getsectbyname("__DATA", "__sdt")) == NULL
) {
519 printf("DTrace section not found.\n");
523 if ((orig_ts
== NULL
) || (orig_st
== NULL
) || (orig_le
== NULL
)) {
527 sym
= (kernel_nlist_t
*)(orig_le
->vmaddr
+ orig_st
->symoff
- orig_le
->fileoff
);
528 strings
= (char *)(orig_le
->vmaddr
+ orig_st
->stroff
- orig_le
->fileoff
);
531 * Iterate over SDT section and establish all SDT probes.
533 dtrace_sdt_def_t
*sdtdef
= (dtrace_sdt_def_t
*)(orig_dt
->addr
);
534 for (size_t k
= 0; k
< orig_dt
->size
/ sizeof(dtrace_sdt_def_t
); k
++, sdtdef
++) {
535 const char *funcname
;
538 sdt_probedesc_t
*sdpd
= kmem_alloc(sizeof(sdt_probedesc_t
), KM_SLEEP
);
540 /* Unescape probe name and keep a note of the size of original memory allocation. */
541 sdpd
->sdpd_name
= sdt_strdup_name(sdtdef
->dsd_name
);
542 sdpd
->sdpd_namelen
= strlen(sdtdef
->dsd_name
) + 1;
544 /* Used only for provider structure lookup so there is no need to make dynamic copy. */
545 sdpd
->sdpd_prov
= sdtdef
->dsd_prov
;
548 * Find the symbol immediately preceding the sdt probe site just discovered,
549 * that symbol names the function containing the sdt probe.
551 funcname
= "<unknown>";
552 for (i
= 0; i
< orig_st
->nsyms
; i
++) {
553 uint8_t jn_type
= sym
[i
].n_type
& N_TYPE
;
554 char *jname
= strings
+ sym
[i
].n_un
.n_strx
;
556 if ((N_SECT
!= jn_type
&& N_ABS
!= jn_type
)) {
560 if (0 == sym
[i
].n_un
.n_strx
) { /* iff a null, "", name. */
568 if (sdtdef
->dsd_addr
<= (unsigned long)sym
[i
].n_value
) {
572 if ((unsigned long)sym
[i
].n_value
> best
) {
573 best
= (unsigned long)sym
[i
].n_value
;
578 len
= strlen(funcname
) + 1;
579 sdpd
->sdpd_func
= kmem_alloc(len
, KM_SLEEP
);
580 strncpy(sdpd
->sdpd_func
, funcname
, len
);
582 sdpd
->sdpd_offset
= sdtdef
->dsd_addr
;
584 /* PR8353094 - mask off thumb-bit */
585 sdpd
->sdpd_offset
&= ~0x1U
;
586 #elif defined(__arm64__)
587 sdpd
->sdpd_offset
&= ~0x1LU
;
590 sdpd
->sdpd_next
= g_sdt_mach_module
.sdt_probes
;
591 g_sdt_mach_module
.sdt_probes
= sdpd
;
599 int majdevno
= cdevsw_add(SDT_MAJOR
, &sdt_cdevsw
);
602 printf("sdt_init: failed to allocate a major number!\n");
606 if (dtrace_sdt_probes_restricted()) {
610 sdt_attach((dev_info_t
*)(uintptr_t)majdevno
);
617 sdt_provide_module(void *arg
, struct modctl
*ctl
)
621 ASSERT(dtrace_kernel_symbol_mode
!= DTRACE_KERNEL_SYMBOLS_NEVER
);
622 LCK_MTX_ASSERT(&mod_lock
, LCK_MTX_ASSERT_OWNED
);
624 if (MOD_SDT_DONE(ctl
)) {
628 if (MOD_IS_MACH_KERNEL(ctl
)) {
629 __sdt_provide_module(arg
, &g_sdt_kernctl
);
631 sdt_probedesc_t
*sdpd
= g_sdt_mach_module
.sdt_probes
;
633 sdt_probedesc_t
*this_sdpd
= sdpd
;
634 kmem_free((void *)sdpd
->sdpd_name
, sdpd
->sdpd_namelen
);
635 kmem_free((void *)sdpd
->sdpd_func
, strlen(sdpd
->sdpd_func
) + 1);
636 sdpd
= sdpd
->sdpd_next
;
637 kmem_free((void *)this_sdpd
, sizeof(sdt_probedesc_t
));
639 g_sdt_mach_module
.sdt_probes
= NULL
;
642 * APPLE NOTE: sdt probes for kexts not yet implemented
646 /* Need to mark this module as completed */
647 ctl
->mod_flags
|= MODCTL_SDT_PROBES_PROVIDED
;