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 /* #pragma ident "@(#)sdt.c 1.9 08/07/01 SMI" */
30 #define _KERNEL /* Solaris vs. Darwin */
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/errno.h>
38 #include <sys/ioctl.h>
40 #include <sys/fcntl.h>
41 #include <miscfs/devfs/devfs.h>
44 #include <arm/caches_internal.h>
47 #include <sys/dtrace.h>
48 #include <sys/dtrace_impl.h>
50 #include <sys/dtrace_glue.h>
52 #include <sys/sdt_impl.h>
53 extern int dtrace_kernel_symbol_mode
;
55 /* #include <machine/trap.h */
56 struct savearea_t
; /* Used anonymously */
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 0xdefc
64 #elif defined(__arm64__)
65 typedef kern_return_t (*perfCallback
)(int, struct savearea_t
*, __unused
int, __unused
int);
66 extern perfCallback tempDTraceTrapHook
;
67 extern kern_return_t
fbt_perfCallback(int, struct savearea_t
*, __unused
int, __unused
int);
68 #define SDT_PATCHVAL 0xe7eeee7e
70 #elif defined(__x86_64__)
71 typedef kern_return_t (*perfCallback
)(int, struct savearea_t
*, uintptr_t *, int);
72 extern perfCallback tempDTraceTrapHook
;
73 extern kern_return_t
fbt_perfCallback(int, struct savearea_t
*, uintptr_t *, int);
74 #define SDT_PATCHVAL 0xf0
77 #error Unknown architecture
80 #define SDT_PROBETAB_SIZE 0x1000 /* 4k entries -- 16K total */
82 #define DTRACE_PROBE_PREFIX "_dtrace_probe$"
84 static dev_info_t
*sdt_devi
;
85 static int sdt_verbose
= 0;
86 sdt_probe_t
**sdt_probetab
;
87 int sdt_probetab_size
;
88 int sdt_probetab_mask
;
92 __sdt_provide_module(void *arg
, struct modctl
*ctl
)
95 struct module *mp
= (struct module *)ctl
->mod_address
;
96 char *modname
= ctl
->mod_modname
;
97 sdt_probedesc_t
*sdpd
;
98 sdt_probe_t
*sdp
, *old
;
103 * One for all, and all for one: if we haven't yet registered all of
104 * our providers, we'll refuse to provide anything.
106 for (prov
= sdt_providers
; prov
->sdtp_name
!= NULL
; prov
++) {
107 if (prov
->sdtp_id
== DTRACE_PROVNONE
)
111 if (!mp
|| mp
->sdt_nprobes
!= 0 || (sdpd
= mp
->sdt_probes
) == NULL
)
114 for (sdpd
= mp
->sdt_probes
; sdpd
!= NULL
; sdpd
= sdpd
->sdpd_next
) {
115 const char *name
= sdpd
->sdpd_name
, *func
;
120 for (prov
= sdt_providers
; prov
->sdtp_prefix
!= NULL
; prov
++) {
121 const char *prefpart
, *prefix
= prov
->sdtp_prefix
;
123 if ((prefpart
= strstr(name
, prefix
))) {
124 name
= prefpart
+ strlen(prefix
);
129 nname
= kmem_alloc(len
= strlen(name
) + 1, KM_SLEEP
);
131 for (i
= 0, j
= 0; name
[j
] != '\0'; i
++) {
132 if (name
[j
] == '_' && name
[j
+ 1] == '_') {
136 nname
[i
] = name
[j
++];
142 sdp
= kmem_zalloc(sizeof (sdt_probe_t
), KM_SLEEP
);
143 sdp
->sdp_loadcnt
= ctl
->mod_loadcnt
;
145 sdp
->sdp_name
= nname
;
146 sdp
->sdp_namelen
= len
;
147 sdp
->sdp_provider
= prov
;
149 func
= sdpd
->sdpd_func
;
155 * We have our provider. Now create the probe.
157 if ((id
= dtrace_probe_lookup(prov
->sdtp_id
, modname
,
158 func
, nname
)) != DTRACE_IDNONE
) {
159 old
= dtrace_probe_arg(prov
->sdtp_id
, id
);
162 sdp
->sdp_next
= old
->sdp_next
;
166 sdp
->sdp_id
= dtrace_probe_create(prov
->sdtp_id
,
167 modname
, func
, nname
, SDT_AFRAMES
, sdp
);
173 printf ("__sdt_provide_module: sdpd=0x%p sdp=0x%p name=%s, id=%d\n", sdpd
, sdp
, nname
, sdp
->sdp_id
);
177 sdt_probetab
[SDT_ADDR2NDX(sdpd
->sdpd_offset
)];
178 sdt_probetab
[SDT_ADDR2NDX(sdpd
->sdpd_offset
)] = sdp
;
180 sdp
->sdp_patchval
= SDT_PATCHVAL
;
181 sdp
->sdp_patchpoint
= (sdt_instr_t
*)sdpd
->sdpd_offset
;
182 sdp
->sdp_savedval
= *sdp
->sdp_patchpoint
;
188 sdt_destroy(void *arg
, dtrace_id_t id
, void *parg
)
190 #pragma unused(arg,id)
191 sdt_probe_t
*sdp
= parg
, *old
, *last
, *hash
;
194 #if !defined(__APPLE__)
196 * APPLE NOTE: sdt probes for kexts not yet implemented
198 struct modctl
*ctl
= sdp
->sdp_ctl
;
200 if (ctl
!= NULL
&& ctl
->mod_loadcnt
== sdp
->sdp_loadcnt
) {
201 if ((ctl
->mod_loadcnt
== sdp
->sdp_loadcnt
&&
203 ((struct module *)(ctl
->mod_mp
))->sdt_nprobes
--;
206 #endif /* __APPLE__ */
208 while (sdp
!= NULL
) {
212 * Now we need to remove this probe from the sdt_probetab.
214 ndx
= SDT_ADDR2NDX(sdp
->sdp_patchpoint
);
216 hash
= sdt_probetab
[ndx
];
218 while (hash
!= sdp
) {
219 ASSERT(hash
!= NULL
);
221 hash
= hash
->sdp_hashnext
;
225 last
->sdp_hashnext
= sdp
->sdp_hashnext
;
227 sdt_probetab
[ndx
] = sdp
->sdp_hashnext
;
230 kmem_free(sdp
->sdp_name
, sdp
->sdp_namelen
);
232 kmem_free(old
, sizeof (sdt_probe_t
));
238 sdt_enable(void *arg
, dtrace_id_t id
, void *parg
)
240 #pragma unused(arg,id)
241 sdt_probe_t
*sdp
= parg
;
242 struct modctl
*ctl
= sdp
->sdp_ctl
;
247 * If this module has disappeared since we discovered its probes,
248 * refuse to enable it.
250 if (!ctl
->mod_loaded
) {
252 cmn_err(CE_NOTE
, "sdt is failing for probe %s "
253 "(module %s unloaded)",
254 sdp
->sdp_name
, ctl
->mod_modname
);
260 * Now check that our modctl has the expected load count. If it
261 * doesn't, this module must have been unloaded and reloaded -- and
262 * we're not going to touch it.
264 if (ctl
->mod_loadcnt
!= sdp
->sdp_loadcnt
) {
266 cmn_err(CE_NOTE
, "sdt is failing for probe %s "
267 "(module %s reloaded)",
268 sdp
->sdp_name
, ctl
->mod_modname
);
273 dtrace_casptr(&tempDTraceTrapHook
, NULL
, fbt_perfCallback
);
274 if (tempDTraceTrapHook
!= (perfCallback
)fbt_perfCallback
) {
276 cmn_err(CE_NOTE
, "sdt_enable is failing for probe %s "
277 "in module %s: tempDTraceTrapHook already occupied.",
278 sdp
->sdp_name
, ctl
->mod_modname
);
283 while (sdp
!= NULL
) {
284 (void)ml_nofault_copy( (vm_offset_t
)&sdp
->sdp_patchval
, (vm_offset_t
)sdp
->sdp_patchpoint
,
285 (vm_size_t
)sizeof(sdp
->sdp_patchval
));
288 * Make the patched instruction visible via a data + instruction
289 * cache fush on platforms that need it
291 flush_dcache((vm_offset_t
)sdp
->sdp_patchpoint
,(vm_size_t
)sizeof(sdp
->sdp_patchval
), 0);
292 invalidate_icache((vm_offset_t
)sdp
->sdp_patchpoint
,(vm_size_t
)sizeof(sdp
->sdp_patchval
), 0);
303 sdt_disable(void *arg
, dtrace_id_t id
, void *parg
)
305 #pragma unused(arg,id)
306 sdt_probe_t
*sdp
= parg
;
307 struct modctl
*ctl
= sdp
->sdp_ctl
;
311 if (!ctl
->mod_loaded
|| ctl
->mod_loadcnt
!= sdp
->sdp_loadcnt
)
314 while (sdp
!= NULL
) {
315 (void)ml_nofault_copy( (vm_offset_t
)&sdp
->sdp_savedval
, (vm_offset_t
)sdp
->sdp_patchpoint
,
316 (vm_size_t
)sizeof(sdp
->sdp_savedval
));
318 * Make the patched instruction visible via a data + instruction
319 * cache flush on platforms that need it
321 flush_dcache((vm_offset_t
)sdp
->sdp_patchpoint
,(vm_size_t
)sizeof(sdp
->sdp_savedval
), 0);
322 invalidate_icache((vm_offset_t
)sdp
->sdp_patchpoint
,(vm_size_t
)sizeof(sdp
->sdp_savedval
), 0);
330 static dtrace_pops_t sdt_pops
= {
345 sdt_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
)
348 sdt_provider_t
*prov
;
350 if (ddi_create_minor_node(devi
, "sdt", S_IFCHR
,
351 0, DDI_PSEUDO
, 0) == DDI_FAILURE
) {
352 cmn_err(CE_NOTE
, "/dev/sdt couldn't create minor node");
353 ddi_remove_minor_node(devi
, NULL
);
354 return (DDI_FAILURE
);
357 ddi_report_dev(devi
);
360 if (sdt_probetab_size
== 0)
361 sdt_probetab_size
= SDT_PROBETAB_SIZE
;
363 sdt_probetab_mask
= sdt_probetab_size
- 1;
365 kmem_zalloc(sdt_probetab_size
* sizeof (sdt_probe_t
*), KM_SLEEP
);
366 dtrace_invop_add(sdt_invop
);
368 for (prov
= sdt_providers
; prov
->sdtp_name
!= NULL
; prov
++) {
369 if (dtrace_register(prov
->sdtp_name
, prov
->sdtp_attr
,
370 DTRACE_PRIV_KERNEL
, NULL
,
371 &sdt_pops
, prov
, &prov
->sdtp_id
) != 0) {
372 cmn_err(CE_WARN
, "failed to register sdt provider %s",
377 return (DDI_SUCCESS
);
381 * APPLE NOTE: sdt_detach not implemented
383 #if !defined(__APPLE__)
386 sdt_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
388 sdt_provider_t
*prov
;
395 return (DDI_SUCCESS
);
398 return (DDI_FAILURE
);
401 for (prov
= sdt_providers
; prov
->sdtp_name
!= NULL
; prov
++) {
402 if (prov
->sdtp_id
!= DTRACE_PROVNONE
) {
403 if (dtrace_unregister(prov
->sdtp_id
) != 0)
404 return (DDI_FAILURE
);
406 prov
->sdtp_id
= DTRACE_PROVNONE
;
410 dtrace_invop_remove(sdt_invop
);
411 kmem_free(sdt_probetab
, sdt_probetab_size
* sizeof (sdt_probe_t
*));
413 return (DDI_SUCCESS
);
415 #endif /* __APPLE__ */
419 int _sdt_open(dev_t dev
, int flags
, int devtype
, struct proc
*p
)
421 #pragma unused(dev,flags,devtype,p)
425 #define SDT_MAJOR -24 /* let the kernel pick the device number */
428 * A struct describing which functions will get invoked for certain
431 static struct cdevsw sdt_cdevsw
=
433 _sdt_open
, /* open */
434 eno_opcl
, /* close */
435 eno_rdwrt
, /* read */
436 eno_rdwrt
, /* write */
437 eno_ioctl
, /* ioctl */
438 (stop_fcn_t
*)nulldev
, /* stop */
439 (reset_fcn_t
*)nulldev
, /* reset */
441 eno_select
, /* select */
443 eno_strat
, /* strategy */
449 static int gSDTInited
= 0;
450 static struct modctl g_sdt_kernctl
;
451 static struct module g_sdt_mach_module
;
453 #include <mach-o/nlist.h>
454 #include <libkern/kernel_mach_header.h>
456 void sdt_init( void )
460 int majdevno
= cdevsw_add(SDT_MAJOR
, &sdt_cdevsw
);
463 printf("sdt_init: failed to allocate a major number!\n");
468 if (dtrace_sdt_probes_restricted()) {
472 if (MH_MAGIC_KERNEL
!= _mh_execute_header
.magic
) {
473 g_sdt_kernctl
.mod_address
= (vm_address_t
)NULL
;
474 g_sdt_kernctl
.mod_size
= 0;
476 kernel_mach_header_t
*mh
;
477 struct load_command
*cmd
;
478 kernel_segment_command_t
*orig_ts
= NULL
, *orig_le
= NULL
;
479 struct symtab_command
*orig_st
= NULL
;
480 kernel_nlist_t
*sym
= NULL
;
484 g_sdt_mach_module
.sdt_nprobes
= 0;
485 g_sdt_mach_module
.sdt_probes
= NULL
;
487 g_sdt_kernctl
.mod_address
= (vm_address_t
)&g_sdt_mach_module
;
488 g_sdt_kernctl
.mod_size
= 0;
489 strncpy((char *)&(g_sdt_kernctl
.mod_modname
), "mach_kernel", KMOD_MAX_NAME
);
491 g_sdt_kernctl
.mod_next
= NULL
;
492 g_sdt_kernctl
.mod_stale
= NULL
;
493 g_sdt_kernctl
.mod_id
= 0;
494 g_sdt_kernctl
.mod_loadcnt
= 1;
495 g_sdt_kernctl
.mod_loaded
= 1;
496 g_sdt_kernctl
.mod_flags
= 0;
497 g_sdt_kernctl
.mod_nenabled
= 0;
499 mh
= &_mh_execute_header
;
500 cmd
= (struct load_command
*) &mh
[1];
501 for (i
= 0; i
< mh
->ncmds
; i
++) {
502 if (cmd
->cmd
== LC_SEGMENT_KERNEL
) {
503 kernel_segment_command_t
*orig_sg
= (kernel_segment_command_t
*) cmd
;
505 if (LIT_STRNEQL(orig_sg
->segname
, SEG_TEXT
))
507 else if (LIT_STRNEQL(orig_sg
->segname
, SEG_LINKEDIT
))
509 else if (LIT_STRNEQL(orig_sg
->segname
, ""))
510 orig_ts
= orig_sg
; /* kexts have a single unnamed segment */
512 else if (cmd
->cmd
== LC_SYMTAB
)
513 orig_st
= (struct symtab_command
*) cmd
;
515 cmd
= (struct load_command
*) ((uintptr_t) cmd
+ cmd
->cmdsize
);
518 if ((orig_ts
== NULL
) || (orig_st
== NULL
) || (orig_le
== NULL
))
521 sym
= (kernel_nlist_t
*)(orig_le
->vmaddr
+ orig_st
->symoff
- orig_le
->fileoff
);
522 strings
= (char *)(orig_le
->vmaddr
+ orig_st
->stroff
- orig_le
->fileoff
);
524 for (i
= 0; i
< orig_st
->nsyms
; i
++) {
525 uint8_t n_type
= sym
[i
].n_type
& (N_TYPE
| N_EXT
);
526 char *name
= strings
+ sym
[i
].n_un
.n_strx
;
527 const char *prev_name
;
531 /* Check that the symbol is a global and that it has a name. */
532 if (((N_SECT
| N_EXT
) != n_type
&& (N_ABS
| N_EXT
) != n_type
))
535 if (0 == sym
[i
].n_un
.n_strx
) /* iff a null, "", name. */
538 /* Lop off omnipresent leading underscore. */
542 if (strncmp(name
, DTRACE_PROBE_PREFIX
, sizeof(DTRACE_PROBE_PREFIX
) - 1) == 0) {
543 sdt_probedesc_t
*sdpd
= kmem_alloc(sizeof(sdt_probedesc_t
), KM_SLEEP
);
544 int len
= strlen(name
) + 1;
546 sdpd
->sdpd_name
= kmem_alloc(len
, KM_SLEEP
);
547 strncpy(sdpd
->sdpd_name
, name
, len
); /* NUL termination is ensured. */
549 prev_name
= "<unknown>";
553 * Find the symbol immediately preceding the sdt probe site just discovered,
554 * that symbol names the function containing the sdt probe.
556 for (j
= 0; j
< orig_st
->nsyms
; j
++) {
557 uint8_t jn_type
= sym
[j
].n_type
& N_TYPE
;
558 char *jname
= strings
+ sym
[j
].n_un
.n_strx
;
560 if ((N_SECT
!= jn_type
&& N_ABS
!= jn_type
))
563 if (0 == sym
[j
].n_un
.n_strx
) /* iff a null, "", name. */
569 if (*(unsigned long *)sym
[i
].n_value
<= (unsigned long)sym
[j
].n_value
)
572 if ((unsigned long)sym
[j
].n_value
> best
) {
573 best
= (unsigned long)sym
[j
].n_value
;
578 sdpd
->sdpd_func
= kmem_alloc((len
= strlen(prev_name
) + 1), KM_SLEEP
);
579 strncpy(sdpd
->sdpd_func
, prev_name
, len
); /* NUL termination is ensured. */
581 sdpd
->sdpd_offset
= *(unsigned long *)sym
[i
].n_value
;
583 /* PR8353094 - mask off thumb-bit */
584 sdpd
->sdpd_offset
&= ~0x1U
;
585 #elif defined(__arm64__)
586 sdpd
->sdpd_offset
&= ~0x1LU
;
590 printf("sdt_init: sdpd_offset=0x%lx, n_value=0x%lx, name=%s\n",
591 sdpd
->sdpd_offset
, *(unsigned long *)sym
[i
].n_value
, name
);
594 sdpd
->sdpd_next
= g_sdt_mach_module
.sdt_probes
;
595 g_sdt_mach_module
.sdt_probes
= sdpd
;
602 sdt_attach( (dev_info_t
*)(uintptr_t)majdevno
, DDI_ATTACH
);
606 panic("sdt_init: called twice!\n");
613 sdt_provide_module(void *arg
, struct modctl
*ctl
)
617 ASSERT(dtrace_kernel_symbol_mode
!= DTRACE_KERNEL_SYMBOLS_NEVER
);
618 LCK_MTX_ASSERT(&mod_lock
, LCK_MTX_ASSERT_OWNED
);
620 if (MOD_SDT_DONE(ctl
))
623 if (MOD_IS_MACH_KERNEL(ctl
)) {
624 __sdt_provide_module(arg
, &g_sdt_kernctl
);
626 sdt_probedesc_t
*sdpd
= g_sdt_mach_module
.sdt_probes
;
628 sdt_probedesc_t
*this_sdpd
= sdpd
;
629 kmem_free((void *)sdpd
->sdpd_name
, strlen(sdpd
->sdpd_name
) + 1);
630 kmem_free((void *)sdpd
->sdpd_func
, strlen(sdpd
->sdpd_func
) + 1);
631 sdpd
= sdpd
->sdpd_next
;
632 kmem_free((void *)this_sdpd
, sizeof(sdt_probedesc_t
));
634 g_sdt_mach_module
.sdt_probes
= NULL
;
637 * APPLE NOTE: sdt probes for kexts not yet implemented
641 /* Need to mark this module as completed */
642 ctl
->mod_flags
|= MODCTL_SDT_PROBES_PROVIDED
;