diff options
author | ahl <none@none> | 2006-03-30 01:12:03 -0800 |
---|---|---|
committer | ahl <none@none> | 2006-03-30 01:12:03 -0800 |
commit | ac448965596bc1c42f7accb3023f48d5fa9b8180 (patch) | |
tree | 2fec65de48a83b92568802081a1e3981d2aab1f7 | |
parent | 507c32411f3f101e90ca2120f042b5ee698ba1d5 (diff) | |
download | illumos-joyent-ac448965596bc1c42f7accb3023f48d5fa9b8180.tar.gz |
6405927 USDT is-enabled probes
6405929 USDT DOF with zero probes results in an unsatisfiable memory allocation
6405932 dead variables in usr/src/uts/common/dtrace/dtrace.c
6405939 ::dofdump doesn't use section sizes correctly
-rw-r--r-- | usr/src/cmd/mdb/common/modules/dtrace/dof.c | 78 | ||||
-rw-r--r-- | usr/src/cmd/mdb/common/modules/dtrace/dtrace.c | 10 | ||||
-rw-r--r-- | usr/src/lib/libdtrace/common/dt_dof.c | 42 | ||||
-rw-r--r-- | usr/src/lib/libdtrace/common/dt_dof.h | 9 | ||||
-rw-r--r-- | usr/src/lib/libdtrace/common/dt_link.c | 206 | ||||
-rw-r--r-- | usr/src/lib/libdtrace/common/dt_open.c | 6 | ||||
-rw-r--r-- | usr/src/lib/libdtrace/common/dt_program.c | 24 | ||||
-rw-r--r-- | usr/src/lib/libdtrace/common/dt_program.h | 9 | ||||
-rw-r--r-- | usr/src/lib/libdtrace/common/dt_provider.c | 55 | ||||
-rw-r--r-- | usr/src/lib/libdtrace/common/dt_provider.h | 11 | ||||
-rw-r--r-- | usr/src/uts/common/dtrace/dtrace.c | 153 | ||||
-rw-r--r-- | usr/src/uts/common/dtrace/fasttrap.c | 116 | ||||
-rw-r--r-- | usr/src/uts/common/sys/dtrace.h | 15 | ||||
-rw-r--r-- | usr/src/uts/common/sys/fasttrap.h | 11 | ||||
-rw-r--r-- | usr/src/uts/common/sys/fasttrap_impl.h | 42 | ||||
-rw-r--r-- | usr/src/uts/intel/dtrace/fasttrap_isa.c | 67 | ||||
-rw-r--r-- | usr/src/uts/sparc/dtrace/fasttrap_isa.c | 48 |
17 files changed, 646 insertions, 256 deletions
diff --git a/usr/src/cmd/mdb/common/modules/dtrace/dof.c b/usr/src/cmd/mdb/common/modules/dtrace/dof.c index e305d849ca..5631c4c3b4 100644 --- a/usr/src/cmd/mdb/common/modules/dtrace/dof.c +++ b/usr/src/cmd/mdb/common/modules/dtrace/dof.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -19,8 +18,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -828,19 +828,20 @@ dof_sect_strtab(uintptr_t addr, dof_sec_t *sec) } static int -dof_sect_provider(uintptr_t addr, dof_sec_t *sec, dof_sec_t *dofs) +dof_sect_provider(dof_hdr_t *dofh, uintptr_t addr, dof_sec_t *sec, + dof_sec_t *dofs) { dof_provider_t pv; dof_probe_t *pb; - char *strtab; - uint32_t *offs; + char *strtab, *p; + uint32_t *offs, *enoffs; uint8_t *args = NULL; size_t sz; int i, j; dof_stridx_t narg, xarg; - if (mdb_vread(&pv, sizeof (dof_provider_t), - addr + sec->dofs_offset) != sizeof (dof_provider_t)) { + sz = MIN(sec->dofs_size, sizeof (dof_provider_t)); + if (mdb_vread(&pv, sz, addr + sec->dofs_offset) != sz) { mdb_warn("failed to read DOF provider"); return (-1); } @@ -870,13 +871,25 @@ dof_sect_provider(uintptr_t addr, dof_sec_t *sec, dof_sec_t *dofs) offs = mdb_alloc(sz, UM_SLEEP | UM_GC); if (mdb_vread(offs, sz, addr + dofs[pv.dofpv_proffs].dofs_offset) != sz) { - mdb_warn("failed to read offs"); + mdb_warn("failed to read offsets"); return (-1); } + enoffs = NULL; + if (dofh->dofh_ident[DOF_ID_VERSION] != DOF_VERSION_1 || + pv.dofpv_prenoffs == 0) { + sz = dofs[pv.dofpv_prenoffs].dofs_size; + enoffs = mdb_alloc(sz, UM_SLEEP | UM_GC); + if (mdb_vread(enoffs, sz, addr + + dofs[pv.dofpv_prenoffs].dofs_offset) != sz) { + mdb_warn("failed to read is-enabled offsets"); + return (-1); + } + } + sz = dofs[pv.dofpv_probes].dofs_size; - pb = mdb_alloc(sz, UM_SLEEP | UM_GC); - if (mdb_vread(pb, sz, addr + dofs[pv.dofpv_probes].dofs_offset) != sz) { + p = mdb_alloc(sz, UM_SLEEP | UM_GC); + if (mdb_vread(p, sz, addr + dofs[pv.dofpv_probes].dofs_offset) != sz) { mdb_warn("failed to read probes"); return (-1); } @@ -884,39 +897,56 @@ dof_sect_provider(uintptr_t addr, dof_sec_t *sec, dof_sec_t *dofs) (void) mdb_inc_indent(2); for (i = 0; i < sz / dofs[pv.dofpv_probes].dofs_entsize; i++) { + pb = (dof_probe_t *)(uintptr_t)(p + + i * dofs[pv.dofpv_probes].dofs_entsize); + mdb_printf("%lx probe %s:%s {\n", (ulong_t)(addr + dofs[pv.dofpv_probes].dofs_offset + i * dofs[pv.dofpv_probes].dofs_entsize), - strtab + pb[i].dofpr_func, - strtab + pb[i].dofpr_name); + strtab + pb->dofpr_func, + strtab + pb->dofpr_name); (void) mdb_inc_indent(2); - mdb_printf("addr: %p\n", (ulong_t)pb[i].dofpr_addr); + mdb_printf("addr: %p\n", (ulong_t)pb->dofpr_addr); mdb_printf("offs: "); - for (j = 0; j < pb[i].dofpr_noffs; j++) { + for (j = 0; j < pb->dofpr_noffs; j++) { mdb_printf("%s %x", "," + (j == 0), - offs[pb[i].dofpr_offidx + j]); + offs[pb->dofpr_offidx + j]); } mdb_printf("\n"); + if (dofh->dofh_ident[DOF_ID_VERSION] != DOF_VERSION_1) { + mdb_printf("enoffs: "); + if (enoffs == NULL) { + if (pb->dofpr_nenoffs != 0) + mdb_printf("<error>"); + } else { + for (j = 0; j < pb->dofpr_nenoffs; j++) { + mdb_printf("%s %x", "," + (j == 0), + enoffs[pb->dofpr_enoffidx + j]); + } + } + mdb_printf("\n"); + } + mdb_printf("nargs:"); - narg = pb[i].dofpr_nargv; - for (j = 0; j < pb[i].dofpr_nargc; j++) { + narg = pb->dofpr_nargv; + for (j = 0; j < pb->dofpr_nargc; j++) { mdb_printf("%s %s", "," + (j == 0), strtab + narg); narg += strlen(strtab + narg) + 1; } mdb_printf("\n"); mdb_printf("xargs:"); - xarg = pb[i].dofpr_xargv; - for (j = 0; j < pb[i].dofpr_xargc; j++) { + xarg = pb->dofpr_xargv; + for (j = 0; j < pb->dofpr_xargc; j++) { mdb_printf("%s %s", "," + (j == 0), strtab + xarg); xarg += strlen(strtab + xarg) + 1; } mdb_printf("\n"); mdb_printf("map: "); - for (j = 0; j < pb[i].dofpr_xargc; j++) { + for (j = 0; j < pb->dofpr_xargc; j++) { mdb_printf("%s %d->%d", "," + (j == 0), - args[pb[i].dofpr_argidx + j], j); + args[pb->dofpr_argidx + j], j); } (void) mdb_dec_indent(2); @@ -990,7 +1020,7 @@ dofdump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) (void) mdb_inc_indent(2); switch (dofs[i].dofs_type) { case DOF_SECT_PROVIDER: - (void) dof_sect_provider(addr, &dofs[i], dofs); + (void) dof_sect_provider(&dofh, addr, &dofs[i], dofs); break; case DOF_SECT_STRTAB: (void) dof_sect_strtab(addr, &dofs[i]); diff --git a/usr/src/cmd/mdb/common/modules/dtrace/dtrace.c b/usr/src/cmd/mdb/common/modules/dtrace/dtrace.c index e051dc481b..55decccef3 100644 --- a/usr/src/cmd/mdb/common/modules/dtrace/dtrace.c +++ b/usr/src/cmd/mdb/common/modules/dtrace/dtrace.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -19,8 +18,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -457,7 +457,7 @@ dtracemdb_dof_create(dtrace_state_t *state) dof->dofh_ident[DOF_ID_MODEL] = DOF_MODEL_NATIVE; dof->dofh_ident[DOF_ID_ENCODING] = DOF_ENCODE_NATIVE; - dof->dofh_ident[DOF_ID_VERSION] = DOF_VERSION_1; + dof->dofh_ident[DOF_ID_VERSION] = DOF_VERSION; dof->dofh_ident[DOF_ID_DIFVERS] = DIF_VERSION; dof->dofh_ident[DOF_ID_DIFIREG] = DIF_DIR_NREGS; dof->dofh_ident[DOF_ID_DIFTREG] = DIF_DTR_NREGS; diff --git a/usr/src/lib/libdtrace/common/dt_dof.c b/usr/src/lib/libdtrace/common/dt_dof.c index 9795e019d9..718a2dc0c5 100644 --- a/usr/src/lib/libdtrace/common/dt_dof.c +++ b/usr/src/lib/libdtrace/common/dt_dof.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -19,6 +18,7 @@ * * CDDL HEADER END */ + /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. @@ -62,6 +62,7 @@ dt_dof_init(dtrace_hdl_t *dtp) dt_buf_create(dtp, &ddo->ddo_probes, "probe data", 0); dt_buf_create(dtp, &ddo->ddo_args, "probe args", 0); dt_buf_create(dtp, &ddo->ddo_offs, "probe offs", 0); + dt_buf_create(dtp, &ddo->ddo_enoffs, "probe is-enabled offs", 0); dt_buf_create(dtp, &ddo->ddo_rels, "probe rels", 0); dt_buf_create(dtp, &ddo->ddo_xlms, "xlate members", 0); @@ -83,6 +84,7 @@ dt_dof_fini(dtrace_hdl_t *dtp) dt_buf_destroy(dtp, &ddo->ddo_probes); dt_buf_destroy(dtp, &ddo->ddo_args); dt_buf_destroy(dtp, &ddo->ddo_offs); + dt_buf_destroy(dtp, &ddo->ddo_enoffs); dt_buf_destroy(dtp, &ddo->ddo_rels); dt_buf_destroy(dtp, &ddo->ddo_xlms); @@ -122,6 +124,7 @@ dt_dof_reset(dtrace_hdl_t *dtp, dtrace_prog_t *pgp) dt_buf_reset(dtp, &ddo->ddo_probes); dt_buf_reset(dtp, &ddo->ddo_args); dt_buf_reset(dtp, &ddo->ddo_offs); + dt_buf_reset(dtp, &ddo->ddo_enoffs); dt_buf_reset(dtp, &ddo->ddo_rels); dt_buf_reset(dtp, &ddo->ddo_xlms); @@ -428,17 +431,29 @@ dof_add_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data) dofpr.dofpr_nargc = prp->pr_nargc; dofpr.dofpr_xargc = prp->pr_xargc; - dofpr.dofpr_pad = 0; + dofpr.dofpr_pad1 = 0; + dofpr.dofpr_pad2 = 0; for (pip = prp->pr_inst; pip != NULL; pip = pip->pi_next) { + dt_dprintf("adding probe for %s:%s\n", pip->pi_fname, + prp->pr_name); + dofpr.dofpr_func = dof_add_string(ddo, pip->pi_fname); + + assert(pip->pi_noffs > 0); + dofpr.dofpr_offidx = dt_buf_len(&ddo->ddo_offs) / sizeof (uint32_t); dofpr.dofpr_noffs = pip->pi_noffs; - dt_buf_write(dtp, &ddo->ddo_offs, pip->pi_offs, pip->pi_noffs * sizeof (uint32_t), sizeof (uint32_t)); + dofpr.dofpr_enoffidx = + dt_buf_len(&ddo->ddo_enoffs) / sizeof (uint32_t); + dofpr.dofpr_nenoffs = pip->pi_nenoffs; + dt_buf_write(dtp, &ddo->ddo_enoffs, pip->pi_enoffs, + pip->pi_noffs * sizeof (uint32_t), sizeof (uint32_t)); + /* * If pi_rname isn't set, the relocation will be against the * function name. If it is, the relocation will be against @@ -497,6 +512,7 @@ dof_add_provider(dt_dof_t *ddo, const dt_provider_t *pvp) dt_buf_reset(dtp, &ddo->ddo_probes); dt_buf_reset(dtp, &ddo->ddo_args); dt_buf_reset(dtp, &ddo->ddo_offs); + dt_buf_reset(dtp, &ddo->ddo_enoffs); dt_buf_reset(dtp, &ddo->ddo_rels); (void) dt_idhash_iter(pvp->pv_probes, dof_add_probe, ddo); @@ -513,11 +529,18 @@ dof_add_provider(dt_dof_t *ddo, const dt_provider_t *pvp) dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_args, sizeof (uint8_t)); + assert(dt_buf_len(&ddo->ddo_offs) > 0); + dofpv.dofpv_proffs = dof_add_lsect(ddo, NULL, DOF_SECT_PROFFS, sizeof (uint_t), 0, sizeof (uint_t), dt_buf_len(&ddo->ddo_offs)); dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_offs, sizeof (uint_t)); + dofpv.dofpv_prenoffs = dof_add_lsect(ddo, NULL, DOF_SECT_PRENOFFS, + sizeof (uint_t), 0, sizeof (uint_t), dt_buf_len(&ddo->ddo_enoffs)); + + dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_enoffs, sizeof (uint_t)); + dofpv.dofpv_strtab = ddo->ddo_strsec; dofpv.dofpv_name = dof_add_string(ddo, pvp->pv_desc.dtvd_name); @@ -549,7 +572,7 @@ dof_add_provider(dt_dof_t *ddo, const dt_provider_t *pvp) } static int -dof_hdr(dtrace_hdl_t *dtp, dof_hdr_t *hp) +dof_hdr(dtrace_hdl_t *dtp, uint8_t dofversion, dof_hdr_t *hp) { /* * If our config values cannot fit in a uint8_t, we can't generate a @@ -574,7 +597,7 @@ dof_hdr(dtrace_hdl_t *dtp, dof_hdr_t *hp) hp->dofh_ident[DOF_ID_MODEL] = DOF_MODEL_ILP32; hp->dofh_ident[DOF_ID_ENCODING] = DOF_ENCODE_NATIVE; - hp->dofh_ident[DOF_ID_VERSION] = DOF_VERSION_1; + hp->dofh_ident[DOF_ID_VERSION] = dofversion; hp->dofh_ident[DOF_ID_DIFVERS] = dtp->dt_conf.dtc_difversion; hp->dofh_ident[DOF_ID_DIFIREG] = dtp->dt_conf.dtc_difintregs; hp->dofh_ident[DOF_ID_DIFTREG] = dtp->dt_conf.dtc_diftupregs; @@ -617,7 +640,7 @@ dtrace_dof_create(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t flags) flags |= dtp->dt_dflags; - if (dof_hdr(dtp, &h) != 0) + if (dof_hdr(dtp, pgp->dp_dofversion, &h) != 0) return (NULL); if (dt_dof_reset(dtp, pgp) != 0) @@ -885,7 +908,8 @@ dtrace_getopt_dof(dtrace_hdl_t *dtp) len += sizeof (dof_optdesc_t) * nopts; - if ((dof = dt_zalloc(dtp, len)) == NULL || dof_hdr(dtp, dof) != 0) { + if ((dof = dt_zalloc(dtp, len)) == NULL || + dof_hdr(dtp, DOF_VERSION, dof) != 0) { dt_free(dtp, dof); return (NULL); } diff --git a/usr/src/lib/libdtrace/common/dt_dof.h b/usr/src/lib/libdtrace/common/dt_dof.h index 9d20f624e7..e0a4bf5250 100644 --- a/usr/src/lib/libdtrace/common/dt_dof.h +++ b/usr/src/lib/libdtrace/common/dt_dof.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -19,8 +18,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -51,6 +51,7 @@ typedef struct dt_dof { dt_buf_t ddo_probes; /* probe section data */ dt_buf_t ddo_args; /* probe arguments section data */ dt_buf_t ddo_offs; /* probe offsets section data */ + dt_buf_t ddo_enoffs; /* is-enabled offsets section data */ dt_buf_t ddo_rels; /* probe relocation section data */ dt_buf_t ddo_xlms; /* xlate members section data */ } dt_dof_t; diff --git a/usr/src/lib/libdtrace/common/dt_link.c b/usr/src/lib/libdtrace/common/dt_link.c index ffc95fac06..60fe4b5f36 100644 --- a/usr/src/lib/libdtrace/common/dt_link.c +++ b/usr/src/lib/libdtrace/common/dt_link.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -19,6 +18,7 @@ * * CDDL HEADER END */ + /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. @@ -47,6 +47,7 @@ #include <dt_impl.h> #include <dt_provider.h> +#include <dt_program.h> #include <dt_string.h> #define ESHDR_NULL 0 @@ -742,6 +743,7 @@ dt_symtab_lookup(Elf_Data *data_sym, uintptr_t addr, uint_t shn, GElf_Sym *sym) #define DT_OP_RET 0x81c7e008 #define DT_OP_NOP 0x01000000 #define DT_OP_CALL 0x40000000 +#define DT_OP_CLR_O0 0x90102000 #define DT_IS_MOV_O7(inst) (((inst) & 0xffffe000) == 0x9e100000) #define DT_IS_RESTORE(inst) (((inst) & 0xc1f80000) == 0x81e80000) @@ -750,8 +752,10 @@ dt_symtab_lookup(Elf_Data *data_sym, uintptr_t addr, uint_t shn, GElf_Sym *sym) #define DT_RS2(inst) ((inst) & 0x1f) #define DT_MAKE_RETL(reg) (0x81c02008 | ((reg) << 14)) +/*ARGSUSED*/ static int -dt_modtext(char *p, GElf_Rela *rela, uint32_t *off) +dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, + uint32_t *off) { uint32_t *ip; @@ -769,22 +773,25 @@ dt_modtext(char *p, GElf_Rela *rela, uint32_t *off) return (-1); /* - * We may have already processed this object file in an earlier - * linker invocation in which case we'd expect to see a ret/restore - * pair, a retl-like/mov pair or a nop; return success in that case. + * We may have already processed this object file in an earlier linker + * invocation. Check to see if the present instruction sequence matches + * the one we would install. */ - if (DT_IS_RESTORE(ip[1])) { - if (ip[0] == DT_OP_RET) { - return (0); - } - } else if (DT_IS_MOV_O7(ip[1])) { - if (DT_IS_RETL(ip[0])) { + if (isenabled) { + if (ip[0] == DT_OP_CLR_O0) return (0); - } } else { - if (ip[0] == DT_OP_NOP) { - (*off) += sizeof (ip[0]); - return (0); + if (DT_IS_RESTORE(ip[1])) { + if (ip[0] == DT_OP_RET) + return (0); + } else if (DT_IS_MOV_O7(ip[1])) { + if (DT_IS_RETL(ip[0])) + return (0); + } else { + if (ip[0] == DT_OP_NOP) { + (*off) += sizeof (ip[0]); + return (0); + } } } @@ -797,22 +804,39 @@ dt_modtext(char *p, GElf_Rela *rela, uint32_t *off) return (-1); } - /* - * If the call is followed by a restore, it's a tail call so change - * the call to a ret. If the call if followed by a mov of a register - * into %o7, it's a tail call in leaf context so change the call to - * a retl-like instruction that returns to that register value + 8 - * (rather than the typical %o7 + 8). Otherwise we adjust the offset - * to land on what was once the delay slot of the call so we - * correctly get all the arguments. - */ - if (DT_IS_RESTORE(ip[1])) { - ip[0] = DT_OP_RET; - } else if (DT_IS_MOV_O7(ip[1])) { - ip[0] = DT_MAKE_RETL(DT_RS2(ip[1])); + if (isenabled) { + /* + * It would necessarily indicate incorrect usage if an is- + * enabled probe were tail-called so flag that as an error. + * It's also potentially (very) tricky to handle gracefully, + * but could be done if this were a desired use scenario. + */ + if (DT_IS_RESTORE(ip[1]) || DT_IS_MOV_O7(ip[1])) { + dt_dprintf("tail call to is-enabled probe at %llx\n", + (u_longlong_t)rela->r_offset); + return (-1); + } + + ip[0] = DT_OP_CLR_O0; } else { - ip[0] = DT_OP_NOP; - (*off) += sizeof (ip[0]); + /* + * If the call is followed by a restore, it's a tail call so + * change the call to a ret. If the call if followed by a mov + * of a register into %o7, it's a tail call in leaf context + * so change the call to a retl-like instruction that returns + * to that register value + 8 (rather than the typical %o7 + + * 8). Otherwise we adjust the offset to land on what was + * once the delay slot of the call so we correctly get all + * the arguments. + */ + if (DT_IS_RESTORE(ip[1])) { + ip[0] = DT_OP_RET; + } else if (DT_IS_MOV_O7(ip[1])) { + ip[0] = DT_MAKE_RETL(DT_RS2(ip[1])); + } else { + ip[0] = DT_OP_NOP; + (*off) += sizeof (ip[0]); + } } return (0); @@ -822,16 +846,22 @@ dt_modtext(char *p, GElf_Rela *rela, uint32_t *off) #define DT_OP_NOP 0x90 #define DT_OP_CALL 0xe8 +#define DT_OP_REX_RAX 0x48 +#define DT_OP_XOR_EAX_0 0x33 +#define DT_OP_XOR_EAX_1 0xc0 static int -dt_modtext(char *p, GElf_Rela *rela, uint32_t *off) +dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, + uint32_t *off) { uint8_t *ip = (uint8_t *)(p + rela->r_offset - 1); /* * On x86, the first byte of the instruction is the call opcode and * the next four bytes are the 32-bit address; the relocation is for - * the address so we back up one byte to land on the opcode. + * the address operand. We back up the offset to the first byte of + * the instruction. For is-enabled probes, we later advance the offset + * so that it hits the first nop in the instruction sequence. */ (*off) -= 1; @@ -845,13 +875,31 @@ dt_modtext(char *p, GElf_Rela *rela, uint32_t *off) return (-1); /* - * We may have already processed this object file in an earlier - * linker invocation in which case we'd expect to see a bunch - * of nops; return success in that case. + * We may have already processed this object file in an earlier linker + * invocation. Check to see if the present instruction sequence matches + * the one we would install. For is-enabled probes, we advance the + * offset to the first nop instruction in the sequence. */ - if (ip[0] == DT_OP_NOP && ip[1] == DT_OP_NOP && ip[2] == DT_OP_NOP && - ip[3] == DT_OP_NOP && ip[4] == DT_OP_NOP) - return (0); + if (!isenabled) { + if (ip[0] == DT_OP_NOP && ip[1] == DT_OP_NOP && + ip[2] == DT_OP_NOP && ip[3] == DT_OP_NOP && + ip[4] == DT_OP_NOP) + return (0); + } else if (dtp->dt_oflags & DTRACE_O_LP64) { + if (ip[0] == DT_OP_REX_RAX && + ip[1] == DT_OP_XOR_EAX_0 && ip[2] == DT_OP_XOR_EAX_1 && + ip[3] == DT_OP_NOP && ip[4] == DT_OP_NOP) { + (*off) += 3; + return (0); + } + } else { + if (ip[0] == DT_OP_XOR_EAX_0 && ip[1] == DT_OP_XOR_EAX_1 && + ip[2] == DT_OP_NOP && ip[3] == DT_OP_NOP && + ip[4] == DT_OP_NOP) { + (*off) += 2; + return (0); + } + } /* * We only expect a call instrution with a 32-bit displacement. @@ -862,11 +910,34 @@ dt_modtext(char *p, GElf_Rela *rela, uint32_t *off) return (-1); } - ip[0] = DT_OP_NOP; - ip[1] = DT_OP_NOP; - ip[2] = DT_OP_NOP; - ip[3] = DT_OP_NOP; - ip[4] = DT_OP_NOP; + /* + * Establish the instruction sequence -- all nops for probes, and an + * instruction to clear the return value register (%eax/%rax) followed + * by nops for is-enabled probes. For is-enabled probes, we advance + * the offset to the first nop. This isn't stricly necessary but makes + * for more readable disassembly when the probe is enabled. + */ + if (!isenabled) { + ip[0] = DT_OP_NOP; + ip[1] = DT_OP_NOP; + ip[2] = DT_OP_NOP; + ip[3] = DT_OP_NOP; + ip[4] = DT_OP_NOP; + } else if (dtp->dt_oflags & DTRACE_O_LP64) { + ip[0] = DT_OP_REX_RAX; + ip[1] = DT_OP_XOR_EAX_0; + ip[2] = DT_OP_XOR_EAX_1; + ip[3] = DT_OP_NOP; + ip[4] = DT_OP_NOP; + (*off) += 3; + } else { + ip[0] = DT_OP_XOR_EAX_0; + ip[1] = DT_OP_XOR_EAX_1; + ip[2] = DT_OP_NOP; + ip[3] = DT_OP_NOP; + ip[4] = DT_OP_NOP; + (*off) += 2; + } return (0); } @@ -904,12 +975,13 @@ dt_link_error(dtrace_hdl_t *dtp, Elf *elf, int fd, dt_link_pair_t *bufs, } static int -process_obj(dtrace_hdl_t *dtp, const char *obj) +process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp) { - static const char dt_prefix[] = "__dtrace_"; + static const char dt_prefix[] = "__dtrace"; + static const char dt_enabled[] = "enabled"; static const char dt_symprefix[] = "$dtrace"; static const char dt_symfmt[] = "%s%d.%s"; - int fd, i, ndx, mod = 0; + int fd, i, ndx, eprobe, mod = 0; Elf *elf = NULL; GElf_Ehdr ehdr; Elf_Scn *scn_rel, *scn_sym, *scn_str, *scn_tgt; @@ -1037,7 +1109,7 @@ process_obj(dtrace_hdl_t *dtp, const char *obj) /* * We're looking for relocations to symbols matching this form: * - * __dtrace_<prov>___<probe> + * __dtrace[enabled]_<prov>___<probe> * * For the generated object, we need to record the location * identified by the relocation, and create a new relocation @@ -1192,6 +1264,25 @@ process_obj(dtrace_hdl_t *dtp, const char *obj) continue; s += sizeof (dt_prefix) - 1; + + /* + * Check to see if this is an 'is-enabled' check as + * opposed to a normal probe. + */ + if (strncmp(s, dt_enabled, + sizeof (dt_enabled) - 1) == 0) { + s += sizeof (dt_enabled) - 1; + eprobe = 1; + *eprobesp = 1; + dt_dprintf("is-enabled probe\n"); + } else { + eprobe = 0; + dt_dprintf("normal probe\n"); + } + + if (*s++ != '_') + goto err; + if ((p = strstr(s, "___")) == NULL || p - s >= sizeof (pname)) goto err; @@ -1257,10 +1348,12 @@ process_obj(dtrace_hdl_t *dtp, const char *obj) assert(fsym.st_value <= rela.r_offset); off = rela.r_offset - fsym.st_value; - if (dt_modtext(data_tgt->d_buf, &rela, &off) != 0) + if (dt_modtext(dtp, data_tgt->d_buf, eprobe, + &rela, &off) != 0) { goto err; + } - if (dt_probe_define(pvp, prp, s, r, off) != 0) { + if (dt_probe_define(pvp, prp, s, r, off, eprobe) != 0) { return (dt_link_error(dtp, elf, fd, bufs, "failed to allocate space for probe")); } @@ -1318,7 +1411,7 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags, int fd, status, i, cur; char *cmd, tmp; size_t len; - int ret = 0; + int eprobes = 0, ret = 0; /* * A NULL program indicates a special use in which we just link @@ -1367,10 +1460,17 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags, } for (i = 0; i < objc; i++) { - if (process_obj(dtp, objv[i]) != 0) + if (process_obj(dtp, objv[i], &eprobes) != 0) return (-1); /* errno is set for us */ } + /* + * If there are is-enabled probes then we need to force use of DOF + * version 2. + */ + if (eprobes && pgp->dp_dofversion < DOF_VERSION_2) + pgp->dp_dofversion = DOF_VERSION_2; + if ((dof = dtrace_dof_create(dtp, pgp, dflags)) == NULL) return (-1); /* errno is set for us */ diff --git a/usr/src/lib/libdtrace/common/dt_open.c b/usr/src/lib/libdtrace/common/dt_open.c index b857661728..79e29c3c7f 100644 --- a/usr/src/lib/libdtrace/common/dt_open.c +++ b/usr/src/lib/libdtrace/common/dt_open.c @@ -96,14 +96,16 @@ #define DT_VERS_1_1 DT_VERSION_NUMBER(1, 1, 0) #define DT_VERS_1_2 DT_VERSION_NUMBER(1, 2, 0) #define DT_VERS_1_2_1 DT_VERSION_NUMBER(1, 2, 1) -#define DT_VERS_LATEST DT_VERS_1_2_1 -#define DT_VERS_STRING "Sun D 1.2.1" +#define DT_VERS_1_2_2 DT_VERSION_NUMBER(1, 2, 2) +#define DT_VERS_LATEST DT_VERS_1_2_2 +#define DT_VERS_STRING "Sun D 1.2.2" const dt_version_t _dtrace_versions[] = { DT_VERS_1_0, /* D API 1.0.0 (PSARC 2001/466) Solaris 10 FCS */ DT_VERS_1_1, /* D API 1.1.0 Solaris Express 6/05 */ DT_VERS_1_2, /* D API 1.2.0 Solaris 10 Update 1 */ DT_VERS_1_2_1, /* D API 1.2.1 Solaris Express 4/06 */ + DT_VERS_1_2_2, /* D API 1.2.2 Solaris Express 6/06 */ 0 }; diff --git a/usr/src/lib/libdtrace/common/dt_program.c b/usr/src/lib/libdtrace/common/dt_program.c index e0d3ada107..d751c4817b 100644 --- a/usr/src/lib/libdtrace/common/dt_program.c +++ b/usr/src/lib/libdtrace/common/dt_program.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -50,6 +49,13 @@ dt_program_create(dtrace_hdl_t *dtp) else (void) dt_set_errno(dtp, EDT_NOMEM); + /* + * By default, programs start with DOF version 1 so that output files + * containing DOF are backward compatible. If a program requires new + * DOF features, the version is increased as needed. + */ + pgp->dp_dofversion = DOF_VERSION_1; + return (pgp); } @@ -425,6 +431,10 @@ dt_header_decl(dt_idhash_t *dhp, dt_ident_t *idp, void *data) if (fprintf(infop->dthi_out, ");\n") < 0) return (dt_set_errno(dtp, errno)); + if (fprintf(infop->dthi_out, "extern int " + "__dtraceenabled_%s___%s(void);\n", infop->dthi_pfname, fname) < 0) + return (dt_set_errno(dtp, errno)); + return (0); } @@ -481,6 +491,14 @@ dt_header_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data) if (fprintf(infop->dthi_out, ")\n") < 0) return (dt_set_errno(dtp, errno)); + if (fprintf(infop->dthi_out, "#define\t%s_%s_ENABLED() \\\n", + infop->dthi_pmname, mname) < 0) + return (dt_set_errno(dtp, errno)); + + if (fprintf(infop->dthi_out, "\t__dtraceenabled_%s___%s()\n", + infop->dthi_pfname, fname) < 0) + return (dt_set_errno(dtp, errno)); + return (0); } diff --git a/usr/src/lib/libdtrace/common/dt_program.h b/usr/src/lib/libdtrace/common/dt_program.h index b4311baed2..3fe1c39136 100644 --- a/usr/src/lib/libdtrace/common/dt_program.h +++ b/usr/src/lib/libdtrace/common/dt_program.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -19,8 +18,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -46,6 +46,7 @@ struct dtrace_prog { dt_list_t dp_stmts; /* linked list of dt_stmt_t's */ ulong_t **dp_xrefs; /* array of translator reference bitmaps */ uint_t dp_xrefslen; /* length of dp_xrefs array */ + uint8_t dp_dofversion; /* DOF version this program requires */ }; extern dtrace_prog_t *dt_program_create(dtrace_hdl_t *); diff --git a/usr/src/lib/libdtrace/common/dt_provider.c b/usr/src/lib/libdtrace/common/dt_provider.c index 056442aa8f..9c5ff9e1a1 100644 --- a/usr/src/lib/libdtrace/common/dt_provider.c +++ b/usr/src/lib/libdtrace/common/dt_provider.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -19,6 +18,7 @@ * * CDDL HEADER END */ + /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. @@ -498,6 +498,7 @@ dt_probe_destroy(dt_probe_t *prp) for (pip = prp->pr_inst; pip != NULL; pip = pip_next) { pip_next = pip->pi_next; dt_free(dtp, pip->pi_offs); + dt_free(dtp, pip->pi_enoffs); dt_free(dtp, pip); } @@ -508,10 +509,12 @@ dt_probe_destroy(dt_probe_t *prp) int dt_probe_define(dt_provider_t *pvp, dt_probe_t *prp, - const char *fname, const char *rname, uint32_t offset) + const char *fname, const char *rname, uint32_t offset, int isenabled) { dtrace_hdl_t *dtp = pvp->pv_hdl; dt_probe_instance_t *pip; + uint32_t **offs; + uint_t *noffs, *maxoffs; assert(fname != NULL); @@ -526,7 +529,15 @@ dt_probe_define(dt_provider_t *pvp, dt_probe_t *prp, if ((pip = dt_zalloc(dtp, sizeof (*pip))) == NULL) return (-1); - if ((pip->pi_offs = dt_alloc(dtp, sizeof (uint32_t))) == NULL) { + if ((pip->pi_offs = dt_zalloc(dtp, + sizeof (uint32_t))) == NULL) { + dt_free(dtp, pip); + return (-1); + } + + if ((pip->pi_enoffs = dt_zalloc(dtp, + sizeof (uint32_t))) == NULL) { + dt_free(dtp, pip->pi_offs); dt_free(dtp, pip); return (-1); } @@ -540,34 +551,48 @@ dt_probe_define(dt_provider_t *pvp, dt_probe_t *prp, } (void) strcpy(pip->pi_rname, rname); } + pip->pi_noffs = 0; pip->pi_maxoffs = 1; + pip->pi_nenoffs = 0; + pip->pi_maxenoffs = 1; + pip->pi_next = prp->pr_inst; prp->pr_inst = pip; } - if (pip->pi_noffs == pip->pi_maxoffs) { - uint_t new_max = pip->pi_maxoffs * 2; + if (isenabled) { + offs = &pip->pi_enoffs; + noffs = &pip->pi_nenoffs; + maxoffs = &pip->pi_maxenoffs; + } else { + offs = &pip->pi_offs; + noffs = &pip->pi_noffs; + maxoffs = &pip->pi_maxoffs; + } + + if (*noffs == *maxoffs) { + uint_t new_max = *maxoffs * 2; uint32_t *new_offs = dt_alloc(dtp, sizeof (uint32_t) * new_max); if (new_offs == NULL) return (-1); - bcopy(pip->pi_offs, new_offs, - sizeof (uint32_t) * pip->pi_maxoffs); + bcopy(*offs, new_offs, sizeof (uint32_t) * *maxoffs); - dt_free(dtp, pip->pi_offs); - pip->pi_maxoffs = new_max; - pip->pi_offs = new_offs; + dt_free(dtp, *offs); + *maxoffs = new_max; + *offs = new_offs; } - dt_dprintf("defined probe %s:%s %s() +0x%x (%s)\n", + dt_dprintf("defined probe %s %s:%s %s() +0x%x (%s)\n", + isenabled ? "(is-enabled)" : "", pvp->pv_desc.dtvd_name, prp->pr_ident->di_name, fname, offset, rname != NULL ? rname : fname); - assert(pip->pi_noffs < pip->pi_maxoffs); - pip->pi_offs[pip->pi_noffs++] = offset; + assert(*noffs < *maxoffs); + *offs[(*noffs)++] = offset; return (0); } diff --git a/usr/src/lib/libdtrace/common/dt_provider.h b/usr/src/lib/libdtrace/common/dt_provider.h index 97436557d4..af4ec33dcb 100644 --- a/usr/src/lib/libdtrace/common/dt_provider.h +++ b/usr/src/lib/libdtrace/common/dt_provider.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -19,6 +18,7 @@ * * CDDL HEADER END */ + /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. @@ -67,8 +67,11 @@ typedef struct dt_probe_instance { char pi_fname[DTRACE_FUNCNAMELEN]; /* function name */ char pi_rname[DTRACE_FUNCNAMELEN + 20]; /* mangled relocation name */ uint32_t *pi_offs; /* offsets into the function */ + uint32_t *pi_enoffs; /* is-enabled offsets */ uint_t pi_noffs; /* number of offsets */ uint_t pi_maxoffs; /* size of pi_offs allocation */ + uint_t pi_nenoffs; /* number of is-enabled offsets */ + uint_t pi_maxenoffs; /* size of pi_enoffs allocation */ struct dt_probe_instance *pi_next; /* next instance in the list */ } dt_probe_instance_t; @@ -104,7 +107,7 @@ extern void dt_probe_declare(dt_provider_t *, dt_probe_t *); extern void dt_probe_destroy(dt_probe_t *); extern int dt_probe_define(dt_provider_t *, dt_probe_t *, - const char *, const char *, uint32_t); + const char *, const char *, uint32_t, int); extern dt_node_t *dt_probe_tag(dt_probe_t *, uint_t, dt_node_t *); diff --git a/usr/src/uts/common/dtrace/dtrace.c b/usr/src/uts/common/dtrace/dtrace.c index 3ee6670006..eabf7a8016 100644 --- a/usr/src/uts/common/dtrace/dtrace.c +++ b/usr/src/uts/common/dtrace/dtrace.c @@ -18,6 +18,7 @@ * * CDDL HEADER END */ + /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. @@ -183,8 +184,6 @@ static dtrace_ecb_t *dtrace_ecb_create_cache; /* cached created ECB */ static dtrace_genid_t dtrace_probegen; /* current probe generation */ static dtrace_helpers_t *dtrace_deferred_pid; /* deferred helper list */ static dtrace_enabling_t *dtrace_retained; /* list of retained enablings */ -static dtrace_state_t *dtrace_state; /* temporary variable */ -static int dtrace_err; /* temporary variable */ /* * DTrace Locking @@ -6638,10 +6637,10 @@ dtrace_helper_provide_one(dof_helper_t *dhp, dof_sec_t *sec, pid_t pid) { uintptr_t daddr = (uintptr_t)dhp->dofhp_dof; dof_hdr_t *dof = (dof_hdr_t *)daddr; - dof_sec_t *str_sec, *prb_sec, *arg_sec, *off_sec; + dof_sec_t *str_sec, *prb_sec, *arg_sec, *off_sec, *enoff_sec; dof_provider_t *provider; dof_probe_t *probe; - uint32_t *off; + uint32_t *off, *enoff; uint8_t *arg; char *strtab; uint_t i, nprobes; @@ -6664,6 +6663,17 @@ dtrace_helper_provide_one(dof_helper_t *dhp, dof_sec_t *sec, pid_t pid) strtab = (char *)(uintptr_t)(daddr + str_sec->dofs_offset); off = (uint32_t *)(uintptr_t)(daddr + off_sec->dofs_offset); arg = (uint8_t *)(uintptr_t)(daddr + arg_sec->dofs_offset); + enoff = NULL; + + /* + * See dtrace_helper_provider_validate(). + */ + if (dof->dofh_ident[DOF_ID_VERSION] != DOF_VERSION_1 && + provider->dofpv_prenoffs != 0) { + enoff_sec = (dof_sec_t *)(uintptr_t)(daddr + dof->dofh_secoff + + provider->dofpv_prenoffs * dof->dofh_secsize); + enoff = (uint32_t *)(uintptr_t)(daddr + enoff_sec->dofs_offset); + } nprobes = prb_sec->dofs_size / prb_sec->dofs_entsize; @@ -6690,6 +6700,13 @@ dtrace_helper_provide_one(dof_helper_t *dhp, dof_sec_t *sec, pid_t pid) dhpb.dthpb_base = probe->dofpr_addr; dhpb.dthpb_offs = off + probe->dofpr_offidx; dhpb.dthpb_noffs = probe->dofpr_noffs; + if (enoff != NULL) { + dhpb.dthpb_enoffs = enoff + probe->dofpr_enoffidx; + dhpb.dthpb_nenoffs = probe->dofpr_nenoffs; + } else { + dhpb.dthpb_enoffs = NULL; + dhpb.dthpb_nenoffs = 0; + } dhpb.dthpb_args = arg + probe->dofpr_argidx; dhpb.dthpb_nargc = probe->dofpr_nargc; dhpb.dthpb_xargc = probe->dofpr_xargc; @@ -10015,7 +10032,7 @@ dtrace_dof_create(dtrace_state_t *state) dof->dofh_ident[DOF_ID_MODEL] = DOF_MODEL_NATIVE; dof->dofh_ident[DOF_ID_ENCODING] = DOF_ENCODE_NATIVE; - dof->dofh_ident[DOF_ID_VERSION] = DOF_VERSION_1; + dof->dofh_ident[DOF_ID_VERSION] = DOF_VERSION; dof->dofh_ident[DOF_ID_DIFVERS] = DIF_VERSION; dof->dofh_ident[DOF_ID_DIFIREG] = DIF_DIR_NREGS; dof->dofh_ident[DOF_ID_DIFTREG] = DIF_DTR_NREGS; @@ -10733,7 +10750,8 @@ dtrace_dof_slurp(dof_hdr_t *dof, dtrace_vstate_t *vstate, cred_t *cr, return (-1); } - if (dof->dofh_ident[DOF_ID_VERSION] != DOF_VERSION_1) { + if (dof->dofh_ident[DOF_ID_VERSION] != DOF_VERSION_1 && + dof->dofh_ident[DOF_ID_VERSION] != DOF_VERSION_2) { dtrace_dof_error(dof, "DOF version mismatch"); return (-1); } @@ -12456,7 +12474,7 @@ static int dtrace_helper_provider_validate(dof_hdr_t *dof, dof_sec_t *sec) { uintptr_t daddr = (uintptr_t)dof; - dof_sec_t *str_sec, *prb_sec, *arg_sec, *off_sec; + dof_sec_t *str_sec, *prb_sec, *arg_sec, *off_sec, *enoff_sec; dof_provider_t *provider; dof_probe_t *probe; uint8_t *arg; @@ -12472,6 +12490,18 @@ dtrace_helper_provider_validate(dof_hdr_t *dof, dof_sec_t *sec) return (-1); } + /* + * The section needs to be large enough to contain the DOF provider + * structure appropriate for the given version. + */ + if (sec->dofs_size < + ((dof->dofh_ident[DOF_ID_VERSION] == DOF_VERSION_1) ? + offsetof(dof_provider_t, dofpv_prenoffs) : + sizeof (dof_provider_t))) { + dtrace_dof_error(dof, "provider section too small"); + return (-1); + } + provider = (dof_provider_t *)(uintptr_t)(daddr + sec->dofs_offset); str_sec = dtrace_dof_sect(dof, DOF_SECT_STRTAB, provider->dofpv_strtab); prb_sec = dtrace_dof_sect(dof, DOF_SECT_PROBES, provider->dofpv_probes); @@ -12482,6 +12512,13 @@ dtrace_helper_provider_validate(dof_hdr_t *dof, dof_sec_t *sec) arg_sec == NULL || off_sec == NULL) return (-1); + enoff_sec = NULL; + + if (dof->dofh_ident[DOF_ID_VERSION] != DOF_VERSION_1 && + provider->dofpv_prenoffs != 0 && (enoff_sec = dtrace_dof_sect(dof, + DOF_SECT_PRENOFFS, provider->dofpv_prenoffs)) == NULL) + return (-1); + strtab = (char *)(uintptr_t)(daddr + str_sec->dofs_offset); if (provider->dofpv_name >= str_sec->dofs_size || @@ -12543,8 +12580,12 @@ dtrace_helper_provider_validate(dof_hdr_t *dof, dof_sec_t *sec) return (-1); } - - if (probe->dofpr_offidx + probe->dofpr_noffs < + /* + * The offset count must not wrap the index and there must be + * at least one offset. The offsets must also not overflow the + * section's data. + */ + if (probe->dofpr_offidx + probe->dofpr_noffs <= probe->dofpr_offidx || (probe->dofpr_offidx + probe->dofpr_noffs) * off_sec->dofs_entsize > off_sec->dofs_size) { @@ -12552,6 +12593,31 @@ dtrace_helper_provider_validate(dof_hdr_t *dof, dof_sec_t *sec) return (-1); } + if (dof->dofh_ident[DOF_ID_VERSION] != DOF_VERSION_1) { + /* + * If there's no is-enabled offset section, make sure + * there aren't any is-enabled offsets. Otherwise + * perform the same checks as for probe offsets + * (immediately above), except that having zero + * is-enabled offsets is permitted. + */ + if (enoff_sec == NULL) { + if (probe->dofpr_enoffidx != 0 || + probe->dofpr_nenoffs != 0) { + dtrace_dof_error(dof, "is-enabled " + "offsets with null section"); + return (-1); + } + } else if (probe->dofpr_enoffidx + + probe->dofpr_nenoffs < probe->dofpr_enoffidx || + (probe->dofpr_enoffidx + probe->dofpr_nenoffs) * + enoff_sec->dofs_entsize > enoff_sec->dofs_size) { + dtrace_dof_error(dof, "invalid is-enabled " + "offset"); + return (-1); + } + } + if (probe->dofpr_argidx + probe->dofpr_xargc < probe->dofpr_argidx || (probe->dofpr_argidx + probe->dofpr_xargc) * @@ -12615,7 +12681,8 @@ dtrace_helper_slurp(dof_hdr_t *dof, dof_helper_t *dhp) dtrace_helpers_t *help; dtrace_vstate_t *vstate; dtrace_enabling_t *enab = NULL; - int i, gen, rv, nhelpers = 0, destroy = 1; + int i, gen, rv, nhelpers = 0, nprovs = 0, destroy = 1; + uintptr_t daddr = (uintptr_t)dof; ASSERT(MUTEX_HELD(&dtrace_lock)); @@ -12631,6 +12698,27 @@ dtrace_helper_slurp(dof_hdr_t *dof, dof_helper_t *dhp) } /* + * Look for helper providers and validate their descriptions. + */ + if (dhp != NULL) { + for (i = 0; i < dof->dofh_secnum; i++) { + dof_sec_t *sec = (dof_sec_t *)(uintptr_t)(daddr + + dof->dofh_secoff + i * dof->dofh_secsize); + + if (sec->dofs_type != DOF_SECT_PROVIDER) + continue; + + if (dtrace_helper_provider_validate(dof, sec) != 0) { + dtrace_enabling_destroy(enab); + dtrace_dof_destroy(dof); + return (-1); + } + + nprovs++; + } + } + + /* * Now we need to walk through the ECB descriptions in the enabling. */ for (i = 0; i < enab->dten_ndesc; i++) { @@ -12655,7 +12743,6 @@ dtrace_helper_slurp(dof_hdr_t *dof, dof_helper_t *dhp) (void) dtrace_helper_destroygen(help->dthps_generation); dtrace_enabling_destroy(enab); dtrace_dof_destroy(dof); - dtrace_err = rv; return (-1); } @@ -12665,43 +12752,18 @@ dtrace_helper_slurp(dof_hdr_t *dof, dof_helper_t *dhp) if (nhelpers < enab->dten_ndesc) dtrace_dof_error(dof, "unmatched helpers"); - if (dhp != NULL) { - uintptr_t daddr = (uintptr_t)dof; - int err = 0, count = 0; - - /* - * Look for helper probes. - */ - for (i = 0; i < dof->dofh_secnum; i++) { - dof_sec_t *sec = (dof_sec_t *)(uintptr_t)(daddr + - dof->dofh_secoff + i * dof->dofh_secsize); - - if (sec->dofs_type != DOF_SECT_PROVIDER) - continue; - - if (dtrace_helper_provider_validate(dof, sec) != 0) { - err = 1; - break; - } - - count++; - } - - dhp->dofhp_dof = (uint64_t)(uintptr_t)dof; - if (err == 0 && count > 0 && - dtrace_helper_provider_add(dhp) == 0) - destroy = 0; - else - dhp = NULL; - } - gen = help->dthps_generation++; dtrace_enabling_destroy(enab); - if (dhp != NULL) { - mutex_exit(&dtrace_lock); - dtrace_helper_provider_register(curproc, help, dhp); - mutex_enter(&dtrace_lock); + if (dhp != NULL && nprovs > 0) { + dhp->dofhp_dof = (uint64_t)(uintptr_t)dof; + if (dtrace_helper_provider_add(dhp) == 0) { + mutex_exit(&dtrace_lock); + dtrace_helper_provider_register(curproc, help, dhp); + mutex_enter(&dtrace_lock); + + destroy = 0; + } } if (destroy) @@ -13460,7 +13522,6 @@ dtrace_ioctl_helper(int cmd, intptr_t arg, int *rv) return (rval); mutex_enter(&dtrace_lock); - dtrace_err = 0; /* * dtrace_helper_slurp() takes responsibility for the dof -- diff --git a/usr/src/uts/common/dtrace/fasttrap.c b/usr/src/uts/common/dtrace/fasttrap.c index 3829012db5..30394b4ee4 100644 --- a/usr/src/uts/common/dtrace/fasttrap.c +++ b/usr/src/uts/common/dtrace/fasttrap.c @@ -52,7 +52,6 @@ #include <sys/vmsystm.h> #include <sys/prsystm.h> - #include <vm/as.h> #include <vm/seg.h> #include <vm/seg_dev.h> @@ -510,7 +509,7 @@ fasttrap_tracepoint_enable(proc_t *p, fasttrap_probe_t *probe, uint_t index) * like to install. If we can't find a match, and have an allocated * tracepoint ready to go, enable that one now. * - * A tracepoint whose proc is defunct is also considered defunct. + * A tracepoint whose process is defunct is also considered defunct. */ again: mutex_enter(&bucket->ftb_mtx); @@ -535,17 +534,26 @@ again: */ ASSERT(tp->ftt_ids != NULL || tp->ftt_retids != NULL); - if (probe->ftp_type == DTFTP_RETURN || - probe->ftp_type == DTFTP_POST_OFFSETS) { - id->fti_next = tp->ftt_retids; - membar_producer(); - tp->ftt_retids = id; - membar_producer(); - } else { + switch (id->fti_ptype) { + case DTFTP_ENTRY: + case DTFTP_OFFSETS: + case DTFTP_IS_ENABLED: id->fti_next = tp->ftt_ids; membar_producer(); tp->ftt_ids = id; membar_producer(); + break; + + case DTFTP_RETURN: + case DTFTP_POST_OFFSETS: + id->fti_next = tp->ftt_retids; + membar_producer(); + tp->ftt_retids = id; + membar_producer(); + break; + + default: + ASSERT(0); } mutex_exit(&bucket->ftb_mtx); @@ -603,20 +611,29 @@ again: ASSERT(new_tp->ftt_ids == NULL); ASSERT(new_tp->ftt_retids == NULL); - if (probe->ftp_type == DTFTP_RETURN || - probe->ftp_type == DTFTP_POST_OFFSETS) { - id->fti_next = NULL; - new_tp->ftt_retids = id; - } else { + switch (id->fti_ptype) { + case DTFTP_ENTRY: + case DTFTP_OFFSETS: + case DTFTP_IS_ENABLED: id->fti_next = NULL; new_tp->ftt_ids = id; + break; + + case DTFTP_RETURN: + case DTFTP_POST_OFFSETS: + id->fti_next = NULL; + new_tp->ftt_retids = id; + break; + + default: + ASSERT(0); } /* * If the ISA-dependent initialization goes to plan, go back to the * beginning and try to install this freshly made tracepoint. */ - if (fasttrap_tracepoint_init(p, probe, new_tp, pc) == 0) + if (fasttrap_tracepoint_init(p, new_tp, pc, id->fti_ptype) == 0) goto again; new_tp->ftt_ids = NULL; @@ -639,6 +656,7 @@ fasttrap_tracepoint_disable(proc_t *p, fasttrap_probe_t *probe, uint_t index) pid = probe->ftp_pid; pc = probe->ftp_tps[index].fit_tp->ftt_pc; + id = &probe->ftp_tps[index].fit_id; ASSERT(probe->ftp_tps[index].fit_tp->ftt_pid == pid); @@ -659,13 +677,22 @@ fasttrap_tracepoint_disable(proc_t *p, fasttrap_probe_t *probe, uint_t index) */ ASSERT(tp != NULL); - if (probe->ftp_type == DTFTP_RETURN || - probe->ftp_type == DTFTP_POST_OFFSETS) { - ASSERT(tp->ftt_retids != NULL); - idp = &tp->ftt_retids; - } else { + switch (id->fti_ptype) { + case DTFTP_ENTRY: + case DTFTP_OFFSETS: + case DTFTP_IS_ENABLED: ASSERT(tp->ftt_ids != NULL); idp = &tp->ftt_ids; + break; + + case DTFTP_RETURN: + case DTFTP_POST_OFFSETS: + ASSERT(tp->ftt_retids != NULL); + idp = &tp->ftt_retids; + break; + + default: + ASSERT(0); } while ((*idp)->fti_probe != probe) { @@ -1548,7 +1575,6 @@ fasttrap_add_probe(fasttrap_probe_spec_t *pdata) pp->ftp_fsize = pdata->ftps_size; pp->ftp_pid = pdata->ftps_pid; pp->ftp_ntps = pdata->ftps_noffs; - pp->ftp_type = pdata->ftps_type; for (i = 0; i < pdata->ftps_noffs; i++) { tp = kmem_zalloc(sizeof (fasttrap_tracepoint_t), @@ -1560,6 +1586,7 @@ fasttrap_add_probe(fasttrap_probe_spec_t *pdata) pp->ftp_tps[i].fit_tp = tp; pp->ftp_tps[i].fit_id.fti_probe = pp; + pp->ftp_tps[i].fit_id.fti_ptype = pdata->ftps_type; } pp->ftp_id = dtrace_probe_create(provider->ftp_provid, @@ -1589,7 +1616,6 @@ fasttrap_add_probe(fasttrap_probe_spec_t *pdata) pp->ftp_fsize = pdata->ftps_size; pp->ftp_pid = pdata->ftps_pid; pp->ftp_ntps = 1; - pp->ftp_type = pdata->ftps_type; tp = kmem_zalloc(sizeof (fasttrap_tracepoint_t), KM_SLEEP); @@ -1600,6 +1626,7 @@ fasttrap_add_probe(fasttrap_probe_spec_t *pdata) pp->ftp_tps[0].fit_tp = tp; pp->ftp_tps[0].fit_id.fti_probe = pp; + pp->ftp_tps[0].fit_id.fti_ptype = pdata->ftps_type; pp->ftp_id = dtrace_probe_create(provider->ftp_provid, pdata->ftps_mod, pdata->ftps_func, name_str, @@ -1712,7 +1739,8 @@ fasttrap_meta_create_probe(void *arg, void *parg, fasttrap_probe_t *pp; fasttrap_tracepoint_t *tp; size_t size; - int i; + int i, j; + uint32_t ntps; mutex_enter(&provider->ftp_mtx); @@ -1722,31 +1750,31 @@ fasttrap_meta_create_probe(void *arg, void *parg, return; } - atomic_add_32(&fasttrap_total, dhpb->dthpb_noffs); + ntps = dhpb->dthpb_noffs + dhpb->dthpb_nenoffs; + + atomic_add_32(&fasttrap_total, ntps); if (fasttrap_total > fasttrap_max) { - atomic_add_32(&fasttrap_total, -dhpb->dthpb_noffs); + atomic_add_32(&fasttrap_total, -ntps); mutex_exit(&provider->ftp_mtx); return; } - size = sizeof (fasttrap_probe_t) + - sizeof (pp->ftp_tps[0]) * (dhpb->dthpb_noffs - 1); + ASSERT(dhpb->dthpb_noffs > 0); + size = sizeof (fasttrap_probe_t) + sizeof (pp->ftp_tps[0]) * (ntps - 1); pp = kmem_zalloc(size, KM_SLEEP); pp->ftp_prov = provider; pp->ftp_pid = provider->ftp_pid; - pp->ftp_ntps = dhpb->dthpb_noffs; -#ifdef __sparc - pp->ftp_type = DTFTP_POST_OFFSETS; -#else - pp->ftp_type = DTFTP_OFFSETS; -#endif + pp->ftp_ntps = ntps; pp->ftp_nargs = dhpb->dthpb_xargc; pp->ftp_xtypes = dhpb->dthpb_xtypes; pp->ftp_ntypes = dhpb->dthpb_ntypes; - for (i = 0; i < pp->ftp_ntps; i++) { + /* + * First create a tracepoint for each actual point of interest. + */ + for (i = 0; i < dhpb->dthpb_noffs; i++) { tp = kmem_zalloc(sizeof (fasttrap_tracepoint_t), KM_SLEEP); tp->ftt_proc = provider->ftp_proc; @@ -1755,6 +1783,26 @@ fasttrap_meta_create_probe(void *arg, void *parg, pp->ftp_tps[i].fit_tp = tp; pp->ftp_tps[i].fit_id.fti_probe = pp; +#ifdef __sparc + pp->ftp_tps[i].fit_id.fti_ptype = DTFTP_POST_OFFSETS; +#else + pp->ftp_tps[i].fit_id.fti_ptype = DTFTP_OFFSETS; +#endif + } + + /* + * Then create a tracepoint for each is-enabled point. + */ + for (j = 0; i < ntps; i++, j++) { + tp = kmem_zalloc(sizeof (fasttrap_tracepoint_t), KM_SLEEP); + + tp->ftt_proc = provider->ftp_proc; + tp->ftt_pc = dhpb->dthpb_base + dhpb->dthpb_enoffs[j]; + tp->ftt_pid = provider->ftp_pid; + + pp->ftp_tps[i].fit_tp = tp; + pp->ftp_tps[i].fit_id.fti_probe = pp; + pp->ftp_tps[i].fit_id.fti_ptype = DTFTP_IS_ENABLED; } /* diff --git a/usr/src/uts/common/sys/dtrace.h b/usr/src/uts/common/sys/dtrace.h index 57765c1d31..48d876a651 100644 --- a/usr/src/uts/common/sys/dtrace.h +++ b/usr/src/uts/common/sys/dtrace.h @@ -18,6 +18,7 @@ * * CDDL HEADER END */ + /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. @@ -599,8 +600,9 @@ typedef struct dof_hdr { #define DOF_ENCODE_NATIVE DOF_ENCODE_LSB #endif -#define DOF_VERSION_1 1 /* DOF_ID_VERSION */ -#define DOF_VERSION DOF_VERSION_1 +#define DOF_VERSION_1 1 /* DOF version 1: Solaris 10 FCS */ +#define DOF_VERSION_2 2 /* DOF version 2: Solaris Express 6/06 */ +#define DOF_VERSION DOF_VERSION_2 /* Latest DOF version */ #define DOF_FL_VALID 0 /* mask of all valid dofh_flags bits */ @@ -645,6 +647,7 @@ typedef struct dof_sec { #define DOF_SECT_XLIMPORT 23 /* dof_xlator_t */ #define DOF_SECT_XLEXPORT 24 /* dof_xlator_t */ #define DOF_SECT_PREXPORT 25 /* dof_secidx_t array (exported objs) */ +#define DOF_SECT_PRENOFFS 26 /* uint32_t array (enabled offsets) */ #define DOF_SECF_LOAD 1 /* section should be loaded */ @@ -719,6 +722,7 @@ typedef struct dof_provider { dof_attr_t dofpv_funcattr; /* function attributes */ dof_attr_t dofpv_nameattr; /* name attributes */ dof_attr_t dofpv_argsattr; /* args attributes */ + dof_secidx_t dofpv_prenoffs; /* link to DOF_SECT_PRENOFFS section */ } dof_provider_t; typedef struct dof_probe { @@ -732,7 +736,10 @@ typedef struct dof_probe { uint8_t dofpr_nargc; /* native argument count */ uint8_t dofpr_xargc; /* translated argument count */ uint16_t dofpr_noffs; /* number of offset entries for probe */ - uint32_t dofpr_pad; /* reserved for future use */ + uint32_t dofpr_enoffidx; /* index of first is-enabled offset */ + uint16_t dofpr_nenoffs; /* number of is-enabled offsets */ + uint16_t dofpr_pad1; /* reserved for future use */ + uint32_t dofpr_pad2; /* reserved for future use */ } dof_probe_t; typedef struct dof_xlator { @@ -2082,7 +2089,9 @@ typedef struct dtrace_helper_probedesc { char *dthpb_name; /* probe name */ uint64_t dthpb_base; /* base address */ uint32_t *dthpb_offs; /* offsets array */ + uint32_t *dthpb_enoffs; /* is-enabled offsets array */ uint32_t dthpb_noffs; /* offsets count */ + uint32_t dthpb_nenoffs; /* is-enabled offsets count */ uint8_t *dthpb_args; /* argument mapping array */ uint8_t dthpb_xargc; /* translated argument count */ uint8_t dthpb_nargc; /* native argument count */ diff --git a/usr/src/uts/common/sys/fasttrap.h b/usr/src/uts/common/sys/fasttrap.h index 2eddfd3560..7f803144bc 100644 --- a/usr/src/uts/common/sys/fasttrap.h +++ b/usr/src/uts/common/sys/fasttrap.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -19,8 +18,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -46,7 +46,8 @@ typedef enum fasttrap_probe_type { DTFTP_ENTRY, DTFTP_RETURN, DTFTP_OFFSETS, - DTFTP_POST_OFFSETS + DTFTP_POST_OFFSETS, + DTFTP_IS_ENABLED } fasttrap_probe_type_t; typedef struct fasttrap_probe_spec { diff --git a/usr/src/uts/common/sys/fasttrap_impl.h b/usr/src/uts/common/sys/fasttrap_impl.h index 7f500951aa..4d3dd2f7be 100644 --- a/usr/src/uts/common/sys/fasttrap_impl.h +++ b/usr/src/uts/common/sys/fasttrap_impl.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -19,8 +18,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -96,6 +96,7 @@ typedef struct fasttrap_tracepoint fasttrap_tracepoint_t; struct fasttrap_id { fasttrap_probe_t *fti_probe; /* referrring probe */ fasttrap_id_t *fti_next; /* enabled probe list on tp */ + fasttrap_probe_type_t fti_ptype; /* probe type */ }; typedef struct fasttrap_id_tp { @@ -109,12 +110,11 @@ struct fasttrap_probe { fasttrap_provider_t *ftp_prov; /* this probe's provider */ uintptr_t ftp_faddr; /* associated function's addr */ size_t ftp_fsize; /* associated function's size */ - fasttrap_probe_type_t ftp_type; /* type of probe */ - uint_t ftp_enabled; /* is this probe enabled */ uint64_t ftp_gen; /* modification generation */ uint64_t ftp_ntps; /* number of tracepoints */ uint8_t *ftp_argmap; /* native to translated args */ uint8_t ftp_nargs; /* translated argument count */ + uint8_t ftp_enabled; /* is this probe enabled */ char *ftp_xtypes; /* translated types index */ char *ftp_ntypes; /* native types index */ fasttrap_id_tp_t ftp_tps[1]; /* flexible array */ @@ -125,26 +125,26 @@ struct fasttrap_probe { &(id)->fti_probe->ftp_tps[0]) struct fasttrap_tracepoint { - fasttrap_proc_t *ftt_proc; /* associated process struct */ - uintptr_t ftt_pc; /* address of tracepoint */ - pid_t ftt_pid; /* pid of tracepoint */ - fasttrap_machtp_t ftt_mtp; /* ISA-specific portion */ - fasttrap_id_t *ftt_ids; /* NULL-terminated list */ - fasttrap_id_t *ftt_retids; /* NULL-terminated list */ - fasttrap_tracepoint_t *ftt_next; /* link in global hash */ + fasttrap_proc_t *ftt_proc; /* associated process struct */ + uintptr_t ftt_pc; /* address of tracepoint */ + pid_t ftt_pid; /* pid of tracepoint */ + fasttrap_machtp_t ftt_mtp; /* ISA-specific portion */ + fasttrap_id_t *ftt_ids; /* NULL-terminated list */ + fasttrap_id_t *ftt_retids; /* NULL-terminated list */ + fasttrap_tracepoint_t *ftt_next; /* link in global hash */ }; typedef struct fasttrap_bucket { - kmutex_t ftb_mtx; - void *ftb_data; + kmutex_t ftb_mtx; /* bucket lock */ + void *ftb_data; /* data payload */ - uint8_t ftb_pad[64 - sizeof (kmutex_t) - sizeof (void *)]; + uint8_t ftb_pad[64 - sizeof (kmutex_t) - sizeof (void *)]; } fasttrap_bucket_t; typedef struct fasttrap_hash { - ulong_t fth_nent; - ulong_t fth_mask; - fasttrap_bucket_t *fth_table; + ulong_t fth_nent; /* power-of-2 num. of entries */ + ulong_t fth_mask; /* fth_nent - 1 */ + fasttrap_bucket_t *fth_table; /* array of buckets */ } fasttrap_hash_t; /* @@ -170,8 +170,8 @@ extern fasttrap_hash_t fasttrap_tpoints; /* * Must be implemented by fasttrap_isa.c */ -extern int fasttrap_tracepoint_init(proc_t *, fasttrap_probe_t *, - fasttrap_tracepoint_t *, uintptr_t); +extern int fasttrap_tracepoint_init(proc_t *, fasttrap_tracepoint_t *, + uintptr_t, fasttrap_probe_type_t); extern int fasttrap_tracepoint_install(proc_t *, fasttrap_tracepoint_t *); extern int fasttrap_tracepoint_remove(proc_t *, fasttrap_tracepoint_t *); diff --git a/usr/src/uts/intel/dtrace/fasttrap_isa.c b/usr/src/uts/intel/dtrace/fasttrap_isa.c index bf2ab2f6c6..4be5fab23e 100644 --- a/usr/src/uts/intel/dtrace/fasttrap_isa.c +++ b/usr/src/uts/intel/dtrace/fasttrap_isa.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -19,8 +18,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -41,10 +41,10 @@ * Lossless User-Land Tracing on x86 * --------------------------------- * - * Most instructions' execution is not dependent on their address; for these - * instrutions it is sufficient to copy them into the user process's address - * space and execute them. To effectively single-step an instruction in - * user-land, we copy out the following sequence of instructions to scratch + * The execution of most instructions is not dependent on the address; for + * these instructions it is sufficient to copy them into the user process's + * address space and execute them. To effectively single-step an instruction + * in user-land, we copy out the following sequence of instructions to scratch * space in the user thread's ulwp_t structure. * * We then set the program counter (%eip or %rip) to point to this scratch @@ -222,8 +222,8 @@ fasttrap_anarg(struct regs *rp, int function_entry, int argno) /*ARGSUSED*/ int -fasttrap_tracepoint_init(proc_t *p, fasttrap_probe_t *probe, - fasttrap_tracepoint_t *tp, uintptr_t pc) +fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, uintptr_t pc, + fasttrap_probe_type_t type) { uint8_t instr[FASTTRAP_MAX_INSTR_SIZE + 10]; size_t len = FASTTRAP_MAX_INSTR_SIZE; @@ -737,6 +737,7 @@ fasttrap_pid_probe(struct regs *rp) fasttrap_tracepoint_t *tp, tp_local; pid_t pid; dtrace_icookie_t cookie; + uint_t is_enabled = 0; /* * It's possible that a user (in a veritable orgy of bad planning) @@ -809,7 +810,7 @@ fasttrap_pid_probe(struct regs *rp) for (id = tp->ftt_ids; id != NULL; id = id->fti_next) { fasttrap_probe_t *probe = id->fti_probe; - if (probe->ftp_type == DTFTP_ENTRY) { + if (id->fti_ptype == DTFTP_ENTRY) { /* * We note that this was an entry * probe to help ustack() find the @@ -822,6 +823,15 @@ fasttrap_pid_probe(struct regs *rp) rp->r_r8); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_ENTRY); dtrace_interrupt_enable(cookie); + } else if (id->fti_ptype == DTFTP_IS_ENABLED) { + /* + * Note that in this case, we don't + * call dtrace_probe() since it's only + * an artificial probe meant to change + * the flow of control so that it + * encounters the true probe. + */ + is_enabled = 1; } else if (probe->ftp_argmap == NULL) { dtrace_probe(probe->ftp_id, rp->r_rdi, rp->r_rsi, rp->r_rdx, rp->r_rcx, @@ -858,7 +868,7 @@ fasttrap_pid_probe(struct regs *rp) for (id = tp->ftt_ids; id != NULL; id = id->fti_next) { fasttrap_probe_t *probe = id->fti_probe; - if (probe->ftp_type == DTFTP_ENTRY) { + if (id->fti_ptype == DTFTP_ENTRY) { /* * We note that this was an entry * probe to help ustack() find the @@ -870,6 +880,15 @@ fasttrap_pid_probe(struct regs *rp) s3, s4, s5); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_ENTRY); dtrace_interrupt_enable(cookie); + } else if (id->fti_ptype == DTFTP_IS_ENABLED) { + /* + * Note that in this case, we don't + * call dtrace_probe() since it's only + * an artificial probe meant to change + * the flow of control so that it + * encounters the true probe. + */ + is_enabled = 1; } else if (probe->ftp_argmap == NULL) { dtrace_probe(probe->ftp_id, s0, s1, s2, s3, s4); @@ -904,6 +923,29 @@ fasttrap_pid_probe(struct regs *rp) */ rp->r_pc = pc + tp->ftt_size; + /* + * If there's an is-enabled probe connected to this tracepoint it + * means that there was a 'xorl %eax, %eax' or 'xorq %rax, %rax' + * instruction that was placed there by DTrace when the binary was + * linked. As this probe is, in fact, enabled, we need to stuff 1 + * into %eax or %rax. Accordingly, we can bypass all the instruction + * emulation logic since we know the inevitable result. It's possible + * that a user could construct a scenario where the 'is-enabled' + * probe was on some other instruction, but that would be a rather + * exotic way to shoot oneself in the foot. + */ + if (is_enabled) { + rp->r_r0 = 1; + new_pc = rp->r_pc; + goto done; + } + + /* + * We emulate certain types of instructions to ensure correctness + * (in the case of position dependent instructions) or optimize + * common cases. The rest we have the thread execute back in user- + * land. + */ switch (tp->ftt_type) { case FASTTRAP_T_RET: case FASTTRAP_T_RET16: @@ -1393,6 +1435,7 @@ fasttrap_pid_probe(struct regs *rp) panic("fasttrap: mishandled an instruction"); } +done: /* * If there were no return probes when we first found the tracepoint, * we should feel no obligation to honor any return probes that were diff --git a/usr/src/uts/sparc/dtrace/fasttrap_isa.c b/usr/src/uts/sparc/dtrace/fasttrap_isa.c index d84b208650..93d627adb7 100644 --- a/usr/src/uts/sparc/dtrace/fasttrap_isa.c +++ b/usr/src/uts/sparc/dtrace/fasttrap_isa.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -21,7 +20,7 @@ */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -309,7 +308,7 @@ fasttrap_return_common(struct regs *rp, uintptr_t pc, pid_t pid, for (id = tp->ftt_retids; id != NULL; id = id->fti_next) { fasttrap_probe_t *probe = id->fti_probe; - if (probe->ftp_type == DTFTP_POST_OFFSETS) { + if (id->fti_ptype == DTFTP_POST_OFFSETS) { if (probe->ftp_argmap == NULL) { dtrace_probe(probe->ftp_id, rp->r_o0, rp->r_o1, rp->r_o2, rp->r_o3, rp->r_o4); @@ -394,7 +393,7 @@ fasttrap_pid_probe(struct regs *rp) uintptr_t orig_pc = pc; fasttrap_bucket_t *bucket; kmutex_t *pid_mtx; - uint_t fake_restore = 0; + uint_t fake_restore = 0, is_enabled = 0; dtrace_icookie_t cookie; /* @@ -453,12 +452,18 @@ fasttrap_pid_probe(struct regs *rp) for (id = tp->ftt_ids; id != NULL; id = id->fti_next) { fasttrap_probe_t *probe = id->fti_probe; - int isentry; + int isentry = (id->fti_ptype == DTFTP_ENTRY); + + if (id->fti_ptype == DTFTP_IS_ENABLED) { + is_enabled = 1; + continue; + } + /* * We note that this was an entry probe to help ustack() find * the first caller. */ - if ((isentry = (probe->ftp_type == DTFTP_ENTRY)) != 0) { + if (isentry) { cookie = dtrace_interrupt_disable(); DTRACE_CPUFLAG_SET(CPU_DTRACE_ENTRY); } @@ -480,7 +485,25 @@ fasttrap_pid_probe(struct regs *rp) tp = &tp_local; /* - * We emulate certain types of instructions do ensure correctness + * If there's an is-enabled probe conntected to this tracepoint it + * means that there was a 'mov %g0, %o0' instruction that was placed + * there by DTrace when the binary was linked. As this probe is, in + * fact, enabled, we need to stuff 1 into %o0. Accordingly, we can + * bypass all the instruction emulation logic since we know the + * inevitable result. It's possible that a user could construct a + * scenario where the 'is-enabled' probe was on some other + * instruction, but that would be a rather exotic way to shoot oneself + * in the foot. + */ + if (is_enabled) { + rp->r_o0 = 1; + pc = rp->r_npc; + npc = pc + 4; + goto done; + } + + /* + * We emulate certain types of instructions to ensure correctness * (in the case of position dependent instructions) or optimize * common cases. The rest we have the thread execute back in user- * land. @@ -928,6 +951,7 @@ fasttrap_pid_probe(struct regs *rp) ASSERT(pc != rp->r_g7 + 4); ASSERT(pc != rp->r_g7 + 8); +done: /* * If there were no return probes when we first found the tracepoint, * we should feel no obligation to honor any return probes that were @@ -1029,8 +1053,8 @@ fasttrap_tracepoint_remove(proc_t *p, fasttrap_tracepoint_t *tp) } int -fasttrap_tracepoint_init(proc_t *p, fasttrap_probe_t *probe, - fasttrap_tracepoint_t *tp, uintptr_t pc) +fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, uintptr_t pc, + fasttrap_probe_type_t type) { uint32_t instr; int32_t disp; @@ -1224,7 +1248,7 @@ fasttrap_tracepoint_init(proc_t *p, fasttrap_probe_t *probe, * (near FASTTRAP_T_SAVE) for details. */ if (fasttrap_optimize_save != 0 && - probe->ftp_type == DTFTP_ENTRY && + type == DTFTP_ENTRY && I(instr) == 1 && RD(instr) == R_SP) tp->ftt_type = FASTTRAP_T_SAVE; break; |