]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
dtrace: function boundary tracing (FBT) implementation
authorKris Van Hees <kris.van.hees@oracle.com>
Sat, 17 Dec 2016 23:08:44 +0000 (18:08 -0500)
committerKris Van Hees <kris.van.hees@oracle.com>
Sat, 24 Dec 2016 06:29:02 +0000 (01:29 -0500)
This commit provides the actual implementation of the FBT provider.

Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com>
Orabug: 21220305
Orabug: 24829326

12 files changed:
dtrace/Kbuild
dtrace/dtrace_isa_sparc64.c
dtrace/fasttrap_dev.c
dtrace/fasttrap_sparc64.c
dtrace/fbt_dev.c [new file with mode: 0644]
dtrace/fbt_impl.h [new file with mode: 0644]
dtrace/fbt_mod.c [new file with mode: 0644]
dtrace/fbt_sparc64.c [new file with mode: 0644]
dtrace/fbt_x86_64.c [new file with mode: 0644]
dtrace/include/sparc64/dtrace/isa_arch.h
dtrace/include/sparc64/dtrace/mod_arch.h
dtrace/include/x86_64/dtrace/mod_arch.h

index 32a0ecf64a10df7e76e3296631012afe53385f2a..785bc2335c23302d0e9f7f0ed56f192187898ca3 100644 (file)
@@ -29,6 +29,7 @@ EXTRA_CFLAGS                  := -I$(src)/include -I$(src)/include/uapi \
 
 obj-$(CONFIG_DT_CORE)          += dtrace.o
 obj-$(CONFIG_DT_FASTTRAP)      += fasttrap.o
+obj-$(CONFIG_DT_FBT)           += fbt.o
 obj-$(CONFIG_DT_PROFILE)       += profile.o
 obj-$(CONFIG_DT_SDT)           += sdt.o
 obj-$(CONFIG_DT_SYSTRACE)      += systrace.o
@@ -47,6 +48,7 @@ dtrace-y                      := dtrace_mod.o dtrace_dev.o \
                                   dtrace_ptofapi.o dtrace_predicate.o \
                                   dtrace_spec.o dtrace_state.o dtrace_util.o
 fasttrap-y                     := fasttrap_mod.o fasttrap_dev.o fasttrap_$(UTS_MACHINE).o
+fbt-y                          := fbt_mod.o fbt_dev.o fbt_$(UTS_MACHINE).o
 profile-y                      := profile_mod.o profile_dev.o
 sdt-y                          := sdt_mod.o sdt_dev.o sdt_$(UTS_MACHINE).o
 systrace-y                     := systrace_mod.o systrace_dev.o
index 903216e8936123a0ff06f642839aeae9990977ee..8901fb10377619a4eeff71a5048cf6891bc41ce3 100644 (file)
 
 uint64_t dtrace_getarg(int argno, int aframes)
 {
-       uintptr_t               val;
        struct sparc_v9_frame   *fp;
        uint64_t                rval;
-       int                     lvl;
 
        /*
         * Account for the fact that dtrace_getarg() consumes an additional
@@ -47,10 +45,10 @@ uint64_t dtrace_getarg(int argno, int aframes)
 
 #ifdef FIXME
        if (argno < 6) {
-               if ((lvl = dtrace_fish(aframes, REG_I0 + argno, &val)) == 0)
+               if ((lvl = dtrace_fish(aframes, ASM_REG_I0 + argno, &val)) == 0)
                        return val;
        } else {
-               if ((lvl = dtrace_fish(aframes, REG_I6, &val)) == 0) {
+               if ((lvl = dtrace_fish(aframes, ASM_REG_I6, &val)) == 0) {
                        /*
                         * We have a stack pointer; grab the argument.
                         */
@@ -94,19 +92,19 @@ ulong_t dtrace_getreg(struct task_struct *task, uint_t reg)
 {
        struct pt_regs  *rp = task_pt_regs(task);
 
-       if (reg <= REG_O7)                      /* G[0-7], O[0-7] */
+       if (reg <= ASM_REG_O7)                  /* G[0-7], O[0-7] */
                return rp->u_regs[reg];         /* 0 .. 15 */
 
-       if (reg <= REG_I7) {                    /* L[0-7], I[0-7] */
+       if (reg <= ASM_REG_I7) {                /* L[0-7], I[0-7] */
                if (rp->tstate & TSTATE_PRIV) {
                        struct reg_window       *rw;
 
                        rw = (struct reg_window *)(rp->u_regs[14] + STACK_BIAS);
 
-                       if (reg <= REG_L7)
-                               return rw->locals[reg - REG_L0];
+                       if (reg <= ASM_REG_L7)
+                               return rw->locals[reg - ASM_REG_L0];
                        else
-                               return rw->ins[reg - REG_I0];
+                               return rw->ins[reg - ASM_REG_I0];
                } else {
                        mm_segment_t                    old_fs;
                        struct reg_window __user        *rw;
@@ -120,10 +118,14 @@ ulong_t dtrace_getreg(struct task_struct *task, uint_t reg)
 
                        DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
 
-                       if (reg <= REG_L7)
-                               val = dtrace_fulword(&rw->locals[reg - REG_L0]);
+                       if (reg <= ASM_REG_L7)
+                               val = dtrace_fulword(
+                                       &rw->locals[reg - ASM_REG_L0]
+                                     );
                        else
-                               val = dtrace_fulword(&rw->locals[reg - REG_I0]);
+                               val = dtrace_fulword(
+                                       &rw->locals[reg - ASM_REG_I0]
+                                     );
 
                        DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
 
@@ -154,11 +156,18 @@ ulong_t dtrace_getreg(struct task_struct *task, uint_t reg)
 
 void pdata_init(dtrace_module_t *pdata, struct module *mp)
 {
-       if (mp->pdata)
-               pdata->sdt_tab = mp->pdata;
+       if (mp->pdata) {
+               pdata->sdt_tab = (asm_instr_t *)((uintptr_t)mp->pdata +
+                                                DTRACE_PD_SDT_OFF(mp));
+               pdata->fbt_tab = (asm_instr_t *)((uintptr_t)mp->pdata +
+                                                DTRACE_PD_FBT_OFF(mp));
+       } else {
+               pdata->sdt_tab = NULL;
+               pdata->fbt_tab = NULL;
+       }
 }
 
 void pdata_cleanup(dtrace_module_t *pdata, struct module *mp)
 {
-       mp->pdata = pdata->sdt_tab;
+       mp->pdata = (void *)((uintptr_t)pdata->sdt_tab - DTRACE_PD_SDT_OFF(mp));
 }
index e5fafcde9e7c5e06493c4f46be288dcd47feadc5..3d8b9b0bae3e4294d7c4ce20e56907dec7537920 100644 (file)
@@ -753,13 +753,6 @@ static int fasttrap_uint32_cmp(const void *ap, const void *bp)
        return (*(const uint32_t *)ap - *(const uint32_t *)bp);
 }
 
-#if 0
-static int fasttrap_uint64_cmp(const void *ap, const void *bp)
-{
-       return (*(const uint64_t *)ap - *(const uint64_t *)bp);
-}
-#endif
-
 void fasttrap_meta_create_probe(void *arg, void *parg,
                                dtrace_helper_probedesc_t *dhpb)
 {
@@ -1068,7 +1061,7 @@ static fasttrap_provider_t *fasttrap_provider_lookup(pid_t pid,
                                                     const dtrace_pattr_t *pa)
 {
        fasttrap_provider_t     *fp, *new_fp = NULL;
-       fasttrap_proc_t         *proc;
+       fasttrap_proc_t         *proc = NULL;
        fasttrap_bucket_t       *bucket;
        char                    provname[DTRACE_PROVNAMELEN];
        struct task_struct      *p;
index 2a52933bd01363e19f553e5c8b0fddafcd957bf5..732e7a2c42b55170cd1ecaae06a02c7b1d194ef0 100644 (file)
@@ -116,6 +116,6 @@ void fasttrap_pid_probe_arch(fasttrap_probe_t *ftp, struct pt_regs *regs)
 
 void fasttrap_set_enabled(struct pt_regs *regs)
 {
-       regs->u_regs[REG_O0] = 1;
+       regs->u_regs[ASM_REG_O0] = 1;
 }
 
diff --git a/dtrace/fbt_dev.c b/dtrace/fbt_dev.c
new file mode 100644 (file)
index 0000000..b0cc683
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * FILE:       fbt_dev.c
+ * DESCRIPTION:        Function Boundary Tracing: device file handling
+ *
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 2010, 2011, 2012, 2013 Oracle, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/kallsyms.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/dtrace_fbt.h>
+
+#include "dtrace.h"
+#include "dtrace_dev.h"
+#include "fbt_impl.h"
+
+#define FBT_PROBETAB_SIZE      0x8000          /* 32k entries -- 128K total */
+
+fbt_probe_t            **fbt_probetab;
+int                    fbt_probetab_size = FBT_PROBETAB_SIZE;
+int                    fbt_probetab_mask;
+
+static void *fbt_provide_probe(struct module *mp, char *func, int type, int
+                              stype, asm_instr_t *addr, void *pfbt)
+{
+       fbt_probe_t     *fbp;
+       fbt_probe_t     *prev;
+
+       /*
+        * Only syscalls for now...
+        */
+       if (strncmp(func, "SyS_", 4))
+               return NULL;
+
+       switch (type) {
+       case FBT_ENTRY:
+               fbp = kzalloc(sizeof(fbt_probe_t), GFP_KERNEL);
+               fbp->fbp_name = kstrdup(func, GFP_KERNEL);
+               fbp->fbp_id = dtrace_probe_create(fbt_id, mp->name, func,
+                                                 "entry", 3, fbp);
+               fbp->fbp_module = mp;
+               fbp->fbp_loadcnt = 1; /* FIXME */
+               fbp->fbp_primary = 1; /* FIXME */
+               fbp->fbp_patchpoint = addr;
+               fbt_provide_probe_arch(fbp, type, stype);
+                fbp->fbp_hashnext = fbt_probetab[FBT_ADDR2NDX(addr)];
+
+               fbt_probetab[FBT_ADDR2NDX(addr)] = fbp;
+
+               PDATA(mp)->fbt_probe_cnt++;
+
+               return fbp;
+       case FBT_RETURN:
+               fbp = kzalloc(sizeof(fbt_probe_t), GFP_KERNEL);
+               fbp->fbp_name = kstrdup(func, GFP_KERNEL);
+
+               prev = (fbt_probe_t *)pfbt;
+               if (prev != NULL) {
+                       prev->fbp_next = fbp;
+                       fbp->fbp_id = prev->fbp_id;
+               } else {
+                       fbp->fbp_id = dtrace_probe_create(fbt_id, mp->name,
+                                                         func, "return", 3,
+                                                         fbp);
+               }
+
+               fbp->fbp_module = mp;
+               fbp->fbp_loadcnt = 1; /* FIXME */
+               fbp->fbp_primary = 1; /* FIXME */
+               fbp->fbp_patchpoint = addr;
+               fbt_provide_probe_arch(fbp, type, stype);
+                fbp->fbp_hashnext = fbt_probetab[FBT_ADDR2NDX(addr)];
+
+               fbt_probetab[FBT_ADDR2NDX(addr)] = fbp;
+
+               PDATA(mp)->fbt_probe_cnt++;
+
+               return fbp;
+       default:
+               printk(KERN_INFO "FBT: Invalid probe type %d (%d) for %s\n",
+                      type, stype, func);
+
+               return NULL;
+       }
+}
+
+void fbt_provide_module(void *arg, struct module *mp)
+{
+       /*
+        * Nothing to do if the module FBT probes were already created.
+        */
+       if (PDATA(mp)->fbt_probe_cnt != 0)
+               return;
+
+       if (strncmp(mp->name, "vmlinux", 7))
+               return;
+
+       dtrace_fbt_init((fbt_add_probe_fn)fbt_provide_probe);
+}
+
+int _fbt_enable(void *arg, dtrace_id_t id, void *parg)
+{
+       fbt_probe_t     *fbp = parg;
+       fbt_probe_t     *curr;
+
+       /*
+        * Ensure that we have a reference to the module.
+        */
+       if (!try_module_get(fbp->fbp_module))
+               return -EAGAIN;
+
+       /*
+        * If at least one other enabled probe exists for this module, drop the
+        * reference we took above, because we only need one to prevent the
+        * module from being unloaded.
+        */
+       PDATA(fbp->fbp_module)->enabled_cnt++;
+       if (PDATA(fbp->fbp_module)->enabled_cnt > 1)
+               module_put(fbp->fbp_module);
+
+       for (curr = fbp; curr != NULL; curr = curr->fbp_next)
+               fbt_enable_arch(curr, id, arg);
+
+       return 0;
+}
+
+void _fbt_disable(void *arg, dtrace_id_t id, void *parg)
+{
+       fbt_probe_t     *fbp = parg;
+       fbt_probe_t     *curr;
+
+       for (curr = fbp; curr != NULL; curr = curr->fbp_next)
+               fbt_disable_arch(curr, id, arg);
+
+       /*
+        * If we are disabling a probe, we know it was enabled, and therefore
+        * we know that we have a reference on the module to prevent it from
+        * being unloaded.  If we disable the last probe on the module, we can
+        * drop the reference.
+        */
+       PDATA(fbp->fbp_module)->enabled_cnt--;
+       if (PDATA(fbp->fbp_module)->enabled_cnt == 0)
+               module_put(fbp->fbp_module);
+}
+
+void fbt_destroy(void *arg, dtrace_id_t id, void *parg)
+{
+       fbt_probe_t     *fbp = parg;
+       fbt_probe_t     *nxt, *hbp, *lst;
+       struct module   *mp = fbp->fbp_module;
+       int             ndx;
+
+       do {
+               if (mp != NULL)
+                       PDATA(mp)->fbt_probe_cnt--;
+
+               ndx = FBT_ADDR2NDX(fbp->fbp_patchpoint);
+               lst = NULL;
+               hbp = fbt_probetab[ndx];
+
+               while (hbp != fbp) {
+                       ASSERT(hbp != NULL);
+
+                       lst = hbp;
+                       hbp = hbp->fbp_hashnext;
+               }
+
+               if (lst != NULL)
+                       lst->fbp_hashnext = fbp->fbp_hashnext;
+               else
+                       fbt_probetab[ndx] = fbp->fbp_hashnext;
+
+               nxt = fbp->fbp_next;
+
+               kfree(fbp);
+
+               fbp = nxt;
+       } while (fbp != NULL);
+}
+
+static long fbt_ioctl(struct file *file,
+                        unsigned int cmd, unsigned long arg)
+{
+       return -EAGAIN;
+}
+
+static int fbt_open(struct inode *inode, struct file *file)
+{
+       return -EAGAIN;
+}
+
+static int fbt_close(struct inode *inode, struct file *file)
+{
+       return 0;
+}
+
+static const struct file_operations fbt_fops = {
+       .owner  = THIS_MODULE,
+        .unlocked_ioctl = fbt_ioctl,
+        .open   = fbt_open,
+        .release = fbt_close,
+};
+
+static struct miscdevice fbt_dev = {
+       .minor = DT_DEV_FBT_MINOR,
+       .name = "fbt",
+       .nodename = "dtrace/provider/fbt",
+       .fops = &fbt_fops,
+};
+
+int fbt_dev_init(void)
+{
+       int ret = 0;
+
+       fbt_probetab_mask = fbt_probetab_size - 1;
+       fbt_probetab = dtrace_vzalloc_try(fbt_probetab_size *
+                                         sizeof (fbt_probe_t *));
+
+       ret = misc_register(&fbt_dev);
+       if (ret)
+               pr_err("%s: Can't register misc device %d\n",
+                      fbt_dev.name, fbt_dev.minor);
+
+       fbt_dev_init_arch();
+
+       return ret;
+}
+
+void fbt_dev_exit(void)
+{
+       fbt_dev_exit_arch();
+
+       misc_deregister(&fbt_dev);
+
+       vfree(fbt_probetab);
+       fbt_probetab_mask = 0;
+       fbt_probetab_size = 0;
+}
diff --git a/dtrace/fbt_impl.h b/dtrace/fbt_impl.h
new file mode 100644 (file)
index 0000000..c86355a
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef _FBT_H_
+#define _FBT_H_
+
+#include <asm/dtrace_arch.h>
+
+typedef struct fbt_probe {
+        char                   *fbp_name;      /* name of probe */
+        dtrace_id_t            fbp_id;         /* probe ID */
+        struct module          *fbp_module;    /* defining module */
+        int                    fbp_loadcnt;    /* load count for module */
+        int                    fbp_primary;    /* non-zero if primary mod */
+        asm_instr_t            *fbp_patchpoint;/* patch point */
+        asm_instr_t            fbp_patchval;   /* instruction to patch */
+        asm_instr_t            fbp_savedval;   /* saved instruction value */
+       uintptr_t               fbp_roffset;
+        int                    fbp_rval;
+        struct fbt_probe       *fbp_next;      /* next probe */
+        struct fbt_probe       *fbp_hashnext;  /* next on hash */
+} fbt_probe_t;
+
+#define FBT_ADDR2NDX(addr)     ((((uintptr_t)(addr)) >> 4) & \
+                                       fbt_probetab_mask)
+
+extern fbt_probe_t             **fbt_probetab;
+extern int                     fbt_probetab_size;
+extern int                     fbt_probetab_mask;
+
+extern void fbt_provide_probe_arch(fbt_probe_t *, int, int);
+extern void fbt_enable_arch(fbt_probe_t *, dtrace_id_t, void *);
+extern void fbt_disable_arch(fbt_probe_t *, dtrace_id_t, void *);
+
+extern void fbt_provide_module(void *, struct module *);
+extern int _fbt_enable(void *, dtrace_id_t, void *);
+extern void _fbt_disable(void *, dtrace_id_t, void *);
+extern void fbt_destroy(void *, dtrace_id_t, void *);
+
+extern dtrace_provider_id_t    fbt_id;
+
+extern int fbt_dev_init_arch(void);
+extern void fbt_dev_exit_arch(void);
+
+extern int fbt_dev_init(void);
+extern void fbt_dev_exit(void);
+
+#endif /* _FBT_H_ */
diff --git a/dtrace/fbt_mod.c b/dtrace/fbt_mod.c
new file mode 100644 (file)
index 0000000..fd04cf8
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * FILE:       fbt_mod.c
+ * DESCRIPTION:        Function Boundary Tracing: module handling
+ *
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 2010, 2011, 2012, 2013 Oracle, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <linux/module.h>
+
+#include "dtrace.h"
+#include "dtrace_dev.h"
+#include "fbt_impl.h"
+
+MODULE_AUTHOR("Kris Van Hees (kris.van.hees@oracle.com)");
+MODULE_DESCRIPTION("Function Boundary Tracing");
+MODULE_VERSION("v0.1");
+MODULE_LICENSE("CDDL");
+
+static const dtrace_pattr_t fbt_attr = {
+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
+};
+
+DT_PROVIDER_POPS(fbt)
+
+static dtrace_pops_t fbt_pops = {
+       NULL,
+       fbt_provide_module,
+       fbt_enable,
+       fbt_disable,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       fbt_destroy
+};
+
+DT_PROVIDER_MODULE(fbt, DTRACE_PRIV_KERNEL)
diff --git a/dtrace/fbt_sparc64.c b/dtrace/fbt_sparc64.c
new file mode 100644 (file)
index 0000000..4375361
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * FILE:       fbt_sparc64.c
+ * DESCRIPTION:        Function Boundary Tracing: architecture-specific implementation
+ *
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 2010-2014 Oracle, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <linux/dtrace_fbt.h>
+#include <asm/dtrace_util.h>
+#include <dtrace/isa_arch.h>
+
+#include "dtrace.h"
+#include "dtrace_dev.h"
+#include "fbt_impl.h"
+
+/*
+ * For entry probes, we generate the following trampoline (for id < 0xfff):
+ *
+ *     sethi   %hi(id), %o0
+ *     or      %o0, %lo(id), %o0
+ *     mov     %i0, %o1
+ *     mov     %i1, %o2
+ *     mov     %i2, %o3
+ *     mov     %i3, %o4
+ *     mov     %i4, %o5
+ *     call    dtrace_probe
+ *      nop
+ *     sethi   %hi(instr), %o7
+ *     or      %o7, %lo(instr), %o7
+ *     retl
+ *      nop
+ *
+ * otherwise we use:
+ *
+ *     or      %g0, id, %o0
+ *     mov     %i0, %o1
+ *     mov     %i1, %o2
+ *     mov     %i2, %o3
+ *     mov     %i3, %o4
+ *     mov     %i4, %o5
+ *     call    dtrace_probe
+ *      nop
+ *     sethi   %hi(instr), %o7
+ *     or      %o7, %lo(instr), %o7
+ *     retl
+ *      nop
+ */
+#ifndef FBT_TRAMP_SIZE
+# error The kernel must define FBT_TRAMP_SIZE!
+#elif FBT_TRAMP_SIZE < 13
+# error FBT_TRAMP_SIZE must be at least 13 instructions!
+#endif
+
+static void add_entry_tramp(fbt_probe_t *fbp, int nargs)
+{
+       struct module   *mp = fbp->fbp_module;
+       dtrace_id_t     id = fbp->fbp_id;
+       size_t          idx = PDATA(mp)->fbt_probe_cnt;
+       asm_instr_t     *trampoline = &(PDATA(mp)->fbt_tab[idx *
+                                                          FBT_TRAMP_SIZE]);
+       asm_instr_t     *instr = trampoline;
+
+       if (id > (uint32_t)ASM_SIMM13_MAX) {
+               *instr++ = ASM_SETHI(id, ASM_REG_O0);
+               *instr++ = ASM_ORLO(ASM_REG_O0, id, ASM_REG_O0);
+       } else
+               *instr++ = ASM_ORSIMM13(ASM_REG_G0, id, ASM_REG_O0);
+
+       if (nargs >= 1)
+               *instr++ = ASM_MOV(ASM_REG_I0, ASM_REG_O1);
+       if (nargs >= 2)
+               *instr++ = ASM_MOV(ASM_REG_I1, ASM_REG_O2);
+       if (nargs >= 3)
+               *instr++ = ASM_MOV(ASM_REG_I2, ASM_REG_O3);
+       if (nargs >= 4)
+               *instr++ = ASM_MOV(ASM_REG_I3, ASM_REG_O4);
+       if (nargs >= 5)
+               *instr++ = ASM_MOV(ASM_REG_I4, ASM_REG_O5);
+
+       *instr = ASM_CALL(instr, dtrace_probe);
+        instr++;
+
+       *instr++ = ASM_NOP;
+
+       if ((uintptr_t)fbp->fbp_patchpoint > (uintptr_t)ASM_SIMM13_MAX) {
+               *instr++ = ASM_SETHI(
+                               (uintptr_t)fbp->fbp_patchpoint, ASM_REG_O7
+                          );
+               *instr++ = ASM_ORLO(ASM_REG_O7, (uintptr_t)fbp->fbp_patchpoint,
+                                   ASM_REG_O7);
+       } else
+               *instr++ = ASM_ORSIMM13(ASM_REG_G0,
+                                       (uintptr_t)fbp->fbp_patchpoint,
+                                        ASM_REG_O7);
+
+       *instr++ = ASM_RETL;
+       *instr++ = ASM_NOP;
+
+       fbp->fbp_patchval = ASM_CALL(fbp->fbp_patchpoint, trampoline);
+       fbp->fbp_savedval = *fbp->fbp_patchpoint;
+}
+
+void fbt_provide_probe_arch(fbt_probe_t *fbp, int type, int stype)
+{
+       switch (type) {
+       case FBT_ENTRY:
+               add_entry_tramp(fbp, stype);
+               return;
+       case FBT_RETURN:
+               pr_info("%s: %s: FBT_RETURN not supported yet\n",
+                       __func__, fbp->fbp_name);
+               return;
+       default:
+               pr_info("%s: %s: Unknown FBT type %d\n",
+                       __func__, fbp->fbp_name, type);
+               return;
+       }
+}
+
+void fbt_enable_arch(fbt_probe_t *fbp, dtrace_id_t id, void *arg)
+{
+       *fbp->fbp_patchpoint = fbp->fbp_patchval;
+}
+
+void fbt_disable_arch(fbt_probe_t *fbp, dtrace_id_t id, void *arg)
+{
+       *fbp->fbp_patchpoint = fbp->fbp_savedval;
+}
+
+int fbt_dev_init_arch(void)
+{
+       return 0;
+}
+
+void fbt_dev_exit_arch(void)
+{
+}
diff --git a/dtrace/fbt_x86_64.c b/dtrace/fbt_x86_64.c
new file mode 100644 (file)
index 0000000..9a873c7
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * FILE:       fbt_x86_64.c
+ * DESCRIPTION:        Function Boundary Tracing: architecture-specific implementation
+ *
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 2010-2014 Oracle, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <linux/dtrace_fbt.h>
+#include <asm/dtrace_util.h>
+
+#include "dtrace.h"
+#include "dtrace_dev.h"
+#include "fbt_impl.h"
+
+#define FBT_PATCHVAL           0xf0
+
+static uint8_t fbt_invop(struct pt_regs *regs)
+{
+       fbt_probe_t     *fbp = fbt_probetab[FBT_ADDR2NDX(regs->ip)];
+
+       for (; fbp != NULL; fbp = fbp->fbp_hashnext) {
+               if ((uintptr_t)fbp->fbp_patchpoint == regs->ip) {
+                       this_cpu_core->cpu_dtrace_regs = regs;
+
+                       dtrace_probe(fbp->fbp_id, regs->di, regs->si,
+                                    regs->dx, regs->cx, regs->r8);
+
+                       this_cpu_core->cpu_dtrace_regs = NULL;
+
+                       return fbp->fbp_rval;
+               }
+       }
+
+       return 0;
+}
+
+void fbt_provide_probe_arch(fbt_probe_t *fbp, int type, int stype)
+{
+       fbp->fbp_patchval = FBT_PATCHVAL;
+       fbp->fbp_savedval = *fbp->fbp_patchpoint;
+       fbp->fbp_rval = type == FBT_ENTRY ? DTRACE_INVOP_MOV_RSP_RBP
+                                         : DTRACE_INVOP_RET;
+}
+
+void fbt_enable_arch(fbt_probe_t *fbp, dtrace_id_t id, void *arg)
+{
+       dtrace_invop_enable((uint8_t *)fbp->fbp_patchpoint);
+}
+
+void fbt_disable_arch(fbt_probe_t *fbp, dtrace_id_t id, void *arg)
+{
+       dtrace_invop_disable((uint8_t *)fbp->fbp_patchpoint,
+                            fbp->fbp_savedval);
+}
+
+int fbt_dev_init_arch(void)
+{
+       return dtrace_invop_add(fbt_invop);
+}
+
+void fbt_dev_exit_arch(void)
+{
+       dtrace_invop_remove(fbt_invop);
+}
index 5bd2ca3b3af0a5cf51ada2f600c4aac5a1c4308f..1ad496f3c1266e0cda61c5d1011ba4d9c5095eac 100644 (file)
@@ -2,8 +2,8 @@
 #define _SPARC64_ISA_ARCH_H
 
 /*
- * FILE:       isa_arch.h
- * DESCRIPTION:        Dynamic Tracing: sparc64 ISA-specific definitions
+ * FILE:        isa_arch.c
+ * DESCRIPTION: Dynamic Tracing: sparc64 ISA-specific definitions
  *
  * CDDL HEADER START
  *
  * Use is subject to license terms.
  */
 
+
 /* Register indices */
-#define REG_G0         0
-#define REG_G1         (REG_G0 + 1)
-#define REG_G2         (REG_G0 + 2)
-#define REG_G3         (REG_G0 + 3)
-#define REG_G4         (REG_G0 + 4)
-#define REG_G5         (REG_G0 + 5)
-#define REG_G6         (REG_G0 + 6)
-#define REG_G7         (REG_G0 + 7)
-
-#define REG_O0         (REG_G7 + 1)    /* 8 */
-#define REG_O1         (REG_O0 + 1)
-#define REG_O2         (REG_O0 + 2)
-#define REG_O3         (REG_O0 + 3)
-#define REG_O4         (REG_O0 + 4)
-#define REG_O5         (REG_O0 + 5)
-#define REG_O6         (REG_O0 + 6)
-#define REG_O7         (REG_O0 + 7)
-
-#define REG_L0         (REG_O7 + 1)    /* 16 */
-#define REG_L1         (REG_L0 + 1)
-#define REG_L2         (REG_L0 + 2)
-#define REG_L3         (REG_L0 + 3)
-#define REG_L4         (REG_L0 + 4)
-#define REG_L5         (REG_L0 + 5)
-#define REG_L6         (REG_L0 + 6)
-#define REG_L7         (REG_L0 + 7)
-
-#define REG_I0         (REG_L7 + 1)    /* 24 */
-#define REG_I1         (REG_I0 + 1)
-#define REG_I2         (REG_I0 + 2)
-#define REG_I3         (REG_I0 + 3)
-#define REG_I4         (REG_I0 + 4)
-#define REG_I5         (REG_I0 + 5)
-#define REG_I6         (REG_I0 + 6)
-#define REG_I7         (REG_I0 + 7)
-
-#define REG_CCR                (REG_I7 + 1)    /* 32 */
-
-#define REG_PC         (REG_CCR + 1)   /* 33 */
-#define REG_nPC                (REG_PC + 1)    /* 34 */
-#define REG_Y          (REG_nPC + 1)   /* 35 */
-
-#define        REG_ASI         (REG_Y + 1)     /* 36 */
-#define        REG_FPRS        (REG_ASI + 1)   /* 37 */
+#define ASM_REG_G0             0
+#define ASM_REG_G1             (ASM_REG_G0 + 1)
+#define ASM_REG_G2             (ASM_REG_G0 + 2)
+#define ASM_REG_G3             (ASM_REG_G0 + 3)
+#define ASM_REG_G4             (ASM_REG_G0 + 4)
+#define ASM_REG_G5             (ASM_REG_G0 + 5)
+#define ASM_REG_G6             (ASM_REG_G0 + 6)
+#define ASM_REG_G7             (ASM_REG_G0 + 7)
+
+#define ASM_REG_O0             (ASM_REG_G7 + 1)        /* 8 */
+#define ASM_REG_O1             (ASM_REG_O0 + 1)
+#define ASM_REG_O2             (ASM_REG_O0 + 2)
+#define ASM_REG_O3             (ASM_REG_O0 + 3)
+#define ASM_REG_O4             (ASM_REG_O0 + 4)
+#define ASM_REG_O5             (ASM_REG_O0 + 5)
+#define ASM_REG_O6             (ASM_REG_O0 + 6)
+#define ASM_REG_O7             (ASM_REG_O0 + 7)
+
+#define ASM_REG_L0             (ASM_REG_O7 + 1)        /* 16 */
+#define ASM_REG_L1             (ASM_REG_L0 + 1)
+#define ASM_REG_L2             (ASM_REG_L0 + 2)
+#define ASM_REG_L3             (ASM_REG_L0 + 3)
+#define ASM_REG_L4             (ASM_REG_L0 + 4)
+#define ASM_REG_L5             (ASM_REG_L0 + 5)
+#define ASM_REG_L6             (ASM_REG_L0 + 6)
+#define ASM_REG_L7             (ASM_REG_L0 + 7)
+
+#define ASM_REG_I0             (ASM_REG_L7 + 1)        /* 24 */
+#define ASM_REG_I1             (ASM_REG_I0 + 1)
+#define ASM_REG_I2             (ASM_REG_I0 + 2)
+#define ASM_REG_I3             (ASM_REG_I0 + 3)
+#define ASM_REG_I4             (ASM_REG_I0 + 4)
+#define ASM_REG_I5             (ASM_REG_I0 + 5)
+#define ASM_REG_I6             (ASM_REG_I0 + 6)
+#define ASM_REG_I7             (ASM_REG_I0 + 7)
+
+#define REG_CCR                        (ASM_REG_I7 + 1)        /* 32 */
+#define REG_PC                 (REG_CCR + 1)           /* 33 */
+#define REG_nPC                        (REG_PC + 1)            /* 34 */
+#define REG_Y                  (REG_nPC + 1)           /* 35 */
+#define REG_ASI                        (REG_Y + 1)             /* 36 */
+#define REG_FPRS               (REG_ASI + 1)           /* 37 */
+
+#define ASM_REG_PC             5
+
+#define ASM_REG_ISGLOBAL(r)    ((r) >= ASM_REG_G0 && (r) <= ASM_REG_G7)
+#define ASM_REG_ISOUTPUT(r)    ((r) >= ASM_REG_O0 && (r) <= ASM_REG_O7)
+#define ASM_REG_ISLOCAL(r)     ((r) >= ASM_REH_L0 && (r) <= ASM_REG_L7)
+#define ASM_REG_ISINPUT(r)     ((r) >= ASM_REG_I0 && (r) <= ASM_REG_I7)
+#define ASM_REG_ISVOLATILE(r)                                                \
+        ((ASM_REG_ISGLOBAL(r) || ASM_REG_ISOUTPUT(r)) && (r) != ASM_REG_G0)
+#define ASM_REG_NLOCALS                8
+
+#define ASM_REG_MARKLOCAL(locals, r)                                         \
+       if (ASM_REG_ISLOCAL(r))                                               \
+               (locals)[(r) - ASM_REG_L0] = 1;
+
+#define ASM_REG_INITLOCALS(local, locals)                                    \
+       for ((local) = 0; (local) < ASM_REG_NLOCALS; (local)++)               \
+               (locals)[(local)] = 0;                                        \
+       (local) = ASM_REG_L0
+
+#define ASM_REG_ALLOCLOCAL(local, locals)                                    \
+       while ((locals)[(local) - ASM_REG_L0])                                \
+               (local)++;                                                    \
+       (locals)[(local) - ASM_REG_L0] = 1;
+
+#define ASM_OP_MASK            0xc0000000
+#define ASM_OP_SHIFT           30
+#define ASM_OP(val)            ((val) & ASM_OP_MASK)
+
+#define ASM_SIMM13_MASK                0x1fff
+#define ASM_SIMM13_MAX         ((int32_t)0xfff)
+#define ASM_IMM22_MASK         0x3fffff
+#define ASM_IMM22_SHIFT                10
+#define ASM_IMM10_MASK         0x3ff
+
+#define ASM_DISP30_MASK                0x3fffffff
+#define ASM_DISP30(from, to)                                                 \
+       (((long)(to) - (long)(from)) >= 0                                     \
+         ? ((((uintptr_t)(to) - (uintptr_t)(from)) >> 2) & ASM_DISP30_MASK)  \
+         : ((((long)(to) - (long)(from)) >> 2) & ASM_DISP30_MASK))
+
+#define ASM_DISP22_MASK                0x3fffff
+#define ASM_DISP22(from, to)                                                 \
+       ((((uintptr_t)(to) - (uintptr_t)(from)) >> 2) & ASM_DISP22_MASK)
+
+#define ASM_DISP19_MASK                0x7ffff
+#define ASM_DISP19(from, to)                                                 \
+       ((((uintptr_t)(to) - (uintptr_t)(from)) >> 2) & ASM_DISP19_MASK)
+
+#define ASM_DISP16_HISHIFT     20
+#define ASM_DISP16_HIMASK      (0x3 << ASM_DISP16_HISHIFT)
+#define ASM_DISP16_LOMASK      (0x3fff)
+#define ASM_DISP16_MASK                (ASM_DISP16_HIMASK | ASM_DISP16_LOMASK)
+#define ASM_DISP16(val)                                                              \
+       ((((val) & ASM_DISP16_HIMASK) >> 6) | ((val) & ASM_DISP16_LOMASK))
+
+#define ASM_DISP14_MASK                0x3fff
+#define ASM_DISP14(from, to)                                                 \
+       (((uintptr_t)(to) - (uintptr_t)(from) >> 2) & ASM_DISP14_MASK)
+
+#define ASM_OP0                        (((uint32_t)0) << ASM_OP_SHIFT)
+#define ASM_OP1                        (((uint32_t)1) << ASM_OP_SHIFT)
+#define ASM_OP2                        (((uint32_t)2) << ASM_OP_SHIFT)
+#define ASM_ILLTRAP            0
+
+#define ASM_ANNUL_SHIFT                29
+#define ASM_ANNUL              (1 << ASM_ANNUL_SHIFT)
+
+#define ASM_FMT3_OP3_SHIFT     19
+#define ASM_FMT3_OP_MASK       0xc1f80000
+#define ASM_FMT3_OP(val)       ((val) & ASM_FMT3_OP_MASK)
+
+#define ASM_FMT3_RD_SHIFT      25
+#define ASM_FMT3_RD_MASK       (0x1f << ASM_FMT3_RD_SHIFT)
+#define ASM_FMT3_RD(val)                                                     \
+       (((val) & ASM_FMT3_RD_MASK) >> ASM_FMT3_RD_SHIFT)
+
+#define ASM_FMT3_RS1_SHIFT     14
+#define ASM_FMT3_RS1_MASK      (0x1f << ASM_FMT3_RS1_SHIFT)
+#define ASM_FMT3_RS1(val)                                                    \
+       (((val) & ASM_FMT3_RS1_MASK) >> ASM_FMT3_RS1_SHIFT)
+#define ASM_FMT3_RS1_SET(val, rs1)                                           \
+       (val) = ((val) & ~ASM_FMT3_RS1_MASK) | ((rs1) << ASM_FMT3_RS1_SHIFT)
+
+#define ASM_FMT3_RS2_SHIFT     0
+#define ASM_FMT3_RS2_MASK      (0x1f << ASM_FMT3_RS2_SHIFT)
+#define ASM_FMT3_RS2(val)                                                    \
+       (((val) & ASM_FMT3_RS2_MASK) >> ASM_FMT3_RS2_SHIFT)
+#define ASM_FMT3_RS2_SET(val, rs2)                                           \
+       (val) = ((val) & ~ASM_FMT3_RS2_MASK) | ((rs2) << ASM_FMT3_RS2_SHIFT)
+
+#define ASM_FMT3_IMM_SHIFT     13
+#define ASM_FMT3_IMM           (1 << ASM_FMT3_IMM_SHIFT)
+#define ASM_FMT3_SIMM13_MASK   ASM_SIMM13_MASK
+
+#define ASM_FMT3_ISIMM(val)    ((val) & ASM_FMT3_IMM)
+#define ASM_FMT3_SIMM13(val)   ((val) & ASM_FMT3_SIMM13_MASK)
+
+#define ASM_FMT2_OP2_SHIFT     22
+#define ASM_FMT2_OP2_MASK      (0x7 << ASM_FMT2_OP2_SHIFT)
+#define ASM_FMT2_RD_SHIFT      25
+
+#define ASM_FMT1_OP(val)       ((val) & ASM_OP_MASK)
+#define ASM_FMT1_DISP30(val)   ((val) & ASM_DISP30_MASK)
+
+#define ASM_FMT2_OP2_BPCC      (0x01 << ASM_FMT2_OP2_SHIFT)
+#define ASM_FMT2_OP2_BCC       (0x02 << ASM_FMT2_OP2_SHIFT)
+#define ASM_FMT2_OP2_BPR       (0x03 << ASM_FMT2_OP2_SHIFT)
+#define ASM_FMT2_OP2_SETHI     (0x04 << ASM_FMT2_OP2_SHIFT)
+
+#define ASM_FMT2_COND_SHIFT    25
+#define ASM_FMT2_COND_BA       (0x8 << ASM_FMT2_COND_SHIFT)
+#define ASM_FMT2_COND_BL       (0x3 << ASM_FMT2_COND_SHIFT)
+#define ASM_FMT2_COND_BGE      (0xb << ASM_FMT2_COND_SHIFT)
+
+#define ASM_OP_RESTORE         (ASM_OP2 | (0x3d << ASM_FMT3_OP3_SHIFT))
+#define ASM_OP_SAVE            (ASM_OP2 | (0x3c << ASM_FMT3_OP3_SHIFT))
+#define ASM_OP_JMPL            (ASM_OP2 | (0x38 << ASM_FMT3_OP3_SHIFT))
+#define ASM_OP_RETURN          (ASM_OP2 | (0x39 << ASM_FMT3_OP3_SHIFT))
+#define ASM_OP_CALL            ASM_OP1
+#define ASM_OP_SETHI           (ASM_OP0 | ASM_FMT2_OP2_SETHI)
+#define ASM_OP_ADD             (ASM_OP2 | (0x00 << ASM_FMT3_OP3_SHIFT))
+#define ASM_OP_OR              (ASM_OP2 | (0x02 << ASM_FMT3_OP3_SHIFT))
+#define ASM_OP_SUB             (ASM_OP2 | (0x04 << ASM_FMT3_OP3_SHIFT))
+#define ASM_OP_CC              (ASM_OP2 | (0x10 << ASM_FMT3_OP3_SHIFT))
+#define ASM_OP_UDIV            (ASM_OP2 | (0x0e << ASM_FMT3_OP3_SHIFT))
+#define ASM_OP_BA              (ASM_OP0 | ASM_FMT2_OP2_BCC | ASM_FMT2_COND_BA)
+#define ASM_OP_BL              (ASM_OP0 | ASM_FMT2_OP2_BCC | ASM_FMT2_COND_BL)
+#define ASM_OP_BGE             (ASM_OP0 | ASM_FMT2_OP2_BCC | ASM_FMT2_COND_BGE)
+#define ASM_OP_BAPCC           (ASM_OP0 | ASM_FMT2_OP2_BPCC | ASM_FMT2_COND_BA)
+#define ASM_OP_RD              (ASM_OP2 | (0x28 << ASM_FMT3_OP3_SHIFT))
+
+#define ASM_ORLO(rs, val, rd)                                                \
+       (ASM_OP_OR | ((rs) << ASM_FMT3_RS1_SHIFT) |                           \
+        ((rd) << ASM_FMT3_RD_SHIFT) | ASM_FMT3_IMM | ((val) & ASM_IMM10_MASK))
+
+#define ASM_ORSIMM13(rs, val, rd)                                            \
+       (ASM_OP_OR | ((rs) << ASM_FMT3_RS1_SHIFT) |                           \
+        ((rd) << ASM_FMT3_RD_SHIFT) | ASM_FMT3_IMM |                         \
+        ((val) & ASM_SIMM13_MASK))
+
+#define ASM_ADDSIMM13(rs, val, rd)                                           \
+       (ASM_OP_ADD | ((rs) << ASM_FMT3_RS1_SHIFT) |                          \
+        ((rd) << ASM_FMT3_RD_SHIFT) | ASM_FMT3_IMM |                         \
+        ((val) & ASM_SIMM13_MASK))
+
+#define ASM_UDIVSIMM13(rs, val, rd)                                          \
+       (ASM_OP_UDIV | ((rs) << ASM_FMT3_RS1_SHIFT) |                         \
+        ((rd) << ASM_FMT3_RD_SHIFT) | ASM_FMT3_IMM |                         \
+        ((val) & ASM_SIMM13_MASK))
+
+#define ASM_ADD(rs1, rs2, rd)                                                \
+       (ASM_OP_ADD | ((rs1) << ASM_FMT3_RS1_SHIFT) |                         \
+        ((rs2) << ASM_FMT3_RS2_SHIFT) | ((rd) << ASM_FMT3_RD_SHIFT))
+
+#define ASM_CMP(rs1, rs2)                                                    \
+       (ASM_OP_SUB | ASM_OP_CC | ((rs1) << ASM_FMT3_RS1_SHIFT) |             \
+        ((rs2) << ASM_FMT3_RS2_SHIFT) | (ASM_REG_G0 << ASM_FMT3_RD_SHIFT))
+
+#define ASM_MOV(rs, rd)                                                              \
+       (ASM_OP_OR | (ASM_REG_G0 << ASM_FMT3_RS1_SHIFT) |                     \
+        ((rs) << ASM_FMT3_RS2_SHIFT) | ((rd) << ASM_FMT3_RD_SHIFT))
+
+#define ASM_SETHI(val, reg)                                                  \
+       (ASM_OP_SETHI | (reg << ASM_FMT2_RD_SHIFT) |                          \
+        ((val >> ASM_IMM22_SHIFT) & ASM_IMM22_MASK))
+
+#define ASM_NOP                        ASM_SETHI(0, 0)
+
+#define ASM_CALL(orig, dest)   (ASM_OP_CALL | ASM_DISP30(orig, dest))
+
+#define ASM_RET                                                                      \
+       (ASM_OP_JMPL | (ASM_REG_I7 << ASM_FMT3_RS1_SHIFT) |                   \
+        (ASM_REG_G0 << ASM_FMT3_RD_SHIFT) | ASM_FMT3_IMM |                   \
+        (sizeof (asm_instr_t) << 1))
+
+#define ASM_RETL                                                             \
+       (ASM_OP_JMPL | (ASM_REG_O7 << ASM_FMT3_RS1_SHIFT) |                   \
+        (ASM_REG_G0 << ASM_FMT3_RD_SHIFT) | ASM_FMT3_IMM |                   \
+        (sizeof (asm_instr_t) << 1))
+
+#define ASM_SAVEIMM(rd, val, rs1)                                            \
+       (ASM_OP_SAVE | ((rs1) << ASM_FMT3_RS1_SHIFT) |                        \
+        ((rd) << ASM_FMT3_RD_SHIFT) | ASM_FMT3_IMM | ((val) & ASM_SIMM13_MASK))
+
+#define ASM_RESTORE(rd, rs1, rs2)                                            \
+       (ASM_OP_RESTORE | ((rs1) << ASM_FMT3_RS1_SHIFT) |                     \
+        ((rd) << ASM_FMT3_RD_SHIFT) | ((rs2) << ASM_FMT3_RS2_SHIFT))
+
+#define ASM_RETURN(rs1, val)                                                 \
+       (ASM_OP_RETURN | ((rs1) << ASM_FMT3_RS1_SHIFT) |                      \
+        ASM_FMT3_IMM | ((val) & ASM_SIMM13_MASK))
+
+#define ASM_BA(orig, dest)     (ASM_OP_BA | ASM_DISP22(orig, dest))
+#define ASM_BAA(orig, dest)    (ASM_BA(orig, dest) | ASM_ANNUL)
+#define ASM_BL(orig, dest)     (ASM_OP_BL | ASM_DISP22(orig, dest))
+#define ASM_BGE(orig, dest)    (ASM_OP_BGE | ASM_DISP22(orig, dest))
+#define ASM_BDEST(va, instr)   ((uintptr_t)(va) +                            \
+       (((int32_t)(((instr) & ASM_DISP22_MASK) << 10)) >> 8))
+#define ASM_BPCCDEST(va, instr)        ((uintptr_t)(va) +                            \
+       (((int32_t)(((instr) & ASM_DISP19_MASK) << 13)) >> 11))
+#define ASM_BPRDEST(va, instr) ((uintptr_t)(va) +                            \
+       (((int32_t)((ASM_DISP16(instr)) << 16)) >> 14))
+
+/*
+ * We're only going to treat a save as safe if
+ *   (a) both rs1 and rd are %sp and
+ *   (b) if the instruction has a simm, the value isn't 0.
+ */
+#define ASM_IS_SAVE(instr)                                                   \
+       (ASM_FMT3_OP(instr) == ASM_OP_SAVE &&                                 \
+        ASM_FMT3_RD(instr) == ASM_REG_O6 &&                                  \
+        ASM_FMT3_RS1(instr) == ASM_REG_O6 &&                                 \
+        !(ASM_FMT3_ISIMM(instr) && ASM_FMT3_SIMM13(instr) == 0))
+
+#define ASM_IS_BA(instr)       (((instr) & ~ASM_DISP22_MASK) == ASM_OP_BA)
+#define ASM_IS_BAPCC(instr)    (((instr) & ~ASM_DISP22_MASK) == ASM_OP_BAPCC)
+
+#define ASM_IS_RDPC(instr)     ((ASM_FMT3_OP(instr) == ASM_OP_RD) &&         \
+                                (ASM_FMT3_RD(instr) == ASM_REG_PC))
+
+#define ASM_IS_PCRELATIVE(instr)                                             \
+        ((((instr) & ASM_OP_MASK) == ASM_OP0 &&                                      \
+         ((instr) & ASM_FMT2_OP2_MASK) != ASM_FMT2_OP2_SETHI) ||             \
+        ((instr) & ASM_OP_MASK) == ASM_OP1 ||                                \
+        ASM_IS_RDPC(instr))
+
+#define ASM_IS_CTI(instr)                                                    \
+       ((((instr) & ASM_OP_MASK) == ASM_OP0 &&                               \
+         ((instr) & ASM_FMT2_OP2_MASK) != ASM_FMT2_OP2_SETHI) ||             \
+        ((instr) & ASM_OP_MASK) == ASM_OP1 ||                                \
+        (ASM_FMT3_OP(instr) == ASM_OP_JMPL) ||                               \
+        (ASM_FMT3_OP(instr) == ASM_OP_RETURN))
+
+#define ASM_IS_NOP(instr)      ((instr) == ASM_NOP)
+
+#define ASM_IS_CALL(instr)     (((instr) & ASM_OP_MASK) == ASM_OP_CALL)
+
+#define ASM_MOD_INPUTS(instr)  (ASM_OP(instr) == ASM_OP2 &&                  \
+                                ASM_REG_ISINPUT(ASM_FMT3_RD(instr)))
+#define ASM_MOD_OUTPUTS(instr) (ASM_OP(instr) == ASM_OP2 &&                  \
+                                ASM_REG_ISOUTPUT(ASM_FMT3_RD(instr)))
 
 /*
  * Our own personal SPARC V9 stack layout structure, because the one in
  * <kernel-source-tree>/arch/sparc/include/uapi/asm/ptrace.h is wrong.
  */
 struct sparc_v9_frame {
-        unsigned long locals[8];
-        unsigned long ins[6];
-        struct sparc_v9_frame *fp;
-        unsigned long callers_pc;
-        unsigned long xargs[6];
-        unsigned long xxargs[1];
+       unsigned long locals[8];
+       unsigned long ins[6];
+       struct sparc_v9_frame *fp;
+       unsigned long callers_pc;
+       unsigned long xargs[6];
+       unsigned long xxargs[1];
 };
 
-
 #endif /* _SPARC64_ISA_ARCH_H */
index b665012c48baea1d8406f3347569b39394596920..b61fc3e0468398cae3d1de7d3bc2e58df1f01e3e 100644 (file)
  *     - pdata: pointer to a dtrace_module struct (for DTrace)
  */
 typedef struct dtrace_module {
+        int             enabled_cnt;
         size_t          sdt_probe_cnt;
-        int             sdt_enabled;
        asm_instr_t     *sdt_tab;
         size_t          fbt_probe_cnt;
+       asm_instr_t     *fbt_tab;
 } dtrace_module_t;
 
 #endif /* _SPARC64_MOD_ARCH_H */
index 583baca0d65fb61a9bf8c8dd6ff886351f2570cd..2aa222011f13d8c4bcda32bf8548c2f770d65b1b 100644 (file)
@@ -36,8 +36,8 @@
  *     - pdata: pointer to a dtrace_module struct (for DTrace)
  */
 typedef struct dtrace_module {
+        int             enabled_cnt;
         size_t          sdt_probe_cnt;
-        int             sdt_enabled;
         size_t          fbt_probe_cnt;
 } dtrace_module_t;