14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * CDDL HEADER START
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * The contents of this file are subject to the terms of the
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * Common Development and Distribution License (the "License").
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * You may not use this file except in compliance with the License.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * See the License for the specific language governing permissions
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * and limitations under the License.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * When distributing Covered Code, include this CDDL HEADER in each
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * If applicable, add the following below this CDDL HEADER, with the
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * fields enclosed by brackets "[]" replaced with your own identifying
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * information: Portions Copyright [yyyy] [name of copyright owner]
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * CDDL HEADER END
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * Use is subject to license terms.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync#define FBT_ADDR2NDX(addr) ((((uintptr_t)(addr)) >> 4) & fbt_probetab_mask)
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync#define FBT_PROBETAB_SIZE 0x8000 /* 32k entries -- 128K total */
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncfbt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t rval)
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync fbt_probe_t *fbt = fbt_probetab[FBT_ADDR2NDX(addr)];
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * When accessing the arguments on the stack,
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * we must protect against accessing beyond
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * the stack. We can safely set NOFAULT here
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * -- we know that interrupts are already
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * disabled.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * On amd64, stack[0] contains the dereferenced
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * stack pointer, stack[1] contains savfp,
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * stack[2] contains savpc. We want to step
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * over these entries.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * On amd64, we instrument the ret, not the
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * leave. We therefore need to set the caller
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * to assure that the top frame of a stack()
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * action is correct.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync return (0);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync/*ARGSUSED*/
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * Employees of dtrace and their families are ineligible. Void
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * where prohibited.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (strcmp(list->modl_modp->mod_modname, "dtrace") == 0)
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * KMDB is ineligible for instrumentation -- it may execute in
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * any context, including probe context.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (str == NULL || symhdr == NULL || symhdr->sh_addr == NULL) {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * If this module doesn't (yet) have its string or symbol
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * table allocated, clear out.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * This module has some FBT entries allocated; we're afraid
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * to screw with it.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * Weak symbols are not candidates. This could be made to
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * work (where weak functions and their underlying function
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * appear as two disjoint probes), but it's not simple.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * Anything beginning with "dtrace_" may be called
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * from probe context unless it explitly indicates
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * that it won't be called from probe context by
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * using the prefix "dtrace_safe_".
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * Any function name beginning with "kdi_" or
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * containing the string "_kdi_" is a part of the
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * kernel debugger interface and may be called in
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * arbitrary context -- including probe context.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * Due to 4524008, _init and _fini may have a bloated st_size.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * While this bug was fixed quite some time ago, old drivers
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * may be lurking. We need to develop a better solution to
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * this problem, such that correct _init and _fini functions
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * (the vast majority) may be correctly traced. One solution
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * may be to scan through the entire symbol table to see if
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * any symbol overlaps with _init. If none does, set a bit in
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * the module structure that this module has correct _init and
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * _fini sizes. This will cause some pain the first time a
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * module is scanned, but at least it would be O(N) instead of
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * O(N log N)...
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * In order to be eligible, the function must begin with the
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * following sequence:
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * pushl %esp
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * movl %esp, %ebp
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * Note that there are two variants of encodings that generate
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * the movl; we must check for both. For 64-bit, we would
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * normally insist that a function begin with the following
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * sequence:
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * pushq %rbp
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * movq %rsp, %rbp
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * However, the compiler for 64-bit often splits these two
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * instructions -- and the first instruction in the function
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * is often not the pushq. As a result, on 64-bit we look
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * for any "pushq %rbp" in the function and we instrument
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * this with a breakpoint instruction.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * We either don't save the frame pointer in this
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * function, or we ran into some disassembly
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * screw-up. Either way, we bail.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * If this disassembly fails, then we've likely walked off into
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * a jump table or some other unsuitable area. Bail out of the
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * disassembly now.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * We only instrument "ret" on amd64 -- we don't yet instrument
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * ret imm16, largely because the compiler doesn't seem to
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * (yet) emit them in the kernel...
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * We (desperately) want to avoid erroneously instrumenting a
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * jump table, especially given that our markers are pretty
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * short: two bytes on x86, and just one byte on amd64. To
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * determine if we're looking at a true instruction sequence
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * or an inline jump table that happens to contain the same
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * byte sequences, we resort to some heuristic sleeze: we
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * treat this instruction as being contained within a pointer,
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * and see if that pointer points to within the body of the
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * function. If it does, we refuse to instrument it.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync for (j = 0; j < sizeof (uintptr_t); j++) {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (ptr >= (uint8_t *)sym->st_value && ptr < limit) {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * We have a winner!
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync/*ARGSUSED*/
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (ctl != NULL && ctl->mod_loadcnt == fbt->fbtp_loadcnt) {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * Now we need to remove this probe from the fbt_probetab.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync/*ARGSUSED*/
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync "(module %s unloaded)",
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync return (0);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * Now check that our modctl has the expected load count. If it
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * doesn't, this module must have been unloaded and reloaded -- and
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * we're not going to touch it.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync "(module %s reloaded)",
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync return (0);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync return (0);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync/*ARGSUSED*/
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt))
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync/*ARGSUSED*/
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt))
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync/*ARGSUSED*/
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt))
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync/*ARGSUSED*/
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncfbt_getargdesc(void *arg, dtrace_id_t id, void *parg, dtrace_argdesc_t *desc)
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt))
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (fbt->fbtp_roffset != 0 && desc->dtargd_ndx == 0) {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * We have no CTF information for this module -- and therefore
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * no args[] information.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * If we have a parent container, we must manually import it.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * We must iterate over all modules to find the module that
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * is our parent.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if ((pfp = ctf_modopen(mod->mod_mp, &error)) == NULL) {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (ctf_func_info(fp, fbt->fbtp_symndx, &f) == CTF_ERR)
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (ctf_func_args(fp, fbt->fbtp_symndx, argc, argv) == CTF_ERR)
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync kmem_free(fbt_probetab, fbt_probetab_size * sizeof (fbt_probe_t *));
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync kmem_zalloc(fbt_probetab_size * sizeof (fbt_probe_t *), KM_SLEEP);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync dtrace_register("fbt", &fbt_attr, DTRACE_PRIV_KERNEL, NULL,
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync/*ARGSUSED*/
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncfbt_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync *result = (void *)0;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync/*ARGSUSED*/
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncfbt_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync return (0);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync 0, /* streamtab */
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync 0, /* refcnt */
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * Module linkage information for the kernel.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync &mod_driverops, /* module type (this is a pseudo driver) */